blob: 471ff29aa4f73e0f80f99996a3eec23f52f50a89 [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* Shared library add-on to iptables to add redirect support. */
Jan Engelhardt32b8e612010-07-23 21:16:14 +02002#include <stdbool.h>
Marc Bouchere6869a82000-03-20 06:03:29 +00003#include <stdio.h>
4#include <netdb.h>
5#include <string.h>
6#include <stdlib.h>
7#include <getopt.h>
Jan Engelhardt5d9678a2008-11-20 10:15:35 +01008#include <xtables.h>
Jan Engelhardt4e418542009-02-21 03:46:37 +01009#include <limits.h> /* INT_MAX in ip_tables.h */
Marc Bouchere6869a82000-03-20 06:03:29 +000010#include <linux/netfilter_ipv4/ip_tables.h>
Jan Engelhardt978e27e2009-02-21 04:42:32 +010011#include <net/netfilter/nf_nat.h>
Marc Bouchere6869a82000-03-20 06:03:29 +000012
Patrick McHardyef399a32007-05-29 11:24:45 +000013#define IPT_REDIRECT_OPT_DEST 0x01
14#define IPT_REDIRECT_OPT_RANDOM 0x02
15
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 Engelhardt1d5b63d2007-10-04 16:29:00 +000025static const struct option REDIRECT_opts[] = {
Jan Engelhardt32b8e612010-07-23 21:16:14 +020026 {.name = "to-ports", .has_arg = true, .val = '1'},
27 {.name = "random", .has_arg = false, .val = '2'},
28 XT_GETOPT_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;
37
Marc Bouchere6869a82000-03-20 06:03:29 +000038}
39
40/* Parses ports */
41static void
Jan Engelhardt978e27e2009-02-21 04:42:32 +010042parse_ports(const char *arg, struct nf_nat_multi_range *mr)
Marc Bouchere6869a82000-03-20 06:03:29 +000043{
Stephen Beahm63ef52a2010-12-09 06:15:50 -050044 char *end = "";
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020045 unsigned int port, maxport;
Marc Bouchere6869a82000-03-20 06:03:29 +000046
47 mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
48
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020049 if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) &&
50 (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1)
51 xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
Phil Oester3836fcc2006-06-20 13:45:38 +000052
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020053 switch (*end) {
54 case '\0':
Marc Bouchere6869a82000-03-20 06:03:29 +000055 mr->range[0].min.tcp.port
56 = mr->range[0].max.tcp.port
Rusty Russellf9b2e662000-04-19 11:24:02 +000057 = htons(port);
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020058 return;
59 case '-':
60 if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) &&
61 (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1)
62 break;
Marc Bouchere6869a82000-03-20 06:03:29 +000063
Marc Bouchere6869a82000-03-20 06:03:29 +000064 if (maxport < port)
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020065 break;
66
Rusty Russellf9b2e662000-04-19 11:24:02 +000067 mr->range[0].min.tcp.port = htons(port);
68 mr->range[0].max.tcp.port = htons(maxport);
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020069 return;
70 default:
71 break;
Marc Bouchere6869a82000-03-20 06:03:29 +000072 }
Dmitry V. Levin84d758b2010-05-14 13:24:51 +020073 xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
Marc Bouchere6869a82000-03-20 06:03:29 +000074}
75
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000076static int REDIRECT_parse(int c, char **argv, int invert, unsigned int *flags,
77 const void *e, struct xt_entry_target **target)
Marc Bouchere6869a82000-03-20 06:03:29 +000078{
Yasuyuki KOZAKAIac8b2712007-07-24 06:06:59 +000079 const struct ipt_entry *entry = e;
Jan Engelhardt978e27e2009-02-21 04:42:32 +010080 struct nf_nat_multi_range *mr
81 = (struct nf_nat_multi_range *)(*target)->data;
Marc Bouchere6869a82000-03-20 06:03:29 +000082 int portok;
83
84 if (entry->ip.proto == IPPROTO_TCP
Patrick McHardy36d870c2005-07-22 06:39:45 +000085 || entry->ip.proto == IPPROTO_UDP
Patrick McHardy5a942f92008-11-04 13:22:40 +010086 || entry->ip.proto == IPPROTO_SCTP
87 || entry->ip.proto == IPPROTO_DCCP
Patrick McHardy36d870c2005-07-22 06:39:45 +000088 || entry->ip.proto == IPPROTO_ICMP)
Marc Bouchere6869a82000-03-20 06:03:29 +000089 portok = 1;
90 else
91 portok = 0;
92
93 switch (c) {
94 case '1':
95 if (!portok)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010096 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy5a942f92008-11-04 13:22:40 +010097 "Need TCP, UDP, SCTP or DCCP with port specification");
Marc Bouchere6869a82000-03-20 06:03:29 +000098
Jan Engelhardtbf971282009-11-03 19:55:11 +010099 if (xtables_check_inverse(optarg, &invert, NULL, 0, argv))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100100 xtables_error(PARAMETER_PROBLEM,
Marc Bouchere6869a82000-03-20 06:03:29 +0000101 "Unexpected `!' after --to-ports");
102
103 parse_ports(optarg, mr);
Patrick McHardyef399a32007-05-29 11:24:45 +0000104 if (*flags & IPT_REDIRECT_OPT_RANDOM)
105 mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
106 *flags |= IPT_REDIRECT_OPT_DEST;
107 return 1;
108
109 case '2':
110 if (*flags & IPT_REDIRECT_OPT_DEST) {
111 mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
112 *flags |= IPT_REDIRECT_OPT_RANDOM;
113 } else
114 *flags |= IPT_REDIRECT_OPT_RANDOM;
Marc Bouchere6869a82000-03-20 06:03:29 +0000115 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +0000116 }
Jan Engelhardtd09b6d52011-01-08 03:02:37 +0100117 return 0;
Marc Bouchere6869a82000-03-20 06:03:29 +0000118}
119
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000120static void REDIRECT_print(const void *ip, const struct xt_entry_target *target,
121 int numeric)
Marc Bouchere6869a82000-03-20 06:03:29 +0000122{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200123 const struct nf_nat_multi_range *mr = (const void *)target->data;
124 const struct nf_nat_range *r = &mr->range[0];
Marc Bouchere6869a82000-03-20 06:03:29 +0000125
Marc Bouchere6869a82000-03-20 06:03:29 +0000126 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100127 printf(" redir ports ");
Rusty Russellf9b2e662000-04-19 11:24:02 +0000128 printf("%hu", ntohs(r->min.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000129 if (r->max.tcp.port != r->min.tcp.port)
Rusty Russellf9b2e662000-04-19 11:24:02 +0000130 printf("-%hu", ntohs(r->max.tcp.port));
Patrick McHardyef399a32007-05-29 11:24:45 +0000131 if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM)
Jan Engelhardt73866352010-12-18 02:04:59 +0100132 printf(" random");
Marc Bouchere6869a82000-03-20 06:03:29 +0000133 }
134}
135
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000136static void REDIRECT_save(const void *ip, const struct xt_entry_target *target)
Marc Bouchere6869a82000-03-20 06:03:29 +0000137{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200138 const struct nf_nat_multi_range *mr = (const void *)target->data;
139 const struct nf_nat_range *r = &mr->range[0];
Marc Bouchere6869a82000-03-20 06:03:29 +0000140
141 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100142 printf(" --to-ports ");
Rusty Russellf9b2e662000-04-19 11:24:02 +0000143 printf("%hu", ntohs(r->min.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000144 if (r->max.tcp.port != r->min.tcp.port)
Rusty Russellf9b2e662000-04-19 11:24:02 +0000145 printf("-%hu", ntohs(r->max.tcp.port));
Patrick McHardyef399a32007-05-29 11:24:45 +0000146 if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM)
Jan Engelhardt73866352010-12-18 02:04:59 +0100147 printf(" --random");
Marc Bouchere6869a82000-03-20 06:03:29 +0000148 }
149}
150
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200151static struct xtables_target redirect_tg_reg = {
Pablo Neira8caee8b2004-12-28 13:11:59 +0000152 .name = "REDIRECT",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200153 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100154 .family = NFPROTO_IPV4,
Jan Engelhardt978e27e2009-02-21 04:42:32 +0100155 .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)),
156 .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)),
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000157 .help = REDIRECT_help,
158 .init = REDIRECT_init,
159 .parse = REDIRECT_parse,
160 .print = REDIRECT_print,
161 .save = REDIRECT_save,
162 .extra_opts = REDIRECT_opts,
Marc Bouchere6869a82000-03-20 06:03:29 +0000163};
164
165void _init(void)
166{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200167 xtables_register_target(&redirect_tg_reg);
Marc Bouchere6869a82000-03-20 06:03:29 +0000168}