summaryrefslogtreecommitdiffstats
path: root/extensions/libebt_dnat.c
blob: c179d8c19bc157c512d2e5a997633a2d5a00f263 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/* 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_D '1'
#define NAT_D_TARGET '2'
static const struct option brdnat_opts[] =
{
	{ "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 brdnat_print_help(void)
{
	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 brdnat_init(struct xt_entry_target *target)
{
	struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;

	natinfo->target = EBT_ACCEPT;
}

#define OPT_DNAT        0x01
#define OPT_DNAT_TARGET 0x02
static int brdnat_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_D:
		EBT_CHECK_OPTION(flags, OPT_DNAT);
		if (!(addr = ether_aton(optarg)))
			xtables_error(PARAMETER_PROBLEM, "Problem with specified --to-destination mac");
		memcpy(natinfo->mac, addr, ETH_ALEN);
		break;
	case NAT_D_TARGET:
		EBT_CHECK_OPTION(flags, OPT_DNAT_TARGET);
		if (ebt_fill_target(optarg, (unsigned int *)&natinfo->target))
			xtables_error(PARAMETER_PROBLEM, "Illegal --dnat-target target");
		break;
	default:
		return 0;
	}
	return 1;
}

static void brdnat_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 brdnat_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-dst ");
	ebt_print_mac(natinfo->mac);
	printf(" --dnat-target %s", ebt_target_name(natinfo->target));
}

static const char* brdnat_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 brdnat_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 daddr set %s %s ",
		     ether_ntoa((struct ether_addr *)natinfo->mac),
		     brdnat_verdict(natinfo->target));

	return 1;
}

static struct xtables_target brdnat_target =
{
	.name		= "dnat",
	.version	= XTABLES_VERSION,
	.family		= NFPROTO_BRIDGE,
	.size           = XT_ALIGN(sizeof(struct ebt_nat_info)),
	.userspacesize	= XT_ALIGN(sizeof(struct ebt_nat_info)),
	.help		= brdnat_print_help,
	.init		= brdnat_init,
	.parse		= brdnat_parse,
	.final_check	= brdnat_final_check,
	.print		= brdnat_print,
	.xlate		= brdnat_xlate,
	.extra_opts	= brdnat_opts,
};

void _init(void)
{
	xtables_register_target(&brdnat_target);
}