1/* Shared library add-on to iptables to add TOS matching support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7
8#include <iptables.h>
9#include <linux/netfilter_ipv4/ipt_tos.h>
10
11/* TOS names and values. */
12static
13struct TOS_value
14{
15	unsigned char TOS;
16	const char *name;
17} TOS_values[] = {
18	{ IPTOS_LOWDELAY,    "Minimize-Delay" },
19	{ IPTOS_THROUGHPUT,  "Maximize-Throughput" },
20	{ IPTOS_RELIABILITY, "Maximize-Reliability" },
21	{ IPTOS_MINCOST,     "Minimize-Cost" },
22	{ IPTOS_NORMALSVC,   "Normal-Service" },
23};
24
25/* Function which prints out usage message. */
26static void
27help(void)
28{
29	unsigned int i;
30
31	printf(
32"TOS match v%s options:\n"
33"[!] --tos value                 Match Type of Service field from one of the\n"
34"                                following numeric or descriptive values:\n",
35XTABLES_VERSION);
36
37	for (i = 0; i < sizeof(TOS_values)/sizeof(struct TOS_value);i++)
38		printf("                                     %s %u (0x%02x)\n",
39		       TOS_values[i].name,
40                       TOS_values[i].TOS,
41                       TOS_values[i].TOS);
42	fputc('\n', stdout);
43}
44
45static struct option opts[] = {
46	{ .name = "tos", .has_arg = true, .val = '1' },
47	XT_GETOPT_TABLEEND
48};
49
50static void
51parse_tos(const char *s, struct ipt_tos_info *info)
52{
53	unsigned int i;
54	unsigned int tos;
55
56	if (xtables_strtoui(s, NULL, &tos, 0, UINT8_MAX)) {
57		if (tos == IPTOS_LOWDELAY
58		    || tos == IPTOS_THROUGHPUT
59		    || tos == IPTOS_RELIABILITY
60		    || tos == IPTOS_MINCOST
61		    || tos == IPTOS_NORMALSVC) {
62		    	info->tos = (u_int8_t )tos;
63		    	return;
64		}
65	} else {
66		for (i = 0; i<sizeof(TOS_values)/sizeof(struct TOS_value); i++)
67			if (strcasecmp(s,TOS_values[i].name) == 0) {
68				info->tos = TOS_values[i].TOS;
69				return;
70			}
71	}
72	xtables_error(PARAMETER_PROBLEM, "Bad TOS value `%s'", s);
73}
74
75/* Function which parses command options; returns true if it
76   ate an option */
77static int
78parse(int c, char **argv, int invert, unsigned int *flags,
79      const void *entry,
80      struct xt_entry_match **match)
81{
82	struct ipt_tos_info *tosinfo = (struct ipt_tos_info *)(*match)->data;
83
84	switch (c) {
85	case '1':
86		/* Ensure that `--tos' haven't been used yet. */
87		if (*flags == 1)
88			xtables_error(PARAMETER_PROBLEM,
89					"tos match: only use --tos once!");
90
91		parse_tos(argv[optind-1], tosinfo);
92		if (invert)
93			tosinfo->invert = 1;
94		*flags = 1;
95		break;
96
97	default:
98		return 0;
99	}
100	return 1;
101}
102
103static void
104print_tos(u_int8_t tos, int numeric)
105{
106	unsigned int i;
107
108	if (!numeric) {
109		for (i = 0; i<sizeof(TOS_values)/sizeof(struct TOS_value); i++)
110			if (TOS_values[i].TOS == tos) {
111				printf("%s ", TOS_values[i].name);
112				return;
113			}
114	}
115	printf("0x%02x ", tos);
116}
117
118/* Final check; must have specified --tos. */
119static void
120final_check(unsigned int flags)
121{
122	if (!flags)
123		xtables_error(PARAMETER_PROBLEM,
124			   "TOS match: You must specify `--tos'");
125}
126
127/* Prints out the matchinfo. */
128static void
129print(const void *ip,
130      const struct xt_entry_match *match,
131      int numeric)
132{
133	const struct ipt_tos_info *info = (const struct ipt_tos_info *)match->data;
134
135	printf("TOS match ");
136	if (info->invert)
137		printf("!");
138	print_tos(info->tos, numeric);
139}
140
141/* Saves the union ipt_matchinfo in parsable form to stdout. */
142static void
143save(const void *ip, const struct xt_entry_match *match)
144{
145	const struct ipt_tos_info *info = (const struct ipt_tos_info *)match->data;
146
147	if (info->invert)
148		printf("! ");
149	printf("--tos ");
150	print_tos(info->tos, 0);
151}
152
153static struct xtables_match tos = {
154	.name		= "tos",
155	.version	= XTABLES_VERSION,
156	.size		= XT_ALIGN(sizeof(struct ipt_tos_info)),
157	.userspacesize	= XT_ALIGN(sizeof(struct ipt_tos_info)),
158	.help		= &help,
159	.parse		= &parse,
160	.final_check	= &final_check,
161	.print		= &print,
162	.save		= &save,
163	.extra_opts	= opts
164};
165
166void _init(void)
167{
168	xtables_register_match(&tos);
169}
170