libipt_REDIRECT.c revision 59ccf53b9414d998afd6169cb2d6ba0f3c249081
1/* Shared library add-on to iptables to add redirect support. */ 2#include <stdio.h> 3#include <netdb.h> 4#include <string.h> 5#include <stdlib.h> 6#include <getopt.h> 7#include <xtables.h> 8#include <limits.h> /* INT_MAX in ip_tables.h */ 9#include <linux/netfilter_ipv4/ip_tables.h> 10#include <net/netfilter/nf_nat.h> 11 12#define IPT_REDIRECT_OPT_DEST 0x01 13#define IPT_REDIRECT_OPT_RANDOM 0x02 14 15static void REDIRECT_help(void) 16{ 17 printf( 18"REDIRECT target options:\n" 19" --to-ports <port>[-<port>]\n" 20" Port (range) to map to.\n" 21" [--random]\n"); 22} 23 24static const struct option REDIRECT_opts[] = { 25 { "to-ports", 1, NULL, '1' }, 26 { "random", 0, NULL, '2' }, 27 { .name = NULL } 28}; 29 30static void REDIRECT_init(struct xt_entry_target *t) 31{ 32 struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data; 33 34 /* Actually, it's 0, but it's ignored at the moment. */ 35 mr->rangesize = 1; 36 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 int REDIRECT_parse(int c, char **argv, int invert, unsigned int *flags, 76 const void *e, struct xt_entry_target **target) 77{ 78 const struct ipt_entry *entry = e; 79 struct nf_nat_multi_range *mr 80 = (struct nf_nat_multi_range *)(*target)->data; 81 int portok; 82 83 if (entry->ip.proto == IPPROTO_TCP 84 || entry->ip.proto == IPPROTO_UDP 85 || entry->ip.proto == IPPROTO_SCTP 86 || entry->ip.proto == IPPROTO_DCCP 87 || entry->ip.proto == IPPROTO_ICMP) 88 portok = 1; 89 else 90 portok = 0; 91 92 switch (c) { 93 case '1': 94 if (!portok) 95 xtables_error(PARAMETER_PROBLEM, 96 "Need TCP, UDP, SCTP or DCCP with port specification"); 97 98 if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) 99 xtables_error(PARAMETER_PROBLEM, 100 "Unexpected `!' after --to-ports"); 101 102 parse_ports(optarg, mr); 103 if (*flags & IPT_REDIRECT_OPT_RANDOM) 104 mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; 105 *flags |= IPT_REDIRECT_OPT_DEST; 106 return 1; 107 108 case '2': 109 if (*flags & IPT_REDIRECT_OPT_DEST) { 110 mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; 111 *flags |= IPT_REDIRECT_OPT_RANDOM; 112 } else 113 *flags |= IPT_REDIRECT_OPT_RANDOM; 114 return 1; 115 116 default: 117 return 0; 118 } 119} 120 121static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, 122 int numeric) 123{ 124 const struct nf_nat_multi_range *mr = (const void *)target->data; 125 const struct nf_nat_range *r = &mr->range[0]; 126 127 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { 128 printf("redir ports "); 129 printf("%hu", ntohs(r->min.tcp.port)); 130 if (r->max.tcp.port != r->min.tcp.port) 131 printf("-%hu", ntohs(r->max.tcp.port)); 132 printf(" "); 133 if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) 134 printf("random "); 135 } 136} 137 138static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) 139{ 140 const struct nf_nat_multi_range *mr = (const void *)target->data; 141 const struct nf_nat_range *r = &mr->range[0]; 142 143 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { 144 printf("--to-ports "); 145 printf("%hu", ntohs(r->min.tcp.port)); 146 if (r->max.tcp.port != r->min.tcp.port) 147 printf("-%hu", ntohs(r->max.tcp.port)); 148 printf(" "); 149 if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) 150 printf("--random "); 151 } 152} 153 154static struct xtables_target redirect_tg_reg = { 155 .name = "REDIRECT", 156 .version = XTABLES_VERSION, 157 .family = NFPROTO_IPV4, 158 .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 159 .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 160 .help = REDIRECT_help, 161 .init = REDIRECT_init, 162 .parse = REDIRECT_parse, 163 .print = REDIRECT_print, 164 .save = REDIRECT_save, 165 .extra_opts = REDIRECT_opts, 166}; 167 168void _init(void) 169{ 170 xtables_register_target(&redirect_tg_reg); 171} 172