changing trunk/trunk to trunk
[iptables.git] / extensions / libipt_MASQUERADE.c
1 /* 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>
9 #include <linux/netfilter/nf_nat.h>
10
11 /* Function which prints out usage message. */
12 static void MASQUERADE_help(void)
13 {
14         printf(
15 "MASQUERADE target options:\n"
16 " --to-ports <port>[-<port>]\n"
17 "                               Port (range) to map to.\n"
18 " --random\n"
19 "                               Randomize source port.\n");
20 }
21
22 static const struct option MASQUERADE_opts[] = {
23         { "to-ports", 1, NULL, '1' },
24         { "random", 0, NULL, '2' },
25         { .name = NULL }
26 };
27
28 /* Initialize the target. */
29 static void MASQUERADE_init(struct xt_entry_target *t)
30 {
31         struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data;
32
33         /* Actually, it's 0, but it's ignored at the moment. */
34         mr->rangesize = 1;
35
36 }
37
38 /* Parses ports */
39 static void
40 parse_ports(const char *arg, struct ip_nat_multi_range *mr)
41 {
42         const char *dash;
43         int port;
44
45         mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
46
47         port = atoi(arg);
48         if (port <= 0 || port > 65535)
49                 exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", arg);
50
51         dash = strchr(arg, '-');
52         if (!dash) {
53                 mr->range[0].min.tcp.port
54                         = mr->range[0].max.tcp.port
55                         = htons(port);
56         } else {
57                 int maxport;
58
59                 maxport = atoi(dash + 1);
60                 if (maxport == 0 || maxport > 65535)
61                         exit_error(PARAMETER_PROBLEM,
62                                    "Port `%s' not valid\n", dash+1);
63                 if (maxport < port)
64                         /* People are stupid.  Present reader excepted. */
65                         exit_error(PARAMETER_PROBLEM,
66                                    "Port range `%s' funky\n", arg);
67                 mr->range[0].min.tcp.port = htons(port);
68                 mr->range[0].max.tcp.port = htons(maxport);
69         }
70 }
71
72 /* Function which parses command options; returns true if it
73    ate an option */
74 static int MASQUERADE_parse(int c, char **argv, int invert, unsigned int *flags,
75                             const void *e, struct xt_entry_target **target)
76 {
77         const struct ipt_entry *entry = e;
78         int portok;
79         struct ip_nat_multi_range *mr
80                 = (struct ip_nat_multi_range *)(*target)->data;
81
82         if (entry->ip.proto == IPPROTO_TCP
83             || entry->ip.proto == IPPROTO_UDP
84             || entry->ip.proto == IPPROTO_ICMP)
85                 portok = 1;
86         else
87                 portok = 0;
88
89         switch (c) {
90         case '1':
91                 if (!portok)
92                         exit_error(PARAMETER_PROBLEM,
93                                    "Need TCP or UDP with port specification");
94
95                 if (check_inverse(optarg, &invert, NULL, 0))
96                         exit_error(PARAMETER_PROBLEM,
97                                    "Unexpected `!' after --to-ports");
98
99                 parse_ports(optarg, mr);
100                 return 1;
101
102         case '2':
103                 mr->range[0].flags |=  IP_NAT_RANGE_PROTO_RANDOM;
104                 return 1;
105
106         default:
107                 return 0;
108         }
109 }
110
111 /* Prints out the targinfo. */
112 static void
113 MASQUERADE_print(const void *ip, const struct xt_entry_target *target,
114                  int numeric)
115 {
116         struct ip_nat_multi_range *mr
117                 = (struct ip_nat_multi_range *)target->data;
118         struct ip_nat_range *r = &mr->range[0];
119
120         if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
121                 printf("masq ports: ");
122                 printf("%hu", ntohs(r->min.tcp.port));
123                 if (r->max.tcp.port != r->min.tcp.port)
124                         printf("-%hu", ntohs(r->max.tcp.port));
125                 printf(" ");
126         }
127
128         if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
129                 printf("random ");
130 }
131
132 /* Saves the union ipt_targinfo in parsable form to stdout. */
133 static void
134 MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
135 {
136         struct ip_nat_multi_range *mr
137                 = (struct ip_nat_multi_range *)target->data;
138         struct ip_nat_range *r = &mr->range[0];
139
140         if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
141                 printf("--to-ports %hu", ntohs(r->min.tcp.port));
142                 if (r->max.tcp.port != r->min.tcp.port)
143                         printf("-%hu", ntohs(r->max.tcp.port));
144                 printf(" ");
145         }
146
147         if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
148                 printf("--random ");
149 }
150
151 static struct xtables_target masquerade_tg_reg = {
152         .name           = "MASQUERADE",
153         .version        = XTABLES_VERSION,
154         .family         = PF_INET,
155         .size           = XT_ALIGN(sizeof(struct ip_nat_multi_range)),
156         .userspacesize  = XT_ALIGN(sizeof(struct ip_nat_multi_range)),
157         .help           = MASQUERADE_help,
158         .init           = MASQUERADE_init,
159         .parse          = MASQUERADE_parse,
160         .print          = MASQUERADE_print,
161         .save           = MASQUERADE_save,
162         .extra_opts     = MASQUERADE_opts,
163 };
164
165 void _init(void)
166 {
167         xtables_register_target(&masquerade_tg_reg);
168 }