libipt_REDIRECT.c revision ae06c6dc6d68d11ed15d4c6c47b7b7a709d3c9cb
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 9enum { 10 O_TO_PORTS = 0, 11 O_RANDOM, 12 F_TO_PORTS = 1 << O_TO_PORTS, 13 F_RANDOM = 1 << O_RANDOM, 14}; 15 16static 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 25static 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 31static 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 */ 40static void 41parse_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 75static 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 107static 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 123static 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 138static 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 152void _init(void) 153{ 154 xtables_register_target(&redirect_tg_reg); 155} 156