10e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy/*
20e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
30e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy *
40e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy * Based on Rusty Russell's IPv4 MASQUERADE target. Development of IPv6 NAT
50e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy * funded by Astaro.
60e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy */
70e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
80e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <stdio.h>
90e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <netdb.h>
100e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <string.h>
110e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <stdlib.h>
120e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <getopt.h>
130e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <xtables.h>
140e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <limits.h> /* INT_MAX in ip_tables.h */
150e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <linux/netfilter_ipv6/ip6_tables.h>
160e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy#include <linux/netfilter/nf_nat.h>
170e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
180e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardyenum {
190e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	O_TO_PORTS = 0,
200e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	O_RANDOM,
210e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy};
220e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
230e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic void MASQUERADE_help(void)
240e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy{
250e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	printf(
260e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy"MASQUERADE target options:\n"
270e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy" --to-ports <port>[-<port>]\n"
280e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy"				Port (range) to map to.\n"
290e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy" --random\n"
300e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy"				Randomize source port.\n");
310e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy}
320e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
330e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic const struct xt_option_entry MASQUERADE_opts[] = {
340e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	{.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
350e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
360e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	XTOPT_TABLEEND,
370e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy};
380e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
390e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy/* Parses ports */
400e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic void
410e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardyparse_ports(const char *arg, struct nf_nat_range *r)
420e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy{
430e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	char *end;
440e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	unsigned int port, maxport;
450e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
460e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	r->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
470e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
480e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX))
490e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
500e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
510e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	switch (*end) {
520e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	case '\0':
530e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		r->min_proto.tcp.port
540e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy			= r->max_proto.tcp.port
550e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy			= htons(port);
560e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		return;
570e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	case '-':
580e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX))
590e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy			break;
600e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
610e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		if (maxport < port)
620e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy			break;
630e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
640e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		r->min_proto.tcp.port = htons(port);
650e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		r->max_proto.tcp.port = htons(maxport);
660e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		return;
670e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	default:
680e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		break;
690e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	}
700e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
710e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy}
720e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
730e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic void MASQUERADE_parse(struct xt_option_call *cb)
740e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy{
750e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	const struct ip6t_entry *entry = cb->xt_entry;
760e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	struct nf_nat_range *r = cb->data;
770e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	int portok;
780e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
790e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	if (entry->ipv6.proto == IPPROTO_TCP ||
800e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	    entry->ipv6.proto == IPPROTO_UDP ||
810e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	    entry->ipv6.proto == IPPROTO_SCTP ||
820e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	    entry->ipv6.proto == IPPROTO_DCCP ||
830e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	    entry->ipv6.proto == IPPROTO_ICMP)
840e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		portok = 1;
850e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	else
860e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		portok = 0;
870e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
880e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	xtables_option_parse(cb);
890e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	switch (cb->entry->id) {
900e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	case O_TO_PORTS:
910e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		if (!portok)
920e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy			xtables_error(PARAMETER_PROBLEM,
930e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy				   "Need TCP, UDP, SCTP or DCCP with port specification");
940e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		parse_ports(cb->arg, r);
950e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		break;
960e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	case O_RANDOM:
970e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		r->flags |=  NF_NAT_RANGE_PROTO_RANDOM;
980e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		break;
990e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	}
1000e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy}
1010e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
1020e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic void
1030e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardyMASQUERADE_print(const void *ip, const struct xt_entry_target *target,
1040e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy                 int numeric)
1050e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy{
1060e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	const struct nf_nat_range *r = (const void *)target->data;
1070e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
1080e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
1090e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		printf(" masq ports: ");
1100e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		printf("%hu", ntohs(r->min_proto.tcp.port));
1110e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		if (r->max_proto.tcp.port != r->min_proto.tcp.port)
1120e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy			printf("-%hu", ntohs(r->max_proto.tcp.port));
1130e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	}
1140e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
1150e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
1160e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		printf(" random");
1170e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy}
1180e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
1190e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic void
1200e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardyMASQUERADE_save(const void *ip, const struct xt_entry_target *target)
1210e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy{
1220e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	const struct nf_nat_range *r = (const void *)target->data;
1230e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
1240e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
1250e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		printf(" --to-ports %hu", ntohs(r->min_proto.tcp.port));
1260e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		if (r->max_proto.tcp.port != r->min_proto.tcp.port)
1270e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy			printf("-%hu", ntohs(r->max_proto.tcp.port));
1280e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	}
1290e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
1300e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
1310e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy		printf(" --random");
1320e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy}
1330e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
1347a0992da44cfb6cab0ccd1beadcf326df8773552Pablo Neira Ayusostatic int MASQUERADE_xlate(struct xt_xlate *xl,
1357a0992da44cfb6cab0ccd1beadcf326df8773552Pablo Neira Ayuso			    const struct xt_xlate_tg_params *params)
136c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj{
1377a0992da44cfb6cab0ccd1beadcf326df8773552Pablo Neira Ayuso	const struct nf_nat_range *r = (const void *)params->target->data;
138c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj
139c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj	xt_xlate_add(xl, "masquerade");
140c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj
141c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj	if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
142c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj		xt_xlate_add(xl, " to :%hu", ntohs(r->min_proto.tcp.port));
143c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj		if (r->max_proto.tcp.port != r->min_proto.tcp.port)
144c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj			xt_xlate_add(xl, "-%hu", ntohs(r->max_proto.tcp.port));
145c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj	}
146c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj
147c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj	xt_xlate_add(xl, " ");
148c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj	if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
149c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj		xt_xlate_add(xl, "random ");
150c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj
151c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj	return 1;
152c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj}
153c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj
1540e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardystatic struct xtables_target masquerade_tg_reg = {
1550e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	.name		= "MASQUERADE",
1560e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	.version	= XTABLES_VERSION,
1570e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	.family		= NFPROTO_IPV6,
1580e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	.size		= XT_ALIGN(sizeof(struct nf_nat_range)),
1590e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_range)),
1600e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	.help		= MASQUERADE_help,
1610e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	.x6_parse	= MASQUERADE_parse,
1620e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	.print		= MASQUERADE_print,
1630e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	.save		= MASQUERADE_save,
1640e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	.x6_options	= MASQUERADE_opts,
165c656680dc907cf624f1c9647bc33ec0a5d5baf5bShivani Bhardwaj	.xlate		= MASQUERADE_xlate,
1660e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy};
1670e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy
1680e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardyvoid _init(void)
1690e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy{
1700e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy	xtables_register_target(&masquerade_tg_reg);
1710e37f00980eb6b4fc2c5f979cc5fa83c0fff9d30Patrick McHardy}
172