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