move current trunk to branches
[iptables.git] / extensions / libipt_SAME.c
1 /* Shared library add-on to iptables to add simple non load-balancing SNAT 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 /* For 64bit kernel / 32bit userspace */
11 #include "../include/linux/netfilter_ipv4/ipt_SAME.h"
12
13 /* Function which prints out usage message. */
14 static void SAME_help(void)
15 {
16         printf(
17 "SAME target options:\n"
18 " --to <ipaddr>-<ipaddr>\n"
19 "                               Addresses to map source to.\n"
20 "                                May be specified more than\n"
21 "                                 once for multiple ranges.\n"
22 " --nodst\n"
23 "                               Don't use destination-ip in\n"
24 "                                          source selection\n"
25 " --random\n"
26 "                               Randomize source port\n");
27 }
28
29 static const struct option SAME_opts[] = {
30         { "to", 1, NULL, '1' },
31         { "nodst", 0, NULL, '2'},
32         { "random", 0, NULL, '3' },
33         { .name = NULL }
34 };
35
36 /* Initialize the target. */
37 static void SAME_init(struct xt_entry_target *t)
38 {
39         struct ipt_same_info *mr = (struct ipt_same_info *)t->data;
40
41         /* Set default to 0 */
42         mr->rangesize = 0;
43         mr->info = 0;
44         mr->ipnum = 0;
45         
46 }
47
48 /* Parses range of IPs */
49 static void
50 parse_to(char *arg, struct ip_nat_range *range)
51 {
52         char *dash;
53         const struct in_addr *ip;
54
55         range->flags |= IP_NAT_RANGE_MAP_IPS;
56         dash = strchr(arg, '-');
57
58         if (dash)
59                 *dash = '\0';
60
61         ip = numeric_to_ipaddr(arg);
62         if (!ip)
63                 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
64                            arg);
65         range->min_ip = ip->s_addr;
66
67         if (dash) {
68                 ip = numeric_to_ipaddr(dash+1);
69                 if (!ip)
70                         exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
71                                    dash+1);
72         }
73         range->max_ip = ip->s_addr;
74         if (dash)
75                 if (range->min_ip > range->max_ip)
76                         exit_error(PARAMETER_PROBLEM, "Bad IP range `%s-%s'\n", 
77                                    arg, dash+1);
78 }
79
80 #define IPT_SAME_OPT_TO                 0x01
81 #define IPT_SAME_OPT_NODST              0x02
82 #define IPT_SAME_OPT_RANDOM             0x04
83
84 /* Function which parses command options; returns true if it
85    ate an option */
86 static int SAME_parse(int c, char **argv, int invert, unsigned int *flags,
87                       const void *entry, struct xt_entry_target **target)
88 {
89         struct ipt_same_info *mr
90                 = (struct ipt_same_info *)(*target)->data;
91         unsigned int count;
92
93         switch (c) {
94         case '1':
95                 if (mr->rangesize == IPT_SAME_MAX_RANGE)
96                         exit_error(PARAMETER_PROBLEM,
97                                    "Too many ranges specified, maximum "
98                                    "is %i ranges.\n",
99                                    IPT_SAME_MAX_RANGE);
100                 if (check_inverse(optarg, &invert, NULL, 0))
101                         exit_error(PARAMETER_PROBLEM,
102                                    "Unexpected `!' after --to");
103
104                 parse_to(optarg, &mr->range[mr->rangesize]);
105                 /* WTF do we need this for? */
106                 if (*flags & IPT_SAME_OPT_RANDOM)
107                         mr->range[mr->rangesize].flags 
108                                 |= IP_NAT_RANGE_PROTO_RANDOM;
109                 mr->rangesize++;
110                 *flags |= IPT_SAME_OPT_TO;
111                 break;
112                 
113         case '2':
114                 if (*flags & IPT_SAME_OPT_NODST)
115                         exit_error(PARAMETER_PROBLEM,
116                                    "Can't specify --nodst twice");
117                 
118                 mr->info |= IPT_SAME_NODST;
119                 *flags |= IPT_SAME_OPT_NODST;
120                 break;
121
122         case '3':       
123                 *flags |= IPT_SAME_OPT_RANDOM;
124                 for (count=0; count < mr->rangesize; count++)
125                         mr->range[count].flags |= IP_NAT_RANGE_PROTO_RANDOM;
126                 break;
127
128         default:
129                 return 0;
130         }
131         
132         return 1;
133 }
134
135 /* Final check; need --to. */
136 static void SAME_check(unsigned int flags)
137 {
138         if (!(flags & IPT_SAME_OPT_TO))
139                 exit_error(PARAMETER_PROBLEM,
140                            "SAME needs --to");
141 }
142
143 /* Prints out the targinfo. */
144 static void SAME_print(const void *ip, const struct xt_entry_target *target,
145                        int numeric)
146 {
147         unsigned int count;
148         struct ipt_same_info *mr
149                 = (struct ipt_same_info *)target->data;
150         int random_selection = 0;
151         
152         printf("same:");
153         
154         for (count = 0; count < mr->rangesize; count++) {
155                 struct ip_nat_range *r = &mr->range[count];
156                 struct in_addr a;
157
158                 a.s_addr = r->min_ip;
159
160                 printf("%s", ipaddr_to_numeric(&a));
161                 a.s_addr = r->max_ip;
162                 
163                 if (r->min_ip == r->max_ip)
164                         printf(" ");
165                 else
166                         printf("-%s ", ipaddr_to_numeric(&a));
167                 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) 
168                         random_selection = 1;
169         }
170         
171         if (mr->info & IPT_SAME_NODST)
172                 printf("nodst ");
173
174         if (random_selection)
175                 printf("random ");
176 }
177
178 /* Saves the union ipt_targinfo in parsable form to stdout. */
179 static void SAME_save(const void *ip, const struct xt_entry_target *target)
180 {
181         unsigned int count;
182         struct ipt_same_info *mr
183                 = (struct ipt_same_info *)target->data;
184         int random_selection = 0;
185
186         for (count = 0; count < mr->rangesize; count++) {
187                 struct ip_nat_range *r = &mr->range[count];
188                 struct in_addr a;
189
190                 a.s_addr = r->min_ip;
191                 printf("--to %s", ipaddr_to_numeric(&a));
192                 a.s_addr = r->max_ip;
193
194                 if (r->min_ip == r->max_ip)
195                         printf(" ");
196                 else
197                         printf("-%s ", ipaddr_to_numeric(&a));
198                 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) 
199                         random_selection = 1;
200         }
201         
202         if (mr->info & IPT_SAME_NODST)
203                 printf("--nodst ");
204
205         if (random_selection)
206                 printf("--random ");
207 }
208
209 static struct xtables_target same_tg_reg = {
210         .name           = "SAME",
211         .version        = XTABLES_VERSION,
212         .family         = PF_INET,
213         .size           = XT_ALIGN(sizeof(struct ipt_same_info)),
214         .userspacesize  = XT_ALIGN(sizeof(struct ipt_same_info)),
215         .help           = SAME_help,
216         .init           = SAME_init,
217         .parse          = SAME_parse,
218         .final_check    = SAME_check,
219         .print          = SAME_print,
220         .save           = SAME_save,
221         .extra_opts     = SAME_opts,
222 };
223
224 void _init(void)
225 {
226         xtables_register_target(&same_tg_reg);
227 }