forked from Minki/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>
This commit is contained in:
parent
baf7b1e112
commit
d12cdc3ccf
@ -1,6 +1,7 @@
|
|||||||
#ifndef __LINUX_BRIDGE_EBT_NAT_H
|
#ifndef __LINUX_BRIDGE_EBT_NAT_H
|
||||||
#define __LINUX_BRIDGE_EBT_NAT_H
|
#define __LINUX_BRIDGE_EBT_NAT_H
|
||||||
|
|
||||||
|
#define NAT_ARP_BIT (0x00000010)
|
||||||
struct ebt_nat_info
|
struct ebt_nat_info
|
||||||
{
|
{
|
||||||
unsigned char mac[ETH_ALEN];
|
unsigned char mac[ETH_ALEN];
|
||||||
|
@ -26,6 +26,10 @@
|
|||||||
#define EBT_CONTINUE -3
|
#define EBT_CONTINUE -3
|
||||||
#define EBT_RETURN -4
|
#define EBT_RETURN -4
|
||||||
#define NUM_STANDARD_TARGETS 4
|
#define NUM_STANDARD_TARGETS 4
|
||||||
|
/* ebtables target modules store the verdict inside an int. We can
|
||||||
|
* reclaim a part of this int for backwards compatible extensions.
|
||||||
|
* The 4 lsb are more than enough to store the verdict. */
|
||||||
|
#define EBT_VERDICT_BITS 0x0000000F
|
||||||
|
|
||||||
struct ebt_counter
|
struct ebt_counter
|
||||||
{
|
{
|
||||||
|
@ -33,7 +33,7 @@ static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr,
|
|||||||
else
|
else
|
||||||
(*pskb)->mark ^= info->mark;
|
(*pskb)->mark ^= info->mark;
|
||||||
|
|
||||||
return info->target | -16;
|
return info->target | ~EBT_VERDICT_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
|
static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
|
||||||
@ -44,13 +44,13 @@ static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
|
|||||||
|
|
||||||
if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info)))
|
if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
tmp = info->target | -16;
|
tmp = info->target | ~EBT_VERDICT_BITS;
|
||||||
if (BASE_CHAIN && tmp == EBT_RETURN)
|
if (BASE_CHAIN && tmp == EBT_RETURN)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
CLEAR_BASE_CHAIN_BIT;
|
CLEAR_BASE_CHAIN_BIT;
|
||||||
if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0)
|
if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
tmp = info->target & -16;
|
tmp = info->target & ~EBT_VERDICT_BITS;
|
||||||
if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE &&
|
if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE &&
|
||||||
tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE)
|
tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
#include <linux/netfilter_bridge/ebt_nat.h>
|
#include <linux/netfilter_bridge/ebt_nat.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
|
#include <linux/if_arp.h>
|
||||||
|
#include <net/arp.h>
|
||||||
|
|
||||||
static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr,
|
static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr,
|
||||||
const struct net_device *in, const struct net_device *out,
|
const struct net_device *in, const struct net_device *out,
|
||||||
@ -31,24 +33,43 @@ static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr,
|
|||||||
*pskb = nskb;
|
*pskb = nskb;
|
||||||
}
|
}
|
||||||
memcpy(eth_hdr(*pskb)->h_source, info->mac, ETH_ALEN);
|
memcpy(eth_hdr(*pskb)->h_source, info->mac, ETH_ALEN);
|
||||||
return info->target;
|
if (!(info->target & NAT_ARP_BIT) &&
|
||||||
|
eth_hdr(*pskb)->h_proto == htons(ETH_P_ARP)) {
|
||||||
|
struct arphdr _ah, *ap;
|
||||||
|
|
||||||
|
ap = skb_header_pointer(*pskb, 0, sizeof(_ah), &_ah);
|
||||||
|
if (ap == NULL)
|
||||||
|
return EBT_DROP;
|
||||||
|
if (ap->ar_hln != ETH_ALEN)
|
||||||
|
goto out;
|
||||||
|
if (skb_store_bits(*pskb, sizeof(_ah), info->mac,ETH_ALEN))
|
||||||
|
return EBT_DROP;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return info->target | ~EBT_VERDICT_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ebt_target_snat_check(const char *tablename, unsigned int hookmask,
|
static int ebt_target_snat_check(const char *tablename, unsigned int hookmask,
|
||||||
const struct ebt_entry *e, void *data, unsigned int datalen)
|
const struct ebt_entry *e, void *data, unsigned int datalen)
|
||||||
{
|
{
|
||||||
struct ebt_nat_info *info = (struct ebt_nat_info *) data;
|
struct ebt_nat_info *info = (struct ebt_nat_info *) data;
|
||||||
|
int tmp;
|
||||||
|
|
||||||
if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
|
if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (BASE_CHAIN && info->target == EBT_RETURN)
|
tmp = info->target | ~EBT_VERDICT_BITS;
|
||||||
|
if (BASE_CHAIN && tmp == EBT_RETURN)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
CLEAR_BASE_CHAIN_BIT;
|
CLEAR_BASE_CHAIN_BIT;
|
||||||
if (strcmp(tablename, "nat"))
|
if (strcmp(tablename, "nat"))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (hookmask & ~(1 << NF_BR_POST_ROUTING))
|
if (hookmask & ~(1 << NF_BR_POST_ROUTING))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (INVALID_TARGET)
|
|
||||||
|
if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0)
|
||||||
|
return -EINVAL;
|
||||||
|
tmp = info->target | EBT_VERDICT_BITS;
|
||||||
|
if ((tmp & ~NAT_ARP_BIT) != ~NAT_ARP_BIT)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user