Home | History | Annotate | Download | only in extensions
      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 
     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 
     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
     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 
     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
    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
    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 
    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 
    174 void _init(void)
    175 {
    176 	xtables_register_target(&masquerade_tg_reg);
    177 }
    178