diff options
Diffstat (limited to 'extensions/libebt_snat.c')
-rw-r--r-- | extensions/libebt_snat.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/extensions/libebt_snat.c b/extensions/libebt_snat.c new file mode 100644 index 00000000..95b32f9c --- /dev/null +++ b/extensions/libebt_snat.c @@ -0,0 +1,151 @@ +/* ebt_nat + * + * Authors: + * Bart De Schuymer <bdschuym@pandora.be> + * + * June, 2002 + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <netinet/ether.h> +#include <xtables.h> +#include <linux/netfilter_bridge/ebt_nat.h> +#include "iptables/nft.h" +#include "iptables/nft-bridge.h" + +#define NAT_S '1' +#define NAT_S_TARGET '2' +#define NAT_S_ARP '3' +static const struct option brsnat_opts[] = +{ + { "to-source" , required_argument, 0, NAT_S }, + { "to-src" , required_argument, 0, NAT_S }, + { "snat-target" , required_argument, 0, NAT_S_TARGET }, + { "snat-arp" , no_argument, 0, NAT_S_ARP }, + { 0 } +}; + +static void brsnat_print_help(void) +{ + printf( + "snat options:\n" + " --to-src address : MAC address to map source to\n" + " --snat-target target : ACCEPT, DROP, RETURN or CONTINUE\n" + " --snat-arp : also change src address in arp msg\n"); +} + +static void brsnat_init(struct xt_entry_target *target) +{ + struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data; + + natinfo->target = EBT_ACCEPT; +} + +#define OPT_SNAT 0x01 +#define OPT_SNAT_TARGET 0x02 +#define OPT_SNAT_ARP 0x04 +static int brsnat_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_target **target) +{ + struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data; + struct ether_addr *addr; + + switch (c) { + case NAT_S: + EBT_CHECK_OPTION(flags, OPT_SNAT); + if (!(addr = ether_aton(optarg))) + xtables_error(PARAMETER_PROBLEM, "Problem with specified --to-source mac"); + memcpy(natinfo->mac, addr, ETH_ALEN); + break; + case NAT_S_TARGET: + { unsigned int tmp; + EBT_CHECK_OPTION(flags, OPT_SNAT_TARGET); + if (ebt_fill_target(optarg, &tmp)) + xtables_error(PARAMETER_PROBLEM, "Illegal --snat-target target"); + natinfo->target = (natinfo->target & ~EBT_VERDICT_BITS) | (tmp & EBT_VERDICT_BITS); + } + break; + case NAT_S_ARP: + EBT_CHECK_OPTION(flags, OPT_SNAT_ARP); + natinfo->target ^= NAT_ARP_BIT; + break; + default: + return 0; + } + return 1; +} + +static void brsnat_final_check(unsigned int flags) +{ + if (!flags) + xtables_error(PARAMETER_PROBLEM, + "You must specify proper arguments"); +} + +static void ebt_print_mac(const unsigned char *mac) +{ + printf("%s", ether_ntoa((struct ether_addr *) mac)); +} + +static void brsnat_print(const void *ip, const struct xt_entry_target *target, int numeric) +{ + struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data; + + printf("--to-src "); + ebt_print_mac(natinfo->mac); + if (!(natinfo->target&NAT_ARP_BIT)) + printf(" --snat-arp"); + printf(" --snat-target %s", ebt_target_name((natinfo->target|~EBT_VERDICT_BITS))); +} + +static const char* brsnat_verdict(int verdict) +{ + switch (verdict) { + case EBT_ACCEPT: return "accept"; + case EBT_DROP: return "drop"; + case EBT_CONTINUE: return "continue"; + case EBT_RETURN: return "return"; + } + + return ""; +} + +static int brsnat_xlate(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + const struct ebt_nat_info *natinfo = (const void*)params->target->data; + + xt_xlate_add(xl, "ether saddr set %s ", + ether_ntoa((struct ether_addr *)natinfo->mac)); + + /* NAT_ARP_BIT set -> no arp mangling, not set -> arp mangling (yes, its inverted) */ + if (!(natinfo->target&NAT_ARP_BIT)) + return 0; + + xt_xlate_add(xl, "%s ", brsnat_verdict(natinfo->target | ~EBT_VERDICT_BITS)); + return 1; +} + +static struct xtables_target brsnat_target = +{ + .name = "snat", + .version = XTABLES_VERSION, + .family = NFPROTO_BRIDGE, + .size = XT_ALIGN(sizeof(struct ebt_nat_info)), + .userspacesize = XT_ALIGN(sizeof(struct ebt_nat_info)), + .help = brsnat_print_help, + .init = brsnat_init, + .parse = brsnat_parse, + .final_check = brsnat_final_check, + .print = brsnat_print, + .xlate = brsnat_xlate, + .extra_opts = brsnat_opts, +}; + +void _init(void) +{ + xtables_register_target(&brsnat_target); +} |