diff options
author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2013-08-26 19:36:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-29 15:32:08 -0400 |
commit | b800c3b966bcf004bd8592293a49ed5cb7ea67a9 (patch) | |
tree | e10eef87a5dc18bc16745adde12dae6ff104240b | |
parent | a3a975b1dfe999f3e5d38d38f2387894c4332d96 (diff) |
ipv6: drop fragmented ndisc packets by default (RFC 6980)
This patch implements RFC6980: Drop fragmented ndisc packets by
default. If a fragmented ndisc packet is received the user is informed
that it is possible to disable the check.
Cc: Fernando Gont <fernando@gont.com.ar>
Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/networking/ip-sysctl.txt | 6 | ||||
-rw-r--r-- | include/linux/ipv6.h | 1 | ||||
-rw-r--r-- | include/uapi/linux/ipv6.h | 1 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 10 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 17 |
5 files changed, 35 insertions, 0 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index debfe857d8f9..a2be556032c9 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt | |||
@@ -1349,6 +1349,12 @@ mldv2_unsolicited_report_interval - INTEGER | |||
1349 | MLDv2 report retransmit will take place. | 1349 | MLDv2 report retransmit will take place. |
1350 | Default: 1000 (1 second) | 1350 | Default: 1000 (1 second) |
1351 | 1351 | ||
1352 | suppress_frag_ndisc - INTEGER | ||
1353 | Control RFC 6980 (Security Implications of IPv6 Fragmentation | ||
1354 | with IPv6 Neighbor Discovery) behavior: | ||
1355 | 1 - (default) discard fragmented neighbor discovery packets | ||
1356 | 0 - allow fragmented neighbor discovery packets | ||
1357 | |||
1352 | icmp/*: | 1358 | icmp/*: |
1353 | ratelimit - INTEGER | 1359 | ratelimit - INTEGER |
1354 | Limit the maximal rates for sending ICMPv6 packets. | 1360 | Limit the maximal rates for sending ICMPv6 packets. |
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 9ac5047062c8..28ea38439313 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h | |||
@@ -50,6 +50,7 @@ struct ipv6_devconf { | |||
50 | __s32 accept_dad; | 50 | __s32 accept_dad; |
51 | __s32 force_tllao; | 51 | __s32 force_tllao; |
52 | __s32 ndisc_notify; | 52 | __s32 ndisc_notify; |
53 | __s32 suppress_frag_ndisc; | ||
53 | void *sysctl; | 54 | void *sysctl; |
54 | }; | 55 | }; |
55 | 56 | ||
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h index d07ac6903e59..593b0e32d956 100644 --- a/include/uapi/linux/ipv6.h +++ b/include/uapi/linux/ipv6.h | |||
@@ -162,6 +162,7 @@ enum { | |||
162 | DEVCONF_NDISC_NOTIFY, | 162 | DEVCONF_NDISC_NOTIFY, |
163 | DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL, | 163 | DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL, |
164 | DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL, | 164 | DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL, |
165 | DEVCONF_SUPPRESS_FRAG_NDISC, | ||
165 | DEVCONF_MAX | 166 | DEVCONF_MAX |
166 | }; | 167 | }; |
167 | 168 | ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 2d6d1793bbfe..a7183fc9bbc2 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -204,6 +204,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { | |||
204 | .accept_source_route = 0, /* we do not accept RH0 by default. */ | 204 | .accept_source_route = 0, /* we do not accept RH0 by default. */ |
205 | .disable_ipv6 = 0, | 205 | .disable_ipv6 = 0, |
206 | .accept_dad = 1, | 206 | .accept_dad = 1, |
207 | .suppress_frag_ndisc = 1, | ||
207 | }; | 208 | }; |
208 | 209 | ||
209 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | 210 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { |
@@ -241,6 +242,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | |||
241 | .accept_source_route = 0, /* we do not accept RH0 by default. */ | 242 | .accept_source_route = 0, /* we do not accept RH0 by default. */ |
242 | .disable_ipv6 = 0, | 243 | .disable_ipv6 = 0, |
243 | .accept_dad = 1, | 244 | .accept_dad = 1, |
245 | .suppress_frag_ndisc = 1, | ||
244 | }; | 246 | }; |
245 | 247 | ||
246 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ | 248 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ |
@@ -4188,6 +4190,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
4188 | array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad; | 4190 | array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad; |
4189 | array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; | 4191 | array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; |
4190 | array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify; | 4192 | array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify; |
4193 | array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc; | ||
4191 | } | 4194 | } |
4192 | 4195 | ||
4193 | static inline size_t inet6_ifla6_size(void) | 4196 | static inline size_t inet6_ifla6_size(void) |
@@ -5002,6 +5005,13 @@ static struct addrconf_sysctl_table | |||
5002 | .proc_handler = proc_dointvec | 5005 | .proc_handler = proc_dointvec |
5003 | }, | 5006 | }, |
5004 | { | 5007 | { |
5008 | .procname = "suppress_frag_ndisc", | ||
5009 | .data = &ipv6_devconf.suppress_frag_ndisc, | ||
5010 | .maxlen = sizeof(int), | ||
5011 | .mode = 0644, | ||
5012 | .proc_handler = proc_dointvec | ||
5013 | }, | ||
5014 | { | ||
5005 | /* sentinel */ | 5015 | /* sentinel */ |
5006 | } | 5016 | } |
5007 | }, | 5017 | }, |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 04d31c2fbef1..41720feeaa64 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -1519,10 +1519,27 @@ static void pndisc_redo(struct sk_buff *skb) | |||
1519 | kfree_skb(skb); | 1519 | kfree_skb(skb); |
1520 | } | 1520 | } |
1521 | 1521 | ||
1522 | static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb) | ||
1523 | { | ||
1524 | struct inet6_dev *idev = __in6_dev_get(skb->dev); | ||
1525 | |||
1526 | if (!idev) | ||
1527 | return true; | ||
1528 | if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED && | ||
1529 | idev->cnf.suppress_frag_ndisc) { | ||
1530 | net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n"); | ||
1531 | return true; | ||
1532 | } | ||
1533 | return false; | ||
1534 | } | ||
1535 | |||
1522 | int ndisc_rcv(struct sk_buff *skb) | 1536 | int ndisc_rcv(struct sk_buff *skb) |
1523 | { | 1537 | { |
1524 | struct nd_msg *msg; | 1538 | struct nd_msg *msg; |
1525 | 1539 | ||
1540 | if (ndisc_suppress_frag_ndisc(skb)) | ||
1541 | return 0; | ||
1542 | |||
1526 | if (skb_linearize(skb)) | 1543 | if (skb_linearize(skb)) |
1527 | return 0; | 1544 | return 0; |
1528 | 1545 | ||