Add IP_MINTTL socket option - used to set the minimum acceptable TTL a
authorMatthew Dillon <dillon@dragonflybsd.org>
Wed, 4 Apr 2007 06:13:26 +0000 (06:13 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Wed, 4 Apr 2007 06:13:26 +0000 (06:13 +0000)
packet must have when received on a socket.  All packets with a lower TTL
are silently dropped.  Works on already connected/connecting and listening
sockets for RAW/UDP/TCP.

Add IP_RECVTTL socket option support - When set, userland receives the
incoming packet's TTL as ancillary data with recvmsg(2) call.

Allows the implementation of security mechanisms described in RFC3682 (GTSM).

Obtained-from: FreeBSD.
Submitted-by: Hasso Tepper <hasso@estpak.ee>
share/man/man4/ip.4
sys/netinet/in.h
sys/netinet/in_pcb.h
sys/netinet/ip_input.c
sys/netinet/ip_output.c
sys/netinet/raw_ip.c
sys/netinet/tcp_input.c
sys/netinet/udp_usrreq.c

index 0585d77..8d7cc85 100644 (file)
@@ -31,7 +31,7 @@
 .\"
 .\"     @(#)ip.4       8.2 (Berkeley) 11/30/93
 .\" $FreeBSD: src/share/man/man4/ip.4,v 1.13.2.9 2002/05/02 02:40:26 silby Exp $
-.\" $DragonFly: src/share/man/man4/ip.4,v 1.3 2006/02/10 19:01:09 swildner Exp $
+.\" $DragonFly: src/share/man/man4/ip.4,v 1.4 2007/04/04 06:13:25 dillon Exp $
 .\"
 .Dd March 3, 2001
 .Dt IP 4
@@ -114,6 +114,13 @@ int ttl = 60;                   /* max = 255 */
 setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
 .Ed
 .Pp
+.Dv IP_MINTTL
+may be used to set the minimum acceptable TTL a packet must have when
+received on a socket.
+All packets with a lower TTL are silently dropped.
+Works on already connected/connecting and listening sockets for RAW/UDP/TCP.
+It allows to implement security mechanisms described in RFC3682 (GTSM).
+.Pp
 If the
 .Dv IP_RECVDSTADDR
 option is enabled on a
@@ -137,6 +144,28 @@ cmsg_level = IPPROTO_IP
 cmsg_type = IP_RECVDSTADDR
 .Ed
 .Pp
+If the
+.Dv IP_RECVTTL
+option is enabled on a
+.Dv SOCK_DGRAM
+socket, the
+.Xr recvmsg 2
+call will return the
+.Tn IP
+.Tn TTL
+(time to live) field for a
+.Tn UDP
+datagram.
+The msg_control field in the msghdr structure points to a buffer
+that contains a cmsghdr structure followed by the
+.Tn TTL .
+The cmsghdr fields have the following values:
+.Bd -literal
+cmsg_len = sizeof(u_char)
+cmsg_level = IPPROTO_IP
+cmsg_type = IP_RECVTTL
+.Ed
+.Pp
 .Dv IP_PORTRANGE
 may be used to set the port range used for selecting a local port number
 on a socket with an unspecified (zero) port number.
index 2f00144..c867488 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)in.h        8.3 (Berkeley) 1/3/94
  * $FreeBSD: src/sys/netinet/in.h,v 1.48.2.10 2003/08/24 08:24:38 hsu Exp $
- * $DragonFly: src/sys/netinet/in.h,v 1.14 2006/12/29 18:02:56 victor Exp $
+ * $DragonFly: src/sys/netinet/in.h,v 1.15 2007/04/04 06:13:26 dillon Exp $
  */
 
 #ifndef _NETINET_IN_H_
