libipt_MASQUERADE.c revision e37d45ce390c2f5a7f1e64742b9100ecef0def54
1#include <stdio.h>
2#include <netdb.h>
3#include <string.h>
4#include <stdlib.h>
5#include <getopt.h>
6#include <xtables.h>
7#include <limits.h> /* INT_MAX in ip_tables.h */
8#include <linux/netfilter_ipv4/ip_tables.h>
9#include <net/netfilter/nf_nat.h>
10
11enum {
12	O_TO_PORTS = 0,
13	O_RANDOM,
14};
15
16static void MASQUERADE_help(void)
17{
18	printf(
19"MASQUERADE target options:\n"
20" --to-ports <port>[-<port>]\n"
21"				Port (range) to map to.\n"
22" --random\n"
23"				Randomize source port.\n");
24}
25
26static const struct xt_option_entry MASQUERADE_opts[] = {
27	{.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
28	{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
29	XTOPT_TABLEEND,
30};
31
32static void MASQUERADE_init(struct xt_entry_target *t)
33{
34	struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data;
35
36	/* Actually, it's 0, but it's ignored at the moment. */
37	mr->rangesize = 1;
38}
39
40/* Parses ports */
41static void
42parse_ports(const char *arg, struct nf_nat_multi_range *mr)
43{
44	char *end;
45	unsigned int port, maxport;
46
47	mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
48
49	if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX))
50		xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
51
52	switch (*end) {
53	case '\0':
54		mr->range[0].min.tcp.port
55			= mr->range[0].max.tcp.port
56			= htons(port);
57		return;
58	case '-':
59		if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX))
60			break;
61
62		if (maxport < port)
63			break;
64
65		mr->range[0].min.tcp.port = htons(port);
66		mr->range[0].max.tcp.port = htons(maxport);
67		return;
68	default:
69		break;
70	}
71	xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
72}
73
74static void MASQUERADE_parse(struct xt_option_call *cb)
75{
76	const struct ipt_entry *entry = cb->xt_entry;
77	int portok;
78	struct nf_nat_multi_range *mr = cb->data;
79
80	if (entry->ip.proto == IPPROTO_TCP
81	    || entry->ip.proto == IPPROTO_UDP
82	    || entry->ip.proto == IPPROTO_SCTP
83	    || entry->ip.proto == IPPROTO_DCCP
84	    || entry->ip.proto == IPPROTO_ICMP)
85		portok = 1;
86	else
87		portok = 0;
88
89	xtables_option_parse(cb);
90	switch (cb->entry->id) {
91	case O_TO_PORTS:
92		if (!portok)
93			xtables_error(PARAMETER_PROBLEM,
94				   "Need TCP, UDP, SCTP or DCCP with port specification");
95		parse_ports(cb->arg, mr);
96		break;
97	case O_RANDOM:
98		mr->range[0].flags |=  IP_NAT_RANGE_PROTO_RANDOM;
99		break;
100	}
101}
102
103static void
104MASQUERADE_print(const void *ip, const struct xt_entry_target *target,
105                 int numeric)
106{
107	const struct nf_nat_multi_range *mr = (const void *)target->data;
108	const struct nf_nat_range *r = &mr->range[0];
109
110	if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
111		printf(" masq ports: ");
112		printf("%hu", ntohs(r->min.tcp.port));
113		if (r->max.tcp.port != r->min.tcp.port)
114			printf("-%hu", ntohs(r->max.tcp.port));
115	}
116
117	if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
118		printf(" random");
119}
120
121static void
122MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
123{
124	const struct nf_nat_multi_range *mr = (const void *)target->data;
125	const struct nf_nat_range *r = &mr->range[0];
126
127	if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
128		printf(" --to-ports %hu", ntohs(r->min.tcp.port));
129		if (r->max.tcp.port != r->min.tcp.port)
130			printf("-%hu", ntohs(r->max.tcp.port));
131	}
132
133	if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
134		printf(" --random");
135}
136
137static struct xtables_target masquerade_tg_reg = {
138	.name		= "MASQUERADE",
139	.version	= XTABLES_VERSION,
140	.family		= NFPROTO_IPV4,
141	.size		= XT_ALIGN(sizeof(struct nf_nat_multi_range)),
142	.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_multi_range)),
143	.help		= MASQUERADE_help,
144	.init		= MASQUERADE_init,
145	.x6_parse	= MASQUERADE_parse,
146	.print		= MASQUERADE_print,
147	.save		= MASQUERADE_save,
148	.x6_options	= MASQUERADE_opts,
149};
150
151void _init(void)
152{
153	xtables_register_target(&masquerade_tg_reg);
154}
155