Re: Vlans
Lutz Jaenicke <[email protected]> Thu, 2 Nov 2006 11:19:13 +0100
| Newsgroups | gmane.linux.network.bridge.ebtables.user |
|---|---|
| Organization | Innominate Security Technologies AG |
| Message-ID | <[email protected]> |
On Sat, Oct 28, 2006 at 05:21:31PM +0200, Bart De Schuymer wrote: > Op wo, 18-10-2006 te 20:01 +0200, schreef Lutz Jaenicke: > > The ebtables components (those configured with the ebtables command) > > can be used to filter for VLAN tags. The ebtables specific protocol > > matchers for arp, ip, etc are not transparent wrt VLAN: they will > > not match VLAN encapsulated traffic. Note: I do have an extension > > patch to provide this support (configurable) for some really old > > version of ebtables (for kernel 2.4 with br-nf patch) that is due > > to be ported to 2.6.18+ in the next days anyway. > > I can send it to the list for discussion/inclusion as soon as the > > porting is done if there is interest... > > That would be interesting, thanks. I was thinking about a userspace flag > like --vlan-encapsulated to let the user specify she wants to filter the > ip/arp/etc stuff inside the vlan package. The kernel logic best resides > inside the specific matches/targets, shouldn't be too messy. I had implemented it using a /proc/sys control flag as attached below. I am not to happy with this solution, so if you have a better proposal... I am currently overloaded with other projects so please understand that my response time may be somewhat large from time to time. It does not mean that I will not continue to work on this issue :-) Best regards, Lutz -- Dr.-Ing. Lutz Jänicke CTO Innominate Security Technologies AG /protecting industrial networks/ tel: +49.30.6392-3308 fax: +49.30.6392-3307 Albert-Einstein-Str. 14 D-12489 Berlin, Germany www.innominate.com --------------------------------------------------------------- Visit us at the SPS/IPC/Drives in Nuernberg 28 - 30 November 2006, Hall 9, Stand 9-125 --------------------------------------------------------------- ------------------------------------------------------------------------- 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-user mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ebtables-user
ebtables_vlan_transparent.patch
(text/plain, 14.8 KB)
Index: br_netfilter.c
===================================================================
RCS file: /home/ljaenicke/source/mguard/linux-2.6/linux-2.6.15/net/bridge/br_netfilter.c,v
retrieving revision 1.3
diff -u -r1.3 br_netfilter.c
--- br_netfilter.c 10 Oct 2006 15:35:08 -0000 1.3
+++ br_netfilter.c 19 Oct 2006 18:14:09 -0000
@@ -57,6 +57,9 @@
static int brnf_call_ip6tables = 1;
static int brnf_call_arptables = 1;
static int brnf_filter_vlan_tagged = 1;
+#ifdef CONFIG_BRIDGE_NETFILTER
+int ebtables_treat_vlan_transparent = 0;
+#endif
#else
#define brnf_filter_vlan_tagged 1
#endif
@@ -1015,6 +1018,8 @@
return ret;
}
+#define NET_EBTABLES_TREAT_VLAN_TRANSPARENT 2091
+
static ctl_table brnf_table[] = {
{
.ctl_name = NET_BRIDGE_NF_CALL_ARPTABLES,
@@ -1048,6 +1053,14 @@
.mode = 0644,
.proc_handler = &brnf_sysctl_call_tables,
},
+ {
+ .ctl_name = NET_EBTABLES_TREAT_VLAN_TRANSPARENT,
+ .procname = "ebtables-treat-vlan-transparent",
+ .data = &ebtables_treat_vlan_transparent,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &brnf_sysctl_call_tables,
+ },
{ .ctl_name = 0 }
};
Index: br_private.h
===================================================================
RCS file: /home/ljaenicke/source/mguard/linux-2.6/linux-2.6.15/net/bridge/br_private.h,v
retrieving revision 1.3
diff -u -r1.3 br_private.h
--- br_private.h 10 Oct 2006 15:35:08 -0000 1.3
+++ br_private.h 19 Oct 2006 14:43:37 -0000
@@ -195,6 +195,7 @@
#ifdef CONFIG_BRIDGE_NETFILTER
extern int br_netfilter_init(void);
extern void br_netfilter_fini(void);
+extern int ebtables_treat_vlan_transparent;
#else
#define br_netfilter_init() (0)
#define br_netfilter_fini() do { } while(0)
Index: netfilter/ebt_802_3.c
===================================================================
RCS file: /home/ljaenicke/source/mguard/linux-2.6/linux-2.6.15/net/bridge/netfilter/ebt_802_3.c,v
retrieving revision 1.2
diff -u -r1.2 ebt_802_3.c
--- netfilter/ebt_802_3.c 16 Jun 2006 14:20:29 -0000 1.2
+++ netfilter/ebt_802_3.c 19 Oct 2006 18:14:46 -0000
@@ -11,13 +11,18 @@
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_802_3.h>
#include <linux/module.h>
+#include <linux/if_vlan.h>
static int ebt_filter_802_3(const struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, const void *data, unsigned int datalen)
{
struct ebt_802_3_info *info = (struct ebt_802_3_info *)data;
- struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb);
- uint16_t type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type;
+ struct ebt_802_3_hdr _hdr, *hdr;
+ uint16_t type;
+ int offset = (skb->protocol == __constant_htons(ETH_P_8021Q)) ? VLAN_HLEN : 0;
+
+ hdr = skb_header_pointer(skb, offset, sizeof(_hdr), &_hdr);
+ type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type;
if (info->bitmask & EBT_802_3_SAP) {
if (FWINV(info->sap != hdr->llc.ui.ssap, EBT_802_3_SAP))
Index: netfilter/ebt_among.c
===================================================================
RCS file: /home/ljaenicke/source/mguard/linux-2.6/linux-2.6.15/net/bridge/netfilter/ebt_among.c,v
retrieving revision 1.2
diff -u -r1.2 ebt_among.c
--- netfilter/ebt_among.c 16 Jun 2006 14:20:29 -0000 1.2
+++ netfilter/ebt_among.c 19 Oct 2006 18:15:17 -0000
@@ -12,6 +12,7 @@
#include <linux/netfilter_bridge/ebt_among.h>
#include <linux/ip.h>
#include <linux/if_arp.h>
+#include <linux/if_vlan.h>
#include <linux/module.h>
static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh,
@@ -72,23 +73,30 @@
static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr)
{
- if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) {
+ uint16_t h_proto = eth_hdr(skb)->h_proto;
+ int offset = 0;
+ if (h_proto == __constant_htons(ETH_P_8021Q)) {
+ h_proto = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;;
+ offset = VLAN_HLEN;
+ }
+
+ if (h_proto == __constant_htons(ETH_P_IP)) {
struct iphdr _iph, *ih;
- ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
if (ih == NULL)
return -1;
*addr = ih->daddr;
- } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
+ } else if (h_proto == __constant_htons(ETH_P_ARP)) {
struct arphdr _arph, *ah;
uint32_t buf, *bp;
- ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+ ah = skb_header_pointer(skb, offset, sizeof(_arph), &_arph);
if (ah == NULL ||
ah->ar_pln != sizeof(uint32_t) ||
ah->ar_hln != ETH_ALEN)
return -1;
- bp = skb_header_pointer(skb, sizeof(struct arphdr) +
+ bp = skb_header_pointer(skb, offset + sizeof(struct arphdr) +
2 * ETH_ALEN + sizeof(uint32_t),
sizeof(uint32_t), &buf);
if (bp == NULL)
@@ -100,23 +108,30 @@
static int get_ip_src(const struct sk_buff *skb, uint32_t *addr)
{
- if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) {
+ uint16_t h_proto = eth_hdr(skb)->h_proto;
+ int offset = 0;
+ if (h_proto == __constant_htons(ETH_P_8021Q)) {
+ h_proto = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;;
+ offset = VLAN_HLEN;
+ }
+
+ if (h_proto == __constant_htons(ETH_P_IP)) {
struct iphdr _iph, *ih;
- ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
if (ih == NULL)
return -1;
*addr = ih->saddr;
- } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
+ } else if (h_proto == __constant_htons(ETH_P_ARP)) {
struct arphdr _arph, *ah;
uint32_t buf, *bp;
- ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+ ah = skb_header_pointer(skb, offset, sizeof(_arph), &_arph);
if (ah == NULL ||
ah->ar_pln != sizeof(uint32_t) ||
ah->ar_hln != ETH_ALEN)
return -1;
- bp = skb_header_pointer(skb, sizeof(struct arphdr) +
+ bp = skb_header_pointer(skb, offset + sizeof(struct arphdr) +
ETH_ALEN, sizeof(uint32_t), &buf);
if (bp == NULL)
return -1;
Index: netfilter/ebt_arp.c
===================================================================
RCS file: /home/ljaenicke/source/mguard/linux-2.6/linux-2.6.15/net/bridge/netfilter/ebt_arp.c,v
retrieving revision 1.2
diff -u -r1.2 ebt_arp.c
--- netfilter/ebt_arp.c 16 Jun 2006 14:20:29 -0000 1.2
+++ netfilter/ebt_arp.c 19 Oct 2006 18:11:19 -0000
@@ -13,6 +13,7 @@
#include <linux/netfilter_bridge/ebt_arp.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
#include <linux/module.h>
static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in,
@@ -20,8 +21,9 @@
{
struct ebt_arp_info *info = (struct ebt_arp_info *)data;
struct arphdr _arph, *ah;
+ int offset = (skb->protocol == __constant_htons(ETH_P_8021Q)) ? VLAN_HLEN : 0;
- ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+ ah = skb_header_pointer(skb, offset, sizeof(_arph), &_arph);
if (ah == NULL)
return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
@@ -41,7 +43,7 @@
if (ah->ar_pln != sizeof(uint32_t))
return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_SRC_IP) {
- ap = skb_header_pointer(skb, sizeof(struct arphdr) +
+ ap = skb_header_pointer(skb, offset + sizeof(struct arphdr) +
ah->ar_hln, sizeof(_addr),
&_addr);
if (ap == NULL)
@@ -52,7 +54,7 @@
}
if (info->bitmask & EBT_ARP_DST_IP) {
- ap = skb_header_pointer(skb, sizeof(struct arphdr) +
+ ap = skb_header_pointer(skb, offset + sizeof(struct arphdr) +
2*ah->ar_hln+sizeof(uint32_t),
sizeof(_addr), &_addr);
if (ap == NULL)
@@ -71,7 +73,7 @@
if (ah->ar_hln != ETH_ALEN)
return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_SRC_MAC) {
- mp = skb_header_pointer(skb, sizeof(struct arphdr),
+ mp = skb_header_pointer(skb, offset + sizeof(struct arphdr),
sizeof(_mac), &_mac);
if (mp == NULL)
return EBT_NOMATCH;
@@ -84,7 +86,7 @@
}
if (info->bitmask & EBT_ARP_DST_MAC) {
- mp = skb_header_pointer(skb, sizeof(struct arphdr) +
+ mp = skb_header_pointer(skb, offset + sizeof(struct arphdr) +
ah->ar_hln + ah->ar_pln,
sizeof(_mac), &_mac);
if (mp == NULL)
Index: netfilter/ebt_arpreply.c
===================================================================
RCS file: /home/ljaenicke/source/mguard/linux-2.6/linux-2.6.15/net/bridge/netfilter/ebt_arpreply.c,v
retrieving revision 1.2
diff -u -r1.2 ebt_arpreply.c
--- netfilter/ebt_arpreply.c 16 Jun 2006 14:20:29 -0000 1.2
+++ netfilter/ebt_arpreply.c 20 Oct 2006 10:16:44 -0000
@@ -12,6 +12,7 @@
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_arpreply.h>
#include <linux/if_arp.h>
+#include <linux/if_vlan.h>
#include <net/arp.h>
#include <linux/module.h>
@@ -24,8 +25,14 @@
struct arphdr _ah, *ap;
unsigned char _sha[ETH_ALEN], *shp;
struct sk_buff *skb = *pskb;
-
- ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah);
+ struct sk_buff *newskb;
+ struct vlan_hdr _frame, *fp = NULL, *vhdr;
+ int offset = (skb->protocol == __constant_htons(ETH_P_8021Q)) ? VLAN_HLEN : 0;
+
+ if (offset) {
+ fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame);
+ }
+ ap = skb_header_pointer(skb, offset, sizeof(_ah), &_ah);
if (ap == NULL)
return EBT_DROP;
@@ -35,23 +42,32 @@
ap->ar_pln != 4)
return EBT_CONTINUE;
- shp = skb_header_pointer(skb, sizeof(_ah), ETH_ALEN, &_sha);
+ shp = skb_header_pointer(skb, offset + sizeof(_ah), ETH_ALEN, &_sha);
if (shp == NULL)
return EBT_DROP;
- siptr = skb_header_pointer(skb, sizeof(_ah) + ETH_ALEN,
+ siptr = skb_header_pointer(skb, offset + sizeof(_ah) + ETH_ALEN,
sizeof(_sip), &_sip);
if (siptr == NULL)
return EBT_DROP;
- diptr = skb_header_pointer(skb,
+ diptr = skb_header_pointer(skb, offset +
sizeof(_ah) + 2 * ETH_ALEN + sizeof(_sip),
sizeof(_dip), &_dip);
if (diptr == NULL)
return EBT_DROP;
- arp_send(ARPOP_REPLY, ETH_P_ARP, *siptr, (struct net_device *)in,
- *diptr, shp, info->mac, shp);
+ newskb = arp_create(ARPOP_REPLY, ETH_P_ARP, *siptr,
+ (struct net_device *)in,
+ *diptr, shp, info->mac, shp);
+ if (newskb) {
+ if (fp) {
+ vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN);
+ vhdr->h_vlan_TCI = fp->h_vlan_TCI;
+ vhdr->h_vlan_encapsulated_proto = __constant_htons(ETH_P_ARP);
+ }
+ arp_xmit(skb);
+ }
return info->target;
}
Index: netfilter/ebt_ip.c
===================================================================
RCS file: /home/ljaenicke/source/mguard/linux-2.6/linux-2.6.15/net/bridge/netfilter/ebt_ip.c,v
retrieving revision 1.2
diff -u -r1.2 ebt_ip.c
--- netfilter/ebt_ip.c 16 Jun 2006 14:20:29 -0000 1.2
+++ netfilter/ebt_ip.c 19 Oct 2006 14:57:34 -0000
@@ -18,6 +18,7 @@
#include <net/ip.h>
#include <linux/in.h>
#include <linux/module.h>
+#include <linux/if_vlan.h>
struct tcpudphdr {
uint16_t src;
@@ -31,8 +32,8 @@
struct ebt_ip_info *info = (struct ebt_ip_info *)data;
struct iphdr _iph, *ih;
struct tcpudphdr _ports, *pptr;
-
- ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ int offset = (skb->protocol == __constant_htons(ETH_P_8021Q)) ? VLAN_HLEN : 0;
+ ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
if (ih == NULL)
return EBT_NOMATCH;
if (info->bitmask & EBT_IP_TOS &&
@@ -54,7 +55,7 @@
return EBT_MATCH;
if (ntohs(ih->frag_off) & IP_OFFSET)
return EBT_NOMATCH;
- pptr = skb_header_pointer(skb, ih->ihl*4,
+ pptr = skb_header_pointer(skb, offset + ih->ihl*4,
sizeof(_ports), &_ports);
if (pptr == NULL)
return EBT_NOMATCH;
Index: netfilter/ebt_log.c
===================================================================
RCS file: /home/ljaenicke/source/mguard/linux-2.6/linux-2.6.15/net/bridge/netfilter/ebt_log.c,v
retrieving revision 1.2
diff -u -r1.2 ebt_log.c
--- netfilter/ebt_log.c 16 Jun 2006 14:20:29 -0000 1.2
+++ netfilter/ebt_log.c 19 Oct 2006 17:59:20 -0000
@@ -66,6 +66,8 @@
const char *prefix)
{
unsigned int bitmask;
+ __be16 h_proto = eth_hdr(skb)->h_proto;
+ int offset = 0;
spin_lock_bh(&ebt_log_lock);
printk("<%c>%s IN=%s OUT=%s MAC source = ", '0' + loginfo->u.log.level,
@@ -82,11 +84,10 @@
else
bitmask = NF_LOG_MASK;
- if ((bitmask & EBT_LOG_IP) && eth_hdr(skb)->h_proto ==
- htons(ETH_P_IP)){
+ if ((bitmask & EBT_LOG_IP) && h_proto == htons(ETH_P_IP)) {
struct iphdr _iph, *ih;
- ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
if (ih == NULL) {
printk(" INCOMPLETE IP header");
goto out;
@@ -100,7 +101,7 @@
ih->protocol == IPPROTO_DCCP) {
struct tcpudphdr _ports, *pptr;
- pptr = skb_header_pointer(skb, ih->ihl*4,
+ pptr = skb_header_pointer(skb, offset + ih->ihl*4,
sizeof(_ports), &_ports);
if (pptr == NULL) {
printk(" INCOMPLETE TCP/UDP header");
@@ -113,11 +114,11 @@
}
if ((bitmask & EBT_LOG_ARP) &&
- ((eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) ||
- (eth_hdr(skb)->h_proto == htons(ETH_P_RARP)))) {
+ ((h_proto == htons(ETH_P_ARP)) ||
+ (h_proto == htons(ETH_P_RARP)))) {
struct arphdr _arph, *ah;
- ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+ ah = skb_header_pointer(skb, offset, sizeof(_arph), &_arph);
if (ah == NULL) {
printk(" INCOMPLETE ARP header");
goto out;
@@ -133,7 +134,7 @@
ah->ar_pln == sizeof(uint32_t)) {
struct arppayload _arpp, *ap;
- ap = skb_header_pointer(skb, sizeof(_arph),
+ ap = skb_header_pointer(skb, offset + sizeof(_arph),
sizeof(_arpp), &_arpp);
if (ap == NULL) {
printk(" INCOMPLETE ARP payload");
Index: netfilter/ebtables.c
===================================================================
RCS file: /home/ljaenicke/source/mguard/linux-2.6/linux-2.6.15/net/bridge/netfilter/ebtables.c,v
retrieving revision 1.2
diff -u -r1.2 ebtables.c
--- netfilter/ebtables.c 16 Jun 2006 14:20:29 -0000 1.2
+++ netfilter/ebtables.c 19 Oct 2006 14:41:14 -0000
@@ -24,6 +24,7 @@
#include <linux/vmalloc.h>
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/spinlock.h>
+#include <linux/if_vlan.h>
#include <asm/uaccess.h>
#include <linux/smp.h>
#include <linux/cpumask.h>
@@ -132,11 +133,20 @@
int verdict, i;
if (e->bitmask & EBT_802_3) {
- if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
+ unsigned short proto = h->h_proto;
+ struct vlan_ethhdr *vh = (struct vlan_ethhdr *)h;
+ if (h->h_proto == __constant_htons(ETH_P_8021Q) && ebtables_treat_vlan_transparent)
+ proto = vh->h_vlan_encapsulated_proto;
+ if (FWINV2(ntohs(proto) >= 1536, EBT_IPROTO))
return 1;
- } else if (!(e->bitmask & EBT_NOPROTO) &&
- FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
+ } else if (!(e->bitmask & EBT_NOPROTO)) {
+ unsigned short proto = h->h_proto;
+ struct vlan_ethhdr *vh = (struct vlan_ethhdr *)h;
+ if (h->h_proto == __constant_htons(ETH_P_8021Q) && ebtables_treat_vlan_transparent)
+ proto = vh->h_vlan_encapsulated_proto;
+ if (FWINV2(e->ethproto != proto, EBT_IPROTO))
return 1;
+ }
if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
return 1;