From 58adbd9dd5dbc0d48ad6e77848e316556f7c2ce1 Mon Sep 17 00:00:00 2001 From: gborowiak Date: Sun, 7 Sep 2003 13:10:40 +0000 Subject: Initial release --- .../include/linux/netfilter_bridge/ebt_inat.h | 23 ++++ kernel/linux/net/bridge/netfilter/ebt_idnat.c | 127 +++++++++++++++++++++ kernel/linux/net/bridge/netfilter/ebt_isnat.c | 122 ++++++++++++++++++++ 3 files changed, 272 insertions(+) create mode 100644 kernel/linux/include/linux/netfilter_bridge/ebt_inat.h create mode 100644 kernel/linux/net/bridge/netfilter/ebt_idnat.c create mode 100644 kernel/linux/net/bridge/netfilter/ebt_isnat.c (limited to 'kernel/linux') diff --git a/kernel/linux/include/linux/netfilter_bridge/ebt_inat.h b/kernel/linux/include/linux/netfilter_bridge/ebt_inat.h new file mode 100644 index 0000000..d370d7b --- /dev/null +++ b/kernel/linux/include/linux/netfilter_bridge/ebt_inat.h @@ -0,0 +1,23 @@ +#ifndef __LINUX_BRIDGE_EBT_NAT_H +#define __LINUX_BRIDGE_EBT_NAT_H + +struct ebt_inat_tuple +{ + int enabled; + unsigned char mac[ETH_ALEN]; + // EBT_ACCEPT, EBT_DROP or EBT_CONTINUE + int target; +}; + +struct ebt_inat_info +{ + uint32_t ip_subnet; + struct ebt_inat_tuple a[256]; + // EBT_ACCEPT, EBT_DROP, EBT_CONTINUE or EBT_RETURN + int target; +}; + +#define EBT_ISNAT_TARGET "isnat" +#define EBT_IDNAT_TARGET "idnat" + +#endif diff --git a/kernel/linux/net/bridge/netfilter/ebt_idnat.c b/kernel/linux/net/bridge/netfilter/ebt_idnat.c new file mode 100644 index 0000000..75ea05b --- /dev/null +++ b/kernel/linux/net/bridge/netfilter/ebt_idnat.c @@ -0,0 +1,127 @@ +/* + * ebt_idnat + * + * Authors: + * Grzegorz Borowiak + * + * September, 2003 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr) +{ + if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP)) { + *addr = skb->nh.iph->daddr; + return 1; + } + if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) { + + uint32_t arp_len = sizeof(struct arphdr) + + (2 * (((*skb).nh.arph)->ar_hln)) + + (2 * (((*skb).nh.arph)->ar_pln)); + + // Make sure the packet is long enough. + if ((((*skb).nh.raw) + arp_len) > (*skb).tail) + return 0; + // IPv4 addresses are always 4 bytes. + if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t)) + return 0; + + memcpy(addr, ((*skb).nh.raw) + sizeof(struct arphdr) + + (2*(((*skb).nh.arph)->ar_hln)) + + (((*skb).nh.arph)->ar_pln), sizeof(uint32_t)); + + return 2; + } + return 0; +} + +static int ebt_target_idnat(struct sk_buff **pskb, unsigned int hooknr, + const struct net_device *in, const struct net_device *out, + const void *data, unsigned int datalen) +{ + struct ebt_inat_info *info = (struct ebt_inat_info *)data; + uint32_t ip; + int index; + struct ebt_inat_tuple *tuple; + + if (!get_ip_dst(*pskb, &ip)) { + /* not an ARP or IPV4 packet */ + return info->target; + } + + if ((ip & __constant_htonl(0xffffff00)) != info->ip_subnet) { + + /* outside our range */ + return info->target; + } + + index = ((unsigned char*)&ip)[3]; /* the last byte; network packets are big endian */ + tuple = &info->a[index]; + + if (!tuple->enabled) { + /* we do not want to alter packets with this IP */ + return info->target; + } + + memcpy(((**pskb).mac.ethernet)->h_dest, tuple->mac, + ETH_ALEN * sizeof(unsigned char)); + + if ((**pskb).mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) { + /* change the payload */ + memcpy( + (**pskb).nh.raw + sizeof(struct arphdr) + + (**pskb).nh.arph->ar_hln + + (**pskb).nh.arph->ar_pln, tuple->mac, ETH_ALEN); + } + + return tuple->target; +} + +static int ebt_target_idnat_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_inat_info *info = (struct ebt_inat_info *)data; + + if (BASE_CHAIN && info->target == EBT_RETURN) + return -EINVAL; + CLEAR_BASE_CHAIN_BIT; + if ( (strcmp(tablename, "nat") || + (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) && + (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) + return -EINVAL; + if (datalen != EBT_ALIGN(sizeof(struct ebt_inat_info))) + return -EINVAL; + if (INVALID_TARGET) + return -EINVAL; + return 0; +} + +static struct ebt_target idnat = +{ + {NULL, NULL}, EBT_IDNAT_TARGET, ebt_target_idnat, ebt_target_idnat_check, + NULL, THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_target(&idnat); +} + +static void __exit fini(void) +{ + ebt_unregister_target(&idnat); +} + +module_init(init); +module_exit(fini); +EXPORT_NO_SYMBOLS; +MODULE_LICENSE("GPL"); diff --git a/kernel/linux/net/bridge/netfilter/ebt_isnat.c b/kernel/linux/net/bridge/netfilter/ebt_isnat.c new file mode 100644 index 0000000..7f2f844 --- /dev/null +++ b/kernel/linux/net/bridge/netfilter/ebt_isnat.c @@ -0,0 +1,122 @@ +/* + * ebt_isnat + * + * Authors: + * Grzegorz Borowiak + * + * September, 2003 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +static int get_ip_src(const struct sk_buff *skb, uint32_t *addr) +{ + if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP)) { + *addr = skb->nh.iph->saddr; + return 1; + } + if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) { + + uint32_t arp_len = sizeof(struct arphdr) + + (2 * (((*skb).nh.arph)->ar_hln)) + + (2 * (((*skb).nh.arph)->ar_pln)); + + // Make sure the packet is long enough. + if ((((*skb).nh.raw) + arp_len) > (*skb).tail) + return 0; + // IPv4 addresses are always 4 bytes. + if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t)) + return 0; + + memcpy(addr, ((*skb).nh.raw) + sizeof(struct arphdr) + + ((((*skb).nh.arph)->ar_hln)), sizeof(uint32_t)); + + return 2; + } + return 0; +} + +static int ebt_target_isnat(struct sk_buff **pskb, unsigned int hooknr, + const struct net_device *in, const struct net_device *out, + const void *data, unsigned int datalen) +{ + struct ebt_inat_info *info = (struct ebt_inat_info *)data; + uint32_t ip; + int index; + struct ebt_inat_tuple *tuple; + + if (!get_ip_src(*pskb, &ip)) { + /* not an ARP or IPV4 packet */ + return info->target; + } + + if ((ip & __constant_htonl(0xffffff00)) != info->ip_subnet) { + + /* outside our range */ + return info->target; + } + + index = ((unsigned char*)&ip)[3]; /* the last byte; network packets are big endian */ + tuple = &info->a[index]; + + if (!tuple->enabled) { + /* we do not want to alter packets with this IP */ + return info->target; + } + + memcpy(((**pskb).mac.ethernet)->h_source, tuple->mac, ETH_ALEN); + + if ((**pskb).mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) { + /* change the payload */ + memcpy((**pskb).nh.raw + sizeof(struct arphdr), tuple->mac, ETH_ALEN); + } + + return tuple->target; +} + +static int ebt_target_isnat_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_inat_info *info = (struct ebt_inat_info *)data; + + if (datalen != sizeof(struct ebt_inat_info)) + return -EINVAL; + if (BASE_CHAIN && info->target == EBT_RETURN) + return -EINVAL; + CLEAR_BASE_CHAIN_BIT; + if (strcmp(tablename, "nat")) + return -EINVAL; + if (hookmask & ~(1 << NF_BR_POST_ROUTING)) + return -EINVAL; + if (INVALID_TARGET) + return -EINVAL; + return 0; +} + +static struct ebt_target isnat = +{ + {NULL, NULL}, EBT_ISNAT_TARGET, ebt_target_isnat, ebt_target_isnat_check, + NULL, THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_target(&isnat); +} + +static void __exit fini(void) +{ + ebt_unregister_target(&isnat); +} + +module_init(init); +module_exit(fini); +EXPORT_NO_SYMBOLS; +MODULE_LICENSE("GPL"); -- cgit v1.2.3