#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ether.h>
#include <getopt.h>
#include "../include/ebtables_u.h"
#include <linux/netfilter_bridge/ebt_nat.h>
static int to_source_supplied, to_dest_supplied, to_vlan_supplied, strip_tag_supplied, vlan_qos_supplied;
#define NAT_S '1'
#define NAT_D '1'
#define NAT_V '1'
#define NAT_S_TARGET '2'
#define NAT_D_TARGET '2'
#define NAT_V_TARGET '2'
#define NAT_V_STRIP '3'
#define NAT_V_QOS '4'
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 struct option opts_v[] =
{
{ "to-vlan" , required_argument, 0, NAT_V },
{ "vlan-qos" , required_argument, 0, NAT_V_QOS },
{ "strip-tag" , no_argument , 0, NAT_V_STRIP },
{ "vnat-target" , required_argument, 0, NAT_V_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 print_help_v()
{
printf(
"vnat options:\n"
" --to-vlan tag : Vlan ID to be tagged with\n"
" --strip-tag : Gets rid of the tag if present\n"
" --vlan-qos : Vlan priority\n"
" --vnat-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;
}
static void init_v(struct ebt_entry_target *target)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
to_vlan_supplied = 0;
strip_tag_supplied = 0;
vlan_qos_supplied = 0;
natinfo->qos = 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)
{
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);
if (FILL_TARGET(optarg, natinfo->target))
print_error("Illegal --snat-target target");
break;
default:
return 0;
}
return 1;
}
#define OPT_VNAT 0x01
#define OPT_VNAT_STRIP 0x02
#define OPT_VNAT_TARGET 0x03
#define OPT_VNAT_QOS 0x04
static int parse_v(int c, char **argv, int argc,
const struct ebt_u_entry *entry, unsigned int *flags,
struct ebt_entry_target **target)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
uint16_t vid, qos;
switch (c) {
case NAT_V:
check_option(flags, OPT_VNAT);
check_option(flags, OPT_VNAT_STRIP);
to_vlan_supplied = 1;
if (sscanf(optarg, "%hu", &vid) != 1 || vid > 4094)
print_error("Problem with specified "
"vlan id, must be between 0 and 4094");
natinfo->vid = vid;
break;
case NAT_V_TARGET:
check_option(flags, OPT_VNAT_TARGET);
if (FILL_TARGET(optarg, natinfo->target))
print_error("Illegal --vnat-target target");
break;
case NAT_V_STRIP:
check_option(flags, OPT_VNAT);
check_option(flags, OPT_VNAT_STRIP);
strip_tag_supplied = 1;
natinfo->vid = -1;
case NAT_V_QOS:
check_option(flags, OPT_VNAT_QOS);
vlan_qos_supplied = 1;
if (sscanf(optarg, "%hu", &qos) != 1 || vid > 7)
print_error("Problem with specified "
"vlan qos, must be between 0 and 7");
natinfo->qos = qos;
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)
{
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);
if (FILL_TARGET(optarg, natinfo->target))
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 hookmask, unsigned int time)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
if (BASE_CHAIN && natinfo->target == EBT_RETURN)
print_error("--snat-target RETURN not allowed on base chain");
CLEAR_BASE_CHAIN_BIT;
if ((hookmask & ~(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 hookmask, unsigned int time)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
if (BASE_CHAIN && natinfo->target == EBT_RETURN)
print_error("--dnat-target RETURN not allowed on base chain");
CLEAR_BASE_CHAIN_BIT;
if (((hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))
|| strcmp(name, "nat")) &&
((hookmask & ~(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 final_check_v(const struct ebt_u_entry *entry,
const struct ebt_entry_target *target, const char *name,
unsigned int hookmask, unsigned int time)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
if (BASE_CHAIN && natinfo->target == EBT_RETURN)
print_error("--vnat-target RETURN not allowed on base chain");
CLEAR_BASE_CHAIN_BIT;
if ((hookmask & ~(1 << NF_BR_PRE_ROUTING)) || strcmp(name, "nat"))
print_error("Wrong chain for vnat");
if (time == 0
&& ((to_vlan_supplied == 0
&& (strip_tag_supplied == 0 || vlan_qos_supplied == 1))
|| (to_vlan_supplied == 1 && strip_tag_supplied == 1)))
print_error("You must specify only one of --to-vlan or --strip-tag. "
"You cannot specify --vlan-qos with --strip-tag");
}
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", TARGET_NAME(natinfo->target));
}
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", TARGET_NAME(natinfo->target));
}
static void print_v(const struct ebt_u_entry *entry,
const struct ebt_entry_target *target)
{
struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
if (natinfo->vid == (uint16_t)-1) {
printf("--strip-tag ");
} else {
printf("--to-vlan %hd", natinfo->vid);
printf(" --vlan-qos %hd", natinfo->qos);
}
printf(" --vnat-target %s", TARGET_NAME(natinfo->target));
}
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
&& natinfo1->vid == natinfo2->vid
&& natinfo1->qos == natinfo2->qos;
}
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 struct ebt_u_target vnat_target =
{
EBT_VNAT_TARGET,
sizeof(struct ebt_nat_info),
print_help_v,
init_v,
parse_v,
final_check_v,
print_v,
compare,
opts_v
};
static void _init(void) __attribute__ ((constructor));
static void _init(void)
{
register_target(&snat_target);
register_target(&dnat_target);
register_target(&vnat_target);
}