1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <xtables.h> 5 #include <limits.h> /* INT_MAX in ip_tables.h */ 6 #include <linux/netfilter_ipv4/ip_tables.h> 7 #include <net/netfilter/nf_nat.h> 8 9 enum { 10 O_TO_PORTS = 0, 11 O_RANDOM, 12 F_TO_PORTS = 1 << O_TO_PORTS, 13 F_RANDOM = 1 << O_RANDOM, 14 }; 15 16 static void REDIRECT_help(void) 17 { 18 printf( 19 "REDIRECT target options:\n" 20 " --to-ports <port>[-<port>]\n" 21 " Port (range) to map to.\n" 22 " [--random]\n"); 23 } 24 25 static const struct xt_option_entry REDIRECT_opts[] = { 26 {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, 27 {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, 28 XTOPT_TABLEEND, 29 }; 30 31 static void REDIRECT_init(struct xt_entry_target *t) 32 { 33 struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data; 34 35 /* Actually, it's 0, but it's ignored at the moment. */ 36 mr->rangesize = 1; 37 } 38 39 /* Parses ports */ 40 static void 41 parse_ports(const char *arg, struct nf_nat_multi_range *mr) 42 { 43 char *end = ""; 44 unsigned int port, maxport; 45 46 mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; 47 48 if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) && 49 (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1) 50 xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); 51 52 switch (*end) { 53 case '\0': 54 mr->range[0].min.tcp.port 55 = mr->range[0].max.tcp.port 56 = htons(port); 57 return; 58 case '-': 59 if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) && 60 (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1) 61 break; 62 63 if (maxport < port) 64 break; 65 66 mr->range[0].min.tcp.port = htons(port); 67 mr->range[0].max.tcp.port = htons(maxport); 68 return; 69 default: 70 break; 71 } 72 xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); 73 } 74 75 static void REDIRECT_parse(struct xt_option_call *cb) 76 { 77 const struct ipt_entry *entry = cb->xt_entry; 78 struct nf_nat_multi_range *mr = (void *)(*cb->target)->data; 79 int portok; 80 81 if (entry->ip.proto == IPPROTO_TCP 82 || entry->ip.proto == IPPROTO_UDP 83 || entry->ip.proto == IPPROTO_SCTP 84 || entry->ip.proto == IPPROTO_DCCP 85 || entry->ip.proto == IPPROTO_ICMP) 86 portok = 1; 87 else 88 portok = 0; 89 90 xtables_option_parse(cb); 91 switch (cb->entry->id) { 92 case O_TO_PORTS: 93 if (!portok) 94 xtables_error(PARAMETER_PROBLEM, 95 "Need TCP, UDP, SCTP or DCCP with port specification"); 96 parse_ports(cb->arg, mr); 97 if (cb->xflags & F_RANDOM) 98 mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; 99 break; 100 case O_RANDOM: 101 if (cb->xflags & F_TO_PORTS) 102 mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; 103 break; 104 } 105 } 106 107 static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, 108 int numeric) 109 { 110 const struct nf_nat_multi_range *mr = (const void *)target->data; 111 const struct nf_nat_range *r = &mr->range[0]; 112 113 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { 114 printf(" redir ports "); 115 printf("%hu", ntohs(r->min.tcp.port)); 116 if (r->max.tcp.port != r->min.tcp.port) 117 printf("-%hu", ntohs(r->max.tcp.port)); 118 if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) 119 printf(" random"); 120 } 121 } 122 123 static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) 124 { 125 const struct nf_nat_multi_range *mr = (const void *)target->data; 126 const struct nf_nat_range *r = &mr->range[0]; 127 128 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { 129 printf(" --to-ports "); 130 printf("%hu", ntohs(r->min.tcp.port)); 131 if (r->max.tcp.port != r->min.tcp.port) 132 printf("-%hu", ntohs(r->max.tcp.port)); 133 if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) 134 printf(" --random"); 135 } 136 } 137 138 static struct xtables_target redirect_tg_reg = { 139 .name = "REDIRECT", 140 .version = XTABLES_VERSION, 141 .family = NFPROTO_IPV4, 142 .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 143 .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 144 .help = REDIRECT_help, 145 .init = REDIRECT_init, 146 .x6_parse = REDIRECT_parse, 147 .print = REDIRECT_print, 148 .save = REDIRECT_save, 149 .x6_options = REDIRECT_opts, 150 }; 151 152 void _init(void) 153 { 154 xtables_register_target(&redirect_tg_reg); 155 } 156