libipt_MASQUERADE.c revision f9b2e66877b743962a36ec9c37335b9bc3f8b70f
1e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Shared library add-on to iptables to add masquerade support. */
2e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdio.h>
3e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <netdb.h>
4e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <string.h>
5e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdlib.h>
6e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <getopt.h>
7e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <iptables.h>
8e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <linux/netfilter_ipv4/ip_tables.h>
9e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <linux/netfilter_ipv4/ip_nat_rule.h>
10e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
11e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Function which prints out usage message. */
12e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
13e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherhelp(void)
14e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
15e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf(
16e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"MASQUERADE v%s options:\n"
17e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher" --to-ports <port>[-<port>]\n"
18e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"				Port (range) to map to.\n\n",
19e6869a8f59d779ff4d5a0984c86d80db7078496Marc BoucherNETFILTER_VERSION);
20e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
21e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
22e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct option opts[] = {
23e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ "to-ports", 1, 0, '1' },
24e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	{ 0 }
25e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
26e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
27e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Initialize the target. */
28e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
29e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherinit(struct ipt_entry_target *t, unsigned int *nfcache)
30e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
31e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data;
32e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
33e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Actually, it's 0, but it's ignored at the moment. */
34e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	mr->rangesize = 1;
35e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
36e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	/* Can't cache this */
37e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	*nfcache |= NFC_UNKNOWN;
38e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
39e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
40e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Parses ports */
41e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
42e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherparse_ports(const char *arg, struct ip_nat_multi_range *mr)
43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char *dash;
45e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int port;
46e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
47e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
48e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
49e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	port = atoi(arg);
50e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (port == 0 || port > 65535)
51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", arg);
52e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
53e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	dash = strchr(arg, '-');
54e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (!dash) {
55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		mr->range[0].min.tcp.port
56e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			= mr->range[0].max.tcp.port
57f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell			= htons(port);
58e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	} else {
59e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		int maxport;
60e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
61e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		maxport = atoi(dash + 1);
62e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (maxport == 0 || maxport > 65535)
63e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			exit_error(PARAMETER_PROBLEM,
64e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   "Port `%s' not valid\n", dash+1);
65e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (maxport < port)
66e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			/* People are stupid.  Present reader excepted. */
67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			exit_error(PARAMETER_PROBLEM,
68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   "Port range `%s' funky\n", arg);
69f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell		mr->range[0].min.tcp.port = htons(port);
70f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell		mr->range[0].max.tcp.port = htons(maxport);
71e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
72e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
73e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
74e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Function which parses command options; returns true if it
75e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher   ate an option */
76e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int
77e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherparse(int c, char **argv, int invert, unsigned int *flags,
78e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher      const struct ipt_entry *entry,
79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher      struct ipt_entry_target **target)
80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
81e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	int portok;
82e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ip_nat_multi_range *mr
83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		= (struct ip_nat_multi_range *)(*target)->data;
84e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
85e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (entry->ip.proto == IPPROTO_TCP
86e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    || entry->ip.proto == IPPROTO_UDP)
87e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		portok = 1;
88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else
89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		portok = 0;
90e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
91e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	switch (c) {
92e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	case '1':
93e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (!portok)
94e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			exit_error(PARAMETER_PROBLEM,
95e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   "Need TCP or UDP with port specification");
96e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
97e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (check_inverse(optarg, &invert))
98e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			exit_error(PARAMETER_PROBLEM,
99e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher				   "Unexpected `!' after --to-ports");
100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		parse_ports(optarg, mr);
102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 1;
103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	default:
105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return 0;
106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Final check; don't care. */
110e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void final_check(unsigned int flags)
111e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
112e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Prints out the targinfo. */
115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherprint(const struct ipt_ip *ip,
117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher      const struct ipt_entry_target *target,
118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher      int numeric)
119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
120e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ip_nat_multi_range *mr
121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		= (struct ip_nat_multi_range *)target->data;
122e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ip_nat_range *r = &mr->range[0];
123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
124e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
125f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell		printf("masq ports: ");
126f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell		printf("%hu", ntohs(r->min.tcp.port));
127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (r->max.tcp.port != r->min.tcp.port)
128f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell			printf("-%hu", ntohs(r->max.tcp.port));
129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(" ");
130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Saves the union ipt_targinfo in parsable form to stdout. */
134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchersave(const struct ipt_ip *ip, const struct ipt_entry_target *target)
136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ip_nat_multi_range *mr
138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		= (struct ip_nat_multi_range *)target->data;
139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	struct ip_nat_range *r = &mr->range[0];
140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
142f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell		printf("%hu", ntohs(r->min.tcp.port));
143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (r->max.tcp.port != r->min.tcp.port)
144f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell			printf("-%hu", ntohs(r->max.tcp.port));
145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf(" ");
146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
148e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct iptables_target masq
150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher= { NULL,
151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    "MASQUERADE",
152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    NETFILTER_VERSION,
153e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    sizeof(struct ip_nat_multi_range),
154f9b2e66877b743962a36ec9c37335b9bc3f8b70fRusty Russell    sizeof(struct ip_nat_multi_range),
155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    &help,
156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    &init,
157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    &parse,
158e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    &final_check,
159e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    &print,
160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    &save,
161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher    opts
162e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid _init(void)
165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	register_target(&masq);
167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
168