@@ -355,6 +355,9 @@ struct sockaddr_in {
 #define        IP_DUMMYNET_FLUSH       62   /* flush dummynet */
 #define        IP_DUMMYNET_GET         64   /* get entire dummynet pipes */
 
+#define        IP_RECVTTL              65   /* bool; receive IP TTL w/dgram */
+#define        IP_MINTTL               66   /* minimum TTL for packet or drop */
+
 /*
  * Defaults and limits for options
  */
index 1e726de..5c9528b 100644 (file)
@@ -65,7 +65,7 @@
  *
  *     @(#)in_pcb.h    8.1 (Berkeley) 6/10/93
  * $FreeBSD: src/sys/netinet/in_pcb.h,v 1.32.2.7 2003/01/24 05:11:34 sam Exp $
- * $DragonFly: src/sys/netinet/in_pcb.h,v 1.22 2007/03/04 18:51:59 swildner Exp $
+ * $DragonFly: src/sys/netinet/in_pcb.h,v 1.23 2007/04/04 06:13:26 dillon Exp $
  */
 
 #ifndef _NETINET_IN_PCB_H_
@@ -196,6 +196,7 @@ struct inpcb {
 #define        INP_IPV6        0x2
        u_char  inp_ip_ttl;             /* time to live proto */
        u_char  inp_ip_p;               /* protocol proto */
+       u_char  inp_ip_minttl;          /* minimum TTL or drop */
 
        /* protocol dependent part; options */
        struct {
@@ -327,8 +328,10 @@ struct inpcbinfo {         /* XXX documentation, prefixes */
 #define        IN6P_RTHDRDSTOPTS       0x200000 /* receive dstoptions before rthdr */
 #define IN6P_AUTOFLOWLABEL     0x800000 /* attach flowlabel automatically */
 
+#define        INP_RECVTTL             0x80000000 /* receive incoming IP TTL */
+
 #define        INP_CONTROLOPTS         (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\
-                                       INP_RECVIF|\
+                                       INP_RECVIF|INP_RECVTTL|\
                                 IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_HOPOPTS|\
                                 IN6P_DSTOPTS|IN6P_RTHDR|IN6P_RTHDRDSTOPTS|\
                                 IN6P_AUTOFLOWLABEL)
index af4dcbf..bb2bf8c 100644 (file)
@@ -65,7 +65,7 @@
  *
  *     @(#)ip_input.c  8.2 (Berkeley) 1/4/94
  * $FreeBSD: src/sys/netinet/ip_input.c,v 1.130.2.52 2003/03/07 07:01:28 silby Exp $
- * $DragonFly: src/sys/netinet/ip_input.c,v 1.65 2007/03/04 18:51:59 swildner Exp $
+ * $DragonFly: src/sys/netinet/ip_input.c,v 1.66 2007/04/04 06:13:26 dillon Exp $
  */
 
 #define        _IP_VHL
@@ -2171,6 +2171,12 @@ ip_savecontrol(struct inpcb *inp, struct mbuf **mp, struct ip *ip,
                if (*mp)
                        mp = &(*mp)->m_next;
        }
+       if (inp->inp_flags & INP_RECVTTL) {
+               *mp = sbcreatecontrol((caddr_t) &ip->ip_ttl,
+                   sizeof(u_char), IP_RECVTTL, IPPROTO_IP);
+               if (*mp)
+                       mp = &(*mp)->m_next;
+       }
 #ifdef notyet
        /* XXX
         * Moving these out of udp_input() made them even more broken
index 4144b22..64426ae 100644 (file)
@@ -28,7 +28,7 @@
  *
  *     @(#)ip_output.c 8.3 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/netinet/ip_output.c,v 1.99.2.37 2003/04/15 06:44:45 silby Exp $
- * $DragonFly: src/sys/netinet/ip_output.c,v 1.36 2006/12/22 23:57:52 swildner Exp $
+ * $DragonFly: src/sys/netinet/ip_output.c,v 1.37 2007/04/04 06:13:26 dillon Exp $
  */
 
 #define _IP_VHL
@@ -1409,10 +1409,12 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt)
 
                case IP_TOS:
                case IP_TTL:
+               case IP_MINTTL:
                case IP_RECVOPTS:
                case IP_RECVRETOPTS:
                case IP_RECVDSTADDR:
                case IP_RECVIF:
+               case IP_RECVTTL:
                case IP_FAITH:
                        error = sooptcopyin(sopt, &optval, sizeof optval,
                                            sizeof optval);
@@ -1427,6 +1429,12 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt)
                        case IP_TTL:
                                inp->inp_ip_ttl = optval;
                                break;
+                       case IP_MINTTL:
+                               if (optval > 0 && optval <= MAXTTL)
+                                       inp->inp_ip_minttl = optval;
+                               else
+                                       error = EINVAL;
+                               break;
 #define        OPTSET(bit) \
        if (optval) \
                inp->inp_flags |= bit; \
@@ -1449,6 +1457,10 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt)
                                OPTSET(INP_RECVIF);
                                break;
 
+                       case IP_RECVTTL:
+                               OPTSET(INP_RECVTTL);
+                               break;
+
                        case IP_FAITH:
                                OPTSET(INP_FAITH);
                                break;
@@ -1538,9 +1550,11 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt)
 
                case IP_TOS:
                case IP_TTL:
+               case IP_MINTTL:
                case IP_RECVOPTS:
                case IP_RECVRETOPTS:
                case IP_RECVDSTADDR:
+               case IP_RECVTTL:
                case IP_RECVIF:
                case IP_PORTRANGE:
                case IP_FAITH:
@@ -1553,6 +1567,9 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt)
                        case IP_TTL:
                                optval = inp->inp_ip_ttl;
                                break;
