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 };
22
MASQUERADE_help(void)23 static void MASQUERADE_help(void)
24 {
25 printf(
26 "MASQUERADE target options:\n"
27 " --to-ports <port>[-<port>]\n"
28 " Port (range) to map to.\n"
29 " --random\n"
30 " Randomize source port.\n");
31 }
32
33 static const struct xt_option_entry MASQUERADE_opts[] = {
34 {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
35 {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
36 XTOPT_TABLEEND,
37 };
38
39 /* Parses ports */
40 static void
parse_ports(const char * arg,struct nf_nat_range * r)41 parse_ports(const char *arg, struct nf_nat_range *r)
42 {
43 char *end;
44 unsigned int port, maxport;
45
46 r->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
47
48 if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX))
49 xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
50
51 switch (*end) {
52 case '\0':
53 r->min_proto.tcp.port
54 = r->max_proto.tcp.port
55 = htons(port);
56 return;
57 case '-':
58 if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX))
59 break;
60
61 if (maxport < port)
62 break;
63
64 r->min_proto.tcp.port = htons(port);
65 r->max_proto.tcp.port = htons(maxport);
66 return;
67 default:
68 break;
69 }
70 xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
71 }
72
MASQUERADE_parse(struct xt_option_call * cb)73 static void MASQUERADE_parse(struct xt_option_call *cb)
74 {
75 const struct ip6t_entry *entry = cb->xt_entry;
76 struct nf_nat_range *r = cb->data;
77 int portok;
78
79 if (entry->ipv6.proto == IPPROTO_TCP ||
80 entry->ipv6.proto == IPPROTO_UDP ||
81 entry->ipv6.proto == IPPROTO_SCTP ||
82 entry->ipv6.proto == IPPROTO_DCCP ||
83 entry->ipv6.proto == IPPROTO_ICMP)
84 portok = 1;
85 else
86 portok = 0;
87
88 xtables_option_parse(cb);
89 switch (cb->entry->id) {
90 case O_TO_PORTS:
91 if (!portok)
92 xtables_error(PARAMETER_PROBLEM,
93 "Need TCP, UDP, SCTP or DCCP with port specification");
94 parse_ports(cb->arg, r);
95 break;
96 case O_RANDOM:
97 r->flags |= NF_NAT_RANGE_PROTO_RANDOM;
98 break;
99 }
100 }
101
102 static void
MASQUERADE_print(const void * ip,const struct xt_entry_target * target,int numeric)103 MASQUERADE_print(const void *ip, const struct xt_entry_target *target,
104 int numeric)
105 {
106 const struct nf_nat_range *r = (const void *)target->data;
107
108 if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
109 printf(" masq ports: ");
110 printf("%hu", ntohs(r->min_proto.tcp.port));
111 if (r->max_proto.tcp.port != r->min_proto.tcp.port)
112 printf("-%hu", ntohs(r->max_proto.tcp.port));
113 }
114
115 if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
116 printf(" random");
117 }
118
119 static void
MASQUERADE_save(const void * ip,const struct xt_entry_target * target)120 MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
121 {
122 const struct nf_nat_range *r = (const void *)target->data;
123
124 if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
125 printf(" --to-ports %hu", ntohs(r->min_proto.tcp.port));
126 if (r->max_proto.tcp.port != r->min_proto.tcp.port)
127 printf("-%hu", ntohs(r->max_proto.tcp.port));
128 }
129
130 if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
131 printf(" --random");
132 }
133
134 static struct xtables_target masquerade_tg_reg = {
135 .name = "MASQUERADE",
136 .version = XTABLES_VERSION,
137 .family = NFPROTO_IPV6,
138 .size = XT_ALIGN(sizeof(struct nf_nat_range)),
139 .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
140 .help = MASQUERADE_help,
141 .x6_parse = MASQUERADE_parse,
142 .print = MASQUERADE_print,
143 .save = MASQUERADE_save,
144 .x6_options = MASQUERADE_opts,
145 };
146
_init(void)147 void _init(void)
148 {
149 xtables_register_target(&masquerade_tg_reg);
150 }
151