diff options
-rw-r--r-- | include/linux/in6.h | 3 | ||||
-rw-r--r-- | include/linux/ipv6.h | 1 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 12 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 14 |
4 files changed, 29 insertions, 1 deletions
diff --git a/include/linux/in6.h b/include/linux/in6.h index bd55c6e46b2..9b90cb296eb 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h | |||
@@ -265,6 +265,9 @@ struct in6_flowlabel_req { | |||
265 | #define IPV6_PREFER_SRC_CGA 0x0008 | 265 | #define IPV6_PREFER_SRC_CGA 0x0008 |
266 | #define IPV6_PREFER_SRC_NONCGA 0x0800 | 266 | #define IPV6_PREFER_SRC_NONCGA 0x0800 |
267 | 267 | ||
268 | /* RFC5082: Generalized Ttl Security Mechanism */ | ||
269 | #define IPV6_MINHOPCOUNT 73 | ||
270 | |||
268 | /* | 271 | /* |
269 | * Multicast Routing: | 272 | * Multicast Routing: |
270 | * see include/linux/mroute6.h. | 273 | * see include/linux/mroute6.h. |
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index e0cc9a7db2b..1bdbebf08d1 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h | |||
@@ -348,6 +348,7 @@ struct ipv6_pinfo { | |||
348 | * 010: prefer public address | 348 | * 010: prefer public address |
349 | * 100: prefer care-of address | 349 | * 100: prefer care-of address |
350 | */ | 350 | */ |
351 | __u8 min_hopcount; | ||
351 | __u8 tclass; | 352 | __u8 tclass; |
352 | 353 | ||
353 | __u32 dst_cookie; | 354 | __u32 dst_cookie; |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 1160400e9db..92295ad3487 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -767,6 +767,14 @@ pref_skip_coa: | |||
767 | 767 | ||
768 | break; | 768 | break; |
769 | } | 769 | } |
770 | case IPV6_MINHOPCOUNT: | ||
771 | if (optlen < sizeof(int)) | ||
772 | goto e_inval; | ||
773 | if (val < 0 || val > 255) | ||
774 | goto e_inval; | ||
775 | np->min_hopcount = val; | ||
776 | retv = 0; | ||
777 | break; | ||
770 | } | 778 | } |
771 | 779 | ||
772 | release_sock(sk); | 780 | release_sock(sk); |
@@ -1116,6 +1124,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
1116 | val |= IPV6_PREFER_SRC_HOME; | 1124 | val |= IPV6_PREFER_SRC_HOME; |
1117 | break; | 1125 | break; |
1118 | 1126 | ||
1127 | case IPV6_MINHOPCOUNT: | ||
1128 | val = np->min_hopcount; | ||
1129 | break; | ||
1130 | |||
1119 | default: | 1131 | default: |
1120 | return -ENOPROTOOPT; | 1132 | return -ENOPROTOOPT; |
1121 | } | 1133 | } |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 1ababbb4113..6603511e367 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -353,6 +353,11 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
353 | if (sk->sk_state == TCP_CLOSE) | 353 | if (sk->sk_state == TCP_CLOSE) |
354 | goto out; | 354 | goto out; |
355 | 355 | ||
356 | if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) { | ||
357 | NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP); | ||
358 | goto out; | ||
359 | } | ||
360 | |||
356 | tp = tcp_sk(sk); | 361 | tp = tcp_sk(sk); |
357 | seq = ntohl(th->seq); | 362 | seq = ntohl(th->seq); |
358 | if (sk->sk_state != TCP_LISTEN && | 363 | if (sk->sk_state != TCP_LISTEN && |
@@ -1678,6 +1683,7 @@ ipv6_pktoptions: | |||
1678 | static int tcp_v6_rcv(struct sk_buff *skb) | 1683 | static int tcp_v6_rcv(struct sk_buff *skb) |
1679 | { | 1684 | { |
1680 | struct tcphdr *th; | 1685 | struct tcphdr *th; |
1686 | struct ipv6hdr *hdr; | ||
1681 | struct sock *sk; | 1687 | struct sock *sk; |
1682 | int ret; | 1688 | int ret; |
1683 | struct net *net = dev_net(skb->dev); | 1689 | struct net *net = dev_net(skb->dev); |
@@ -1704,12 +1710,13 @@ static int tcp_v6_rcv(struct sk_buff *skb) | |||
1704 | goto bad_packet; | 1710 | goto bad_packet; |
1705 | 1711 | ||
1706 | th = tcp_hdr(skb); | 1712 | th = tcp_hdr(skb); |
1713 | hdr = ipv6_hdr(skb); | ||
1707 | TCP_SKB_CB(skb)->seq = ntohl(th->seq); | 1714 | TCP_SKB_CB(skb)->seq = ntohl(th->seq); |
1708 | TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + | 1715 | TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + |
1709 | skb->len - th->doff*4); | 1716 | skb->len - th->doff*4); |
1710 | TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); | 1717 | TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); |
1711 | TCP_SKB_CB(skb)->when = 0; | 1718 | TCP_SKB_CB(skb)->when = 0; |
1712 | TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb)); | 1719 | TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(hdr); |
1713 | TCP_SKB_CB(skb)->sacked = 0; | 1720 | TCP_SKB_CB(skb)->sacked = 0; |
1714 | 1721 | ||
1715 | sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest); | 1722 | sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest); |
@@ -1720,6 +1727,11 @@ process: | |||
1720 | if (sk->sk_state == TCP_TIME_WAIT) | 1727 | if (sk->sk_state == TCP_TIME_WAIT) |
1721 | goto do_time_wait; | 1728 | goto do_time_wait; |
1722 | 1729 | ||
1730 | if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) { | ||
1731 | NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP); | ||
1732 | goto discard_and_relse; | ||
1733 | } | ||
1734 | |||
1723 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 1735 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
1724 | goto discard_and_relse; | 1736 | goto discard_and_relse; |
1725 | 1737 | ||