libipt_REDIRECT.c revision 849779c4adf8dd65c83fffb65e6b7898df2a55c6
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 <iptables.h>
8#include <linux/netfilter_ipv4/ip_tables.h>
9#include <linux/netfilter_ipv4/ip_nat_rule.h>
10
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",
19NETFILTER_VERSION);
20}
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
36	/* Can't cache this */
37	*nfcache |= NFC_UNKNOWN;
38}
39
40/* Parses ports */
41static void
42parse_ports(const char *arg, struct ip_nat_multi_range *mr)
43{
44	const char *dash;
45	int port;
46
47	mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
48
49	port = atoi(arg);
50	if (port == 0 || port > 65535)
51		exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", arg);
52
53	dash = strchr(arg, '-');
54	if (!dash) {
55		mr->range[0].min.tcp.port
56			= mr->range[0].max.tcp.port
57			= htons(port);
58	} else {
59		int maxport;
60
61		maxport = atoi(dash + 1);
62		if (maxport == 0 || maxport > 65535)
63			exit_error(PARAMETER_PROBLEM,
64				   "Port `%s' not valid\n", dash+1);
65		if (maxport < port)
66			/* People are stupid. */
67			exit_error(PARAMETER_PROBLEM,
68				   "Port range `%s' funky\n", arg);
69		mr->range[0].min.tcp.port = htons(port);
70		mr->range[0].max.tcp.port = htons(maxport);
71	}
72}
73
74/* Function which parses command options; returns true if it
75   ate an option */
76static int
77parse(int c, char **argv, int invert, unsigned int *flags,
78      const struct ipt_entry *entry,
79      struct ipt_entry_target **target)
80{
81	struct ip_nat_multi_range *mr
82		= (struct ip_nat_multi_range *)(*target)->data;
83	int portok;
84
85	if (entry->ip.proto == IPPROTO_TCP
86	    || entry->ip.proto == IPPROTO_UDP)
87		portok = 1;
88	else
89		portok = 0;
90
91	switch (c) {
92	case '1':
93		if (!portok)
94			exit_error(PARAMETER_PROBLEM,
95				   "Need TCP or UDP with port specification");
96
97		if (check_inverse(optarg, &invert))
98			exit_error(PARAMETER_PROBLEM,
99				   "Unexpected `!' after --to-ports");
100
101		parse_ports(optarg, mr);
102		return 1;
103
104	default:
105		return 0;
106	}
107}
108
109/* Final check; don't care. */
110static void final_check(unsigned int flags)
111{
112}
113
114/* Prints out the targinfo. */
115static void
116print(const struct ipt_ip *ip,
117      const struct ipt_entry_target *target,
118      int numeric)
119{
120	struct ip_nat_multi_range *mr
121		= (struct ip_nat_multi_range *)target->data;
122	struct ip_nat_range *r = &mr->range[0];
123
124	if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
125		printf("redir ports ");
126		printf("%hu", ntohs(r->min.tcp.port));
127		if (r->max.tcp.port != r->min.tcp.port)
128			printf("-%hu", ntohs(r->max.tcp.port));
129		printf(" ");
130	}
131}
132
133/* Saves the union ipt_targinfo in parsable form to stdout. */
134static void
135save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
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
141	if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
142		printf("redir ports: ");
143		printf("%hu", ntohs(r->min.tcp.port));
144		if (r->max.tcp.port != r->min.tcp.port)
145			printf("-%hu", ntohs(r->max.tcp.port));
146		printf(" ");
147	}
148}
149
150struct iptables_target redir
151= { NULL,
152    "REDIRECT",
153    NETFILTER_VERSION,
154    sizeof(struct ip_nat_multi_range),
155    sizeof(struct ip_nat_multi_range),
156    &help,
157    &init,
158    &parse,
159    &final_check,
160    &print,
161    &save,
162    opts
163};
164
165void _init(void)
166{
167	register_target(&redir);
168}
169