Home | History | Annotate | Download | only in extensions
      1 /*
      2  * Copyright (c) 2011 Patrick McHardy <kaber (at) 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 
     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
     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 
     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
    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
    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 
    147 void _init(void)
    148 {
    149 	xtables_register_target(&masquerade_tg_reg);
    150 }
    151