+                       case IP_MINTTL:
+                               optval = inp->inp_ip_minttl;
+                               break;
 
 #define        OPTBIT(bit)     (inp->inp_flags & bit ? 1 : 0)
 
@@ -1568,6 +1585,10 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt)
                                optval = OPTBIT(INP_RECVDSTADDR);
                                break;
 
+                       case IP_RECVTTL:
+                               optval = OPTBIT(INP_RECVTTL);
+                               break;
+
                        case IP_RECVIF:
                                optval = OPTBIT(INP_RECVIF);
                                break;
index 4de91b1..0f2d9b1 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)raw_ip.c    8.7 (Berkeley) 5/15/95
  * $FreeBSD: src/sys/netinet/raw_ip.c,v 1.64.2.16 2003/08/24 08:24:38 hsu Exp $
- * $DragonFly: src/sys/netinet/raw_ip.c,v 1.23 2005/08/15 16:46:21 dillon Exp $
+ * $DragonFly: src/sys/netinet/raw_ip.c,v 1.24 2007/04/04 06:13:26 dillon Exp $
  */
 
 #include "opt_inet6.h"
@@ -225,7 +225,11 @@ rip_input(struct mbuf *m, ...)
                /* do not inject data to pcb */
        } else
 #endif /*FAST_IPSEC*/
-       if (last) {
+       /* Check the minimum TTL for socket. */
+       if (last && ip->ip_ttl < last->inp_ip_minttl) {
+               m_freem(opts);
+               ipstat.ips_delivered--;
+       } else if (last) {
                if (last->inp_flags & INP_CONTROLOPTS ||
                    last->inp_socket->so_options & SO_TIMESTAMP)
                        ip_savecontrol(last, &opts, ip, m);
index 7a8569a..0c282a3 100644 (file)
@@ -65,7 +65,7 @@
  *
  *     @(#)tcp_input.c 8.12 (Berkeley) 5/24/95
  * $FreeBSD: src/sys/netinet/tcp_input.c,v 1.107.2.38 2003/05/21 04:46:41 cjc Exp $
- * $DragonFly: src/sys/netinet/tcp_input.c,v 1.64 2007/03/04 18:51:59 swildner Exp $
+ * $DragonFly: src/sys/netinet/tcp_input.c,v 1.65 2007/04/04 06:13:26 dillon Exp $
  */
 
 #include "opt_ipfw.h"          /* for ipfw_fwd         */
@@ -804,6 +804,11 @@ findpcb:
                        goto drop;
        }
 #endif
+       /* Check the minimum TTL for socket. */
+#ifdef INET6
+       if ((isipv6 ? ip6->ip6_hlim : ip->ip_ttl) < inp->inp_ip_minttl)
+               goto drop;
+#endif
 
        tp = intotcpcb(inp);
        if (tp == NULL) {
index cac1d57..128c035 100644 (file)
@@ -65,7 +65,7 @@
  *
  *     @(#)udp_usrreq.c        8.6 (Berkeley) 5/23/95
  * $FreeBSD: src/sys/netinet/udp_usrreq.c,v 1.64.2.18 2003/01/24 05:11:34 sam Exp $
- * $DragonFly: src/sys/netinet/udp_usrreq.c,v 1.39 2007/03/04 18:51:59 swildner Exp $
+ * $DragonFly: src/sys/netinet/udp_usrreq.c,v 1.40 2007/04/04 06:13:26 dillon Exp $
  */
 
 #include "opt_ipsec.h"
@@ -474,6 +474,11 @@ udp_input(struct mbuf *m, ...)
        if (ipsec4_in_reject(m, inp))
                goto bad;
 #endif /*FAST_IPSEC*/
+       /*
+        * Check the minimum TTL for socket.
+        */
+       if (ip->ip_ttl < inp->inp_ip_minttl)
+               goto bad;
 
        /*
         * Construct sockaddr format source address.