blob: e67360a051e12588bda7c876bc511e4527cf2d60 [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001#include <stdio.h>
Marc Bouchere6869a82000-03-20 06:03:29 +00002#include <string.h>
3#include <stdlib.h>
Jan Engelhardt5d9678a2008-11-20 10:15:35 +01004#include <xtables.h>
Jan Engelhardt4e418542009-02-21 03:46:37 +01005#include <limits.h> /* INT_MAX in ip_tables.h */
Marc Bouchere6869a82000-03-20 06:03:29 +00006#include <linux/netfilter_ipv4/ip_tables.h>
Jan Engelhardt978e27e2009-02-21 04:42:32 +01007#include <net/netfilter/nf_nat.h>
Marc Bouchere6869a82000-03-20 06:03:29 +00008
Jan Engelhardtc0bba1a2011-05-09 01:10:30 +02009enum {
10 O_TO_PORTS = 0,
11 O_RANDOM,
12 F_TO_PORTS = 1 << O_TO_PORTS,
13 F_RANDOM = 1 << O_RANDOM,
14};
Patrick McHardyef399a32007-05-29 11:24:45 +000015
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000016static void REDIRECT_help(void)
Marc Bouchere6869a82000-03-20 06:03:29 +000017{
18 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020019"REDIRECT target options:\n"
Marc Bouchere6869a82000-03-20 06:03:29 +000020" --to-ports <port>[-<port>]\n"
Eric Dumazet59ccf532010-07-23 12:54:05 +020021" Port (range) to map to.\n"
22" [--random]\n");
Marc Bouchere6869a82000-03-20 06:03:29 +000023}
24
Jan Engelhardtc0bba1a2011-05-09 01:10:30 +020025static const struct xt_option_entry REDIRECT_opts[] = {
Lutz Jaenickeae06c6d2011-05-18 15:11:47 +020026 {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
Jan Engelhardtc0bba1a2011-05-09 01:10:30 +020027 {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
28 XTOPT_TABLEEND,
Marc Bouchere6869a82000-03-20 06:03:29 +000029};
30
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000031static void REDIRECT_init(struct xt_entry_target *t)
Marc Bouchere6869a82000-03-20 06:03:29 +000032{
Jan Engelhardt978e27e2009-02-21 04:42:32 +010033 struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data;
Marc Bouchere6869a82000-03-20 06:03:29 +000034
35 /* Actually, it's 0, but it's ignored at the moment. */
36 mr->rangesize = 1;
Marc Bouchere6869a82000-03-20 06:03:29 +000037}
38
39/* Parses ports */
40static void
Jan Engelhardt978e27e2009-02-21 04:42:32 +010041parse_ports(const char *arg, struct nf_nat_multi_range *mr)
Marc Bouchere6869a82000-03-20 06:03:29 +000042{
Stephen Beahm63ef52a2010-12-09 06:15:50 -050043 char *end = "";
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020044 unsigned int port, maxport;
Marc Bouchere6869a82000-03-20 06:03:29 +000045
46 mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
47
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020048 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);
Phil Oester3836fcc2006-06-20 13:45:38 +000051
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020052 switch (*end) {
53 case '\0':
Marc Bouchere6869a82000-03-20 06:03:29 +000054 mr->range[0].min.tcp.port
55 = mr->range[0].max.tcp.port
Rusty Russellf9b2e662000-04-19 11:24:02 +000056 = htons(port);
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020057 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;
Marc Bouchere6869a82000-03-20 06:03:29 +000062
Marc Bouchere6869a82000-03-20 06:03:29 +000063 if (maxport < port)
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020064 break;
65
Rusty Russellf9b2e662000-04-19 11:24:02 +000066 mr->range[0].min.tcp.port = htons(port);
67 mr->range[0].max.tcp.port = htons(maxport);
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020068 return;
69 default:
70 break;
Marc Bouchere6869a82000-03-20 06:03:29 +000071 }
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020072 xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
Marc Bouchere6869a82000-03-20 06:03:29 +000073}
74
Jan Engelhardtc0bba1a2011-05-09 01:10:30 +020075static void REDIRECT_parse(struct xt_option_call *cb)
Marc Bouchere6869a82000-03-20 06:03:29 +000076{
Jan Engelhardtc0bba1a2011-05-09 01:10:30 +020077 const struct ipt_entry *entry = cb->xt_entry;
78 struct nf_nat_multi_range *mr = (void *)(*cb->target)->data;
Marc Bouchere6869a82000-03-20 06:03:29 +000079 int portok;
80
81 if (entry->ip.proto == IPPROTO_TCP
Patrick McHardy36d870c2005-07-22 06:39:45 +000082 || entry->ip.proto == IPPROTO_UDP
Patrick McHardy5a942f92008-11-04 13:22:40 +010083 || entry->ip.proto == IPPROTO_SCTP
84 || entry->ip.proto == IPPROTO_DCCP
Patrick McHardy36d870c2005-07-22 06:39:45 +000085 || entry->ip.proto == IPPROTO_ICMP)
Marc Bouchere6869a82000-03-20 06:03:29 +000086 portok = 1;
87 else
88 portok = 0;
89
Jan Engelhardtc0bba1a2011-05-09 01:10:30 +020090 xtables_option_parse(cb);
91 switch (cb->entry->id) {
92 case O_TO_PORTS:
Marc Bouchere6869a82000-03-20 06:03:29 +000093 if (!portok)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010094 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy5a942f92008-11-04 13:22:40 +010095 "Need TCP, UDP, SCTP or DCCP with port specification");
Jan Engelhardtc0bba1a2011-05-09 01:10:30 +020096 parse_ports(cb->arg, mr);
97 if (cb->xflags & F_RANDOM)
Patrick McHardyef399a32007-05-29 11:24:45 +000098 mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
Jan Engelhardtc0bba1a2011-05-09 01:10:30 +020099 break;
100 case O_RANDOM:
101 if (cb->xflags & F_TO_PORTS)
Patrick McHardyef399a32007-05-29 11:24:45 +0000102 mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
Jan Engelhardtc0bba1a2011-05-09 01:10:30 +0200103 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000104 }
105}
106
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000107static void REDIRECT_print(const void *ip, const struct xt_entry_target *target,
108 int numeric)
Marc Bouchere6869a82000-03-20 06:03:29 +0000109{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200110 const struct nf_nat_multi_range *mr = (const void *)target->data;
111 const struct nf_nat_range *r = &mr->range[0];
Marc Bouchere6869a82000-03-20 06:03:29 +0000112
Marc Bouchere6869a82000-03-20 06:03:29 +0000113 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100114 printf(" redir ports ");
Rusty Russellf9b2e662000-04-19 11:24:02 +0000115 printf("%hu", ntohs(r->min.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000116 if (r->max.tcp.port != r->min.tcp.port)
Rusty Russellf9b2e662000-04-19 11:24:02 +0000117 printf("-%hu", ntohs(r->max.tcp.port));
Patrick McHardyef399a32007-05-29 11:24:45 +0000118 if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM)
Jan Engelhardt73866352010-12-18 02:04:59 +0100119 printf(" random");
Marc Bouchere6869a82000-03-20 06:03:29 +0000120 }
121}
122
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000123static void REDIRECT_save(const void *ip, const struct xt_entry_target *target)
Marc Bouchere6869a82000-03-20 06:03:29 +0000124{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200125 const struct nf_nat_multi_range *mr = (const void *)target->data;
126 const struct nf_nat_range *r = &mr->range[0];
Marc Bouchere6869a82000-03-20 06:03:29 +0000127
128 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100129 printf(" --to-ports ");
Rusty Russellf9b2e662000-04-19 11:24:02 +0000130 printf("%hu", ntohs(r->min.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000131 if (r->max.tcp.port != r->min.tcp.port)
Rusty Russellf9b2e662000-04-19 11:24:02 +0000132 printf("-%hu", ntohs(r->max.tcp.port));
Patrick McHardyef399a32007-05-29 11:24:45 +0000133 if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM)
Jan Engelhardt73866352010-12-18 02:04:59 +0100134 printf(" --random");
Marc Bouchere6869a82000-03-20 06:03:29 +0000135 }
136}
137
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200138static struct xtables_target redirect_tg_reg = {
Pablo Neira8caee8b2004-12-28 13:11:59 +0000139 .name = "REDIRECT",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200140 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100141 .family = NFPROTO_IPV4,
Jan Engelhardt978e27e2009-02-21 04:42:32 +0100142 .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)),
143 .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)),
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000144 .help = REDIRECT_help,
145 .init = REDIRECT_init,
Jan Engelhardtc0bba1a2011-05-09 01:10:30 +0200146 .x6_parse = REDIRECT_parse,
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000147 .print = REDIRECT_print,
148 .save = REDIRECT_save,
Jan Engelhardtc0bba1a2011-05-09 01:10:30 +0200149 .x6_options = REDIRECT_opts,
Marc Bouchere6869a82000-03-20 06:03:29 +0000150};
151
152void _init(void)
153{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200154 xtables_register_target(&redirect_tg_reg);
Marc Bouchere6869a82000-03-20 06:03:29 +0000155}