blob: c94bb592e570be628dcfa52f02cf7415a4afc9da [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
11/* Function which prints out usage message. */
12static void
13help(void)
14{
15 printf(
16"REDIRECT v%s options:\n"
17" --to-ports <port>[-<port>]\n"
18" Port (range) to map to.\n\n",
Harald Welte80fe35d2002-05-29 13:08:15 +000019IPTABLES_VERSION);
Marc Bouchere6869a82000-03-20 06:03:29 +000020}
21
22static struct option opts[] = {
23 { "to-ports", 1, 0, '1' },
24 { 0 }
25};
26
27/* Initialize the target. */
28static void
29init(struct ipt_entry_target *t, unsigned int *nfcache)
30{
31 struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data;
32
33 /* Actually, it's 0, but it's ignored at the moment. */
34 mr->rangesize = 1;
35
Marc Bouchere6869a82000-03-20 06:03:29 +000036}
37
38/* Parses ports */
39static void
40parse_ports(const char *arg, struct ip_nat_multi_range *mr)
41{
42 const char *dash;
43 int port;
44
45 mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
46
Phil Oester3836fcc2006-06-20 13:45:38 +000047 if (strchr(arg, '.'))
48 exit_error(PARAMETER_PROBLEM, "IP address not permitted\n");
49
Marc Bouchere6869a82000-03-20 06:03:29 +000050 port = atoi(arg);
51 if (port == 0 || port > 65535)
52 exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", arg);
53
54 dash = strchr(arg, '-');
55 if (!dash) {
56 mr->range[0].min.tcp.port
57 = mr->range[0].max.tcp.port
Rusty Russellf9b2e662000-04-19 11:24:02 +000058 = htons(port);
Marc Bouchere6869a82000-03-20 06:03:29 +000059 } else {
60 int maxport;
61
62 maxport = atoi(dash + 1);
63 if (maxport == 0 || maxport > 65535)
64 exit_error(PARAMETER_PROBLEM,
65 "Port `%s' not valid\n", dash+1);
66 if (maxport < port)
67 /* People are stupid. */
68 exit_error(PARAMETER_PROBLEM,
69 "Port range `%s' funky\n", arg);
Rusty Russellf9b2e662000-04-19 11:24:02 +000070 mr->range[0].min.tcp.port = htons(port);
71 mr->range[0].max.tcp.port = htons(maxport);
Marc Bouchere6869a82000-03-20 06:03:29 +000072 }
73}
74
75/* Function which parses command options; returns true if it
76 ate an option */
77static int
78parse(int c, char **argv, int invert, unsigned int *flags,
79 const struct ipt_entry *entry,
80 struct ipt_entry_target **target)
81{
82 struct ip_nat_multi_range *mr
83 = (struct ip_nat_multi_range *)(*target)->data;
84 int portok;
85
86 if (entry->ip.proto == IPPROTO_TCP
Patrick McHardy36d870c2005-07-22 06:39:45 +000087 || entry->ip.proto == IPPROTO_UDP
88 || 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)
96 exit_error(PARAMETER_PROBLEM,
97 "Need TCP or UDP with port specification");
98
Harald Welteb77f1da2002-03-14 11:35:58 +000099 if (check_inverse(optarg, &invert, NULL, 0))
Marc Bouchere6869a82000-03-20 06:03:29 +0000100 exit_error(PARAMETER_PROBLEM,
101 "Unexpected `!' after --to-ports");
102
103 parse_ports(optarg, mr);
104 return 1;
105
106 default:
107 return 0;
108 }
109}
110
111/* Final check; don't care. */
112static void final_check(unsigned int flags)
113{
114}
115
116/* Prints out the targinfo. */
117static void
118print(const struct ipt_ip *ip,
119 const struct ipt_entry_target *target,
120 int numeric)
121{
122 struct ip_nat_multi_range *mr
123 = (struct ip_nat_multi_range *)target->data;
124 struct ip_nat_range *r = &mr->range[0];
125
Marc Bouchere6869a82000-03-20 06:03:29 +0000126 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
Rusty Russell849779c2000-04-23 15:51:51 +0000127 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));
Marc Bouchere6869a82000-03-20 06:03:29 +0000131 printf(" ");
132 }
133}
134
135/* Saves the union ipt_targinfo in parsable form to stdout. */
136static void
137save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
138{
139 struct ip_nat_multi_range *mr
140 = (struct ip_nat_multi_range *)target->data;
141 struct ip_nat_range *r = &mr->range[0];
142
143 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
Harald Welte963bdcc2001-03-16 20:37:10 +0000144 printf("--to-ports ");
Rusty Russellf9b2e662000-04-19 11:24:02 +0000145 printf("%hu", ntohs(r->min.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000146 if (r->max.tcp.port != r->min.tcp.port)
Rusty Russellf9b2e662000-04-19 11:24:02 +0000147 printf("-%hu", ntohs(r->max.tcp.port));
Marc Bouchere6869a82000-03-20 06:03:29 +0000148 printf(" ");
149 }
150}
151
Pablo Neira8caee8b2004-12-28 13:11:59 +0000152static struct iptables_target redir = {
153 .next = NULL,
154 .name = "REDIRECT",
155 .version = IPTABLES_VERSION,
156 .size = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
157 .userspacesize = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
158 .help = &help,
159 .init = &init,
160 .parse = &parse,
161 .final_check = &final_check,
162 .print = &print,
163 .save = &save,
164 .extra_opts = opts
Marc Bouchere6869a82000-03-20 06:03:29 +0000165};
166
167void _init(void)
168{
169 register_target(&redir);
170}