1 /*
2 * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
3 *
4 * Based on Rusty Russell's IPv4 MASQUERADE target. Development of IPv6 NAT
5 * funded by Astaro.
6 */
7
8 #include <stdio.h>
9 #include <netdb.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <getopt.h>
13 #include <xtables.h>
14 #include <limits.h> /* INT_MAX in ip_tables.h */
15 #include <linux/netfilter_ipv6/ip6_tables.h>
16 #include <linux/netfilter/nf_nat.h>
17
18 enum {
19 O_TO_PORTS = 0,
20 O_RANDOM,
21 O_RANDOM_FULLY,
22 };
23
MASQUERADE_help(void)24 static void MASQUERADE_help(void)
25 {
26 printf(
27 "MASQUERADE target options:\n"
28 " --to-ports <port>[-<port>]\n"
29 " Port (range) to map to.\n"
30 " --random\n"
31 " Randomize source port.\n"
32 " --random-fully\n"
33 " Fully randomize source port.\n");
34 }
35
36 static const struct xt_option_entry MASQUERADE_opts[] = {
37 {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
38 {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
39 {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE},
40 XTOPT_TABLEEND,
41 };
42
43 /* Parses ports */
44 static void
parse_ports(const char * arg,struct nf_nat_range * r)45 parse_ports(const char *arg, struct nf_nat_range *r)
46 {
47 char *end;
48 unsigned int port, maxport;
49
50 r->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
51
52 if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX))
53 xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
54
55 switch (*end) {
56 case '\0':
57 r->min_proto.tcp.port
58 = r->max_proto.tcp.port
59 = htons(port);
60 return;
61 case '-':
62 if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX))
63 break;
64
65 if (maxport < port)
66 break;
67
68 r->min_proto.tcp.port = htons(port);
69 r->max_proto.tcp.port = htons(maxport);
70 return;
71 default:
72 break;
73 }
74 xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
75 }
76
MASQUERADE_parse(struct xt_option_call * cb)77 static void MASQUERADE_parse(struct xt_option_call *cb)
78 {
79 const struct ip6t_entry *entry = cb->xt_entry;
80 struct nf_nat_range *r = cb->data;
81 int portok;
82
83 if (entry->ipv6.proto == IPPROTO_TCP ||
84 entry->ipv6.proto == IPPROTO_UDP ||
85 entry->ipv6.proto == IPPROTO_SCTP ||
86 entry->ipv6.proto == IPPROTO_DCCP ||
87 entry->ipv6.proto == IPPROTO_ICMP)
88 portok = 1;
89 else
90 portok = 0;
91
92 xtables_option_parse(cb);
93 switch (cb->entry->id) {
94 case O_TO_PORTS:
95 if (!portok)
96 xtables_error(PARAMETER_PROBLEM,
97 "Need TCP, UDP, SCTP or DCCP with port specification");
98 parse_ports(cb->arg, r);
99 break;
100 case O_RANDOM:
101 r->flags |= NF_NAT_RANGE_PROTO_RANDOM;
102 break;
103 case O_RANDOM_FULLY:
104 r->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY;
105 break;
106 }
107 }
108
109 static void
MASQUERADE_print(const void * ip,const struct xt_entry_target * target,int numeric)110 MASQUERADE_print(const void *ip, const struct xt_entry_target *target,
111 int numeric)
112 {
113 const struct nf_nat_range *r = (const void *)target->data;
114
115 if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
116 printf(" masq ports: ");
117 printf("%hu", ntohs(r->min_proto.tcp.port));
118 if (r->max_proto.tcp.port != r->min_proto.tcp.port)
119 printf("-%hu", ntohs(r->max_proto.tcp.port));
120 }
121
122 if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
123 printf(" random");
124
125 if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
126 printf(" random-fully");
127 }
128
129 static void
MASQUERADE_save(const void * ip,const struct xt_entry_target * target)130 MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
131 {
132 const struct nf_nat_range *r = (const void *)target->data;
133
134 if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
135 printf(" --to-ports %hu", ntohs(r->min_proto.tcp.port));
136 if (r->max_proto.tcp.port != r->min_proto.tcp.port)
137 printf("-%hu", ntohs(r->max_proto.tcp.port));
138 }
139
140 if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
141 printf(" --random");
142
143 if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
144 printf(" --random-fully");
145 }
146
MASQUERADE_xlate(struct xt_xlate * xl,const struct xt_xlate_tg_params * params)147 static int MASQUERADE_xlate(struct xt_xlate *xl,
148 const struct xt_xlate_tg_params *params)
149 {
150 const struct nf_nat_range *r = (const void *)params->target->data;
151
152 xt_xlate_add(xl, "masquerade");
153
154 if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
155 xt_xlate_add(xl, " to :%hu", ntohs(r->min_proto.tcp.port));
156 if (r->max_proto.tcp.port != r->min_proto.tcp.port)
157 xt_xlate_add(xl, "-%hu", ntohs(r->max_proto.tcp.port));
158 }
159
160 xt_xlate_add(xl, " ");
161 if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
162 xt_xlate_add(xl, "random ");
163
164 xt_xlate_add(xl, " ");
165 if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
166 xt_xlate_add(xl, "random-fully ");
167
168 return 1;
169 }
170
171 static struct xtables_target masquerade_tg_reg = {
172 .name = "MASQUERADE",
173 .version = XTABLES_VERSION,
174 .family = NFPROTO_IPV6,
175 .size = XT_ALIGN(sizeof(struct nf_nat_range)),
176 .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
177 .help = MASQUERADE_help,
178 .x6_parse = MASQUERADE_parse,
179 .print = MASQUERADE_print,
180 .save = MASQUERADE_save,
181 .x6_options = MASQUERADE_opts,
182 .xlate = MASQUERADE_xlate,
183 };
184
_init(void)185 void _init(void)
186 {
187 xtables_register_target(&masquerade_tg_reg);
188 }
189