1/* Shared library add-on to ip6tables to add mobility header support. */
2/*
3 * Copyright (C)2006 USAGI/WIDE Project
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Author:
10 *	Masahide NAKAMURA @USAGI <masahide.nakamura.cz@hitachi.com>
11 *
12 * Based on libip6t_{icmpv6,udp}.c
13 */
14#include <stdint.h>
15#include <stdio.h>
16#include <string.h>
17#include <stdlib.h>
18#include <xtables.h>
19#include <linux/netfilter_ipv6/ip6t_mh.h>
20
21enum {
22	O_MH_TYPE = 0,
23};
24
25struct mh_name {
26	const char *name;
27	uint8_t type;
28};
29
30static const struct mh_name mh_names[] = {
31	{ "binding-refresh-request", 0, },
32	/* Alias */ { "brr", 0, },
33	{ "home-test-init", 1, },
34	/* Alias */ { "hoti", 1, },
35	{ "careof-test-init", 2, },
36	/* Alias */ { "coti", 2, },
37	{ "home-test", 3, },
38	/* Alias */ { "hot", 3, },
39	{ "careof-test", 4, },
40	/* Alias */ { "cot", 4, },
41	{ "binding-update", 5, },
42	/* Alias */ { "bu", 5, },
43	{ "binding-acknowledgement", 6, },
44	/* Alias */ { "ba", 6, },
45	{ "binding-error", 7, },
46	/* Alias */ { "be", 7, },
47};
48
49static void print_types_all(void)
50{
51	unsigned int i;
52	printf("Valid MH types:");
53
54	for (i = 0; i < ARRAY_SIZE(mh_names); ++i) {
55		if (i && mh_names[i].type == mh_names[i-1].type)
56			printf(" (%s)", mh_names[i].name);
57		else
58			printf("\n%s", mh_names[i].name);
59	}
60	printf("\n");
61}
62
63static void mh_help(void)
64{
65	printf(
66"mh match options:\n"
67"[!] --mh-type type[:type]	match mh type\n");
68	print_types_all();
69}
70
71static void mh_init(struct xt_entry_match *m)
72{
73	struct ip6t_mh *mhinfo = (struct ip6t_mh *)m->data;
74
75	mhinfo->types[1] = 0xFF;
76}
77
78static unsigned int name_to_type(const char *name)
79{
80	int namelen = strlen(name);
81	static const unsigned int limit = ARRAY_SIZE(mh_names);
82	unsigned int match = limit;
83	unsigned int i;
84
85	for (i = 0; i < limit; i++) {
86		if (strncasecmp(mh_names[i].name, name, namelen) == 0) {
87			int len = strlen(mh_names[i].name);
88			if (match == limit || len == namelen)
89				match = i;
90		}
91	}
92
93	if (match != limit) {
94		return mh_names[match].type;
95	} else {
96		unsigned int number;
97
98		if (!xtables_strtoui(name, NULL, &number, 0, UINT8_MAX))
99			xtables_error(PARAMETER_PROBLEM,
100				   "Invalid MH type `%s'\n", name);
101		return number;
102	}
103}
104
105static void parse_mh_types(const char *mhtype, uint8_t *types)
106{
107	char *buffer;
108	char *cp;
109
110	buffer = strdup(mhtype);
111	if ((cp = strchr(buffer, ':')) == NULL)
112		types[0] = types[1] = name_to_type(buffer);
113	else {
114		*cp = '\0';
115		cp++;
116
117		types[0] = buffer[0] ? name_to_type(buffer) : 0;
118		types[1] = cp[0] ? name_to_type(cp) : 0xFF;
119
120		if (types[0] > types[1])
121			xtables_error(PARAMETER_PROBLEM,
122				   "Invalid MH type range (min > max)");
123	}
124	free(buffer);
125}
126
127static void mh_parse(struct xt_option_call *cb)
128{
129	struct ip6t_mh *mhinfo = cb->data;
130
131	xtables_option_parse(cb);
132	parse_mh_types(cb->arg, mhinfo->types);
133	if (cb->invert)
134		mhinfo->invflags |= IP6T_MH_INV_TYPE;
135}
136
137static const char *type_to_name(uint8_t type)
138{
139	unsigned int i;
140
141	for (i = 0; i < ARRAY_SIZE(mh_names); ++i)
142		if (mh_names[i].type == type)
143			return mh_names[i].name;
144
145	return NULL;
146}
147
148static void print_type(uint8_t type, int numeric)
149{
150	const char *name;
151	if (numeric || !(name = type_to_name(type)))
152		printf("%u", type);
153	else
154		printf("%s", name);
155}
156
157static void print_types(uint8_t min, uint8_t max, int invert, int numeric)
158{
159	const char *inv = invert ? "!" : "";
160
161	if (min != 0 || max != 0xFF || invert) {
162		printf(" ");
163		if (min == max) {
164			printf("%s", inv);
165			print_type(min, numeric);
166		} else {
167			printf("%s", inv);
168			print_type(min, numeric);
169			printf(":");
170			print_type(max, numeric);
171		}
172	}
173}
174
175static void mh_print(const void *ip, const struct xt_entry_match *match,
176                     int numeric)
177{
178	const struct ip6t_mh *mhinfo = (struct ip6t_mh *)match->data;
179
180	printf(" mh");
181	print_types(mhinfo->types[0], mhinfo->types[1],
182		    mhinfo->invflags & IP6T_MH_INV_TYPE,
183		    numeric);
184	if (mhinfo->invflags & ~IP6T_MH_INV_MASK)
185		printf(" Unknown invflags: 0x%X",
186		       mhinfo->invflags & ~IP6T_MH_INV_MASK);
187}
188
189static void mh_save(const void *ip, const struct xt_entry_match *match)
190{
191	const struct ip6t_mh *mhinfo = (struct ip6t_mh *)match->data;
192
193	if (mhinfo->types[0] == 0 && mhinfo->types[1] == 0xFF)
194		return;
195
196	if (mhinfo->invflags & IP6T_MH_INV_TYPE)
197		printf(" !");
198
199	if (mhinfo->types[0] != mhinfo->types[1])
200		printf(" --mh-type %u:%u", mhinfo->types[0], mhinfo->types[1]);
201	else
202		printf(" --mh-type %u", mhinfo->types[0]);
203}
204
205static const struct xt_option_entry mh_opts[] = {
206	{.name = "mh-type", .id = O_MH_TYPE, .type = XTTYPE_STRING,
207	 .flags = XTOPT_INVERT},
208	XTOPT_TABLEEND,
209};
210
211static struct xtables_match mh_mt6_reg = {
212	.name		= "mh",
213	.version	= XTABLES_VERSION,
214	.family		= NFPROTO_IPV6,
215	.size		= XT_ALIGN(sizeof(struct ip6t_mh)),
216	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_mh)),
217	.help		= mh_help,
218	.init		= mh_init,
219	.x6_parse	= mh_parse,
220	.print		= mh_print,
221	.save		= mh_save,
222	.x6_options	= mh_opts,
223};
224
225void _init(void)
226{
227	xtables_register_match(&mh_mt6_reg);
228}
229