blob: 25b12ca92d71bbf8b6b4997fd49c651fde13e914 [file] [log] [blame]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include <getopt.h>
#include "../include/ebtables_u.h"
#include <linux/netfilter_bridge/ebt_nat.h>
extern char *standard_targets[NUM_STANDARD_TARGETS];
int to_source_supplied, to_dest_supplied;
#define NAT_S '1'
#define NAT_D '1'
#define NAT_S_TARGET '2'
#define NAT_D_TARGET '2'
static struct option opts_s[] =
{
{ "to-source" , required_argument, 0, NAT_S },
{ "to-src" , required_argument, 0, NAT_S },
{ "snat-target" , required_argument, 0, NAT_S_TARGET },
{ 0 }
};
static struct option opts_d[] =
{
{ "to-destination", required_argument, 0, NAT_D },
{ "to-dst" , required_argument, 0, NAT_D },
{ "dnat-target" , required_argument, 0, NAT_D_TARGET },
{ 0 }
};
static void print_help_s()
{
printf(
"snat options:\n"
" --to-src address : MAC address to map source to\n"
" --snat-target target : ACCEPT, DROP, RETURN or CONTINUE\n");
}
static void print_help_d()
{
printf(
"dnat options:\n"
" --to-dst address : MAC address to map destination to\n"
" --dnat-target target : ACCEPT, DROP, RETURN or CONTINUE\n");
}
static void init_s(struct ebt_entry_target *target)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
to_source_supplied = 0;
natinfo->target = EBT_ACCEPT;
return;
}
static void init_d(struct ebt_entry_target *target)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
to_dest_supplied = 0;
natinfo->target = EBT_ACCEPT;
return;
}
#define OPT_SNAT 0x01
#define OPT_SNAT_TARGET 0x02
static int parse_s(int c, char **argv, int argc,
const struct ebt_u_entry *entry, unsigned int *flags,
struct ebt_entry_target **target)
{
int i;
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
struct ether_addr *addr;
switch (c) {
case NAT_S:
check_option(flags, OPT_SNAT);
to_source_supplied = 1;
if (!(addr = ether_aton(optarg)))
print_error("Problem with specified --to-source mac");
memcpy(natinfo->mac, addr, ETH_ALEN);
break;
case NAT_S_TARGET:
check_option(flags, OPT_SNAT_TARGET);
for (i = 0; i < NUM_STANDARD_TARGETS; i++)
if (!strcmp(optarg, standard_targets[i])) {
natinfo->target = -i - 1;
break;
}
if (i == NUM_STANDARD_TARGETS)
print_error("Illegal --snat-target target");
break;
default:
return 0;
}
return 1;
}
#define OPT_DNAT 0x01
#define OPT_DNAT_TARGET 0x02
static int parse_d(int c, char **argv, int argc,
const struct ebt_u_entry *entry, unsigned int *flags,
struct ebt_entry_target **target)
{
int i;
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
struct ether_addr *addr;
switch (c) {
case NAT_D:
check_option(flags, OPT_DNAT);
to_dest_supplied = 1;
if (!(addr = ether_aton(optarg)))
print_error("Problem with specified "
"--to-destination mac");
memcpy(natinfo->mac, addr, ETH_ALEN);
break;
case NAT_D_TARGET:
check_option(flags, OPT_DNAT_TARGET);
for (i = 0; i < NUM_STANDARD_TARGETS; i++)
if (!strcmp(optarg, standard_targets[i])) {
natinfo->target = -i - 1;
break;
}
if (i == NUM_STANDARD_TARGETS)
print_error("Illegal --dnat-target target");
break;
default:
return 0;
}
return 1;
}
static void final_check_s(const struct ebt_u_entry *entry,
const struct ebt_entry_target *target, const char *name,
unsigned int hook_mask, unsigned int time)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
if ((hook_mask & (1 << NF_BR_NUMHOOKS)) && natinfo->target == EBT_RETURN)
print_error("--snat-target RETURN not allowed on base chain");
hook_mask &= ~(1 << NF_BR_NUMHOOKS);
if (!(hook_mask & (1 << NF_BR_POST_ROUTING)) || strcmp(name, "nat"))
print_error("Wrong chain for snat");
if (time == 0 && to_source_supplied == 0)
print_error("No snat address supplied");
}
static void final_check_d(const struct ebt_u_entry *entry,
const struct ebt_entry_target *target, const char *name,
unsigned int hook_mask, unsigned int time)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
if ((hook_mask & (1 << NF_BR_NUMHOOKS)) && natinfo->target == EBT_RETURN)
print_error("--dnat-target RETURN not allowed on base chain");
hook_mask &= ~(1 << NF_BR_NUMHOOKS);
if (((hook_mask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT))) ||
strcmp(name, "nat")) &&
((hook_mask & ~(1 << NF_BR_BROUTING)) || strcmp(name, "broute")))
print_error("Wrong chain for dnat");
if (time == 0 && to_dest_supplied == 0)
print_error("No dnat address supplied");
}
static void print_s(const struct ebt_u_entry *entry,
const struct ebt_entry_target *target)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
printf("--to-src ");
printf("%s", ether_ntoa((struct ether_addr *)natinfo->mac));
printf(" --snat-target %s", standard_targets[-natinfo->target - 1]);
}
static void print_d(const struct ebt_u_entry *entry,
const struct ebt_entry_target *target)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
printf("--to-dst ");
printf("%s", ether_ntoa((struct ether_addr *)natinfo->mac));
printf(" --dnat-target %s", standard_targets[-natinfo->target - 1]);
}
static int compare(const struct ebt_entry_target *t1,
const struct ebt_entry_target *t2)
{
struct ebt_nat_info *natinfo1 = (struct ebt_nat_info *)t1->data;
struct ebt_nat_info *natinfo2 = (struct ebt_nat_info *)t2->data;
return !memcmp(natinfo1->mac, natinfo2->mac, sizeof(natinfo1->mac)) &&
natinfo1->target == natinfo2->target;
}
static struct ebt_u_target snat_target =
{
EBT_SNAT_TARGET,
sizeof(struct ebt_nat_info),
print_help_s,
init_s,
parse_s,
final_check_s,
print_s,
compare,
opts_s,
};
static struct ebt_u_target dnat_target =
{
EBT_DNAT_TARGET,
sizeof(struct ebt_nat_info),
print_help_d,
init_d,
parse_d,
final_check_d,
print_d,
compare,
opts_d,
};
static void _init(void) __attribute__ ((constructor));
static void _init(void)
{
register_target(&snat_target);
register_target(&dnat_target);
}