From 959263625c0076d21cef2380a3a9e17443e7764d Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Wed, 4 Apr 2007 06:13:26 +0000 Subject: [PATCH] Add IP_MINTTL socket option - 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. 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 --- share/man/man4/ip.4 | 31 ++++++++++++++++++++++++++++++- sys/netinet/in.h | 5 ++++- sys/netinet/in_pcb.h | 7 +++++-- sys/netinet/ip_input.c | 8 +++++++- sys/netinet/ip_output.c | 23 ++++++++++++++++++++++- sys/netinet/raw_ip.c | 8 ++++++-- sys/netinet/tcp_input.c | 7 ++++++- sys/netinet/udp_usrreq.c | 7 ++++++- 8 files changed, 86 insertions(+), 10 deletions(-) diff --git a/share/man/man4/ip.4 b/share/man/man4/ip.4 index 0585d77d8f..8d7cc85b31 100644 --- a/share/man/man4/ip.4 +++ b/share/man/man4/ip.4 @@ -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. diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 2f00144f24..c867488867 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -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 */ diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index 1e726de467..5c9528bf0b 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -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) diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index af4dcbf33c..bb2bf8c8bd 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -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 diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 4144b226ff..64426aefdc 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -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; diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 4de91b1ab9..0f2d9b123f 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -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); diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 7a8569a260..0c282a35df 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -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) { diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index cac1d57a2e..128c035534 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -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. -- 2.41.0