iptables-1.2.9-2.3.1.src.rpm
[iptables.git] / extensions / libipt_ROUTE.c
1 /* Shared library add-on to iptables to add ROUTE target support.
2  * Author : Cedric de Launois, <delaunois@info.ucl.ac.be>
3  * v 1.8 2003/06/24
4  */
5
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <getopt.h>
10 #include <iptables.h>
11 #include <net/if.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15 #include <linux/netfilter_ipv4/ip_tables.h>
16 #include <linux/netfilter_ipv4/ipt_ROUTE.h>
17
18 /* Function which prints out usage message. */
19 static void
20 help(void)
21 {
22         printf(
23 "ROUTE target v%s options:\n"
24 "    --oif   \tifname \t\tRoute the packet through `ifname' network interface\n"
25 "    --iif   \tifname \t\tChange the packet's incoming interface to `ifname'\n"
26 "    --gw    \tip     \t\tRoute the packet via this gateway\n"
27 "    --continue\t     \t\tRoute the packet and continue traversing the\n"
28 "            \t       \t\trules. Not valid with --iif.\n"
29 "\n",
30 "1.8");
31 }
32
33 static struct option opts[] = {
34         { "oif", 1, 0, '1' },
35         { "iif", 1, 0, '2' },
36         { "gw", 1, 0, '3' },
37         { "continue", 0, 0, '4' },
38         { 0 }
39 };
40
41 /* Initialize the target. */
42 static void
43 init(struct ipt_entry_target *t, unsigned int *nfcache)
44 {
45         struct ipt_route_target_info *route_info = 
46                 (struct ipt_route_target_info*)t->data;
47
48         route_info->oif[0] = '\0';
49         route_info->iif[0] = '\0';
50         route_info->gw = 0;
51         route_info->flags = 0;
52 }
53
54
55 #define IPT_ROUTE_OPT_OIF      0x01
56 #define IPT_ROUTE_OPT_IIF      0x02
57 #define IPT_ROUTE_OPT_GW       0x04
58 #define IPT_ROUTE_OPT_CONTINUE 0x08
59
60 /* Function which parses command options; returns true if it
61    ate an option */
62 static int
63 parse(int c, char **argv, int invert, unsigned int *flags,
64       const struct ipt_entry *entry,
65       struct ipt_entry_target **target)
66 {
67         struct ipt_route_target_info *route_info = 
68                 (struct ipt_route_target_info*)(*target)->data;
69
70         switch (c) {
71         case '1':
72                 if (*flags & IPT_ROUTE_OPT_OIF)
73                         exit_error(PARAMETER_PROBLEM,
74                                    "Can't specify --oif twice");
75
76                 if (*flags & IPT_ROUTE_OPT_IIF)
77                         exit_error(PARAMETER_PROBLEM,
78                                    "Can't use --oif and --iif together");
79
80                 if (check_inverse(optarg, &invert, NULL, 0))
81                         exit_error(PARAMETER_PROBLEM,
82                                    "Unexpected `!' after --oif");
83
84                 if (strlen(optarg) > sizeof(route_info->oif) - 1)
85                         exit_error(PARAMETER_PROBLEM,
86                                    "Maximum interface name length %u",
87                                    sizeof(route_info->oif) - 1);
88
89                 strcpy(route_info->oif, optarg);
90                 *flags |= IPT_ROUTE_OPT_OIF;
91                 break;
92
93         case '2':
94                 if (*flags & IPT_ROUTE_OPT_IIF)
95                         exit_error(PARAMETER_PROBLEM,
96                                    "Can't specify --iif twice");
97
98                 if (*flags & IPT_ROUTE_OPT_OIF)
99                         exit_error(PARAMETER_PROBLEM,
100                                    "Can't use --iif and --oif together");
101
102                 if (check_inverse(optarg, &invert, NULL, 0))
103                         exit_error(PARAMETER_PROBLEM,
104                                    "Unexpected `!' after --iif");
105
106                 if (strlen(optarg) > sizeof(route_info->iif) - 1)
107                         exit_error(PARAMETER_PROBLEM,
108                                    "Maximum interface name length %u",
109                                    sizeof(route_info->iif) - 1);
110
111                 strcpy(route_info->iif, optarg);
112                 *flags |= IPT_ROUTE_OPT_IIF;
113                 break;
114
115         case '3':
116                 if (*flags & IPT_ROUTE_OPT_GW)
117                         exit_error(PARAMETER_PROBLEM,
118                                    "Can't specify --gw twice");
119
120                 if (check_inverse(optarg, &invert, NULL, 0))
121                         exit_error(PARAMETER_PROBLEM,
122                                    "Unexpected `!' after --gw");
123
124                 if (!inet_aton(optarg, (struct in_addr*)&route_info->gw)) {
125                         exit_error(PARAMETER_PROBLEM,
126                                    "Invalid IP address %s",
127                                    optarg);
128                 }
129
130                 *flags |= IPT_ROUTE_OPT_GW;
131                 break;
132
133         case '4':
134                 if (*flags & IPT_ROUTE_OPT_CONTINUE)
135                         exit_error(PARAMETER_PROBLEM,
136                                    "Can't specify --continue twice");
137
138                 route_info->flags |= IPT_ROUTE_CONTINUE;
139                 *flags |= IPT_ROUTE_OPT_CONTINUE;
140
141                 break;
142
143         default:
144                 return 0;
145         }
146
147         return 1;
148 }
149
150
151 static void
152 final_check(unsigned int flags)
153 {
154         if (!flags)
155                 exit_error(PARAMETER_PROBLEM,
156                            "ROUTE target: oif, iif or gw option required");
157
158         if ((flags & IPT_ROUTE_OPT_CONTINUE) && (flags & IPT_ROUTE_OPT_IIF))
159                 exit_error(PARAMETER_PROBLEM,
160                            "ROUTE target: can't continue traversing the rules with iif option");
161 }
162
163
164 /* Prints out the targinfo. */
165 static void
166 print(const struct ipt_ip *ip,
167       const struct ipt_entry_target *target,
168       int numeric)
169 {
170         const struct ipt_route_target_info *route_info
171                 = (const struct ipt_route_target_info *)target->data;
172
173         printf("ROUTE ");
174
175         if (route_info->oif[0])
176                 printf("oif:%s ", route_info->oif);
177
178         if (route_info->iif[0])
179                 printf("iif:%s ", route_info->iif);
180
181         if (route_info->gw) {
182                 struct in_addr ip = { route_info->gw };
183                 printf("gw:%s ", inet_ntoa(ip));
184         }
185
186         if (route_info->flags & IPT_ROUTE_CONTINUE)
187                 printf("continue");
188
189 }
190
191
192 static void save(const struct ipt_ip *ip, 
193                  const struct ipt_entry_target *target)
194 {
195         const struct ipt_route_target_info *route_info
196                 = (const struct ipt_route_target_info *)target->data;
197
198         if (route_info->oif[0])
199                 printf("--oif %s ", route_info->oif);
200
201         if (route_info->iif[0])
202                 printf("--iif %s ", route_info->iif);
203
204         if (route_info->gw) {
205                 struct in_addr ip = { route_info->gw };
206                 printf("--gw %s ", inet_ntoa(ip));
207         }
208
209         if (route_info->flags & IPT_ROUTE_CONTINUE)
210                 printf("--continue ");
211 }
212
213
214 static
215 struct iptables_target route
216 = { NULL,
217     "ROUTE",
218     IPTABLES_VERSION,
219     IPT_ALIGN(sizeof(struct ipt_route_target_info)),
220     IPT_ALIGN(sizeof(struct ipt_route_target_info)),
221     &help,
222     &init,
223     &parse,
224     &final_check,
225     &print,
226     &save,
227     opts
228 };
229
230 void _init(void)
231 {
232         register_target(&route);
233 }