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