blob: 6b387169ead44f163e73ce0c7416cbb4c5dd057f [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* 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 <iptables.h>
8#include <linux/netfilter_ipv4/ip_tables.h>
Patrick McHardy40d54752007-04-18 07:00:36 +00009#include <linux/netfilter/nf_nat.h>
Marc Bouchere6869a82000-03-20 06:03:29 +000010
Patrick McHardyef399a32007-05-29 11:24:45 +000011#define IPT_REDIRECT_OPT_DEST 0x01
12#define IPT_REDIRECT_OPT_RANDOM 0x02
13
Marc Bouchere6869a82000-03-20 06:03:29 +000014/* Function which prints out usage message. */
15static void
16help(void)
17{
18 printf(
19"REDIRECT v%s options:\n"
20" --to-ports <port>[-<port>]\n"
21" Port (range) to map to.\n\n",
Harald Welte80fe35d2002-05-29 13:08:15 +000022IPTABLES_VERSION);
Marc Bouchere6869a82000-03-20 06:03:29 +000023}
24
25static struct option opts[] = {
26 { "to-ports", 1, 0, '1' },
Patrick McHardyef399a32007-05-29 11:24:45 +000027 { "random", 1, 0, '2' },
Marc Bouchere6869a82000-03-20 06:03:29 +000028 { 0 }
29};
30
31/* Initialize the target. */
32static void
33init(struct ipt_entry_target *t, unsigned int *nfcache)
34{
35 struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data;
36
37 /* Actually, it's 0, but it's ignored at the moment. */
38 mr->rangesize = 1;
39
Marc Bouchere6869a82000-03-20 06:03:29 +000040}
41
42/* Parses ports */
43static void
44parse_ports(const char *arg, struct ip_nat_multi_range *mr)
45{
46 const char *dash;
47 int port;
48
49 mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
50
Phil Oester3836fcc2006-06-20 13:45:38 +000051 if (strchr(arg, '.'))
52 exit_error(PARAMETER_PROBLEM, "IP address not permitted\n");
53
Marc Bouchere6869a82000-03-20 06:03:29 +000054 port = atoi(arg);
55 if (port == 0 || port > 65535)
56 exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", arg);
57
58 dash = strchr(arg, '-');
59 if (!dash) {
60 mr->range[0].min.tcp.port
61 = mr->range[0].max.tcp.port
Rusty Russellf9b2e662000-04-19 11:24:02 +000062 = htons(port);
Marc Bouchere6869a82000-03-20 06:03:29 +000063 } else {
64 int maxport;
65
66 maxport = atoi(dash + 1);
67 if (maxport == 0 || maxport > 65535)
68 exit_error(PARAMETER_PROBLEM,
69 "Port `%s' not valid\n", dash+1);
70 if (maxport < port)
71 /* People are stupid. */
72 exit_error(PARAMETER_PROBLEM,
73 "Port range `%s' funky\n", arg);
Rusty Russellf9b2e662000-04-19 11:24:02 +000074 mr->range[0].min.tcp.port = htons(port);
75 mr->range[0].max.tcp.port = htons(maxport);
Marc Bouchere6869a82000-03-20 06:03:29 +000076 }
77}
78
79/* Function which parses command options; returns true if it
80 ate an option */
81static int
82parse(int c, char **argv, int invert, unsigned int *flags,
83 const struct ipt_entry *entry,
84 struct ipt_entry_target **target)
85{
86 struct ip_nat_multi_range *mr
87 = (struct ip_nat_multi_range *)(*target)->data;
88 int portok;
89
90 if (entry->ip.proto == IPPROTO_TCP
Patrick McHardy36d870c2005-07-22 06:39:45 +000091 || entry->ip.proto == IPPROTO_UDP
92 || entry->ip.proto == IPPROTO_ICMP)
Marc Bouchere6869a82000-03-20 06:03:29 +000093 portok = 1;
94 else
95 portok = 0;
96
97 switch (c) {
98 case '1':
99 if (!portok)
100 exit_error(PARAMETER_PROBLEM,
101 "Need TCP or UDP with port specification");
102
Harald Welteb77f1da2002-03-14 11:35:58 +0000103 if (check_inverse(optarg, &invert, NULL, 0))
Marc Bouchere6869a82000-03-20 06:03:29 +0000104 exit_error(PARAMETER_PROBLEM,
105 "Unexpected `!' after --to-ports");
106
107 parse_ports(optarg, mr);
Patrick McHardyef399a32007-05-29 11:24:45 +0000108 if (*flags & IPT_REDIRECT_OPT_RANDOM)
109 mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
110 *flags |= IPT_REDIRECT_OPT_DEST;
111 return 1;
112
113 case '2':
114 if (*flags & IPT_REDIRECT_OPT_DEST) {
115 mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
116 *flags |= IPT_REDIRECT_OPT_RANDOM;
117 } else
118 *flags |= IPT_REDIRECT_OPT_RANDOM;
Marc Bouchere6869a82000-03-20 06:03:29 +0000119 return 1;
120
121 default:
122 return 0;
123 }
124}
125
126/* Final check; don't care. */
127static void final_check(unsigned int flags)
128{
129}
130
131/* Prints out the targinfo. */
132static void
133print(const struct ipt_ip *ip,
134 const struct ipt_entry_target *target,
135 int numeric)
136{
137 struct ip_nat_multi_range *mr
138 = (struct ip_nat_multi_range *)target->data;
139 struct ip_nat_range *r = &mr->range[0];
140
Marc Bouchere6869a82000-03-20 06:03:29 +0000141 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
Rusty Russell849779c2000-04-23 15:51:51 +0000142 printf("redir 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));
Marc Bouchere6869a82000-03-20 06:03:29 +0000146 printf(" ");
Patrick McHardyef399a32007-05-29 11:24:45 +0000147 if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM)
148 printf("random ");
Marc Bouchere6869a82000-03-20 06:03:29 +0000149 }
150}
151
152/* Saves the union ipt_targinfo in parsable form to stdout. */
153static void
154save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
155{
156 struct ip_nat_multi_range *mr
157 = (struct ip_nat_multi_range *)target->data;
158 struct ip_nat_range *r = &mr->range[0];
159
160 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
Harald Welte963bdcc2001-03-16 20:37:10 +0000161 printf("--to-ports ");
Rusty Russellf9b2e662000-04-19 11:24:02 +0000162 printf("%hu", ntohs(r->min.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000163 if (r->max.tcp.port != r->min.tcp.port)
Rusty Russellf9b2e662000-04-19 11:24:02 +0000164 printf("-%hu", ntohs(r->max.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000165 printf(" ");
Patrick McHardyef399a32007-05-29 11:24:45 +0000166 if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM)
167 printf("--random ");
Marc Bouchere6869a82000-03-20 06:03:29 +0000168 }
169}
170
Pablo Neira8caee8b2004-12-28 13:11:59 +0000171static struct iptables_target redir = {
172 .next = NULL,
173 .name = "REDIRECT",
174 .version = IPTABLES_VERSION,
175 .size = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
176 .userspacesize = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
177 .help = &help,
178 .init = &init,
179 .parse = &parse,
180 .final_check = &final_check,
181 .print = &print,
182 .save = &save,
183 .extra_opts = opts
Marc Bouchere6869a82000-03-20 06:03:29 +0000184};
185
186void _init(void)
187{
188 register_target(&redir);
189}