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",
35IPTABLES_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	{ "tos", 1, 0, '1' },
47	{0}
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 (string_to_number(s, 0, 255, &tos) != -1) {
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	exit_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 struct ipt_entry *entry,
80      unsigned int *nfcache,
81      struct ipt_entry_match **match)
82{
83	struct ipt_tos_info *tosinfo = (struct ipt_tos_info *)(*match)->data;
84
85	switch (c) {
86	case '1':
87		/* Ensure that `--tos' haven't been used yet. */
88		if (*flags == 1)
89			exit_error(PARAMETER_PROBLEM,
90					"tos match: only use --tos once!");
91
92		check_inverse(optarg, &invert, &optind, 0);
93		parse_tos(argv[optind-1], tosinfo);
94		if (invert)
95			tosinfo->invert = 1;
96		*flags = 1;
97		break;
98
99	default:
100		return 0;
101	}
102	return 1;
103}
104
105static void
106print_tos(u_int8_t tos, int numeric)
107{
108	unsigned int i;
109
110	if (!numeric) {
111		for (i = 0; i<sizeof(TOS_values)/sizeof(struct TOS_value); i++)
112			if (TOS_values[i].TOS == tos) {
113				printf("%s ", TOS_values[i].name);
114				return;
115			}
116	}
117	printf("0x%02x ", tos);
118}
119
120/* Final check; must have specified --tos. */
121static void
122final_check(unsigned int flags)
123{
124	if (!flags)
125		exit_error(PARAMETER_PROBLEM,
126			   "TOS match: You must specify `--tos'");
127}
128
129/* Prints out the matchinfo. */
130static void
131print(const struct ipt_ip *ip,
132      const struct ipt_entry_match *match,
133      int numeric)
134{
135	const struct ipt_tos_info *info = (const struct ipt_tos_info *)match->data;
136
137	printf("TOS match ");
138	if (info->invert)
139		printf("!");
140	print_tos(info->tos, numeric);
141}
142
143/* Saves the union ipt_matchinfo in parsable form to stdout. */
144static void
145save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
146{
147	const struct ipt_tos_info *info = (const struct ipt_tos_info *)match->data;
148
149	if (info->invert)
150		printf("! ");
151	printf("--tos ");
152	print_tos(info->tos, 0);
153}
154
155static struct iptables_match tos = {
156	.next		= NULL,
157	.name		= "tos",
158	.version	= IPTABLES_VERSION,
159	.size		= IPT_ALIGN(sizeof(struct ipt_tos_info)),
160	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_tos_info)),
161	.help		= &help,
162	.parse		= &parse,
163	.final_check	= &final_check,
164	.print		= &print,
165	.save		= &save,
166	.extra_opts	= opts
167};
168
169void _init(void)
170{
171	register_match(&tos);
172}
173