Skip to content

Commit b800c3b

Browse files
strssndktndavem330
authored andcommitted
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>
1 parent a3a975b commit b800c3b

File tree

5 files changed

+35
-0
lines changed

5 files changed

+35
-0
lines changed

Documentation/networking/ip-sysctl.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,6 +1349,12 @@ mldv2_unsolicited_report_interval - INTEGER
13491349
MLDv2 report retransmit will take place.
13501350
Default: 1000 (1 second)
13511351

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+
13521358
icmp/*:
13531359
ratelimit - INTEGER
13541360
Limit the maximal rates for sending ICMPv6 packets.

include/linux/ipv6.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ struct ipv6_devconf {
5050
__s32 accept_dad;
5151
__s32 force_tllao;
5252
__s32 ndisc_notify;
53+
__s32 suppress_frag_ndisc;
5354
void *sysctl;
5455
};
5556

include/uapi/linux/ipv6.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ enum {
162162
DEVCONF_NDISC_NOTIFY,
163163
DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL,
164164
DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL,
165+
DEVCONF_SUPPRESS_FRAG_NDISC,
165166
DEVCONF_MAX
166167
};
167168

net/ipv6/addrconf.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
204204
.accept_source_route = 0, /* we do not accept RH0 by default. */
205205
.disable_ipv6 = 0,
206206
.accept_dad = 1,
207+
.suppress_frag_ndisc = 1,
207208
};
208209

209210
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -241,6 +242,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
241242
.accept_source_route = 0, /* we do not accept RH0 by default. */
242243
.disable_ipv6 = 0,
243244
.accept_dad = 1,
245+
.suppress_frag_ndisc = 1,
244246
};
245247

246248
/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -4188,6 +4190,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
41884190
array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
41894191
array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao;
41904192
array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify;
4193+
array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc;
41914194
}
41924195

41934196
static inline size_t inet6_ifla6_size(void)
@@ -5001,6 +5004,13 @@ static struct addrconf_sysctl_table
50015004
.mode = 0644,
50025005
.proc_handler = proc_dointvec
50035006
},
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+
},
50045014
{
50055015
/* sentinel */
50065016
}

net/ipv6/ndisc.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,10 +1519,27 @@ static void pndisc_redo(struct sk_buff *skb)
15191519
kfree_skb(skb);
15201520
}
15211521

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+
15221536
int ndisc_rcv(struct sk_buff *skb)
15231537
{
15241538
struct nd_msg *msg;
15251539

1540+
if (ndisc_suppress_frag_ndisc(skb))
1541+
return 0;
1542+
15261543
if (skb_linearize(skb))
15271544
return 0;
15281545

0 commit comments

Comments
 (0)