Date: Fri, 26 Oct 2007 17:52:06 +0200 From: Matus Harvan <mharvan@inf.ethz.ch> To: freebsd-net@freebsd.org Cc: Max Laier <max@love2party.net>, Brooks Davis <brooks@freebsd.org> Subject: Re: TCP listenall Message-ID: <20071026155206.GH1049@styx.ethz.ch> In-Reply-To: <20070909204148.GB18107@inf.ethz.ch> References: <20070909204148.GB18107@inf.ethz.ch>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --] Hi, I was wondering if I could get some feedback about the patch and whether others think it could be committed. A slightly update version of the patch is at the end of this email. Matus On Sun, Sep 09, 2007 at 10:41:48PM +0200, Matus Harvan wrote: > 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=d&cd=//depot/projects/soc2007/mharvan-mtund/sys.patches/test_catchall/&c=xpc@//depot/projects/soc2007/mharvan-mtund/sys.patches/test_catchall/tcatchalld.c?ac=22 > > 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 =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp.h,v retrieving revision 1.40 diff -u -r1.40 tcp.h --- netinet/tcp.h 25 May 2007 21:28:49 -0000 1.40 +++ netinet/tcp.h 26 Oct 2007 15:41:17 -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 */ #define TCPI_OPT_TIMESTAMPS 0x01 #define TCPI_OPT_SACK 0x02 Index: netinet/tcp_input.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_input.c,v retrieving revision 1.370 diff -u -r1.370 tcp_input.c --- netinet/tcp_input.c 7 Oct 2007 20:44:23 -0000 1.370 +++ netinet/tcp_input.c 26 Oct 2007 15:41:17 -0000 @@ -146,9 +146,15 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, recvbuf_max, CTLFLAG_RW, &tcp_autorcvbuf_max, 0, "Max size of automatic receive buffer"); +static int listenalllim = 5; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, listenalllim, CTLFLAG_RW | CTLFLAG_SECURE, + &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 */ static void tcp_dooptions(struct tcpopt *, u_char *, int, int); static void tcp_do_segment(struct mbuf *, struct tcphdr *, @@ -260,6 +266,11 @@ struct tcphdr tcp_savetcp; short ostate = 0; #endif + static struct rate { + struct timeval lasttime; + int curpps; + } listenallr; + #ifdef INET6 isipv6 = (mtod(m, struct ip *)->ip_v == 6) ? 1 : 0; @@ -448,6 +459,36 @@ ip->ip_dst, th->th_dport, INPLOOKUP_WILDCARD, m->m_pkthdr.rcvif); + } + + /* listenall socket */ + if ((inp == NULL) && (inp_tlistenall != 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) + if (ppsratecheck(&listenallr.lasttime, + &listenallr.curpps, listenalllim)) + inp = inp_tlistenall; +#ifdef DIAGNOSTIC + else + printf("ppsratecheck limited " + "tcp_listenall\n"); +#endif +#ifdef DIAGNOSTIC + else + printf("ppsratecheck limited tcp_listenall\n"); +#endif + } else + inp = inp_tlistenall; } /* Index: netinet/tcp_subr.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_subr.c,v retrieving revision 1.300 diff -u -r1.300 tcp_subr.c --- netinet/tcp_subr.c 7 Oct 2007 20:44:24 -0000 1.300 +++ netinet/tcp_subr.c 26 Oct 2007 15:41:17 -0000 @@ -266,6 +266,7 @@ tcp_rexmit_slop = TCPTV_CPU_VAR; tcp_inflight_rttthresh = TCPTV_INFLIGHT_RTTTHRESH; tcp_finwait2_timeout = TCPTV_FINWAIT2_TIMEOUT; + inp_tlistenall = NULL; INP_INFO_LOCK_INIT(&tcbinfo, "tcp"); LIST_INIT(&tcb); Index: netinet/tcp_usrreq.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_usrreq.c,v retrieving revision 1.163 diff -u -r1.163 tcp_usrreq.c --- netinet/tcp_usrreq.c 7 Oct 2007 20:44:24 -0000 1.163 +++ netinet/tcp_usrreq.c 26 Oct 2007 15:41:17 -0000 @@ -50,6 +50,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> @@ -164,6 +165,13 @@ KASSERT(so->so_pcb == inp, ("tcp_detach: so_pcb != inp")); KASSERT(inp->inp_socket == so, ("tcp_detach: inp_socket != so")); + if (inp == inp_tlistenall) { +#ifdef DIAGNOSTIC + printf("deactivating TCP_LISTENALL - socket closed\n"); +#endif + inp_tlistenall = NULL; + } + tp = intotcpcb(inp); if (inp->inp_vflag & INP_TIMEWAIT) { @@ -1340,6 +1348,29 @@ error = EINVAL; break; + case TCP_LISTENALL: + error = sooptcopyin(sopt, &optval, sizeof optval, + sizeof optval); + if (error) + break; + + priv_check(curthread, + PRIV_NETINET_TCP_LISTENALL); + if (error != 0) + break; + + if (optval > 0) /* enable LISTENALL */ + if (inp_tlistenall == NULL) + inp_tlistenall = inp; + else + error = EBUSY; + + else /* disable LISTENALL */ + if (inp_tlistenall == inp) + inp_tlistenall = NULL; + + break; + default: error = ENOPROTOOPT; break; @@ -1373,6 +1404,13 @@ case TCP_INFO: tcp_fill_info(tp, &ti); error = sooptcopyout(sopt, &ti, sizeof ti); + break; + case TCP_LISTENALL: + if (inp == inp_tlistenall) + optval = 1; + else + optval = 0; + error = sooptcopyout(sopt, &optval, sizeof optval); break; default: error = ENOPROTOOPT; Index: netinet/tcp_var.h =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_var.h,v retrieving revision 1.157 diff -u -r1.157 tcp_var.h --- netinet/tcp_var.h 24 Sep 2007 05:26:24 -0000 1.157 +++ netinet/tcp_var.h 26 Oct 2007 15:41:17 -0000 @@ -493,6 +493,7 @@ 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 =================================================================== RCS file: /home/ncvs/src/sys/sys/priv.h,v retrieving revision 1.15 diff -u -r1.15 priv.h --- sys/priv.h 18 Jun 2007 07:54:27 -0000 1.15 +++ sys/priv.h 26 Oct 2007 15:41:19 -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 */ /* * IPX/SPX privileges. [-- Attachment #2 --] -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.4 (FreeBSD) iD8DBQFHIg0l43LQWDWf0QIRArK6AKCPwCaBSdl+4/+11m264zXOYr5H5QCgjqb7 xjRQW7TnlNcNi0JiFLWbrU4= =wD+w -----END PGP SIGNATURE-----
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20071026155206.GH1049>
