1 /* 2 * Copyright (c) 2011 Patrick McHardy <kaber (at) trash.net> 3 * 4 * Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6 NAT 5 * funded by Astaro. 6 */ 7 8 #include <stdio.h> 9 #include <string.h> 10 #include <stdlib.h> 11 #include <xtables.h> 12 #include <limits.h> /* INT_MAX in ip_tables.h */ 13 #include <linux/netfilter_ipv6/ip6_tables.h> 14 #include <linux/netfilter/nf_nat.h> 15 16 enum { 17 O_TO_PORTS = 0, 18 O_RANDOM, 19 F_TO_PORTS = 1 << O_TO_PORTS, 20 F_RANDOM = 1 << O_RANDOM, 21 }; 22 23 static void REDIRECT_help(void) 24 { 25 printf( 26 "REDIRECT target options:\n" 27 " --to-ports <port>[-<port>]\n" 28 " Port (range) to map to.\n" 29 " [--random]\n"); 30 } 31 32 static const struct xt_option_entry REDIRECT_opts[] = { 33 {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, 34 {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, 35 XTOPT_TABLEEND, 36 }; 37 38 /* Parses ports */ 39 static void 40 parse_ports(const char *arg, struct nf_nat_range *range) 41 { 42 char *end = ""; 43 unsigned int port, maxport; 44 45 range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 46 47 if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) && 48 (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1) 49 xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); 50 51 switch (*end) { 52 case '\0': 53 range->min_proto.tcp.port 54 = range->max_proto.tcp.port 55 = htons(port); 56 return; 57 case '-': 58 if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) && 59 (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1) 60 break; 61 62 if (maxport < port) 63 break; 64 65 range->min_proto.tcp.port = htons(port); 66 range->max_proto.tcp.port = htons(maxport); 67 return; 68 default: 69 break; 70 } 71 xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); 72 } 73 74 static void REDIRECT_parse(struct xt_option_call *cb) 75 { 76 const struct ip6t_entry *entry = cb->xt_entry; 77 struct nf_nat_range *range = (void *)(*cb->target)->data; 78 int portok; 79 80 if (entry->ipv6.proto == IPPROTO_TCP 81 || entry->ipv6.proto == IPPROTO_UDP 82 || entry->ipv6.proto == IPPROTO_SCTP 83 || entry->ipv6.proto == IPPROTO_DCCP 84 || entry->ipv6.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, range); 96 if (cb->xflags & F_RANDOM) 97 range->flags |= NF_NAT_RANGE_PROTO_RANDOM; 98 break; 99 case O_RANDOM: 100 if (cb->xflags & F_TO_PORTS) 101 range->flags |= NF_NAT_RANGE_PROTO_RANDOM; 102 break; 103 } 104 } 105 106 static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, 107 int numeric) 108 { 109 const struct nf_nat_range *range = (const void *)target->data; 110 111 if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { 112 printf(" redir ports "); 113 printf("%hu", ntohs(range->min_proto.tcp.port)); 114 if (range->max_proto.tcp.port != range->min_proto.tcp.port) 115 printf("-%hu", ntohs(range->max_proto.tcp.port)); 116 if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) 117 printf(" random"); 118 } 119 } 120 121 static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) 122 { 123 const struct nf_nat_range *range = (const void *)target->data; 124 125 if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { 126 printf(" --to-ports "); 127 printf("%hu", ntohs(range->min_proto.tcp.port)); 128 if (range->max_proto.tcp.port != range->min_proto.tcp.port) 129 printf("-%hu", ntohs(range->max_proto.tcp.port)); 130 if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) 131 printf(" --random"); 132 } 133 } 134 135 static struct xtables_target redirect_tg_reg = { 136 .name = "REDIRECT", 137 .version = XTABLES_VERSION, 138 .family = NFPROTO_IPV6, 139 .size = XT_ALIGN(sizeof(struct nf_nat_range)), 140 .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), 141 .help = REDIRECT_help, 142 .x6_parse = REDIRECT_parse, 143 .print = REDIRECT_print, 144 .save = REDIRECT_save, 145 .x6_options = REDIRECT_opts, 146 }; 147 148 void _init(void) 149 { 150 xtables_register_target(&redirect_tg_reg); 151 } 152