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);