From: Lennert Buytenhek <buytenh@gnu.org>
To: netdev@oss.sgi.com
Subject: [PATCH,RFC] explicit connection confirmation
Date: Thu, 7 Nov 2002 04:32:08 -0500 [thread overview]
Message-ID: <20021107093207.GA30666@gnu.org> (raw)
(please CC on replies, I am not on this list)
Hi,
This patch gives userland the ability to decide whether to react
with an incoming TCP SYN with a SYN-ACK or a RST. It was hacked
up after Linux Kongress 2001 and has been sitting on my patch
pile since april this year or something.
The basic idea is this:
- Put the listening TCP socket in TCP_CONFIRM_CONNECT mode.
- Sockets returned from accept() on this socket after this will be
sockets in the SYN_RECV state instead of the ESTABLISHED state
(unless syncookies had to be used). By writing to the socket,
you cause a SYN-ACK to be sent, and by immediately closing the
socket you cause a RST to be sent.
There are two issues left, AFAICS:
- SYN_RECV sockets currently don't time out for some reason
- it deadlocks instantly on SMP
It's against 2.4.18. Could someone have a look at it please? I
unfortunately haven't had any time at all lately, so I would be
really happy if someone else could take this over. (Well, I can
dream, can't I?)
cheers,
Lennert
--- linux-2.4.18-11umpr/include/linux/tcp.h.orig Thu Nov 22 20:47:11 2001
+++ linux-2.4.18-11umpr/include/linux/tcp.h Thu Apr 18 19:33:19 2002
@@ -127,6 +127,7 @@
#define TCP_WINDOW_CLAMP 10 /* Bound advertised window */
#define TCP_INFO 11 /* Information about this connection. */
#define TCP_QUICKACK 12 /* Block/reenable quick acks */
+#define TCP_CONFIRM_CONNECT 13 /* Let user control connection acceptance */
#define TCPI_OPT_TIMESTAMPS 1
#define TCPI_OPT_SACK 2
--- linux-2.4.18-11umpr/include/net/sock.h.orig Fri Dec 21 18:42:04 2001
+++ linux-2.4.18-11umpr/include/net/sock.h Thu Apr 18 19:37:52 2002
@@ -302,6 +302,7 @@
__u8 reordering; /* Packet reordering metric. */
__u8 queue_shrunk; /* Write queue has been shrunk recently.*/
__u8 defer_accept; /* User waits for some data after accept() */
+ __u8 confirm_connect;/* User wants control over conn. acceptance */
/* RTT measurement */
__u8 backoff; /* backoff */
@@ -411,6 +412,11 @@
struct open_request *accept_queue;
struct open_request *accept_queue_tail;
+ /* Our corresponding open_request if this socket is unconfirmed
+ * (i.e. if we haven't sent SYN-ACK or RST yet)
+ */
+ struct open_request *unconfirmed_openreq;
+
int write_pending; /* A write to socket waits to start. */
unsigned int keepalive_time; /* time before keep alive takes place */
--- linux-2.4.18-11umpr/include/net/tcp.h.orig Thu Nov 22 20:47:22 2001
+++ linux-2.4.18-11umpr/include/net/tcp.h Fri Apr 19 10:42:51 2002
@@ -505,7 +505,8 @@
sack_ok : 1,
wscale_ok : 1,
ecn_ok : 1,
- acked : 1;
+ acked : 1,
+ unconfirmed : 1;
/* The following two fields can be easily recomputed I think -AK */
__u32 window_clamp; /* window clamp at creation time */
__u32 rcv_wnd; /* rcv_wnd offered first time */
@@ -533,6 +534,17 @@
tcp_openreq_fastfree(req);
}
+static inline int tcp_is_unconfirmed(struct tcp_opt *tp)
+{
+ struct open_request *req;
+
+ req = tp->unconfirmed_openreq;
+ if (req != NULL && req->unconfirmed)
+ return 1;
+
+ return 0;
+}
+
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#define TCP_INET_FAMILY(fam) ((fam) == AF_INET)
#else
@@ -1661,6 +1673,7 @@
req->acked = 0;
req->ecn_ok = 0;
req->rmt_port = skb->h.th->source;
+ req->unconfirmed = 0;
}
#define TCP_MEM_QUANTUM ((int)PAGE_SIZE)
--- linux-2.4.18-11umpr/net/ipv4/tcp.c.orig Fri Dec 21 18:42:05 2001
+++ linux-2.4.18-11umpr/net/ipv4/tcp.c Fri Apr 19 20:50:29 2002
@@ -204,6 +204,7 @@
* Andi Kleen : Make poll agree with SIGIO
* Salvatore Sanfilippo : Support SO_LINGER with linger == 1 and
* lingertime == 0 (RFC 793 ABORT Call)
+ * Lennert Buytenhek : Explicit connection confirmation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -366,6 +367,15 @@
return sk->tp_pinfo.af_tcp.accept_queue ? (POLLIN | POLLRDNORM) : 0;
}
+static void tcp_confirm(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct open_request *req = tp->unconfirmed_openreq;
+
+ req->unconfirmed = 0;
+ req->class->rtx_syn_ack(sk, req, NULL);
+}
+
/*
* Wait for a TCP event.
*
@@ -650,6 +660,9 @@
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
+ if (tcp_is_unconfirmed(tp))
+ tcp_confirm(sk);
+
while((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {
if(sk->err)
return sock_error(sk);
@@ -1814,7 +1827,7 @@
void tcp_close(struct sock *sk, long timeout)
{
struct sk_buff *skb;
- int data_was_unread = 0;
+ int should_send_rst = 0;
lock_sock(sk);
sk->shutdown = SHUTDOWN_MASK;
@@ -1834,12 +1847,19 @@
*/
while((skb=__skb_dequeue(&sk->receive_queue))!=NULL) {
u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq - skb->h.th->fin;
- data_was_unread += len;
+ should_send_rst += len;
__kfree_skb(skb);
}
tcp_mem_reclaim(sk);
+ if (sk->tp_pinfo.af_tcp.unconfirmed_openreq != NULL) {
+ if (tcp_is_unconfirmed(&(sk->tp_pinfo.af_tcp)))
+ should_send_rst = 1;
+ tcp_openreq_free(sk->tp_pinfo.af_tcp.unconfirmed_openreq);
+ sk->tp_pinfo.af_tcp.unconfirmed_openreq = NULL;
+ }
+
/* As outlined in draft-ietf-tcpimpl-prob-03.txt, section
* 3.10, we send a RST here because data was lost. To
* witness the awful effects of the old behavior of always
@@ -1849,7 +1869,7 @@
* the FTP client, wheee... Note: timeout is always zero
* in such a case.
*/
- if(data_was_unread != 0) {
+ if(should_send_rst) {
/* Unread data was tossed, zap the connection. */
NET_INC_STATS_USER(TCPAbortOnClose);
tcp_set_state(sk, TCP_CLOSE);
@@ -2026,6 +2046,11 @@
#endif
}
+ if (tp->unconfirmed_openreq) {
+ tcp_openreq_free(tp->unconfirmed_openreq);
+ tp->unconfirmed_openreq = NULL;
+ }
+
sk->shutdown = 0;
sk->done = 0;
tp->srtt = 0;
@@ -2139,8 +2164,10 @@
newsk = req->sk;
tcp_acceptq_removed(sk);
- tcp_openreq_fastfree(req);
- BUG_TRAP(newsk->state != TCP_SYN_RECV);
+ if (newsk->tp_pinfo.af_tcp.unconfirmed_openreq == NULL)
+ tcp_openreq_fastfree(req);
+ BUG_TRAP(newsk->tp_pinfo.af_tcp.unconfirmed_openreq ||
+ newsk->state != TCP_SYN_RECV);
release_sock(sk);
return newsk;
@@ -2305,6 +2332,10 @@
}
break;
+ case TCP_CONFIRM_CONNECT:
+ tp->confirm_connect = !!val;
+ break;
+
default:
err = -ENOPROTOOPT;
break;
@@ -2429,6 +2460,9 @@
case TCP_QUICKACK:
val = !tp->ack.pingpong;
break;
+ case TCP_CONFIRM_CONNECT:
+ val = tp->confirm_connect || tcp_is_unconfirmed(tp);
+ break;
default:
return -ENOPROTOOPT;
};
--- linux-2.4.18-11umpr/net/ipv4/tcp_input.c.orig Mon Feb 25 20:38:14 2002
+++ linux-2.4.18-11umpr/net/ipv4/tcp_input.c Fri Apr 19 10:52:27 2002
@@ -3749,6 +3749,11 @@
switch(sk->state) {
case TCP_SYN_RECV:
if (acceptable) {
+ if (tp->unconfirmed_openreq != NULL) {
+ tcp_openreq_free(tp->unconfirmed_openreq);
+ tp->unconfirmed_openreq = NULL;
+ }
+
tp->copied_seq = tp->rcv_nxt;
mb();
tcp_set_state(sk, TCP_ESTABLISHED);
--- linux-2.4.18-11umpr/net/ipv4/tcp_minisocks.c.orig Mon Oct 1 18:19:57 2001
+++ linux-2.4.18-11umpr/net/ipv4/tcp_minisocks.c Fri Apr 19 10:24:22 2002
@@ -696,6 +696,7 @@
tcp_init_wl(newtp, req->snt_isn, req->rcv_isn);
newtp->retransmits = 0;
+ newtp->confirm_connect = 0;
newtp->backoff = 0;
newtp->srtt = 0;
newtp->mdev = TCP_TIMEOUT_INIT;
@@ -839,7 +840,8 @@
* Enforce "SYN-ACK" according to figure 8, figure 6
* of RFC793, fixed by RFC1122.
*/
- req->class->rtx_syn_ack(sk, req, NULL);
+ if (!req->unconfirmed)
+ req->class->rtx_syn_ack(sk, req, NULL);
return NULL;
}
@@ -864,7 +866,7 @@
if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
req->rcv_isn+1, req->rcv_isn+1+req->rcv_wnd)) {
/* Out of window: send ACK and drop. */
- if (!(flg & TCP_FLAG_RST))
+ if (!req->unconfirmed && !(flg & TCP_FLAG_RST))
req->class->send_ack(skb, req);
if (paws_reject)
NET_INC_STATS_BH(PAWSEstabRejected);
@@ -907,6 +909,12 @@
return NULL;
}
+ /* @@@ If we are in SYN_RECV and haven't confirmed/rejected
+ * the connection yet, this ACK is acking a never-sent packet.
+ */
+ if (tcp_is_unconfirmed(tp))
+ return NULL;
+
/* OK, ACK is valid, create big socket and
* feed this segment to it. It will repeat all
* the tests. THIS SEGMENT MUST MOVE SOCKET TO
--- linux-2.4.18-11umpr/net/ipv4/tcp_ipv4.c.orig Mon Feb 25 20:38:14 2002
+++ linux-2.4.18-11umpr/net/ipv4/tcp_ipv4.c Fri Apr 19 18:56:45 2002
@@ -1270,12 +1270,14 @@
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
+ struct tcp_opt *master_tp = &(sk->tp_pinfo.af_tcp);
struct tcp_opt tp;
struct open_request *req;
__u32 saddr = skb->nh.iph->saddr;
__u32 daddr = skb->nh.iph->daddr;
__u32 isn = TCP_SKB_CB(skb)->when;
struct dst_entry *dst = NULL;
+ int dont_confirm = 0;
#ifdef CONFIG_SYN_COOKIES
int want_cookie = 0;
#else
@@ -1312,6 +1314,9 @@
if (req == NULL)
goto drop;
+ if (!want_cookie && master_tp->confirm_connect)
+ dont_confirm = 1;
+
tcp_clear_options(&tp);
tp.mss_clamp = 536;
tp.user_mss = sk->tp_pinfo.af_tcp.user_mss;
@@ -1396,11 +1401,31 @@
}
req->snt_isn = isn;
- if (tcp_v4_send_synack(sk, req, dst))
+ if (!dont_confirm && tcp_v4_send_synack(sk, req, dst))
goto drop_and_free;
if (want_cookie) {
tcp_openreq_free(req);
+ } else if (dont_confirm) {
+ struct sock *child;
+ __u8 rcv_wscale;
+
+ req->window_clamp = dst?dst->window:0;
+ tcp_select_initial_window(tcp_full_space(sk), req->mss,
+ &req->rcv_wnd, &req->window_clamp,
+ 0, &rcv_wscale);
+ req->rcv_wscale = rcv_wscale;
+
+ child = tcp_v4_syn_recv_sock(sk, skb, req, NULL);
+ if (child != NULL) {
+ req->unconfirmed = 1;
+ child->tp_pinfo.af_tcp.unconfirmed_openreq = req;
+ tcp_acceptq_queue(sk, req, child);
+ sk->data_ready(sk, 0);
+ sock_put(child);
+ } else {
+ tcp_openreq_free(req);
+ }
} else {
tcp_v4_synq_add(sk, req);
}
--- linux-2.4.18-11umpr/net/ipv4/tcp_timer.c.orig Mon Oct 1 18:19:57 2001
+++ linux-2.4.18-11umpr/net/ipv4/tcp_timer.c Thu Apr 18 19:49:06 2002
@@ -512,7 +512,8 @@
if ((long)(now - req->expires) >= 0) {
if ((req->retrans < thresh ||
(req->acked && req->retrans < max_retries))
- && !req->class->rtx_syn_ack(sk, req, NULL)) {
+ && (req->unconfirmed ||
+ !req->class->rtx_syn_ack(sk, req, NULL))) {
unsigned long timeo;
if (req->retrans++ == 0)
--- linux-2.4.18-11umpr/net/ipv4/af_inet.c.orig Fri Dec 21 18:42:05 2001
+++ linux-2.4.18-11umpr/net/ipv4/af_inet.c Wed Apr 17 20:45:06 2002
@@ -693,7 +693,7 @@
lock_sock(sk2);
- BUG_TRAP((1<<sk2->state)&(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_CLOSE));
+ BUG_TRAP((1<<sk2->state)&(TCPF_SYN_RECV|TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_CLOSE));
sock_graft(sk2, newsock);
next reply other threads:[~2002-11-07 9:32 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-11-07 9:32 Lennert Buytenhek [this message]
2002-11-07 11:27 ` [PATCH,RFC] explicit connection confirmation bert hubert
2002-11-07 12:09 ` Lennert Buytenhek
2002-11-07 13:36 ` jamal
2002-11-07 15:27 ` Lennert Buytenhek
2002-11-08 11:22 ` jamal
2002-11-08 11:52 ` bert hubert
2002-11-08 11:56 ` Marc Boucher
2002-11-08 18:28 ` Lennert Buytenhek
2002-11-07 13:49 ` bert hubert
2002-11-07 14:30 ` Lennert Buytenhek
2002-11-07 16:24 ` bert hubert
2003-08-14 13:11 ` Lennert Buytenhek
2003-08-25 11:09 ` Harald Welte
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20021107093207.GA30666@gnu.org \
--to=buytenh@gnu.org \
--cc=netdev@oss.sgi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.