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