tcp: Generalized TTL Security Mechanism
authorStephen Hemminger <shemminger@vyatta.com>
Tue, 12 Jan 2010 00:28:01 +0000 (16:28 -0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 12 Jan 2010 00:28:01 +0000 (16:28 -0800)
This patch adds the kernel portions needed to implement
RFC 5082 Generalized TTL Security Mechanism (GTSM).
It is a lightweight security measure against forged
packets causing DoS attacks (for BGP).

This is already implemented the same way in BSD kernels.
For the necessary Quagga patch
  http://www.gossamer-threads.com/lists/quagga/dev/17389

Description from Cisco
  http://www.cisco.com/en/US/docs/ios/12_3t/12_3t7/feature/guide/gt_btsh.html

It does add one byte to each socket structure, but I did
a little rearrangement to reuse a hole (on 64 bit), but it
does grow the structure on 32 bit

This should be documented on ip(4) man page and the Glibc in.h
file also needs update.  IPV6_MINHOPLIMIT should also be added
(although BSD doesn't support that).

Only TCP is supported, but could also be added to UDP, DCCP, SCTP
if desired.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/in.h
include/net/inet_sock.h
net/ipv4/ip_sockglue.c
net/ipv4/tcp_ipv4.c

index b615649db129ea9add3ec53731ddad3f94ce1c0f..583c76f9c30fbef3a7427e5acf1e3159dfe65318 100644 (file)
@@ -84,6 +84,8 @@ struct in_addr {
 #define IP_ORIGDSTADDR       20
 #define IP_RECVORIGDSTADDR   IP_ORIGDSTADDR
 
+#define IP_MINTTL       21
+
 /* IP_MTU_DISCOVER values */
 #define IP_PMTUDISC_DONT               0       /* Never send DF frames */
 #define IP_PMTUDISC_WANT               1       /* Use per route hints  */
index bd4c53f75ac02576eacc0e5ea4da33704fe57d34..83fd34437cf1f3eb7509a35856573c3ede5b171c 100644 (file)
@@ -122,10 +122,12 @@ struct inet_sock {
        __be32                  inet_saddr;
        __s16                   uc_ttl;
        __u16                   cmsg_flags;
-       struct ip_options       *opt;
        __be16                  inet_sport;
        __u16                   inet_id;
+
+       struct ip_options       *opt;
        __u8                    tos;
+       __u8                    min_ttl;
        __u8                    mc_ttl;
        __u8                    pmtudisc;
        __u8                    recverr:1,
index cafad9baff039b8c164e2da282a754c6822294a8..644dc43a55dec954dc7232b3edb58c3412951540 100644 (file)
@@ -451,7 +451,8 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                             (1<<IP_TTL) | (1<<IP_HDRINCL) |
                             (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
                             (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
-                            (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) ||
+                            (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT) |
+                            (1<<IP_MINTTL))) ||
            optname == IP_MULTICAST_TTL ||
            optname == IP_MULTICAST_ALL ||
            optname == IP_MULTICAST_LOOP ||
@@ -936,6 +937,14 @@ mc_msf_out:
                inet->transparent = !!val;
                break;
 
+       case IP_MINTTL:
+               if (optlen < 1)
+                       goto e_inval;
+               if (val < 0 || val > 255)
+                       goto e_inval;
+               inet->min_ttl = val;
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
@@ -1198,6 +1207,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
        case IP_TRANSPARENT:
                val = inet->transparent;
                break;
+       case IP_MINTTL:
+               val = inet->min_ttl;
+               break;
        default:
                release_sock(sk);
                return -ENOPROTOOPT;
index 65b8ebfd078a35e909c7cbf0c4e1c7bda594ac2f..382f667238ecec4361829c7158445e85e48b373c 100644 (file)
@@ -1649,6 +1649,9 @@ int tcp_v4_rcv(struct sk_buff *skb)
        if (!sk)
                goto no_tcp_socket;
 
+       if (iph->ttl < inet_sk(sk)->min_ttl)
+               goto discard_and_relse;
+
 process:
        if (sk->sk_state == TCP_TIME_WAIT)
                goto do_time_wait;