1/* Shared library add-on to iptables to add ROUTE target support.
2 * Author : C�dric de Launois, <delaunois@info.ucl.ac.be>
3 */
4
5#include <stdio.h>
6#include <string.h>
7#include <stdlib.h>
8#include <getopt.h>
9#include <iptables.h>
10#include <net/if.h>
11#include <linux/netfilter_ipv4/ip_tables.h>
12#include <linux/netfilter_ipv4/ipt_ROUTE.h>
13
14/* Function which prints out usage message. */
15static void
16help(void)
17{
18	printf(
19"ROUTE target v%s options:\n"
20"  --iface   name                Send this packet directly through iface name.\n"
21"  --ifindex index               Send this packet directly through iface index.\n"
22"\n",
23IPTABLES_VERSION);
24}
25
26static struct option opts[] = {
27	{ "iface", 1, 0, '1' },
28	{ "ifindex", 1, 0, '2' },
29	{ 0 }
30};
31
32/* Initialize the target. */
33static void
34init(struct ipt_entry_target *t, unsigned int *nfcache)
35{
36}
37
38#define IPT_ROUTE_OPT_IF    0x01
39
40/* Function which parses command options; returns true if it
41   ate an option */
42static int
43parse(int c, char **argv, int invert, unsigned int *flags,
44      const struct ipt_entry *entry,
45      struct ipt_entry_target **target)
46{
47	struct ipt_route_target_info *route_info =
48		(struct ipt_route_target_info*)(*target)->data;
49
50	switch (c) {
51		char *end;
52	case '1':
53		if (*flags & IPT_ROUTE_OPT_IF)
54			exit_error(PARAMETER_PROBLEM,
55				   "Can't specify --iface or --ifindex twice");
56
57		if (check_inverse(optarg, &invert, NULL, 0))
58			exit_error(PARAMETER_PROBLEM,
59				   "Unexpected `!' after --iface");
60
61		if (strlen(optarg) > sizeof(route_info->if_name) - 1)
62			exit_error(PARAMETER_PROBLEM,
63				   "Maximum interface name length %u",
64				   sizeof(route_info->if_name) - 1);
65
66		strcpy(route_info->if_name, optarg);
67		route_info->if_index = 0;
68		*flags |= IPT_ROUTE_OPT_IF;
69		break;
70
71	case '2':
72		if (*flags & IPT_ROUTE_OPT_IF)
73			exit_error(PARAMETER_PROBLEM,
74				   "Can't specify --iface or --ifindex twice");
75
76		if (check_inverse(optarg, &invert, NULL, 0))
77			exit_error(PARAMETER_PROBLEM,
78				   "Unexpected `!' after --ifindex");
79
80		route_info->if_name[0] = 0;
81		route_info->if_index = strtoul(optarg, &end, 0);
82		if (*end != '\0' || end == optarg)
83			exit_error(PARAMETER_PROBLEM, "Bad ROUTE ifindex `%s'",
84				   optarg);
85
86		if (route_info->if_index == 0)
87			exit_error(PARAMETER_PROBLEM,
88				   "Interface index can't be 0 !");
89
90		*flags |= IPT_ROUTE_OPT_IF;
91		break;
92
93	default:
94		return 0;
95	}
96
97	return 1;
98}
99
100static void
101final_check(unsigned int flags)
102{
103	if (!flags)
104		exit_error(PARAMETER_PROBLEM,
105		           "ROUTE target: Parameter --iface is required");
106}
107
108/* Prints out the targinfo. */
109static void
110print(const struct ipt_ip *ip,
111      const struct ipt_entry_target *target,
112      int numeric)
113{
114	const struct ipt_route_target_info *route_info
115		= (const struct ipt_route_target_info *)target->data;
116
117	printf("ROUTE ");
118
119	if (route_info->if_name[0] != 0)
120		printf("iface %s ", route_info->if_name);
121	else
122		printf("ifindex %u ", route_info->if_index);
123}
124
125static
126struct iptables_target route
127= { NULL,
128    "ROUTE",
129    IPTABLES_VERSION,
130    IPT_ALIGN(sizeof(struct ipt_route_target_info)),
131    IPT_ALIGN(sizeof(struct ipt_route_target_info)),
132    &help,
133    &init,
134    &parse,
135    &final_check,
136    &print,
137    NULL, /* save */
138    opts
139};
140
141void _init(void)
142{
143	register_target(&route);
144}
145