kernel: bridge: multicast: backport a few more fixes for 3.10
The following patches unfortunately didn't hit the kernel stable branches yet, therefore cherrypicking them for OpenWRT here: * bridge: fix netfilter/NF_BR_LOCAL_OUT for own, locally generated queries * bridge: multicast: enable snooping on general queries only * bridge: multicast: add sanity check for general query destination Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@43841 3c298f89-4303-0410-b956-a3cf2f4a3e73master
parent
28f5eeb833
commit
71919ae344
|
@ -1,3 +1,88 @@
|
|||
commit f0b4eeced518c632210ef2aea44fc92cc9e86cce
|
||||
Author: Linus Lüssing <linus.luessing@web.de>
|
||||
Date: Mon Nov 17 12:20:28 2014 +0100
|
||||
|
||||
bridge: fix netfilter/NF_BR_LOCAL_OUT for own, locally generated queries
|
||||
|
||||
Ebtables on the OUTPUT chain (NF_BR_LOCAL_OUT) would not work as expected
|
||||
for both locally generated IGMP and MLD queries. The IP header specific
|
||||
filter options are off by 14 Bytes for netfilter (actual output on
|
||||
interfaces is fine).
|
||||
|
||||
NF_HOOK() expects the skb->data to point to the IP header, not the
|
||||
ethernet one (while dev_queue_xmit() does not). Luckily there is an
|
||||
br_dev_queue_push_xmit() helper function already - let's just use that.
|
||||
|
||||
Introduced by eb1d16414339a6e113d89e2cca2556005d7ce919
|
||||
("bridge: Add core IGMP snooping support")
|
||||
|
||||
Ebtables example:
|
||||
|
||||
$ ebtables -I OUTPUT -p IPv6 -o eth1 --logical-out br0 \
|
||||
--log --log-level 6 --log-ip6 --log-prefix="~EBT: " -j DROP
|
||||
|
||||
before (broken):
|
||||
|
||||
~EBT: IN= OUT=eth1 MAC source = 02:04:64:a4:39:c2 \
|
||||
MAC dest = 33:33:00:00:00:01 proto = 0x86dd IPv6 \
|
||||
SRC=64a4:39c2:86dd:6000:0000:0020:0001:fe80 IPv6 \
|
||||
DST=0000:0000:0000:0004:64ff:fea4:39c2:ff02, \
|
||||
IPv6 priority=0x3, Next Header=2
|
||||
|
||||
after (working):
|
||||
|
||||
~EBT: IN= OUT=eth1 MAC source = 02:04:64:a4:39:c2 \
|
||||
MAC dest = 33:33:00:00:00:01 proto = 0x86dd IPv6 \
|
||||
SRC=fe80:0000:0000:0000:0004:64ff:fea4:39c2 IPv6 \
|
||||
DST=ff02:0000:0000:0000:0000:0000:0000:0001, \
|
||||
IPv6 priority=0x0, Next Header=0
|
||||
|
||||
Signed-off-by: Linus Lüssing <linus.luessing@web.de>
|
||||
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
|
||||
commit 20a599bec95a52fa72432b2376a2ce47c5bb68fb
|
||||
Author: Linus Lüssing <linus.luessing@web.de>
|
||||
Date: Mon Mar 10 22:25:25 2014 +0100
|
||||
|
||||
bridge: multicast: enable snooping on general queries only
|
||||
|
||||
Without this check someone could easily create a denial of service
|
||||
by injecting multicast-specific queries to enable the bridge
|
||||
snooping part if no real querier issuing periodic general queries
|
||||
is present on the link which would result in the bridge wrongly
|
||||
shutting down ports for multicast traffic as the bridge did not learn
|
||||
about these listeners.
|
||||
|
||||
With this patch the snooping code is enabled upon receiving valid,
|
||||
general queries only.
|
||||
|
||||
Signed-off-by: Linus Lüssing <linus.luessing@web.de>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
commit 9ed973cc40c588abeaa58aea0683ea665132d11d
|
||||
Author: Linus Lüssing <linus.luessing@web.de>
|
||||
Date: Mon Mar 10 22:25:24 2014 +0100
|
||||
|
||||
bridge: multicast: add sanity check for general query destination
|
||||
|
||||
General IGMP and MLD queries are supposed to have the multicast
|
||||
link-local all-nodes address as their destination according to RFC2236
|
||||
section 9, RFC3376 section 4.1.12/9.1, RFC2710 section 8 and RFC3810
|
||||
section 5.1.15.
|
||||
|
||||
Without this check, such malformed IGMP/MLD queries can result in a
|
||||
denial of service: The queries are ignored by most IGMP/MLD listeners
|
||||
therefore they will not respond with an IGMP/MLD report. However,
|
||||
without this patch these malformed MLD queries would enable the
|
||||
snooping part in the bridge code, potentially shutting down the
|
||||
according ports towards these hosts for multicast traffic as the
|
||||
bridge did not learn about these listeners.
|
||||
|
||||
Reported-by: Jan Stancek <jstancek@redhat.com>
|
||||
Signed-off-by: Linus Lüssing <linus.luessing@web.de>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
commit 3c3769e63301fd92fcaf51870c371583dd0282ce
|
||||
Author: Linus Lüssing <linus.luessing@web.de>
|
||||
Date: Wed Sep 4 02:13:39 2013 +0200
|
||||
|
@ -229,7 +314,17 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
static void __br_multicast_send_query(struct net_bridge *br,
|
||||
struct net_bridge_port *port,
|
||||
struct br_ip *ip)
|
||||
@@ -790,37 +809,45 @@ static void __br_multicast_send_query(st
|
||||
@@ -781,46 +800,53 @@ static void __br_multicast_send_query(st
|
||||
return;
|
||||
|
||||
if (port) {
|
||||
- __skb_push(skb, sizeof(struct ethhdr));
|
||||
skb->dev = port->dev;
|
||||
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
|
||||
- dev_queue_xmit);
|
||||
+ br_dev_queue_push_xmit);
|
||||
} else
|
||||
netif_rx(skb);
|
||||
}
|
||||
|
||||
static void br_multicast_send_query(struct net_bridge *br,
|
||||
|
@ -288,7 +383,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
struct net_bridge *br = port->br;
|
||||
|
||||
spin_lock(&br->multicast_lock);
|
||||
@@ -828,25 +855,43 @@ static void br_multicast_port_query_expi
|
||||
@@ -828,25 +854,43 @@ static void br_multicast_port_query_expi
|
||||
port->state == BR_STATE_BLOCKING)
|
||||
goto out;
|
||||
|
||||
|
@ -339,7 +434,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
}
|
||||
|
||||
void br_multicast_del_port(struct net_bridge_port *port)
|
||||
@@ -854,13 +899,13 @@ void br_multicast_del_port(struct net_br
|
||||
@@ -854,13 +898,13 @@ void br_multicast_del_port(struct net_br
|
||||
del_timer_sync(&port->multicast_router_timer);
|
||||
}
|
||||
|
||||
|
@ -358,7 +453,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
}
|
||||
|
||||
void br_multicast_enable_port(struct net_bridge_port *port)
|
||||
@@ -871,7 +916,10 @@ void br_multicast_enable_port(struct net
|
||||
@@ -871,7 +915,10 @@ void br_multicast_enable_port(struct net
|
||||
if (br->multicast_disabled || !netif_running(br->dev))
|
||||
goto out;
|
||||
|
||||
|
@ -370,7 +465,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
|
||||
out:
|
||||
spin_unlock(&br->multicast_lock);
|
||||
@@ -890,7 +938,10 @@ void br_multicast_disable_port(struct ne
|
||||
@@ -890,7 +937,10 @@ void br_multicast_disable_port(struct ne
|
||||
if (!hlist_unhashed(&port->rlist))
|
||||
hlist_del_init_rcu(&port->rlist);
|
||||
del_timer(&port->multicast_router_timer);
|
||||
|
@ -382,7 +477,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
spin_unlock(&br->multicast_lock);
|
||||
}
|
||||
|
||||
@@ -1015,6 +1066,17 @@ static int br_ip6_multicast_mld2_report(
|
||||
@@ -1015,6 +1065,17 @@ static int br_ip6_multicast_mld2_report(
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -400,19 +495,22 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
/*
|
||||
* Add port to rotuer_list
|
||||
* list is maintained ordered by pointer value
|
||||
@@ -1065,12 +1127,13 @@ timer:
|
||||
@@ -1065,12 +1126,14 @@ timer:
|
||||
|
||||
static void br_multicast_query_received(struct net_bridge *br,
|
||||
struct net_bridge_port *port,
|
||||
- int saddr)
|
||||
+ struct bridge_mcast_querier *querier,
|
||||
+ int saddr,
|
||||
+ unsigned long max_delay)
|
||||
{
|
||||
if (saddr)
|
||||
-{
|
||||
- if (saddr)
|
||||
- mod_timer(&br->multicast_querier_timer,
|
||||
- jiffies + br->multicast_querier_interval);
|
||||
- else if (timer_pending(&br->multicast_querier_timer))
|
||||
+ struct bridge_mcast_querier *querier,
|
||||
+ int saddr,
|
||||
+ bool is_general_query,
|
||||
+ unsigned long max_delay)
|
||||
+{
|
||||
+ if (saddr && is_general_query)
|
||||
+ br_multicast_update_querier_timer(br, querier, max_delay);
|
||||
+ else if (timer_pending(&querier->timer))
|
||||
return;
|
||||
|
@ -427,17 +525,33 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
group = ih->group;
|
||||
|
||||
if (skb->len == sizeof(*ih)) {
|
||||
@@ -1122,6 +1183,9 @@ static int br_ip4_multicast_query(struct
|
||||
@@ -1122,6 +1183,17 @@ static int br_ip4_multicast_query(struct
|
||||
IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
|
||||
}
|
||||
|
||||
+ /* RFC2236+RFC3376 (IGMPv2+IGMPv3) require the multicast link layer
|
||||
+ * all-systems destination addresses (224.0.0.1) for general queries
|
||||
+ */
|
||||
+ if (!group && iph->daddr != htonl(INADDR_ALLHOSTS_GROUP)) {
|
||||
+ err = -EINVAL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ br_multicast_query_received(br, port, &br->ip4_querier, !!iph->saddr,
|
||||
+ max_delay);
|
||||
+ !group, max_delay);
|
||||
+
|
||||
if (!group)
|
||||
goto out;
|
||||
|
||||
@@ -1174,8 +1238,6 @@ static int br_ip6_multicast_query(struct
|
||||
@@ -1166,6 +1238,7 @@ static int br_ip6_multicast_query(struct
|
||||
unsigned long max_delay;
|
||||
unsigned long now = jiffies;
|
||||
const struct in6_addr *group = NULL;
|
||||
+ bool is_general_query;
|
||||
int err = 0;
|
||||
u16 vid = 0;
|
||||
|
||||
@@ -1174,8 +1247,6 @@ static int br_ip6_multicast_query(struct
|
||||
(port && port->state == BR_STATE_DISABLED))
|
||||
goto out;
|
||||
|
||||
|
@ -446,17 +560,28 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
/* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
|
||||
if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
|
||||
err = -EINVAL;
|
||||
@@ -1203,6 +1265,9 @@ static int br_ip6_multicast_query(struct
|
||||
@@ -1203,6 +1274,20 @@ static int br_ip6_multicast_query(struct
|
||||
max_delay = max(msecs_to_jiffies(MLDV2_MRC(ntohs(mld2q->mld2q_mrc))), 1UL);
|
||||
}
|
||||
|
||||
+ is_general_query = group && ipv6_addr_any(group);
|
||||
+
|
||||
+ /* RFC2710+RFC3810 (MLDv1+MLDv2) require the multicast link layer
|
||||
+ * all-nodes destination address (ff02::1) for general queries
|
||||
+ */
|
||||
+ if (is_general_query && !ipv6_addr_is_ll_all_nodes(&ip6h->daddr)) {
|
||||
+ err = -EINVAL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ br_multicast_query_received(br, port, &br->ip6_querier,
|
||||
+ !ipv6_addr_any(&ip6h->saddr), max_delay);
|
||||
+ !ipv6_addr_any(&ip6h->saddr),
|
||||
+ is_general_query, max_delay);
|
||||
+
|
||||
if (!group)
|
||||
goto out;
|
||||
|
||||
@@ -1235,7 +1300,9 @@ out:
|
||||
@@ -1235,7 +1320,9 @@ out:
|
||||
|
||||
static void br_multicast_leave_group(struct net_bridge *br,
|
||||
struct net_bridge_port *port,
|
||||
|
@ -467,7 +592,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
{
|
||||
struct net_bridge_mdb_htable *mdb;
|
||||
struct net_bridge_mdb_entry *mp;
|
||||
@@ -1246,7 +1313,7 @@ static void br_multicast_leave_group(str
|
||||
@@ -1246,7 +1333,7 @@ static void br_multicast_leave_group(str
|
||||
spin_lock(&br->multicast_lock);
|
||||
if (!netif_running(br->dev) ||
|
||||
(port && port->state == BR_STATE_DISABLED) ||
|
||||
|
@ -476,7 +601,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
goto out;
|
||||
|
||||
mdb = mlock_dereference(br->mdb, br);
|
||||
@@ -1254,6 +1321,31 @@ static void br_multicast_leave_group(str
|
||||
@@ -1254,6 +1341,31 @@ static void br_multicast_leave_group(str
|
||||
if (!mp)
|
||||
goto out;
|
||||
|
||||
|
@ -508,7 +633,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
if (port && (port->flags & BR_MULTICAST_FAST_LEAVE)) {
|
||||
struct net_bridge_port_group __rcu **pp;
|
||||
|
||||
@@ -1306,7 +1398,6 @@ static void br_multicast_leave_group(str
|
||||
@@ -1306,7 +1418,6 @@ static void br_multicast_leave_group(str
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -516,7 +641,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
out:
|
||||
spin_unlock(&br->multicast_lock);
|
||||
}
|
||||
@@ -1317,6 +1408,8 @@ static void br_ip4_multicast_leave_group
|
||||
@@ -1317,6 +1428,8 @@ static void br_ip4_multicast_leave_group
|
||||
__u16 vid)
|
||||
{
|
||||
struct br_ip br_group;
|
||||
|
@ -525,7 +650,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
|
||||
if (ipv4_is_local_multicast(group))
|
||||
return;
|
||||
@@ -1325,7 +1418,7 @@ static void br_ip4_multicast_leave_group
|
||||
@@ -1325,7 +1438,7 @@ static void br_ip4_multicast_leave_group
|
||||
br_group.proto = htons(ETH_P_IP);
|
||||
br_group.vid = vid;
|
||||
|
||||
|
@ -534,7 +659,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
@@ -1335,15 +1428,18 @@ static void br_ip6_multicast_leave_group
|
||||
@@ -1335,15 +1448,18 @@ static void br_ip6_multicast_leave_group
|
||||
__u16 vid)
|
||||
{
|
||||
struct br_ip br_group;
|
||||
|
@ -555,7 +680,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
}
|
||||
#endif
|
||||
|
||||
@@ -1473,8 +1569,14 @@ static int br_multicast_ipv6_rcv(struct
|
||||
@@ -1473,8 +1589,14 @@ static int br_multicast_ipv6_rcv(struct
|
||||
* - MLD has always Router Alert hop-by-hop option
|
||||
* - But we do not support jumbrograms.
|
||||
*/
|
||||
|
@ -572,7 +697,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
ip6h->payload_len == 0)
|
||||
return 0;
|
||||
|
||||
@@ -1605,19 +1707,32 @@ int br_multicast_rcv(struct net_bridge *
|
||||
@@ -1605,19 +1727,32 @@ int br_multicast_rcv(struct net_bridge *
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -612,7 +737,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
|
||||
void br_multicast_init(struct net_bridge *br)
|
||||
{
|
||||
@@ -1626,6 +1741,7 @@ void br_multicast_init(struct net_bridge
|
||||
@@ -1626,6 +1761,7 @@ void br_multicast_init(struct net_bridge
|
||||
|
||||
br->multicast_router = 1;
|
||||
br->multicast_querier = 0;
|
||||
|
@ -620,7 +745,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
br->multicast_last_member_count = 2;
|
||||
br->multicast_startup_query_count = 2;
|
||||
|
||||
@@ -1636,23 +1752,43 @@ void br_multicast_init(struct net_bridge
|
||||
@@ -1636,23 +1772,43 @@ void br_multicast_init(struct net_bridge
|
||||
br->multicast_querier_interval = 255 * HZ;
|
||||
br->multicast_membership_interval = 260 * HZ;
|
||||
|
||||
|
@ -670,7 +795,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
}
|
||||
|
||||
void br_multicast_stop(struct net_bridge *br)
|
||||
@@ -1664,8 +1800,12 @@ void br_multicast_stop(struct net_bridge
|
||||
@@ -1664,8 +1820,12 @@ void br_multicast_stop(struct net_bridge
|
||||
int i;
|
||||
|
||||
del_timer_sync(&br->multicast_router_timer);
|
||||
|
@ -685,7 +810,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
|
||||
spin_lock_bh(&br->multicast_lock);
|
||||
mdb = mlock_dereference(br->mdb, br);
|
||||
@@ -1767,18 +1907,24 @@ unlock:
|
||||
@@ -1767,18 +1927,24 @@ unlock:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -713,7 +838,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
}
|
||||
}
|
||||
|
||||
@@ -1813,7 +1959,10 @@ rollback:
|
||||
@@ -1813,7 +1979,10 @@ rollback:
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
|
@ -725,7 +850,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
|
||||
unlock:
|
||||
spin_unlock_bh(&br->multicast_lock);
|
||||
@@ -1823,6 +1972,8 @@ unlock:
|
||||
@@ -1823,6 +1992,8 @@ unlock:
|
||||
|
||||
int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
|
||||
{
|
||||
|
@ -734,7 +859,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
val = !!val;
|
||||
|
||||
spin_lock_bh(&br->multicast_lock);
|
||||
@@ -1830,8 +1981,22 @@ int br_multicast_set_querier(struct net_
|
||||
@@ -1830,8 +2001,22 @@ int br_multicast_set_querier(struct net_
|
||||
goto unlock;
|
||||
|
||||
br->multicast_querier = val;
|
||||
|
@ -918,7 +1043,7 @@ Date: Tue May 21 21:52:54 2013 +0000
|
|||
static ssize_t show_multicast_querier(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
@@ -734,6 +759,7 @@ static struct attribute *bridge_attrs[]
|
||||
@@ -734,6 +759,7 @@ static struct attribute *bridge_attrs[]
|
||||
&dev_attr_multicast_router.attr,
|
||||
&dev_attr_multicast_snooping.attr,
|
||||
&dev_attr_multicast_querier.attr,
|
||||
|
|
|
@ -67,13 +67,13 @@
|
|||
default:
|
||||
--- a/net/bridge/br_multicast.c
|
||||
+++ b/net/bridge/br_multicast.c
|
||||
@@ -802,7 +802,7 @@ static void __br_multicast_send_query(st
|
||||
@@ -801,7 +801,7 @@ static void __br_multicast_send_query(st
|
||||
|
||||
if (port) {
|
||||
__skb_push(skb, sizeof(struct ethhdr));
|
||||
skb->dev = port->dev;
|
||||
- NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
|
||||
+ BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
|
||||
dev_queue_xmit);
|
||||
br_dev_queue_push_xmit);
|
||||
} else
|
||||
netif_rx(skb);
|
||||
--- a/net/bridge/br_netfilter.c
|
||||
|
|
Loading…
Reference in New Issue