diff mbox

tcp: Generalized TTL Security Mechanism

Message ID 20100110220034.4d46ba8a@nehalam
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

stephen hemminger Jan. 11, 2010, 6 a.m. UTC
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>

---
 include/linux/in.h      |    1 +
 include/net/inet_sock.h |    9 +++++++++
 net/ipv4/ip_sockglue.c  |   14 +++++++++++++-
 net/ipv4/tcp_ipv4.c     |    2 ++
 4 files changed, 25 insertions(+), 1 deletion(-)

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Eric Dumazet Jan. 11, 2010, 11:25 a.m. UTC | #1
Le 11/01/2010 07:00, Stephen Hemminger a écrit :
> 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>
> 

> --- a/net/ipv4/tcp_ipv4.c	2010-01-10 21:06:42.931093698 -0800
> +++ b/net/ipv4/tcp_ipv4.c	2010-01-10 21:08:21.537513427 -0800
> @@ -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;

Just wondering if perfoming the check at connection establishment time
(SYN or SYN-ACK packet) instead of every received packet would be enough ?

Of course, for listeners waiting for connexions from different peers (and different
ttl values), it would be tricky.

Check should be done at user level, if we store ttl value of SYN packet and let
user application read its value by a getsockopt()

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
stephen hemminger Jan. 11, 2010, 4:25 p.m. UTC | #2
On Mon, 11 Jan 2010 12:25:23 +0100
Eric Dumazet <eric.dumazet@gmail.com> wrote:

> Le 11/01/2010 07:00, Stephen Hemminger a écrit :
> > 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>
> > 
> 
> > --- a/net/ipv4/tcp_ipv4.c	2010-01-10 21:06:42.931093698 -0800
> > +++ b/net/ipv4/tcp_ipv4.c	2010-01-10 21:08:21.537513427 -0800
> > @@ -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;
> 
> Just wondering if perfoming the check at connection establishment time
> (SYN or SYN-ACK packet) instead of every received packet would be enough ?

We could but:
  1. GTSM is trying to protect against Man in the Middle attacks to existing
     BGP connections
  2. That is not what BSD (or other vendors) do.

> Of course, for listeners waiting for connexions from different peers (and different
> ttl values), it would be tricky.
> 
> Check should be done at user level, if we store ttl value of SYN packet and let
> user application read its value by a getsockopt()

I think IP_RECVTTL would work for that idea.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Eric Dumazet Jan. 11, 2010, 5:04 p.m. UTC | #3
Le 11/01/2010 17:25, Stephen Hemminger a écrit :

> We could but:
>   1. GTSM is trying to protect against Man in the Middle attacks to existing
>      BGP connections
>   2. That is not what BSD (or other vendors) do.

Yes, unfortunately, I am afraid we are forced to be compatable.


> 
>> Of course, for listeners waiting for connexions from different peers (and different
>> ttl values), it would be tricky.
>>
>> Check should be done at user level, if we store ttl value of SYN packet and let
>> user application read its value by a getsockopt()
> 
> I think IP_RECVTTL would work for that idea.

Yes, if it was extented to TCP somehow.

Given this is an IP level option, check could be done at IP level, so that other protocols
can use it too ?

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Eric Dumazet Jan. 11, 2010, 5:10 p.m. UTC | #4
Le 11/01/2010 18:04, Eric Dumazet a écrit :
> Given this is an IP level option, check could be done at IP level, so that other protocols
> can use it too ?

Oops, this is stupid, we dont have the socket pointer at IP level :)

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller Jan. 12, 2010, 12:27 a.m. UTC | #5
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 11 Jan 2010 18:10:28 +0100

> Le 11/01/2010 18:04, Eric Dumazet a écrit :
>> Given this is an IP level option, check could be done at IP level, so that other protocols
>> can use it too ?
> 
> Oops, this is stupid, we dont have the socket pointer at IP level :)

Right.

But we can later add a helper to place in each protocols receive path,
at the point where it first has a socket to work with.

I'm going to apply Stephen's original patch.

Thanks!
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller Jan. 12, 2010, 12:28 a.m. UTC | #6
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Sun, 10 Jan 2010 22:00:34 -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>

