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