From 936cd18dade566c7ca5fd50cb4658f71f87ffcc1 Mon Sep 17 00:00:00 2001 From: Andre Oppermann Date: Mon, 22 Aug 2005 16:13:08 +0000 Subject: [PATCH] Add socketoption 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. This option is only really useful when set to 255 preventing packets from outside the directly connected networks reaching local listeners on sockets. Allows userland implementation of 'The Generalized TTL Security Mechanism (GTSM)' according to RFC3682. Examples of such use include the Cisco IOS BGP implementation command "neighbor ttl-security". MFC after: 2 weeks Sponsored by: TCP/IP Optimization Fundraise 2005 --- sys/netinet/in.h | 1 + sys/netinet/in_pcb.h | 1 + sys/netinet/ip_output.c | 14 ++++++++++++++ sys/netinet/raw_ip.c | 3 +++ sys/netinet/tcp_input.c | 5 +++++ sys/netinet/tcp_reass.c | 5 +++++ sys/netinet/udp_usrreq.c | 3 +++ 7 files changed, 32 insertions(+) diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 45c269ca89ae..f006ae3ea32f 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -415,6 +415,7 @@ __END_DECLS #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 99e12ad4c870..3d267ae9edcd 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -133,6 +133,7 @@ struct inpcb { #define INP_ONESBCAST 0x10 /* send all-ones broadcast */ 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 { diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 90c50a30508d..b292d803eb41 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1189,6 +1189,7 @@ ip_ctloutput(so, sopt) case IP_TOS: case IP_TTL: + case IP_MINTTL: case IP_RECVOPTS: case IP_RECVRETOPTS: case IP_RECVDSTADDR: @@ -1209,6 +1210,14 @@ ip_ctloutput(so, 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) do { \ INP_LOCK(inp); \ if (optval) \ @@ -1333,6 +1342,7 @@ ip_ctloutput(so, sopt) case IP_TOS: case IP_TTL: + case IP_MINTTL: case IP_RECVOPTS: case IP_RECVRETOPTS: case IP_RECVDSTADDR: @@ -1351,6 +1361,10 @@ ip_ctloutput(so, sopt) optval = inp->inp_ip_ttl; break; + case IP_MINTTL: + optval = inp->inp_ip_minttl; + break; + #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0) case IP_RECVOPTS: diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 3d2c6d27d933..8a128eb515d0 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -157,6 +157,9 @@ raw_append(struct inpcb *last, struct ip *ip, struct mbuf *n) if (!policyfail && mac_check_inpcb_deliver(last, n) != 0) policyfail = 1; #endif + /* Check the minimum TTL for socket. */ + if (last->inp_ip_minttl && last->inp_ip_minttl > ip->ip_ttl) + policyfail = 1; if (!policyfail) { struct mbuf *opts = NULL; struct socket *so; diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index c86a3eca3681..369315d484a2 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -740,6 +740,11 @@ findpcb: goto dropwithreset; } INP_LOCK(inp); + + /* Check the minimum TTL for socket. */ + if (inp->inp_ip_minttl && inp->inp_ip_minttl > ip->ip_ttl) + goto drop; + if (inp->inp_vflag & INP_TIMEWAIT) { /* * The only option of relevance is TOF_CC, and only if diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index c86a3eca3681..369315d484a2 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -740,6 +740,11 @@ findpcb: goto dropwithreset; } INP_LOCK(inp); + + /* Check the minimum TTL for socket. */ + if (inp->inp_ip_minttl && inp->inp_ip_minttl > ip->ip_ttl) + goto drop; + if (inp->inp_vflag & INP_TIMEWAIT) { /* * The only option of relevance is TOF_CC, and only if diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 0ffb00445ce8..6de2d7b77474 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -384,6 +384,9 @@ udp_input(m, off) return; } INP_LOCK(inp); + /* Check the minimum TTL for socket. */ + if (inp->inp_ip_minttl && inp->inp_ip_minttl > ip->ip_ttl) + goto badheadlocked; udp_append(inp, ip, m, iphlen + sizeof(struct udphdr), &udp_in); INP_UNLOCK(inp); INP_INFO_RUNLOCK(&udbinfo);