Re: [PATCH] bridge-nf: Allow IPTables to filter PPPoE traffic
Bart De Schuymer <[email protected]>
| Newsgroups | gmane.linux.network.bridge.ebtables.devel |
|---|---|
| Message-ID | <[email protected]> |
Op ma, 05-02-2007 te 16:48 -0500, schreef Michael Milner:
> Hi,
>
> I've put together some code to allow IPTables to filter PPPoE traffic in
> the same way that bridge-nf allows iptables to filter VLAN traffic.
>
> I don't have much experience with this code so my approach is very
> simplistic and modelled after the VLAN code. I have some questions as
> comments in the patches.
>
> I also added a new sysctl entry to allow the functionality to be disabled.
>
> The patch is against 2.6.15. Comments appreciated. It works fine for me
> but I wanted some input before submitting it "officially".
Please update this to 2.6.20. More comments are below.
Thanks,
Bart
> Thanks,
>
> Mike Milner
>
> --- a/include/linux/sysctl.h 2006-03-02 16:18:41.000000000 -0500
> +++ b/include/linux/sysctl.h 2007-01-16 15:42:27.000000000 -0500
> @@ -726,6 +726,7 @@ enum {
> NET_BRIDGE_NF_CALL_IPTABLES = 2,
> NET_BRIDGE_NF_CALL_IP6TABLES = 3,
> NET_BRIDGE_NF_FILTER_VLAN_TAGGED = 4,
> + NET_BRIDGE_NF_FILTER_PPPOE_TAGGED = 5,
> };
>
> /* CTL_PROC names: */
>
> --- a/include/linux/netfilter_bridge.h 2006-03-02 16:18:41.000000000 -0500
> +++ b/include/linux/netfilter_bridge.h 2007-02-02 14:31:15.000000000 -0500
> @@ -72,6 +72,19 @@ void nf_bridge_maybe_copy_header(struct
> if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
> memcpy(skb->data - 18, skb->nf_bridge->data, 18);
> skb_push(skb, 4);
> + }
> + else if (skb->protocol == __constant_htons(ETH_P_PPP_SES)) {
Please make this one line, i.e. "} else if ". The same comment holds in
some other places.
> + /*
> + * Not sure about '24'. Default else block below
> + * copies 16 bytes. Block above copies 18 (2 more) but
> + * skb_push's 4 bytes. VLAN header is 4 bytes, so why
> + * aren't 4 extra bytes being memcpy'd?
> + *
> + * I'm memcpy'ing AND skb_push'ing 8 extra bytes, the size
> + * of the PPPoE header.
> + */
Ethernet header is only 14 bytes long, but the networking stack always
puts that in 16 bytes (the first 2 bytes are meaningless afaik). They
probably do that because 16 is a power of 2. Anyway, 14+4=18
> + memcpy(skb->data - 24, skb->nf_bridge->data, 24);
> + skb_push(skb, 8);
> } else
> memcpy(skb->data - 16, skb->nf_bridge->data, 16);
> }
> @@ -84,6 +97,13 @@ void nf_bridge_save_header(struct sk_buf
>
> if (skb->protocol == __constant_htons(ETH_P_8021Q))
> header_size = 18;
> + else if (skb->protocol == __constant_htons(ETH_P_PPP_SES))
> + header_size = 24;
> + /*
> + * Why does the VLAN code only increase the header by 2 bytes?
> + * AFAIK the VLAN header is 4 bytes. I reserve 8 extra bytes,
> + * the size of the PPPoE header.
> + */
>
> memcpy(skb->nf_bridge->data, skb->data - header_size, header_size);
> }
>
> --- a/net/bridge/br_netfilter.c 2006-03-09 08:19:49.000000000 -0500
> +++ b/net/bridge/br_netfilter.c 2007-02-05 16:26:13.000000000 -0500
> @@ -12,6 +12,7 @@
> * Oct 06 2003: filter encapsulated IP/ARP VLAN traffic on untagged bridge
> * (bdschuym)
> * Sep 01 2004: add IPv6 filtering (bdschuym)
> + * Jan 16 2007: let iptables see bridged PPPoE traffic (mdmilner)
> *
> * This program is free software; you can redistribute it and/or
> * modify it under the terms of the GNU General Public License
> @@ -28,6 +29,7 @@
> #include <linux/skbuff.h>
> #include <linux/if_ether.h>
> #include <linux/if_vlan.h>
> +#include <linux/ppp_defs.h>
> #include <linux/netfilter_bridge.h>
> #include <linux/netfilter_ipv4.h>
> #include <linux/netfilter_ipv6.h>
> @@ -53,6 +55,7 @@ static int brnf_call_iptables = 1;
> static int brnf_call_ip6tables = 1;
> static int brnf_call_arptables = 1;
> static int brnf_filter_vlan_tagged = 1;
> +static int brnf_filter_pppoe_tagged = 1;
> #else
> #define brnf_filter_vlan_tagged 1
> #endif
> @@ -67,6 +70,43 @@ static int brnf_filter_vlan_tagged = 1;
> hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_ARP) && \
> brnf_filter_vlan_tagged)
>
> +/**
> + * Entire Ethernet + PPPoE + PPP header
> + */
> +struct pppoe_ethhdr {
> + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
> + unsigned char h_source[ETH_ALEN]; /* source ether addr */
> + __be16 h_pppoe_proto; /* Should always be 0x8864 */
> +#if defined(__LITTLE_ENDIAN_BITFIELD)
> + __u8 ver : 4;
> + __u8 type : 4;
> +#elif defined(__BIG_ENDIAN_BITFIELD)
> + __u8 type : 4;
> + __u8 ver : 4;
> +#elsedevel
> +#error "Please fix <asm/byteorder.h>"
> +#endif
> + __u8 code;
> + __u16 sid;
> + __u16 length;
> + __be16 h_pppoe_encapsulated_proto;
> +} __attribute__ ((packed));
> +
Don't make this new struct, just use include/linux/if_pppox.h.
> +#define PPPOE_HLEN (sizeof(struct pppoe_ethhdr) - ETH_HLEN)
> +
> +/* Extracts the pppoe_ethhdr from an sk_buff */
> +static inline struct pppoe_ethhdr *pppoe_eth_hdr(const struct sk_buff *skb)
> +{
> + return (struct pppoe_ethhdr *)skb->mac.raw;
> +}
> +
> +#define IS_PPPOE_IP (skb->protocol == __constant_htons(ETH_P_PPP_SES) && \
> + pppoe->h_pppoe_encapsulated_proto == __constant_htons(PPP_IP) && \
> + brnf_filter_pppoe_tagged)
> +//#define IS_PPPOE_IPV6 (skb->protocol == __constant_htons(ETH_P_PPP_SES)
> && \
> +// pppoe->h_pppoe_encapsulated_proto == __constant_htons(PPP_P_IPV6) && \
> +// brnf_filter_pppoe_tagged)
> +
> /* We need these fake structures to make netfilter happy --
> * lots of places assume that skb->dst != NULL, which isn't
> * all that unreasonable.
> @@ -195,6 +235,10 @@ static int br_nf_pre_routing_finish_brid
> skb_pull(skb, VLAN_HLEN);
> skb->nh.raw += VLAN_HLEN;
> }
> + else if (skb->protocol == __constant_htons(ETH_P_PPP_SES)) {
> + skb_pull(skb, PPPOE_HLEN);
> + skb->nh.raw += PPPOE_HLEN;
> + }
> skb->dst->output(skb);
> }
> return 0;
> @@ -246,6 +290,11 @@ bridged_dnat:
> skb_push(skb, VLAN_HLEN);
> skb->nh.raw -= VLAN_HLEN;
> }
> + else if (skb->protocol ==
> + __constant_htons(ETH_P_PPP_SES)) {
> + skb_push(skb, PPPOE_HLEN);
> + skb->nh.raw -= PPPOE_HLEN;
> + }
> NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING,
> skb, skb->dev, NULL,
> br_nf_pre_routing_finish_bridge,
> @@ -266,6 +315,10 @@ bridged_dnat:
> skb_push(skb, VLAN_HLEN);
> skb->nh.raw -= VLAN_HLEN;
> }
> + else if (skb->protocol == __constant_htons(ETH_P_PPP_SES)) {
> + skb_push(skb, PPPOE_HLEN);
> + skb->nh.raw -= PPPOE_HLEN;
> + }
> NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
> br_handle_frame_finish, 1);
>
> @@ -408,6 +461,7 @@ static unsigned int br_nf_pre_routing(un
> struct sk_buff *skb = *pskb;
> struct nf_bridge_info *nf_bridge;
> struct vlan_ethhdr *hdr = vlan_eth_hdr(*pskb);
> + struct pppoe_ethhdr *pppoe = pppoe_eth_hdr(*pskb);
>
> if (skb->protocol == __constant_htons(ETH_P_IPV6) || IS_VLAN_IPV6) {
> #ifdef CONFIG_SYSCTL
> @@ -427,7 +481,8 @@ static unsigned int br_nf_pre_routing(un
> return NF_ACCEPT;
> #endif
>
> - if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP)
> + if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP &&
> + !IS_PPPOE_IP)
> return NF_ACCEPT;
>
> if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
> @@ -436,6 +491,13 @@ static unsigned int br_nf_pre_routing(un
> if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
> skb_pull(skb, VLAN_HLEN);
> }
> + else if (skb->protocol == __constant_htons(ETH_P_PPP_SES)) {
> + /* Not sure why VLAN doesn't have the '+=' line, but PPPoE
> + * doesn't work without it
> + */
Later kernel versions differ here. Try 2.6.20.
> + skb_pull(skb, PPPOE_HLEN);
> + skb->nh.raw += PPPOE_HLEN;
> + }
>
> if (!pskb_may_pull(skb, sizeof(struct iphdr)))
> goto inhdr_error;
> @@ -522,6 +584,10 @@ static int br_nf_forward_finish(struct s
> skb_push(skb, VLAN_HLEN);
> skb->nh.raw -= VLAN_HLEN;
> }
> + else if (skb->protocol == __constant_htons(ETH_P_PPP_SES)) {
> + skb_push(skb, PPPOE_HLEN);
> + skb->nh.raw -= PPPOE_HLEN;
> + }
> NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in,
> skb->dev, br_forward_finish, 1);
> return 0;
> @@ -539,6 +605,7 @@ static unsigned int br_nf_forward_ip(uns
> struct sk_buff *skb = *pskb;
> struct nf_bridge_info *nf_bridge;
> struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
> + struct pppoe_ethhdr *pppoe = pppoe_eth_hdr(skb);
> struct net_device *parent;
> int pf;
>
> @@ -549,7 +616,8 @@ static unsigned int br_nf_forward_ip(uns
> if (!parent)
> return NF_DROP;
>
> - if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP)
> + if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP ||
> + IS_PPPOE_IP)
> pf = PF_INET;
> else
> pf = PF_INET6;
> @@ -558,6 +626,10 @@ static unsigned int br_nf_forward_ip(uns
> skb_pull(*pskb, VLAN_HLEN);
> (*pskb)->nh.raw += VLAN_HLEN;
> }
> + else if (skb->protocol == __constant_htons(ETH_P_PPP_SES)) {
> + skb_pull(*pskb, PPPOE_HLEN);
> + (*pskb)->nh.raw += PPPOE_HLEN;
> + }
>
> nf_bridge = skb->nf_bridge;
> if (skb->pkt_type == PACKET_OTHERHOST) {
> @@ -617,6 +689,10 @@ static int br_nf_local_out_finish(struct
> skb_push(skb, VLAN_HLEN);
> skb->nh.raw -= VLAN_HLEN;
> }
> + else if (skb->protocol == __constant_htons(ETH_P_PPP_SES)) {
> + skb_push(skb, PPPOE_HLEN);
> + skb->nh.raw -= PPPOE_HLEN;
> + }
>
> NF_HOOK_THRESH(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
> br_forward_finish, NF_BR_PRI_FIRST + 1);
> @@ -652,12 +728,14 @@ static unsigned int br_nf_local_out(unsi
> struct sk_buff *skb = *pskb;
> struct nf_bridge_info *nf_bridge;
> struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
> + struct pppoe_ethhdr *pppoe = pppoe_eth_hdr(skb);
> int pf;
>
> if (!skb->nf_bridge)
> return NF_ACCEPT;
>
> - if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP)
> + if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP ||
> + IS_PPPOE_IP)
> pf = PF_INET;
> else
> pf = PF_INET6;
> @@ -687,6 +765,10 @@ static unsigned int br_nf_local_out(unsi
> skb_push(skb, VLAN_HLEN);
> skb->nh.raw -= VLAN_HLEN;
> }
> + else if (skb->protocol == __constant_htons(ETH_P_PPP_SES)) {
> + skb_push(skb, PPPOE_HLEN);
> + skb->nh.raw -= PPPOE_HLEN;
> + }
>
> NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev,
> skb->dev, br_forward_finish);
> @@ -705,6 +787,10 @@ static unsigned int br_nf_local_out(unsi
> skb_pull(skb, VLAN_HLEN);
> (*pskb)->nh.raw += VLAN_HLEN;
> }
> + else if (skb->protocol == __constant_htons(ETH_P_PPP_SES)) {
> + skb_pull(skb, PPPOE_HLEN);
> + (*pskb)->nh.raw += PPPOE_HLEN;
> + }
> /* IP forwarded traffic has a physindev, locally
> * generated traffic hasn't. */
> if (realindev != NULL) {
> @@ -736,6 +822,7 @@ static unsigned int br_nf_post_routing(u
> struct sk_buff *skb = *pskb;
> struct nf_bridge_info *nf_bridge = (*pskb)->nf_bridge;
> struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
> + struct pppoe_ethhdr *pppoe = pppoe_eth_hdr(skb);
> struct net_device *realoutdev = bridge_parent(skb->dev);
> int pf;
>
> @@ -755,7 +842,8 @@ static unsigned int br_nf_post_routing(u
> if (!realoutdev)
> return NF_DROP;
>
> - if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP)
> + if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP ||
> + IS_PPPOE_IP)
> pf = PF_INET;
> else
> pf = PF_INET6;
> @@ -778,6 +866,10 @@ static unsigned int br_nf_post_routing(u
> skb_pull(skb, VLAN_HLEN);
> skb->nh.raw += VLAN_HLEN;
> }
> + else if (skb->protocol == __constant_htons(ETH_P_PPP_SES)) {
> + skb_pull(skb, PPPOE_HLEN);
> + skb->nh.raw += PPPOE_HLEN;
> + }
>
> nf_bridge_save_header(skb);
>
> @@ -1004,6 +1096,14 @@ static ctl_table brnf_table[] = {
> .mode = 0644,
> .proc_handler = &brnf_sysctl_call_tables,
> },
> + {
> + .ctl_name = NET_BRIDGE_NF_FILTER_PPPOE_TAGGED,
> + .procname = "bridge-nf-filter-pppoe-tagged",
> + .data = &brnf_filter_pppoe_tagged,
> + .maxlen = sizeof(int),
> + .mode = 0644,
> + .proc_handler = &brnf_sysctl_call_tables,
> + },
> { .ctl_name = 0 }
> };
>
>
>
>
> -------------------------------------------------------------------------
> Using Tomcat but need to do more? Need to support web services, security?
> Get stuff done quickly with pre-integrated technology to make your job easier.
> Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
> http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
> _______________________________________________
> Ebtables-devel mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/ebtables-devel
>
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier.
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642