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