libipt_REDIRECT.c revision 69f564e3890976461de0016cd81171ff8bfa8353
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Shared library add-on to iptables to add redirect support. */ 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netdb.h> 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <getopt.h> 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <xtables.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits.h> /* INT_MAX in ip_tables.h */ 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <linux/netfilter_ipv4/ip_tables.h> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <net/netfilter/nf_nat.h> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define IPT_REDIRECT_OPT_DEST 0x01 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define IPT_REDIRECT_OPT_RANDOM 0x02 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void REDIRECT_help(void) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf( 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"REDIRECT target options:\n" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)" --to-ports <port>[-<port>]\n" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)" Port (range) to map to.\n"); 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const struct option REDIRECT_opts[] = { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "to-ports", 1, NULL, '1' }, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "random", 0, NULL, '2' }, 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { .name = NULL } 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void REDIRECT_init(struct xt_entry_target *t) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Actually, it's 0, but it's ignored at the moment. */ 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mr->rangesize = 1; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/* Parses ports */ 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)parse_ports(const char *arg, struct nf_nat_multi_range *mr) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *dash; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int port; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (strchr(arg, '.')) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xtables_error(PARAMETER_PROBLEM, "IP address not permitted\n"); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = atoi(arg); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (port == 0) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = xtables_service_to_port(arg, NULL); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (port == 0 || port > 65535) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xtables_error(PARAMETER_PROBLEM, "Port \"%s\" not valid\n", arg); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dash = strchr(arg, '-'); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!dash) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mr->range[0].min.tcp.port 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) = mr->range[0].max.tcp.port 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) = htons(port); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int maxport; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) maxport = atoi(dash + 1); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (maxport == 0 || maxport > 65535) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xtables_error(PARAMETER_PROBLEM, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Port `%s' not valid\n", dash+1); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (maxport < port) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* People are stupid. */ 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xtables_error(PARAMETER_PROBLEM, 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Port range `%s' funky\n", arg); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mr->range[0].min.tcp.port = htons(port); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mr->range[0].max.tcp.port = htons(maxport); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int REDIRECT_parse(int c, char **argv, int invert, unsigned int *flags, 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void *e, struct xt_entry_target **target) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const struct ipt_entry *entry = e; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct nf_nat_multi_range *mr 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) = (struct nf_nat_multi_range *)(*target)->data; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int portok; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry->ip.proto == IPPROTO_TCP 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) || entry->ip.proto == IPPROTO_UDP 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci || entry->ip.proto == IPPROTO_SCTP 891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci || entry->ip.proto == IPPROTO_DCCP 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci || entry->ip.proto == IPPROTO_ICMP) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) portok = 1; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) portok = 0; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (c) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case '1': 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!portok) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xtables_error(PARAMETER_PROBLEM, 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Need TCP, UDP, SCTP or DCCP with port specification"); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (xtables_check_inverse(optarg, &invert, NULL, 0)) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xtables_error(PARAMETER_PROBLEM, 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Unexpected `!' after --to-ports"); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_ports(optarg, mr); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*flags & IPT_REDIRECT_OPT_RANDOM) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *flags |= IPT_REDIRECT_OPT_DEST; 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return 1; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case '2': 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*flags & IPT_REDIRECT_OPT_DEST) { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *flags |= IPT_REDIRECT_OPT_RANDOM; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *flags |= IPT_REDIRECT_OPT_RANDOM; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int numeric) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const struct nf_nat_multi_range *mr = (const void *)target->data; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const struct nf_nat_range *r = &mr->range[0]; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("redir ports "); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("%hu", ntohs(r->min.tcp.port)); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (r->max.tcp.port != r->min.tcp.port) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("-%hu", ntohs(r->max.tcp.port)); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf(" "); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("random "); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const struct nf_nat_multi_range *mr = (const void *)target->data; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const struct nf_nat_range *r = &mr->range[0]; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("--to-ports "); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("%hu", ntohs(r->min.tcp.port)); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (r->max.tcp.port != r->min.tcp.port) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("-%hu", ntohs(r->max.tcp.port)); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf(" "); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("--random "); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic struct xtables_target redirect_tg_reg = { 1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci .name = "REDIRECT", 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) .version = XTABLES_VERSION, 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) .family = NFPROTO_IPV4, 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) .help = REDIRECT_help, 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) .init = REDIRECT_init, 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) .parse = REDIRECT_parse, 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) .print = REDIRECT_print, 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) .save = REDIRECT_save, 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) .extra_opts = REDIRECT_opts, 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void _init(void) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xtables_register_target(&redirect_tg_reg); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci