aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_netfilter.c107
1 files changed, 78 insertions, 29 deletions
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 137f23259a93..77f7b5fda45a 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -209,6 +209,72 @@ static inline void nf_bridge_update_protocol(struct sk_buff *skb)
209 skb->protocol = htons(ETH_P_PPP_SES); 209 skb->protocol = htons(ETH_P_PPP_SES);
210} 210}
211 211
212/* When handing a packet over to the IP layer
213 * check whether we have a skb that is in the
214 * expected format
215 */
216
217int br_parse_ip_options(struct sk_buff *skb)
218{
219 struct ip_options *opt;
220 struct iphdr *iph;
221 struct net_device *dev = skb->dev;
222 u32 len;
223
224 iph = ip_hdr(skb);
225 opt = &(IPCB(skb)->opt);
226
227 /* Basic sanity checks */
228 if (iph->ihl < 5 || iph->version != 4)
229 goto inhdr_error;
230
231 if (!pskb_may_pull(skb, iph->ihl*4))
232 goto inhdr_error;
233
234 iph = ip_hdr(skb);
235 if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
236 goto inhdr_error;
237
238 len = ntohs(iph->tot_len);
239 if (skb->len < len) {
240 IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS);
241 goto drop;
242 } else if (len < (iph->ihl*4))
243 goto inhdr_error;
244
245 if (pskb_trim_rcsum(skb, len)) {
246 IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);
247 goto drop;
248 }
249
250 /* Zero out the CB buffer if no options present */
251 if (iph->ihl == 5) {
252 memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
253 return 0;
254 }
255
256 opt->optlen = iph->ihl*4 - sizeof(struct iphdr);
257 if (ip_options_compile(dev_net(dev), opt, skb))
258 goto inhdr_error;
259
260 /* Check correct handling of SRR option */
261 if (unlikely(opt->srr)) {
262 struct in_device *in_dev = __in_dev_get_rcu(dev);
263 if (in_dev && !IN_DEV_SOURCE_ROUTE(in_dev))
264 goto drop;
265
266 if (ip_options_rcv_srr(skb))
267 goto drop;
268 }
269
270 return 0;
271
272inhdr_error:
273 IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS);
274drop:
275 return -1;
276}
277
212/* Fill in the header for fragmented IP packets handled by 278/* Fill in the header for fragmented IP packets handled by
213 * the IPv4 connection tracking code. 279 * the IPv4 connection tracking code.
214 */ 280 */
@@ -549,7 +615,6 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
549{ 615{
550 struct net_bridge_port *p; 616 struct net_bridge_port *p;
551 struct net_bridge *br; 617 struct net_bridge *br;
552 struct iphdr *iph;
553 __u32 len = nf_bridge_encap_header_len(skb); 618 __u32 len = nf_bridge_encap_header_len(skb);
554 619
555 if (unlikely(!pskb_may_pull(skb, len))) 620 if (unlikely(!pskb_may_pull(skb, len)))
@@ -578,28 +643,9 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
578 643
579 nf_bridge_pull_encap_header_rcsum(skb); 644 nf_bridge_pull_encap_header_rcsum(skb);
580 645
581 if (!pskb_may_pull(skb, sizeof(struct iphdr))) 646 if (br_parse_ip_options(skb))
582 goto inhdr_error; 647 /* Drop invalid packet */
583 648 goto out;
584 iph = ip_hdr(skb);
585 if (iph->ihl < 5 || iph->version != 4)
586 goto inhdr_error;
587
588 if (!pskb_may_pull(skb, 4 * iph->ihl))
589 goto inhdr_error;
590
591 iph = ip_hdr(skb);
592 if (ip_fast_csum((__u8 *) iph, iph->ihl) != 0)
593 goto inhdr_error;
594
595 len = ntohs(iph->tot_len);
596 if (skb->len < len || len < 4 * iph->ihl)
597 goto inhdr_error;
598
599 pskb_trim_rcsum(skb, len);
600
601 /* BUG: Should really parse the IP options here. */
602 memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
603 649
604 nf_bridge_put(skb->nf_bridge); 650 nf_bridge_put(skb->nf_bridge);
605 if (!nf_bridge_alloc(skb)) 651 if (!nf_bridge_alloc(skb))
@@ -614,8 +660,6 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
614 660
615 return NF_STOLEN; 661 return NF_STOLEN;
616 662
617inhdr_error:
618// IP_INC_STATS_BH(IpInHdrErrors);
619out: 663out:
620 return NF_DROP; 664 return NF_DROP;
621} 665}
@@ -759,14 +803,19 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff *skb,
759#if defined(CONFIG_NF_CONNTRACK_IPV4) || defined(CONFIG_NF_CONNTRACK_IPV4_MODULE) 803#if defined(CONFIG_NF_CONNTRACK_IPV4) || defined(CONFIG_NF_CONNTRACK_IPV4_MODULE)
760static int br_nf_dev_queue_xmit(struct sk_buff *skb) 804static int br_nf_dev_queue_xmit(struct sk_buff *skb)
761{ 805{
806 int ret;
807
762 if (skb->nfct != NULL && skb->protocol == htons(ETH_P_IP) && 808 if (skb->nfct != NULL && skb->protocol == htons(ETH_P_IP) &&
763 skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu && 809 skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu &&
764 !skb_is_gso(skb)) { 810 !skb_is_gso(skb)) {
765 /* BUG: Should really parse the IP options here. */ 811 if (br_parse_ip_options(skb))
766 memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); 812 /* Drop invalid packet */
767 return ip_fragment(skb, br_dev_queue_push_xmit); 813 return NF_DROP;
814 ret = ip_fragment(skb, br_dev_queue_push_xmit);
768 } else 815 } else
769 return br_dev_queue_push_xmit(skb); 816 ret = br_dev_queue_push_xmit(skb);
817
818 return ret;
770} 819}
771#else 820#else
772static int br_nf_dev_queue_xmit(struct sk_buff *skb) 821static int br_nf_dev_queue_xmit(struct sk_buff *skb)