Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[NETFILTER]: ebtables: add --snap-arp option

The attached patch adds --snat-arp support, which makes it possible to
change the source mac address in both the mac header and the arp header
with one rule.

Signed-off-by: Bart De Schuymer <bdschuym@pandora.be>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by

Bart De Schuymer and committed by
David S. Miller
d12cdc3c baf7b1e1

+32 -6
+1
include/linux/netfilter_bridge/ebt_nat.h
··· 1 1 #ifndef __LINUX_BRIDGE_EBT_NAT_H 2 2 #define __LINUX_BRIDGE_EBT_NAT_H 3 3 4 + #define NAT_ARP_BIT (0x00000010) 4 5 struct ebt_nat_info 5 6 { 6 7 unsigned char mac[ETH_ALEN];
+4
include/linux/netfilter_bridge/ebtables.h
··· 26 26 #define EBT_CONTINUE -3 27 27 #define EBT_RETURN -4 28 28 #define NUM_STANDARD_TARGETS 4 29 + /* ebtables target modules store the verdict inside an int. We can 30 + * reclaim a part of this int for backwards compatible extensions. 31 + * The 4 lsb are more than enough to store the verdict. */ 32 + #define EBT_VERDICT_BITS 0x0000000F 29 33 30 34 struct ebt_counter 31 35 {
+3 -3
net/bridge/netfilter/ebt_mark.c
··· 33 33 else 34 34 (*pskb)->mark ^= info->mark; 35 35 36 - return info->target | -16; 36 + return info->target | ~EBT_VERDICT_BITS; 37 37 } 38 38 39 39 static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, ··· 44 44 45 45 if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info))) 46 46 return -EINVAL; 47 - tmp = info->target | -16; 47 + tmp = info->target | ~EBT_VERDICT_BITS; 48 48 if (BASE_CHAIN && tmp == EBT_RETURN) 49 49 return -EINVAL; 50 50 CLEAR_BASE_CHAIN_BIT; 51 51 if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) 52 52 return -EINVAL; 53 - tmp = info->target & -16; 53 + tmp = info->target & ~EBT_VERDICT_BITS; 54 54 if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE && 55 55 tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE) 56 56 return -EINVAL;
+24 -3
net/bridge/netfilter/ebt_snat.c
··· 12 12 #include <linux/netfilter_bridge/ebt_nat.h> 13 13 #include <linux/module.h> 14 14 #include <net/sock.h> 15 + #include <linux/if_arp.h> 16 + #include <net/arp.h> 15 17 16 18 static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr, 17 19 const struct net_device *in, const struct net_device *out, ··· 33 31 *pskb = nskb; 34 32 } 35 33 memcpy(eth_hdr(*pskb)->h_source, info->mac, ETH_ALEN); 36 - return info->target; 34 + if (!(info->target & NAT_ARP_BIT) && 35 + eth_hdr(*pskb)->h_proto == htons(ETH_P_ARP)) { 36 + struct arphdr _ah, *ap; 37 + 38 + ap = skb_header_pointer(*pskb, 0, sizeof(_ah), &_ah); 39 + if (ap == NULL) 40 + return EBT_DROP; 41 + if (ap->ar_hln != ETH_ALEN) 42 + goto out; 43 + if (skb_store_bits(*pskb, sizeof(_ah), info->mac,ETH_ALEN)) 44 + return EBT_DROP; 45 + } 46 + out: 47 + return info->target | ~EBT_VERDICT_BITS; 37 48 } 38 49 39 50 static int ebt_target_snat_check(const char *tablename, unsigned int hookmask, 40 51 const struct ebt_entry *e, void *data, unsigned int datalen) 41 52 { 42 53 struct ebt_nat_info *info = (struct ebt_nat_info *) data; 54 + int tmp; 43 55 44 56 if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info))) 45 57 return -EINVAL; 46 - if (BASE_CHAIN && info->target == EBT_RETURN) 58 + tmp = info->target | ~EBT_VERDICT_BITS; 59 + if (BASE_CHAIN && tmp == EBT_RETURN) 47 60 return -EINVAL; 48 61 CLEAR_BASE_CHAIN_BIT; 49 62 if (strcmp(tablename, "nat")) 50 63 return -EINVAL; 51 64 if (hookmask & ~(1 << NF_BR_POST_ROUTING)) 52 65 return -EINVAL; 53 - if (INVALID_TARGET) 66 + 67 + if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) 68 + return -EINVAL; 69 + tmp = info->target | EBT_VERDICT_BITS; 70 + if ((tmp & ~NAT_ARP_BIT) != ~NAT_ARP_BIT) 54 71 return -EINVAL; 55 72 return 0; 56 73 }