Applied to net-next-2.6, thanks Stephen.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andi Kleen Jan. 14, 2010, 10:58 a.m. UTC | #7
Stephen Hemminger <shemminger@vyatta.com> writes:
>
> Only TCP is supported, but could also be added to UDP, DCCP, SCTP
> if desired.

Perhaps I'm blind, but where is the default set if the socket
option is not used? 

-Andi
David Miller Jan. 14, 2010, 11:04 a.m. UTC | #8
From: Andi Kleen <andi@firstfloor.org>
Date: Thu, 14 Jan 2010 11:58:13 +0100

> Stephen Hemminger <shemminger@vyatta.com> writes:
>>
>> Only TCP is supported, but could also be added to UDP, DCCP, SCTP
>> if desired.
> 
> Perhaps I'm blind, but where is the default set if the socket
> option is not used? 

Socket allocation memset()'s it to zero.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andi Kleen Jan. 14, 2010, 11:22 a.m. UTC | #9
On Thu, Jan 14, 2010 at 03:04:54AM -0800, David Miller wrote:
> From: Andi Kleen <andi@firstfloor.org>
> Date: Thu, 14 Jan 2010 11:58:13 +0100
> 
> > Stephen Hemminger <shemminger@vyatta.com> writes:
> >>
> >> Only TCP is supported, but could also be added to UDP, DCCP, SCTP
> >> if desired.
> > 
> > Perhaps I'm blind, but where is the default set if the socket
> > option is not used? 
> 
> Socket allocation memset()'s it to zero.

Yes, but there's no special case for zero in the check path?

It's just

+       if (iph->ttl < inet_sk(sk)->min_ttl)
+               goto discard_and_relse;

I'm probably missing something, but naively I would expect all 
packets with ttl > 0 to be discarded then when min_ttl is zero.

-Andi
David Miller Jan. 14, 2010, 11:27 a.m. UTC | #10
From: Andi Kleen <andi@firstfloor.org>
Date: Thu, 14 Jan 2010 12:22:16 +0100

> It's just
> 
> +       if (iph->ttl < inet_sk(sk)->min_ttl)
> +               goto discard_and_relse;
> 
> I'm probably missing something, but naively I would expect all 
> packets with ttl > 0 to be discarded then when min_ttl is zero.

Andi, the feature works from top to bottom.

