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: pgpMooP6oCSdd.pgp
Description: PGP signature

Reply via email to