* TCPCT API update for 2.6.37
@ 2011-01-08 21:36 William Allen Simpson
2011-01-08 22:07 ` [PATCH v1] TCPCT socket API update to draft -02 William Allen Simpson
2011-01-10 17:48 ` [PATCH v1] TCPCT sysctl " William Allen Simpson
0 siblings, 2 replies; 3+ messages in thread
From: William Allen Simpson @ 2011-01-08 21:36 UTC (permalink / raw)
To: Linux Kernel Network Developers
With the recent flurry of messages related to TCPCT, I devoted a nice
snowy Saturday afternoon to updating the socket option code. Linux is
rather fair behind on TCPCT implementation, so this will help with
future software compatibility.
I'm not on this list, so anybody with comments should CC me. Thanks.
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v1] TCPCT socket API update to draft -02
2011-01-08 21:36 TCPCT API update for 2.6.37 William Allen Simpson
@ 2011-01-08 22:07 ` William Allen Simpson
2011-01-10 17:48 ` [PATCH v1] TCPCT sysctl " William Allen Simpson
1 sibling, 0 replies; 3+ messages in thread
From: William Allen Simpson @ 2011-01-08 22:07 UTC (permalink / raw)
To: Linux Kernel Network Developers
[-- Attachment #1: Type: text/plain, Size: 581 bytes --]
Use most recently specified symbols of RFC-to-be-6013.
Permit setting either cookie or s_data or both (sequentially).
Allows different s_data limits for SYN and SYN_ACK.
Split the data value from socket option header, saving more than
1K of stack space in the handler by copying long data values
directly from user space into the kref block.
Signed-off-by: William.Allen.Simpson@gmail.com
---
include/linux/tcp.h | 35 ++++++++++++++++-----
net/ipv4/tcp.c | 86 ++++++++++++++++++++++++++++++++++++--------------
2 files changed, 89 insertions(+), 32 deletions(-)
[-- Attachment #2: TCPCT+API-02v1+2.6.37.patch --]
[-- Type: text/plain, Size: 7093 bytes --]
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index e64f4c6..ddfdd26 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -184,23 +184,42 @@ struct tcp_md5sig {
#define TCP_COOKIE_MAX 16 /* 128-bits */
#define TCP_COOKIE_PAIR_SIZE (2*TCP_COOKIE_MAX)
+/* Implementation-specific data limits */
+#define TCP_SYN_DATA_LIMIT (TCP_MSS_DEFAULT - sizeof(struct tcphdr))
+#define TCP_SYN_ACK_DATA_LIMIT (TCP_MSS_DESIRED)
+
/* Flags for both getsockopt and setsockopt */
-#define TCP_COOKIE_IN_ALWAYS (1 << 0) /* Discard SYN without cookie */
-#define TCP_COOKIE_OUT_NEVER (1 << 1) /* Prohibit outgoing cookies,
+#define TCPCT_IN_ALWAYS (1 << 0) /* Discard SYN without cookie */
+#define TCPCT_OUT_NEVER (1 << 1) /* Prohibit outgoing cookies,
* supercedes everything. */
-
-/* Flags for getsockopt */
-#define TCP_S_DATA_IN (1 << 2) /* Was data received? */
-#define TCP_S_DATA_OUT (1 << 3) /* Was data sent? */
-
-/* TCP_COOKIE_TRANSACTIONS data */
+#define TCPCT_IN_DATA (1 << 2) /* Was data received? */
+#define TCPCT_OUT_DATA (1 << 3) /* Was data sent? */
+/* reserved for future use: bits 4 .. 6 */
+#define TCPCT_EXTEND (1 << 7)
+
+/* Extended Option flags for both getsockopt and setsockopt */
+#define TCPCT_EXTEND_SIZE (0x7) /* mask */
+#define TCPCT_EXTEND_TS32 (0x1) /* default */
+#define TCPCT_EXTEND_TS64 (0x2)
+#define TCPCT_EXTEND_TS128 (0x4)
+
+/* TCP_COOKIE_TRANSACTIONS socket option header */
struct tcp_cookie_transactions {
__u16 tcpct_flags; /* see above */
- __u8 __tcpct_pad1; /* zero */
+ __u8 tcpct_extended;
__u8 tcpct_cookie_desired; /* bytes */
__u16 tcpct_s_data_desired; /* bytes of variable data */
__u16 tcpct_used; /* bytes in value */
- __u8 tcpct_value[TCP_MSS_DEFAULT];
+};
+
+struct tcpct_full {
+ struct tcp_cookie_transactions soh;
+ __u8 tcpct_value[TCP_COOKIE_PAIR_SIZE];
+};
+
+struct tcpct_half {
+ struct tcp_cookie_transactions soh;
+ __u8 tcpct_value[TCP_COOKIE_MAX];
};
#ifdef __KERNEL__
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 6c11eec..28dd6a1 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2143,16 +2143,13 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
case TCP_COOKIE_TRANSACTIONS: {
struct tcp_cookie_transactions ctd;
struct tcp_cookie_values *cvp = NULL;
+ int s_data_used = 0;
if (sizeof(ctd) > optlen)
return -EINVAL;
if (copy_from_user(&ctd, optval, sizeof(ctd)))
return -EFAULT;
- if (ctd.tcpct_used > sizeof(ctd.tcpct_value) ||
- ctd.tcpct_s_data_desired > TCP_MSS_DESIRED)
- return -EINVAL;
-
if (ctd.tcpct_cookie_desired == 0) {
/* default to global value */
} else if ((0x1 & ctd.tcpct_cookie_desired) ||
@@ -2161,7 +2158,33 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
return -EINVAL;
}
- if (TCP_COOKIE_OUT_NEVER & ctd.tcpct_flags) {
+ if (ctd.tcpct_used > 0) {
+ if (ctd.tcpct_used + sizeof(ctd) > optlen)
+ return -EINVAL;
+ if (TCPCT_OUT_DATA & ctd.tcpct_flags) {
+ if (ctd.tcpct_used > TCP_SYN_ACK_DATA_LIMIT)
+ return -EINVAL;
+ if (ctd.tcpct_s_data_desired > 0)
+ return -EINVAL;
+ s_data_used = ctd.tcpct_used;
+ } else {
+ if (ctd.tcpct_used > TCP_COOKIE_PAIR_SIZE)
+ return -EINVAL;
+ if (ctd.tcpct_used !=
+ ctd.tcpct_cookie_desired &&
+ ctd.tcpct_used !=
+ ctd.tcpct_cookie_desired * 2)
+ return -EINVAL;
+ if (ctd.tcpct_s_data_desired >
+ TCP_SYN_DATA_LIMIT)
+ return -EINVAL;
+ }
+ } else if (TCPCT_OUT_DATA & ctd.tcpct_flags) {
+ /* unexpected flag without s_data */
+ return -EINVAL;
+ }
+
+ if (TCPCT_OUT_NEVER & ctd.tcpct_flags) {
/* Supercedes all other values */
lock_sock(sk);
if (tp->cookie_values != NULL) {
@@ -2177,12 +2200,12 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
/* Allocate ancillary memory before locking.
*/
- if (ctd.tcpct_used > 0 ||
+ if (s_data_used > 0 ||
(tp->cookie_values == NULL &&
(sysctl_tcp_cookie_size > 0 ||
ctd.tcpct_cookie_desired > 0 ||
ctd.tcpct_s_data_desired > 0))) {
- cvp = kzalloc(sizeof(*cvp) + ctd.tcpct_used,
+ cvp = kzalloc(sizeof(*cvp) + s_data_used,
GFP_KERNEL);
if (cvp == NULL)
return -ENOMEM;
@@ -2191,7 +2214,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
}
lock_sock(sk);
tp->rx_opt.cookie_in_always =
- (TCP_COOKIE_IN_ALWAYS & ctd.tcpct_flags);
+ (TCPCT_IN_ALWAYS & ctd.tcpct_flags);
tp->rx_opt.cookie_out_never = 0; /* false */
if (tp->cookie_values != NULL) {
@@ -2210,11 +2233,26 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
if (cvp != NULL) {
cvp->cookie_desired = ctd.tcpct_cookie_desired;
- if (ctd.tcpct_used > 0) {
- memcpy(cvp->s_data_payload, ctd.tcpct_value,
- ctd.tcpct_used);
- cvp->s_data_desired = ctd.tcpct_used;
+ if (s_data_used > 0) {
+ if (copy_from_user(cvp->s_data_payload,
+ optval + sizeof(ctd),
+ s_data_used)) {
+ kref_put(&cvp->kref,
+ tcp_cookie_values_release);
+ return -EFAULT;
+ }
+ cvp->s_data_desired = s_data_used;
cvp->s_data_constant = 1; /* true */
+ } else if (ctd.tcpct_used > 0) {
+ if (copy_from_user(cvp->cookie_pair,
+ optval + sizeof(ctd),
+ ctd.tcpct_used)) {
+ kref_put(&cvp->kref,
+ tcp_cookie_values_release);
+ return -EFAULT;
+ }
+ cvp->s_data_desired = ctd.tcpct_s_data_desired;
+ cvp->s_data_constant = 0; /* false */
} else {
/* No constant payload data. */
cvp->s_data_desired = ctd.tcpct_s_data_desired;
@@ -2574,7 +2612,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
return 0;
case TCP_COOKIE_TRANSACTIONS: {
- struct tcp_cookie_transactions ctd;
+ struct tcpct_full ctd;
struct tcp_cookie_values *cvp = tp->cookie_values;
if (get_user(len, optlen))
@@ -2583,23 +2621,23 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
return -EINVAL;
memset(&ctd, 0, sizeof(ctd));
- ctd.tcpct_flags = (tp->rx_opt.cookie_in_always ?
- TCP_COOKIE_IN_ALWAYS : 0)
- | (tp->rx_opt.cookie_out_never ?
- TCP_COOKIE_OUT_NEVER : 0);
+ ctd.soh.tcpct_flags = (tp->rx_opt.cookie_in_always ?
+ TCPCT_IN_ALWAYS : 0)
+ | (tp->rx_opt.cookie_out_never ?
+ TCPCT_OUT_NEVER : 0);
if (cvp != NULL) {
- ctd.tcpct_flags |= (cvp->s_data_in ?
- TCP_S_DATA_IN : 0)
- | (cvp->s_data_out ?
- TCP_S_DATA_OUT : 0);
+ ctd.soh.tcpct_flags |= (cvp->s_data_in ?
+ TCPCT_IN_DATA : 0)
+ | (cvp->s_data_out ?
+ TCPCT_OUT_DATA : 0);
- ctd.tcpct_cookie_desired = cvp->cookie_desired;
- ctd.tcpct_s_data_desired = cvp->s_data_desired;
+ ctd.soh.tcpct_cookie_desired = cvp->cookie_desired;
+ ctd.soh.tcpct_s_data_desired = cvp->s_data_desired;
memcpy(&ctd.tcpct_value[0], &cvp->cookie_pair[0],
cvp->cookie_pair_size);
- ctd.tcpct_used = cvp->cookie_pair_size;
+ ctd.soh.tcpct_used = cvp->cookie_pair_size;
}
if (put_user(sizeof(ctd), optlen))
--
1.7.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH v1] TCPCT sysctl API update to draft -02
2011-01-08 21:36 TCPCT API update for 2.6.37 William Allen Simpson
2011-01-08 22:07 ` [PATCH v1] TCPCT socket API update to draft -02 William Allen Simpson
@ 2011-01-10 17:48 ` William Allen Simpson
1 sibling, 0 replies; 3+ messages in thread
From: William Allen Simpson @ 2011-01-10 17:48 UTC (permalink / raw)
To: Linux Kernel Network Developers
Cc: Eric W. Biederman, Stephen Hemminger, Andi Kleen
[-- Attachment #1: Type: text/plain, Size: 636 bytes --]
Circa 15 months ago, my first submitted patch was a sysctl, and there was a
conflict that appeared in a later merge of trees. Experts, am I in the right
ballpark this time around?
Later, I'll submit the manpage patch to linux-man@vger.kernel.org too.
===
Use most recently specified symbols of RFC-to-be-6013.
Allows different global s_data limits for SYN and SYN_ACK.
Signed-off-by: William.Allen.Simpson@gmail.com
---
include/net/tcp.h | 2 ++
net/ipv4/sysctl_net_ipv4.c | 25 ++++++++++++++++++++++++-
net/ipv4/tcp_output.c | 19 +++++++++++++++++--
3 files changed, 43 insertions(+), 3 deletions(-)
[-- Attachment #2: TCPCT+API-02u1+2.6.37.patch --]
[-- Type: text/plain, Size: 3327 bytes --]
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 38509f0..3ac2bca 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -241,6 +241,8 @@ extern int sysctl_tcp_workaround_signed_windows;
extern int sysctl_tcp_slow_start_after_idle;
extern int sysctl_tcp_max_ssthresh;
extern int sysctl_tcp_cookie_size;
+extern int sysctl_tcp_syn_data_limit;
+extern int sysctl_tcp_syn_ack_data_limit;
extern int sysctl_tcp_thin_linear_timeouts;
extern int sysctl_tcp_thin_dupack;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 1a45665..629f90b 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -30,6 +30,9 @@ static int tcp_adv_win_scale_min = -31;
static int tcp_adv_win_scale_max = 31;
static int ip_ttl_min = 1;
static int ip_ttl_max = 255;
+static int tcp_cookie_max = TCP_COOKIE_MAX;
+static int tcp_syn_data_max = TCP_MSS_DEFAULT - 40;
+static int tcp_syn_ack_data_max = TCP_MSS_DESIRED;
/* Update system visible IP port range */
static void set_local_port_range(int range[2])
@@ -588,7 +591,27 @@ static struct ctl_table ipv4_table[] = {
.data = &sysctl_tcp_cookie_size,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = proc_dointvec
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &tcp_cookie_max,
+ },
+ {
+ .procname = "tcp_syn_data_limit",
+ .data = &sysctl_tcp_syn_data_limit,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &tcp_syn_data_max,
+ },
+ {
+ .procname = "tcp_syn_ack_data_limit",
+ .data = &sysctl_tcp_syn_ack_data_limit,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &tcp_syn_ack_data_max,
},
{
.procname = "tcp_thin_linear_timeouts",
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index dc7c096..3bd3da5 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -63,6 +63,15 @@ int sysctl_tcp_slow_start_after_idle __read_mostly = 1;
int sysctl_tcp_cookie_size __read_mostly = 0; /* TCP_COOKIE_MAX */
EXPORT_SYMBOL_GPL(sysctl_tcp_cookie_size);
+int sysctl_tcp_syn_data_limit __read_mostly = TCP_MSS_DEFAULT - 40;
+EXPORT_SYMBOL_GPL(sysctl_tcp_syn_data_limit);
+
+/* As a matter of security policy, keep the initial setting small for most
+ * client systems to avoid their use in amplification DoS attacks.
+ */
+int sysctl_tcp_syn_ack_data_limit __read_mostly = 80; /* TCP_MSS_DESIRED */
+EXPORT_SYMBOL_GPL(sysctl_tcp_syn_ack_data_limit);
+
/* Account for new data that has been sent to the network. */
static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb)
@@ -2418,10 +2427,16 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
struct tcp_md5sig_key *md5;
int tcp_header_size;
int mss;
- int s_data_desired = 0;
+ int s_data_desired;
- if (cvp != NULL && cvp->s_data_constant && cvp->s_data_desired)
+ if (cvp != NULL &&
+ cvp->s_data_constant &&
+ cvp->s_data_desired > 0 &&
+ cvp->s_data_desired <= sysctl_tcp_syn_ack_data_limit)
s_data_desired = cvp->s_data_desired;
+ else
+ s_data_desired = 0;
+
skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15 + s_data_desired, 1, GFP_ATOMIC);
if (skb == NULL)
return NULL;
--
1.7.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2011-01-10 17:48 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-01-08 21:36 TCPCT API update for 2.6.37 William Allen Simpson
2011-01-08 22:07 ` [PATCH v1] TCPCT socket API update to draft -02 William Allen Simpson
2011-01-10 17:48 ` [PATCH v1] TCPCT sysctl " William Allen Simpson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).