iptables-1.2.9-2.3.1.src.rpm
[iptables.git] / extensions / libipt_REDIRECT.c
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. */
12 static void
13 help(void)
14 {
15         printf(
16 "REDIRECT v%s options:\n"
17 " --to-ports <port>[-<port>]\n"
18 "                               Port (range) to map to.\n\n",
19 IPTABLES_VERSION);
20 }
21
22 static struct option opts[] = {
23         { "to-ports", 1, 0, '1' },
24         { 0 }
25 };
26
27 /* Initialize the target. */
28 static void
29 init(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 */
41 static void
42 parse_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 */
76 static int
77 parse(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, NULL, 0))
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. */
110 static void final_check(unsigned int flags)
111 {
112 }
113
114 /* Prints out the targinfo. */
115 static void
116 print(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. */
134 static void
135 save(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("--to-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
150 static
151 struct iptables_target redir
152 = { NULL,
153     "REDIRECT",
154     IPTABLES_VERSION,
155     IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
156     IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
157     &help,
158     &init,
159     &parse,
160     &final_check,
161     &print,
162     &save,
163     opts
164 };
165
166 void _init(void)
167 {
168         register_target(&redir);
169 }