15eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy/* 25eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> 35eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy * 45eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy * Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6 NAT 55eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy * funded by Astaro. 65eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy */ 75eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 85eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy#include <stdio.h> 95eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy#include <string.h> 105eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy#include <stdlib.h> 115eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy#include <xtables.h> 125eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy#include <limits.h> /* INT_MAX in ip_tables.h */ 135eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy#include <linux/netfilter_ipv6/ip6_tables.h> 145eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy#include <linux/netfilter/nf_nat.h> 155eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 165eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardyenum { 175eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy O_TO_PORTS = 0, 185eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy O_RANDOM, 195eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy F_TO_PORTS = 1 << O_TO_PORTS, 205eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy F_RANDOM = 1 << O_RANDOM, 215eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy}; 225eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 235eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardystatic void REDIRECT_help(void) 245eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy{ 255eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy printf( 265eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy"REDIRECT target options:\n" 275eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy" --to-ports <port>[-<port>]\n" 285eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy" Port (range) to map to.\n" 295eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy" [--random]\n"); 305eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy} 315eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 325eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardystatic const struct xt_option_entry REDIRECT_opts[] = { 335eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, 345eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, 355eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy XTOPT_TABLEEND, 365eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy}; 375eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 385eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy/* Parses ports */ 395eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardystatic void 405eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardyparse_ports(const char *arg, struct nf_nat_range *range) 415eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy{ 425eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy char *end = ""; 435eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy unsigned int port, maxport; 445eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 455eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 465eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 475eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) && 485eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1) 495eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); 505eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 515eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy switch (*end) { 525eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy case '\0': 535eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy range->min_proto.tcp.port 545eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy = range->max_proto.tcp.port 555eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy = htons(port); 565eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy return; 575eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy case '-': 585eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) && 595eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1) 605eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy break; 615eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 625eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy if (maxport < port) 635eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy break; 645eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 655eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy range->min_proto.tcp.port = htons(port); 665eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy range->max_proto.tcp.port = htons(maxport); 675eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy return; 685eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy default: 695eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy break; 705eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy } 715eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); 725eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy} 735eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 745eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardystatic void REDIRECT_parse(struct xt_option_call *cb) 755eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy{ 765eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy const struct ip6t_entry *entry = cb->xt_entry; 775eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy struct nf_nat_range *range = (void *)(*cb->target)->data; 785eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy int portok; 795eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 805eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy if (entry->ipv6.proto == IPPROTO_TCP 815eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy || entry->ipv6.proto == IPPROTO_UDP 825eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy || entry->ipv6.proto == IPPROTO_SCTP 835eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy || entry->ipv6.proto == IPPROTO_DCCP 845eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy || entry->ipv6.proto == IPPROTO_ICMP) 855eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy portok = 1; 865eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy else 875eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy portok = 0; 885eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 895eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy xtables_option_parse(cb); 905eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy switch (cb->entry->id) { 915eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy case O_TO_PORTS: 925eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy if (!portok) 935eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy xtables_error(PARAMETER_PROBLEM, 945eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy "Need TCP, UDP, SCTP or DCCP with port specification"); 955eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy parse_ports(cb->arg, range); 965eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy if (cb->xflags & F_RANDOM) 975eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy range->flags |= NF_NAT_RANGE_PROTO_RANDOM; 985eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy break; 995eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy case O_RANDOM: 1005eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy if (cb->xflags & F_TO_PORTS) 1015eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy range->flags |= NF_NAT_RANGE_PROTO_RANDOM; 1025eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy break; 1035eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy } 1045eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy} 1055eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 1065eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardystatic void REDIRECT_print(const void *ip, const struct xt_entry_target *target, 1075eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy int numeric) 1085eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy{ 1095eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy const struct nf_nat_range *range = (const void *)target->data; 1105eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 1115eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { 1125eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy printf(" redir ports "); 1135eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy printf("%hu", ntohs(range->min_proto.tcp.port)); 1145eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy if (range->max_proto.tcp.port != range->min_proto.tcp.port) 1155eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy printf("-%hu", ntohs(range->max_proto.tcp.port)); 1165eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) 1175eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy printf(" random"); 1185eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy } 1195eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy} 1205eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 1215eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardystatic void REDIRECT_save(const void *ip, const struct xt_entry_target *target) 1225eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy{ 1235eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy const struct nf_nat_range *range = (const void *)target->data; 1245eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 1255eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { 1265eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy printf(" --to-ports "); 1275eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy printf("%hu", ntohs(range->min_proto.tcp.port)); 1285eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy if (range->max_proto.tcp.port != range->min_proto.tcp.port) 1295eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy printf("-%hu", ntohs(range->max_proto.tcp.port)); 1305eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) 1315eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy printf(" --random"); 1325eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy } 1335eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy} 1345eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 1355eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardystatic struct xtables_target redirect_tg_reg = { 1365eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy .name = "REDIRECT", 1375eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy .version = XTABLES_VERSION, 1385eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy .family = NFPROTO_IPV6, 1395eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy .size = XT_ALIGN(sizeof(struct nf_nat_range)), 1405eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), 1415eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy .help = REDIRECT_help, 1425eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy .x6_parse = REDIRECT_parse, 1435eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy .print = REDIRECT_print, 1445eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy .save = REDIRECT_save, 1455eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy .x6_options = REDIRECT_opts, 1465eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy}; 1475eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy 1485eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardyvoid _init(void) 1495eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy{ 1505eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy xtables_register_target(&redirect_tg_reg); 1515eca41982d29bc25b241692d03b09b953e7a908aPatrick McHardy} 152