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