1 /* Shared library add-on to iptables to add source-NAT support. */
8 #include <linux/netfilter_ipv4/ip_tables.h>
9 #include <linux/netfilter_ipv4/ip_nat_rule.h>
11 /* Source NAT data consists of a multi-range, indicating where to map
15 struct ipt_entry_target t;
16 struct ip_nat_multi_range mr;
19 /* Function which prints out usage message. */
25 " --to-source <ipaddr>[-<ipaddr>][:port-port]\n"
26 " Address to map source to.\n"
27 " (You can use this more than once)\n\n",
31 static struct option opts[] = {
32 { "to-source", 1, 0, '1' },
36 static struct ipt_natinfo *
37 append_range(struct ipt_natinfo *info, const struct ip_nat_range *range)
41 /* One rangesize already in struct ipt_natinfo */
42 size = IPT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
44 info = realloc(info, size);
46 exit_error(OTHER_PROBLEM, "Out of memory\n");
48 info->t.u.target_size = size;
49 info->mr.range[info->mr.rangesize] = *range;
55 /* Ranges expected in network order. */
56 static struct ipt_entry_target *
57 parse_to(char *arg, int portok, struct ipt_natinfo *info)
59 struct ip_nat_range range;
60 char *colon, *dash, *error;
63 memset(&range, 0, sizeof(range));
64 colon = strchr(arg, ':');
70 exit_error(PARAMETER_PROBLEM,
71 "Need TCP or UDP with port specification");
73 range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
76 if (port <= 0 || port > 65535)
77 exit_error(PARAMETER_PROBLEM,
78 "Port `%s' not valid\n", colon+1);
80 error = strchr(colon+1, ':');
82 exit_error(PARAMETER_PROBLEM,
83 "Invalid port:port syntax - use dash\n");
85 dash = strchr(colon, '-');
93 maxport = atoi(dash + 1);
94 if (maxport <= 0 || maxport > 65535)
95 exit_error(PARAMETER_PROBLEM,
96 "Port `%s' not valid\n", dash+1);
98 /* People are stupid. */
99 exit_error(PARAMETER_PROBLEM,
100 "Port range `%s' funky\n", colon+1);
101 range.min.tcp.port = htons(port);
102 range.max.tcp.port = htons(maxport);
104 /* Starts with a colon? No IP info...*/
106 return &(append_range(info, &range)->t);
110 range.flags |= IP_NAT_RANGE_MAP_IPS;
111 dash = strchr(arg, '-');
112 if (colon && dash && dash > colon)
118 ip = dotted_to_addr(arg);
120 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
122 range.min_ip = ip->s_addr;
124 ip = dotted_to_addr(dash+1);
126 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
128 range.max_ip = ip->s_addr;
130 range.max_ip = range.min_ip;
132 return &(append_range(info, &range)->t);
135 /* Function which parses command options; returns true if it
138 parse(int c, char **argv, int invert, unsigned int *flags,
139 const struct ipt_entry *entry,
140 struct ipt_entry_target **target)
142 struct ipt_natinfo *info = (void *)*target;
145 if (entry->ip.proto == IPPROTO_TCP
146 || entry->ip.proto == IPPROTO_UDP
147 || entry->ip.proto == IPPROTO_ICMP)
154 if (check_inverse(optarg, &invert, NULL, 0))
155 exit_error(PARAMETER_PROBLEM,
156 "Unexpected `!' after --to-source");
160 get_kernel_version();
161 if (kernel_version > LINUX_VERSION(2, 6, 10))
162 exit_error(PARAMETER_PROBLEM,
163 "Multiple --to-source not supported");
165 *target = parse_to(optarg, portok, info);
174 /* Final check; must have specfied --to-source. */
175 static void final_check(unsigned int flags)
178 exit_error(PARAMETER_PROBLEM,
179 "You must specify --to-source");
182 static void print_range(const struct ip_nat_range *r)
184 if (r->flags & IP_NAT_RANGE_MAP_IPS) {
187 a.s_addr = r->min_ip;
188 printf("%s", addr_to_dotted(&a));
189 if (r->max_ip != r->min_ip) {
190 a.s_addr = r->max_ip;
191 printf("-%s", addr_to_dotted(&a));
194 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
196 printf("%hu", ntohs(r->min.tcp.port));
197 if (r->max.tcp.port != r->min.tcp.port)
198 printf("-%hu", ntohs(r->max.tcp.port));
202 /* Prints out the targinfo. */
204 print(const struct ipt_ip *ip,
205 const struct ipt_entry_target *target,
208 struct ipt_natinfo *info = (void *)target;
212 for (i = 0; i < info->mr.rangesize; i++) {
213 print_range(&info->mr.range[i]);
218 /* Saves the union ipt_targinfo in parsable form to stdout. */
220 save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
222 struct ipt_natinfo *info = (void *)target;
225 for (i = 0; i < info->mr.rangesize; i++) {
226 printf("--to-source ");
227 print_range(&info->mr.range[i]);
232 static struct iptables_target snat = {
235 .version = IPTABLES_VERSION,
236 .size = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
237 .userspacesize = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
240 .final_check = &final_check,
248 register_target(&snat);