The idea is that the min_ttl is set very high, so that
you'll only accept packets from hosts that started with
a ttl of 255 and are within a hop or two from you.  (therefore
you'd set min_ttl to 254 or 253, something like that)

Since the ttl can never be less than zero, the test
will never hit when min_ttl is zero, and thus this is
that state where the socket option is not enabled.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
William Allen Simpson Jan. 14, 2010, 12:38 p.m. UTC | #11
David Miller wrote:
> The idea is that the min_ttl is set very high, so that
> you'll only accept packets from hosts that started with
> a ttl of 255 and are within a hop or two from you.  (therefore
> you'd set min_ttl to 254 or 253, something like that)
> 
That's not a particularly good idea:

http://www.iana.org/assignments/ip-parameters

IP TIME TO LIVE PARAMETER

The current recommended default time to live (TTL) for the Internet
Protocol (IP) is 64 [RFC791, RFC1122].

===

It always bugs me that things get incorrectly labeled "security", yet
cannot secure anything.

Security requires a secret.

Various folks tried all kinds of games with TTL for BGP, but the only
thing that _actually_ provided security was MD5 authentication.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Eric Dumazet Jan. 14, 2010, 1:14 p.m. UTC | #12
Le 14/01/2010 13:38, William Allen Simpson a écrit :
> David Miller wrote:
>> The idea is that the min_ttl is set very high, so that
>> you'll only accept packets from hosts that started with
>> a ttl of 255 and are within a hop or two from you.  (therefore
>> you'd set min_ttl to 254 or 253, something like that)
>>
> That's not a particularly good idea:
> 
> http://www.iana.org/assignments/ip-parameters
> 
> IP TIME TO LIVE PARAMETER
> 
> The current recommended default time to live (TTL) for the Internet
> Protocol (IP) is 64 [RFC791, RFC1122].
> 
> ===
> 
> It always bugs me that things get incorrectly labeled "security", yet
> cannot secure anything.
> 
> Security requires a secret.
> 
> Various folks tried all kinds of games with TTL for BGP, but the only
> thing that _actually_ provided security was MD5 authentication.

Nobody forces you to use RFC 5082, I never had.

But if you use it, better read it before, and not use default ttl of 64 on
devices wanting to connect to your host.

Note this TTL Security mechanism is not replacing MD5 protection

   The Generalized TTL Security Mechanism (GTSM) is designed to protect
   a router's IP-based control plane from CPU-utilization based attacks.
   In particular, while cryptographic techniques can protect the router-
   based infrastructure (e.g., BGP [RFC4271], [RFC4272]) from a wide
   variety of attacks, many attacks based on CPU overload can be
   prevented by the simple mechanism described in this document.  Note
   that the same technique protects against other scarce-resource
   attacks involving a router's CPU, such as attacks against processor-
   line card bandwidth.


Its only a potential protection against CPU overload.


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Pekka Savola March 18, 2010, 6:36 a.m. UTC | #13
Hi,

On Sun, 10 Jan 2010, Stephen Hemminger wrote:
> 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).
...

It's nice to see this added.  However, I must add that a compliant RFC 
5082 implementation is required to have similar TTL treatment for ICMP 
errors which relate to the protected session.  AFAIK this does not 
support that.

The experimental, earlier spec (GTSH, RFC3682) did not have this 
requirement.  Most if not all implementations support only GTSH mode. 
So a backward-compatibility option may be desirable.
stephen hemminger March 18, 2010, 5:59 p.m. UTC | #14
On Thu, 18 Mar 2010 08:36:48 +0200 (EET)
Pekka Savola <pekkas@netcore.fi> wrote:

> Hi,
> 
> On Sun, 10 Jan 2010, Stephen Hemminger wrote:
> > 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).
> ...
> 
> It's nice to see this added.  However, I must add that a compliant RFC 
> 5082 implementation is required to have similar TTL treatment for ICMP 
> errors which relate to the protected session.  AFAIK this does not 
> support that.
> 
> The experimental, earlier spec (GTSH, RFC3682) did not have this 
> requirement.  Most if not all implementations support only GTSH mode. 
> So a backward-compatibility option may be desirable.

The ICMP receive error handling does need to be updated. 

But any application using GTSM should be setting IP_TTL socket option
to set send TTL. But, not sure if Linux TCP ever sends ICMP 
for existing sessions at all.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Pekka Savola March 19, 2010, 7:58 a.m. UTC | #15
On Thu, 18 Mar 2010, Stephen Hemminger wrote:
>> The experimental, earlier spec (GTSH, RFC3682) did not have this
>> requirement.  Most if not all implementations support only GTSH mode.
>> So a backward-compatibility option may be desirable.
>
> The ICMP receive error handling does need to be updated.
>
> But any application using GTSM should be setting IP_TTL socket option
> to set send TTL. But, not sure if Linux TCP ever sends ICMP
> for existing sessions at all.

Thanks, Stephen!  It's nice to see at least one compliant RFC5082 
implementation ;-)

Good point that no one should should probably even be sending ICMP 
messages for TCP sockets, but on receive side the checks are important 
:-)
diff mbox

Patch

--- a/include/linux/in.h	2010-01-10 21:06:42.873122656 -0800
+++ b/include/linux/in.h	2010-01-10 21:06:47.802185618 -0800
@@ -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	*/
--- a/include/net/inet_sock.h	2010-01-10 21:06:42.893123288 -0800
+++ b/include/net/inet_sock.h	2010-01-10 21:17:50.262842588 -0800
@@ -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,
--- a/net/ipv4/ip_sockglue.c	2010-01-10 21:06:42.913123212 -0800
+++ b/net/ipv4/ip_sockglue.c	2010-01-10 21:06:47.822184879 -0800
@@ -451,7 +451,8 @@  static int do_ip_setsockopt(struct sock 
 			     (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 
 	case IP_TRANSPARENT:
 		val = inet->transparent;
 		break;
+	case IP_MINTTL:
+		val = inet->min_ttl;
+		break;
 	default:
 		release_sock(sk);
 		return -ENOPROTOOPT;
--- a/net/ipv4/tcp_ipv4.c	2010-01-10 21:06:42.931093698 -0800
+++ b/net/ipv4/tcp_ipv4.c	2010-01-10 21:08:21.537513427 -0800
@@ -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;