aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/in6.h3
-rw-r--r--include/linux/ipv6.h1
-rw-r--r--net/ipv6/ipv6_sockglue.c12
-rw-r--r--net/ipv6/tcp_ipv6.c14
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:
1678static int tcp_v6_rcv(struct sk_buff *skb) 1683static 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