aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2016-02-04 07:31:19 -0500
committerDavid S. Miller <davem@davemloft.net>2016-02-11 04:27:36 -0500
commitabbc30436d39dfed8ebfca338d253f211ac7b094 (patch)
treed7ce58e0300818d2effa7a7bd03bd5667f0d9d36
parent97daf331455077645ae1f13438bebd3d1a2e94ee (diff)
ipv6: add option to drop unicast encapsulated in L2 multicast
In order to solve a problem with 802.11, the so-called hole-196 attack, add an option (sysctl) called "drop_unicast_in_l2_multicast" which, if enabled, causes the stack to drop IPv6 unicast packets encapsulated in link-layer multi- or broadcast frames. Such frames can (as an attack) be created by any member of the same wireless network and transmitted as valid encrypted frames since the symmetric key for broadcast frames is shared between all stations. Reviewed-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/ip-sysctl.txt6
-rw-r--r--include/linux/ipv6.h1
-rw-r--r--include/uapi/linux/ipv6.h1
-rw-r--r--net/ipv6/addrconf.c8
-rw-r--r--net/ipv6/ip6_input.c10
5 files changed, 26 insertions, 0 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index a53bbfaff1c7..e0e7350a4e6a 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1674,6 +1674,12 @@ stable_secret - IPv6 address
1674 1674
1675 By default the stable secret is unset. 1675 By default the stable secret is unset.
1676 1676
1677drop_unicast_in_l2_multicast - BOOLEAN
1678 Drop any unicast IPv6 packets that are received in link-layer
1679 multicast (or broadcast) frames.
1680
1681 By default this is turned off.
1682
1677icmp/*: 1683icmp/*:
1678ratelimit - INTEGER 1684ratelimit - INTEGER
1679 Limit the maximal rates for sending ICMPv6 packets. 1685 Limit the maximal rates for sending ICMPv6 packets.
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 402753bccafa..4a4c1ae826cb 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -50,6 +50,7 @@ struct ipv6_devconf {
50 __s32 mc_forwarding; 50 __s32 mc_forwarding;
51#endif 51#endif
52 __s32 disable_ipv6; 52 __s32 disable_ipv6;
53 __s32 drop_unicast_in_l2_multicast;
53 __s32 accept_dad; 54 __s32 accept_dad;
54 __s32 force_tllao; 55 __s32 force_tllao;
55 __s32 ndisc_notify; 56 __s32 ndisc_notify;
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
index 38b4fef20219..4c413570efe8 100644
--- a/include/uapi/linux/ipv6.h
+++ b/include/uapi/linux/ipv6.h
@@ -174,6 +174,7 @@ enum {
174 DEVCONF_USE_OIF_ADDRS_ONLY, 174 DEVCONF_USE_OIF_ADDRS_ONLY,
175 DEVCONF_ACCEPT_RA_MIN_HOP_LIMIT, 175 DEVCONF_ACCEPT_RA_MIN_HOP_LIMIT,
176 DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN, 176 DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN,
177 DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
177 DEVCONF_MAX 178 DEVCONF_MAX
178}; 179};
179 180
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 38eeddedfc21..23e325f39f8e 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -4711,6 +4711,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
4711 array[DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN] = cnf->ignore_routes_with_linkdown; 4711 array[DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN] = cnf->ignore_routes_with_linkdown;
4712 /* we omit DEVCONF_STABLE_SECRET for now */ 4712 /* we omit DEVCONF_STABLE_SECRET for now */
4713 array[DEVCONF_USE_OIF_ADDRS_ONLY] = cnf->use_oif_addrs_only; 4713 array[DEVCONF_USE_OIF_ADDRS_ONLY] = cnf->use_oif_addrs_only;
4714 array[DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = cnf->drop_unicast_in_l2_multicast;
4714} 4715}
4715 4716
4716static inline size_t inet6_ifla6_size(void) 4717static inline size_t inet6_ifla6_size(void)
@@ -5785,6 +5786,13 @@ static struct addrconf_sysctl_table
5785 .proc_handler = addrconf_sysctl_ignore_routes_with_linkdown, 5786 .proc_handler = addrconf_sysctl_ignore_routes_with_linkdown,
5786 }, 5787 },
5787 { 5788 {
5789 .procname = "drop_unicast_in_l2_multicast",
5790 .data = &ipv6_devconf.drop_unicast_in_l2_multicast,
5791 .maxlen = sizeof(int),
5792 .mode = 0644,
5793 .proc_handler = proc_dointvec,
5794 },
5795 {
5788 /* sentinel */ 5796 /* sentinel */
5789 } 5797 }
5790 }, 5798 },
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 9075acf081dd..31ac3c56da4b 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -134,6 +134,16 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
134 IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1) 134 IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1)
135 goto err; 135 goto err;
136 136
137 /* If enabled, drop unicast packets that were encapsulated in link-layer
138 * multicast or broadcast to protected against the so-called "hole-196"
139 * attack in 802.11 wireless.
140 */
141 if (!ipv6_addr_is_multicast(&hdr->daddr) &&
142 (skb->pkt_type == PACKET_BROADCAST ||
143 skb->pkt_type == PACKET_MULTICAST) &&
144 idev->cnf.drop_unicast_in_l2_multicast)
145 goto err;
146
137 /* RFC4291 2.7 147 /* RFC4291 2.7
138 * Nodes must not originate a packet to a multicast address whose scope 148 * Nodes must not originate a packet to a multicast address whose scope
139 * field contains the reserved value 0; if such a packet is received, it 149 * field contains the reserved value 0; if such a packet is received, it