blob: c24bb32135aa87a0488dc94677e71042116ee4d4 [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* Shared library add-on to iptables to add masquerade support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7#include <iptables.h>
8#include <linux/netfilter_ipv4/ip_tables.h>
Patrick McHardy40d54752007-04-18 07:00:36 +00009#include <linux/netfilter/nf_nat.h>
Marc Bouchere6869a82000-03-20 06:03:29 +000010
11/* Function which prints out usage message. */
12static void
13help(void)
14{
15 printf(
16"MASQUERADE v%s options:\n"
17" --to-ports <port>[-<port>]\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000018" Port (range) to map to.\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000019" --random\n"
20" Randomize source port.\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000021"\n"
22,
Harald Welte80fe35d2002-05-29 13:08:15 +000023IPTABLES_VERSION);
Marc Bouchere6869a82000-03-20 06:03:29 +000024}
25
26static struct option opts[] = {
27 { "to-ports", 1, 0, '1' },
Eric Leblondae4b0b32007-02-24 15:11:33 +000028 { "random", 0, 0, '2' },
Marc Bouchere6869a82000-03-20 06:03:29 +000029 { 0 }
30};
31
32/* Initialize the target. */
33static void
34init(struct ipt_entry_target *t, unsigned int *nfcache)
35{
36 struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data;
37
38 /* Actually, it's 0, but it's ignored at the moment. */
39 mr->rangesize = 1;
40
Marc Bouchere6869a82000-03-20 06:03:29 +000041}
42
43/* Parses ports */
44static void
45parse_ports(const char *arg, struct ip_nat_multi_range *mr)
46{
47 const char *dash;
48 int port;
49
50 mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
51
52 port = atoi(arg);
Yasuyuki KOZAKAI1d095f82003-10-30 06:36:49 +000053 if (port <= 0 || port > 65535)
Marc Bouchere6869a82000-03-20 06:03:29 +000054 exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", arg);
55
56 dash = strchr(arg, '-');
57 if (!dash) {
58 mr->range[0].min.tcp.port
59 = mr->range[0].max.tcp.port
Rusty Russellf9b2e662000-04-19 11:24:02 +000060 = htons(port);
Marc Bouchere6869a82000-03-20 06:03:29 +000061 } else {
62 int maxport;
63
64 maxport = atoi(dash + 1);
65 if (maxport == 0 || maxport > 65535)
66 exit_error(PARAMETER_PROBLEM,
67 "Port `%s' not valid\n", dash+1);
68 if (maxport < port)
69 /* People are stupid. Present reader excepted. */
70 exit_error(PARAMETER_PROBLEM,
71 "Port range `%s' funky\n", arg);
Rusty Russellf9b2e662000-04-19 11:24:02 +000072 mr->range[0].min.tcp.port = htons(port);
73 mr->range[0].max.tcp.port = htons(maxport);
Marc Bouchere6869a82000-03-20 06:03:29 +000074 }
75}
76
77/* Function which parses command options; returns true if it
78 ate an option */
79static int
80parse(int c, char **argv, int invert, unsigned int *flags,
81 const struct ipt_entry *entry,
82 struct ipt_entry_target **target)
83{
84 int portok;
85 struct ip_nat_multi_range *mr
86 = (struct ip_nat_multi_range *)(*target)->data;
87
88 if (entry->ip.proto == IPPROTO_TCP
Patrick McHardy36d870c2005-07-22 06:39:45 +000089 || entry->ip.proto == IPPROTO_UDP
90 || entry->ip.proto == IPPROTO_ICMP)
Marc Bouchere6869a82000-03-20 06:03:29 +000091 portok = 1;
92 else
93 portok = 0;
94
95 switch (c) {
96 case '1':
97 if (!portok)
98 exit_error(PARAMETER_PROBLEM,
99 "Need TCP or UDP with port specification");
100
Harald Welteb77f1da2002-03-14 11:35:58 +0000101 if (check_inverse(optarg, &invert, NULL, 0))
Marc Bouchere6869a82000-03-20 06:03:29 +0000102 exit_error(PARAMETER_PROBLEM,
103 "Unexpected `!' after --to-ports");
104
105 parse_ports(optarg, mr);
106 return 1;
107
Eric Leblondae4b0b32007-02-24 15:11:33 +0000108 case '2':
109 mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
110 return 1;
Eric Leblondae4b0b32007-02-24 15:11:33 +0000111
Marc Bouchere6869a82000-03-20 06:03:29 +0000112 default:
113 return 0;
114 }
115}
116
117/* Final check; don't care. */
118static void final_check(unsigned int flags)
119{
120}
121
122/* Prints out the targinfo. */
123static void
124print(const struct ipt_ip *ip,
125 const struct ipt_entry_target *target,
126 int numeric)
127{
128 struct ip_nat_multi_range *mr
129 = (struct ip_nat_multi_range *)target->data;
130 struct ip_nat_range *r = &mr->range[0];
131
Marc Bouchere6869a82000-03-20 06:03:29 +0000132 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
Rusty Russellf9b2e662000-04-19 11:24:02 +0000133 printf("masq ports: ");
134 printf("%hu", ntohs(r->min.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000135 if (r->max.tcp.port != r->min.tcp.port)
Rusty Russellf9b2e662000-04-19 11:24:02 +0000136 printf("-%hu", ntohs(r->max.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000137 printf(" ");
138 }
Eric Leblondae4b0b32007-02-24 15:11:33 +0000139
Patrick McHardye656e262007-04-18 12:56:05 +0000140 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
Patrick McHardy9c67def2007-04-18 14:00:11 +0000141 printf("random ");
Marc Bouchere6869a82000-03-20 06:03:29 +0000142}
143
144/* Saves the union ipt_targinfo in parsable form to stdout. */
145static void
146save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
147{
148 struct ip_nat_multi_range *mr
149 = (struct ip_nat_multi_range *)target->data;
150 struct ip_nat_range *r = &mr->range[0];
151
152 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
A. van Schie4b5566b2002-04-01 07:51:25 +0000153 printf("--to-ports %hu", ntohs(r->min.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000154 if (r->max.tcp.port != r->min.tcp.port)
Rusty Russellf9b2e662000-04-19 11:24:02 +0000155 printf("-%hu", ntohs(r->max.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000156 printf(" ");
157 }
Patrick McHardy9c67def2007-04-18 14:00:11 +0000158
159 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
160 printf("--random ");
Marc Bouchere6869a82000-03-20 06:03:29 +0000161}
162
Pablo Neira8caee8b2004-12-28 13:11:59 +0000163static struct iptables_target masq = { NULL,
164 .name = "MASQUERADE",
165 .version = IPTABLES_VERSION,
166 .size = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
167 .userspacesize = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
168 .help = &help,
169 .init = &init,
170 .parse = &parse,
171 .final_check = &final_check,
172 .print = &print,
173 .save = &save,
174 .extra_opts = opts
Marc Bouchere6869a82000-03-20 06:03:29 +0000175};
176
177void _init(void)
178{
179 register_target(&masq);
180}