Date: Sun, 9 Sep 2007 22:41:48 +0200 From: Matus Harvan <mharvan@inf.ethz.ch> To: freebsd-net@freebsd.org Cc: Max Laier <max@love2party.net>, Brooks Davis <brooks@freebsd.org>, mharvan@inf.ethz.ch Subject: TCP listenall Message-ID: <20070909204148.GB18107@inf.ethz.ch>
next in thread | raw e-mail | index | archive | help
--dc+cDN39EJAMEtIO Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Hello, I am a Google Summer of Code student working on mtund, aka Magic Tunnel Daemon aka Super Tunnel Daemon, http://wiki.freebsd.org/SuperTunnelDaemon. For mtund it would be useful to listen on all unused TCP ports, allowing a client behind firewall to use any possible hole it could find. To achieve this I would suggest the patch below. It would add a socket option TCP_LISTENALL. This clearly could only be set on one socket. When activated, the global variable inp_tlistenall would be used to assign traffic to unused TCP ports to that socket. In particular, the changed code in tcp_input() would be used twice - once for the SYN packet (1st packet) and once for the ACK packet (3rd packet). inp_tlistenall is protected by the INP_INFO lock on tcbinfo in all places. The patch also includes rate limiting to mitigate possible DoS misuse. With listenall enabled, a portscan becomes a syn flood. However, as there are already mechanisms to protect against a syn flood attack, such as syncache and syncookies, the rate limit might be left out. The disadvanatage of the rate limit is that a portscan becomes a DoS against the listenall socket. A testing program is available in perforce: http://p4web.freebsd.org/@md=3Dd&cd=3D//depot/projects/soc2007/mharvan-mtun= d/sys.patches/test_catchall/&c=3Dxpc@//depot/projects/soc2007/mharvan-mtund= /sys.patches/test_catchall/tcatchalld.c?ac=3D22 Note that the tcp listenall feature would be usefull to other programs beyond mtund, i.e., a modified ssh daemon for people who won't be able to run mtund, but will be able to run ssh. Matus patch: Index: netinet/tcp.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /home/ncvs/src/sys/netinet/tcp.h,v retrieving revision 1.40 diff -d -u -r1.40 tcp.h --- netinet/tcp.h 25 May 2007 21:28:49 -0000 1.40 +++ netinet/tcp.h 8 Sep 2007 10:35:57 -0000 @@ -147,6 +147,7 @@ #define TCP_NOOPT 0x08 /* don't use TCP options */ #define TCP_MD5SIG 0x10 /* use MD5 digests (RFC2385) */ #define TCP_INFO 0x20 /* retrieve tcp_info structure */ +#define TCP_LISTENALL 0x40 /* listen on all unused TCP ports */ =20 #define TCPI_OPT_TIMESTAMPS 0x01 #define TCPI_OPT_SACK 0x02 Index: netinet/tcp_input.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /home/ncvs/src/sys/netinet/tcp_input.c,v retrieving revision 1.367 diff -d -u -r1.367 tcp_input.c --- netinet/tcp_input.c 30 Jul 2007 11:06:41 -0000 1.367 +++ netinet/tcp_input.c 8 Sep 2007 10:35:57 -0000 @@ -144,9 +144,15 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, recvbuf_max, CTLFLAG_RW, &tcp_autorcvbuf_max, 0, "Max size of automatic receive buffer"); =20 +static int listenalllim =3D 5; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, listenalllim, CTLFLAG_RW | CTLFLAG_SEC= URE, + &listenalllim, 0, + "Rate limit on sockets created by the TCP_LISTENALL socket"); + struct inpcbhead tcb; #define tcb6 tcb /* for KAME src sync over BSD*'s */ struct inpcbinfo tcbinfo; +struct inpcb *inp_tlistenall; /* listening on all unused TCP ports */ =20 static void tcp_dooptions(struct tcpopt *, u_char *, int, int); static void tcp_do_segment(struct mbuf *, struct tcphdr *, @@ -258,6 +264,11 @@ struct tcphdr tcp_savetcp; short ostate =3D 0; #endif + static struct rate { + struct timeval lasttime; + int curpps; + } listenallr; + =20 #ifdef INET6 isipv6 =3D (mtod(m, struct ip *)->ip_v =3D=3D 6) ? 1 : 0; @@ -460,6 +471,36 @@ goto dropunlock; } #endif /* IPSEC */ + + /* listenall socket */ + if ((inp =3D=3D NULL) && (inp_tlistenall !=3D NULL)) { +#ifdef DIAGNOSTIC + printf("listenall socket used (0x%x)\n", + (unsigned int)inp_tlistenall); + char dbuf[INET_ADDRSTRLEN], sbuf[INET_ADDRSTRLEN]; + strcpy(dbuf, inet_ntoa(ip->ip_dst)); + strcpy(sbuf, inet_ntoa(ip->ip_src)); + printf("\tip_src: %s, sport: %hu\n\tip_dst: %s, dport: %hu\n", + sbuf, ntohs(th->th_sport), dbuf, ntohs(th->th_dport)); +#endif + /* do rate limiting for SYN packets */ + if (thflags & TH_SYN) { + if (listenalllim > 0)=20 + if (ppsratecheck(&listenallr.lasttime, + &listenallr.curpps, listenalllim)) + inp =3D inp_tlistenall; +#ifdef DIAGNOSTIC + else + printf("ppsratecheck limited " + "tcp_listenall\n"); +#endif +#ifdef DIAGNOSTIC + else + printf("ppsratecheck limited tcp_listenall\n"); +#endif + } else + inp =3D inp_tlistenall; + } =20 /* * If the INPCB does not exist then all data in the incoming Index: netinet/tcp_subr.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /home/ncvs/src/sys/netinet/tcp_subr.c,v retrieving revision 1.296 diff -d -u -r1.296 tcp_subr.c --- netinet/tcp_subr.c 16 Aug 2007 01:35:55 -0000 1.296 +++ netinet/tcp_subr.c 8 Sep 2007 10:35:57 -0000 @@ -264,6 +264,7 @@ tcp_rexmit_slop =3D TCPTV_CPU_VAR; tcp_inflight_rttthresh =3D TCPTV_INFLIGHT_RTTTHRESH; tcp_finwait2_timeout =3D TCPTV_FINWAIT2_TIMEOUT; + inp_tlistenall =3D NULL; =20 INP_INFO_LOCK_INIT(&tcbinfo, "tcp"); LIST_INIT(&tcb); Index: netinet/tcp_usrreq.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /home/ncvs/src/sys/netinet/tcp_usrreq.c,v retrieving revision 1.160 diff -d -u -r1.160 tcp_usrreq.c --- netinet/tcp_usrreq.c 30 Jul 2007 11:06:41 -0000 1.160 +++ netinet/tcp_usrreq.c 8 Sep 2007 10:35:57 -0000 @@ -48,6 +48,7 @@ #endif /* INET6 */ #include <sys/socket.h> #include <sys/socketvar.h> +#include <sys/priv.h> #include <sys/protosw.h> #include <sys/proc.h> #include <sys/jail.h> @@ -162,6 +163,13 @@ KASSERT(so->so_pcb =3D=3D inp, ("tcp_detach: so_pcb !=3D inp")); KASSERT(inp->inp_socket =3D=3D so, ("tcp_detach: inp_socket !=3D so")); =20 + if (inp =3D=3D inp_tlistenall) { +#ifdef DIAGNOSTIC + printf("deactivating TCP_LISTENALL - socket closed\n"); +#endif + inp_tlistenall =3D NULL; + } + tp =3D intotcpcb(inp); =20 if (inp->inp_vflag & INP_TIMEWAIT) { @@ -1338,6 +1346,29 @@ error =3D EINVAL; break; =20 + case TCP_LISTENALL: + error =3D sooptcopyin(sopt, &optval, sizeof optval, + sizeof optval); + if (error) + break; + + priv_check(curthread, + PRIV_NETINET_TCP_LISTENALL); + if (error !=3D 0) + break; + + if (optval > 0) /* enable LISTENALL */ + if (inp_tlistenall =3D=3D NULL) + inp_tlistenall =3D inp; + else + error =3D EBUSY; + + else /* disable LISTENALL */ + if (inp_tlistenall =3D=3D inp) + inp_tlistenall =3D NULL; + + break; + default: error =3D ENOPROTOOPT; break; @@ -1371,6 +1402,13 @@ case TCP_INFO: tcp_fill_info(tp, &ti); error =3D sooptcopyout(sopt, &ti, sizeof ti); + break; + case TCP_LISTENALL: + if (inp =3D=3D inp_tlistenall) =20 + optval =3D 1; + else + optval =3D 0; + error =3D sooptcopyout(sopt, &optval, sizeof optval); break; default: error =3D ENOPROTOOPT; Index: netinet/tcp_var.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /home/ncvs/src/sys/netinet/tcp_var.h,v retrieving revision 1.155 diff -d -u -r1.155 tcp_var.h --- netinet/tcp_var.h 28 Jul 2007 12:20:39 -0000 1.155 +++ netinet/tcp_var.h 8 Sep 2007 10:35:57 -0000 @@ -493,6 +493,7 @@ =20 extern struct inpcbhead tcb; /* head of queue of active tcpcb's */ extern struct inpcbinfo tcbinfo; +extern struct inpcb *inp_tlistenall; /* listening on all unused TCP ports= */ extern struct tcpstat tcpstat; /* tcp statistics */ extern int tcp_log_in_vain; extern int tcp_mssdflt; /* XXX */ Index: sys/priv.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /home/ncvs/src/sys/sys/priv.h,v retrieving revision 1.15 diff -d -u -r1.15 priv.h --- sys/priv.h 18 Jun 2007 07:54:27 -0000 1.15 +++ sys/priv.h 8 Sep 2007 10:35:58 -0000 @@ -374,6 +374,7 @@ #define PRIV_NETINET_ALIFETIME6 502 /* Administer IPv6 address lifetimes. = */ #define PRIV_NETINET_IPSEC 503 /* Administer IPSEC. */ #define PRIV_NETINET_REUSEPORT 504 /* Allow [rapid] port/address reuse. */ +#define PRIV_NETINET_TCP_LISTENALL 505 /* Allow setting TCP_LISTENALL */ =20 /* * IPX/SPX privileges. --dc+cDN39EJAMEtIO Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.4 (FreeBSD) iD8DBQFG5FqM43LQWDWf0QIRAla4AKCq3dmIZPPzHawK1cnkMNxkr59kxQCgly75 6VElx/PTljiFYwbH4b9S2bs= =M4FW -----END PGP SIGNATURE----- --dc+cDN39EJAMEtIO--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20070909204148.GB18107>