1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <xtables.h>
5 #include <net/netfilter/nf_nat.h>
6 #include <linux/netfilter_ipv4/ipt_SAME.h>
7
8 enum {
9 O_TO_ADDR = 0,
10 O_NODST,
11 O_RANDOM,
12 F_RANDOM = 1 << O_RANDOM,
13 };
14
SAME_help(void)15 static void SAME_help(void)
16 {
17 printf(
18 "SAME target options:\n"
19 " --to <ipaddr>-<ipaddr>\n"
20 " Addresses to map source to.\n"
21 " May be specified more than\n"
22 " once for multiple ranges.\n"
23 " --nodst\n"
24 " Don't use destination-ip in\n"
25 " source selection\n"
26 " --random\n"
27 " Randomize source port\n");
28 }
29
30 static const struct xt_option_entry SAME_opts[] = {
31 {.name = "to", .id = O_TO_ADDR, .type = XTTYPE_STRING,
32 .flags = XTOPT_MAND},
33 {.name = "nodst", .id = O_NODST, .type = XTTYPE_NONE},
34 {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
35 XTOPT_TABLEEND,
36 };
37
38 /* Parses range of IPs */
parse_to(const char * orig_arg,struct nf_nat_range * range)39 static void parse_to(const char *orig_arg, struct nf_nat_range *range)
40 {
41 char *dash, *arg;
42 const struct in_addr *ip;
43
44 arg = strdup(orig_arg);
45 if (arg == NULL)
46 xtables_error(RESOURCE_PROBLEM, "strdup");
47 range->flags |= IP_NAT_RANGE_MAP_IPS;
48 dash = strchr(arg, '-');
49
50 if (dash)
51 *dash = '\0';
52
53 ip = xtables_numeric_to_ipaddr(arg);
54 if (!ip)
55 xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
56 arg);
57 range->min_ip = ip->s_addr;
58
59 if (dash) {
60 ip = xtables_numeric_to_ipaddr(dash+1);
61 if (!ip)
62 xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
63 dash+1);
64 }
65 range->max_ip = ip->s_addr;
66 if (dash)
67 if (range->min_ip > range->max_ip)
68 xtables_error(PARAMETER_PROBLEM, "Bad IP range \"%s-%s\"\n",
69 arg, dash+1);
70 free(arg);
71 }
72
SAME_parse(struct xt_option_call * cb)73 static void SAME_parse(struct xt_option_call *cb)
74 {
75 struct ipt_same_info *mr = cb->data;
76 unsigned int count;
77
78 xtables_option_parse(cb);
79 switch (cb->entry->id) {
80 case O_TO_ADDR:
81 if (mr->rangesize == IPT_SAME_MAX_RANGE)
82 xtables_error(PARAMETER_PROBLEM,
83 "Too many ranges specified, maximum "
84 "is %i ranges.\n",
85 IPT_SAME_MAX_RANGE);
86 parse_to(cb->arg, &mr->range[mr->rangesize]);
87 /* WTF do we need this for? */
88 if (cb->xflags & F_RANDOM)
89 mr->range[mr->rangesize].flags
90 |= IP_NAT_RANGE_PROTO_RANDOM;
91 mr->rangesize++;
92 break;
93 case O_NODST:
94 mr->info |= IPT_SAME_NODST;
95 break;
96 case O_RANDOM:
97 for (count=0; count < mr->rangesize; count++)
98 mr->range[count].flags |= IP_NAT_RANGE_PROTO_RANDOM;
99 break;
100 }
101 }
102
SAME_print(const void * ip,const struct xt_entry_target * target,int numeric)103 static void SAME_print(const void *ip, const struct xt_entry_target *target,
104 int numeric)
105 {
106 unsigned int count;
107 const struct ipt_same_info *mr = (const void *)target->data;
108 int random_selection = 0;
109
110 printf(" same:");
111
112 for (count = 0; count < mr->rangesize; count++) {
113 const struct nf_nat_range *r = &mr->range[count];
114 struct in_addr a;
115
116 a.s_addr = r->min_ip;
117
118 printf("%s", xtables_ipaddr_to_numeric(&a));
119 a.s_addr = r->max_ip;
120
121 if (r->min_ip != r->max_ip)
122 printf("-%s", xtables_ipaddr_to_numeric(&a));
123 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
124 random_selection = 1;
125 }
126
127 if (mr->info & IPT_SAME_NODST)
128 printf(" nodst");
129
130 if (random_selection)
131 printf(" random");
132 }
133
SAME_save(const void * ip,const struct xt_entry_target * target)134 static void SAME_save(const void *ip, const struct xt_entry_target *target)
135 {
136 unsigned int count;
137 const struct ipt_same_info *mr = (const void *)target->data;
138 int random_selection = 0;
139
140 for (count = 0; count < mr->rangesize; count++) {
141 const struct nf_nat_range *r = &mr->range[count];
142 struct in_addr a;
143
144 a.s_addr = r->min_ip;
145 printf(" --to %s", xtables_ipaddr_to_numeric(&a));
146 a.s_addr = r->max_ip;
147
148 if (r->min_ip != r->max_ip)
149 printf("-%s", xtables_ipaddr_to_numeric(&a));
150 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
151 random_selection = 1;
152 }
153
154 if (mr->info & IPT_SAME_NODST)
155 printf(" --nodst");
156
157 if (random_selection)
158 printf(" --random");
159 }
160
161 static struct xtables_target same_tg_reg = {
162 .name = "SAME",
163 .version = XTABLES_VERSION,
164 .family = NFPROTO_IPV4,
165 .size = XT_ALIGN(sizeof(struct ipt_same_info)),
166 .userspacesize = XT_ALIGN(sizeof(struct ipt_same_info)),
167 .help = SAME_help,
168 .x6_parse = SAME_parse,
169 .print = SAME_print,
170 .save = SAME_save,
171 .x6_options = SAME_opts,
172 };
173
_init(void)174 void _init(void)
175 {
176 xtables_register_target(&same_tg_reg);
177 }
178