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