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 18enum { 19 O_TO_PORTS = 0, 20 O_RANDOM, 21}; 22 23static 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 33static 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 */ 40static void 41parse_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 73static 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 102static void 103MASQUERADE_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 119static void 120MASQUERADE_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 134static 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 147void _init(void) 148{ 149 xtables_register_target(&masquerade_tg_reg); 150} 151