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