1 /*
2 * Shared library add-on to iptables to add TOS target support
3 *
4 * Copyright © CC Computer Consultants GmbH, 2007
5 * Contact: Jan Engelhardt <[email protected]>
6 */
7 #include <getopt.h>
8 #include <stdbool.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <netinet/in.h>
13
14 #include <xtables.h>
15 #include <linux/netfilter/xt_DSCP.h>
16 #include "tos_values.c"
17
18 struct ipt_tos_target_info {
19 uint8_t tos;
20 };
21
22 enum {
23 O_SET_TOS = 0,
24 O_AND_TOS,
25 O_OR_TOS,
26 O_XOR_TOS,
27 F_SET_TOS = 1 << O_SET_TOS,
28 F_AND_TOS = 1 << O_AND_TOS,
29 F_OR_TOS = 1 << O_OR_TOS,
30 F_XOR_TOS = 1 << O_XOR_TOS,
31 F_ANY = F_SET_TOS | F_AND_TOS | F_OR_TOS | F_XOR_TOS,
32 };
33
34 static const struct xt_option_entry tos_tg_opts_v0[] = {
35 {.name = "set-tos", .id = O_SET_TOS, .type = XTTYPE_TOSMASK,
36 .excl = F_ANY, .max = 0xFF},
37 XTOPT_TABLEEND,
38 };
39
40 static const struct xt_option_entry tos_tg_opts[] = {
41 {.name = "set-tos", .id = O_SET_TOS, .type = XTTYPE_TOSMASK,
42 .excl = F_ANY, .max = 0x3F},
43 {.name = "and-tos", .id = O_AND_TOS, .type = XTTYPE_UINT8,
44 .excl = F_ANY},
45 {.name = "or-tos", .id = O_OR_TOS, .type = XTTYPE_UINT8,
46 .excl = F_ANY},
47 {.name = "xor-tos", .id = O_XOR_TOS, .type = XTTYPE_UINT8,
48 .excl = F_ANY},
49 XTOPT_TABLEEND,
50 };
51
tos_tg_help_v0(void)52 static void tos_tg_help_v0(void)
53 {
54 const struct tos_symbol_info *symbol;
55
56 printf(
57 "TOS target options:\n"
58 " --set-tos value Set Type of Service/Priority field to value\n"
59 " --set-tos symbol Set TOS field (IPv4 only) by symbol\n"
60 " Accepted symbolic names for value are:\n");
61
62 for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
63 printf(" (0x%02x) %2u %s\n",
64 symbol->value, symbol->value, symbol->name);
65
66 printf("\n");
67 }
68
tos_tg_help(void)69 static void tos_tg_help(void)
70 {
71 const struct tos_symbol_info *symbol;
72
73 printf(
74 "TOS target v%s options:\n"
75 " --set-tos value[/mask] Set Type of Service/Priority field to value\n"
76 " (Zero out bits in mask and XOR value into TOS)\n"
77 " --set-tos symbol Set TOS field (IPv4 only) by symbol\n"
78 " (this zeroes the 4-bit Precedence part!)\n"
79 " Accepted symbolic names for value are:\n",
80 XTABLES_VERSION);
81
82 for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
83 printf(" (0x%02x) %2u %s\n",
84 symbol->value, symbol->value, symbol->name);
85
86 printf(
87 "\n"
88 " --and-tos bits Binary AND the TOS value with bits\n"
89 " --or-tos bits Binary OR the TOS value with bits\n"
90 " --xor-tos bits Binary XOR the TOS value with bits\n"
91 );
92 }
93
tos_tg_parse_v0(struct xt_option_call * cb)94 static void tos_tg_parse_v0(struct xt_option_call *cb)
95 {
96 struct ipt_tos_target_info *info = cb->data;
97
98 xtables_option_parse(cb);
99 if (cb->val.tos_mask != 0xFF)
100 xtables_error(PARAMETER_PROBLEM, "tos match: Your kernel "
101 "is too old to support anything besides "
102 "/0xFF as a mask.");
103 info->tos = cb->val.tos_value;
104 }
105
tos_tg_parse(struct xt_option_call * cb)106 static void tos_tg_parse(struct xt_option_call *cb)
107 {
108 struct xt_tos_target_info *info = cb->data;
109
110 xtables_option_parse(cb);
111 switch (cb->entry->id) {
112 case O_SET_TOS:
113 info->tos_value = cb->val.tos_value;
114 info->tos_mask = cb->val.tos_mask;
115 break;
116 case O_AND_TOS:
117 info->tos_value = 0;
118 info->tos_mask = ~cb->val.u8;
119 break;
120 case O_OR_TOS:
121 info->tos_value = cb->val.u8;
122 info->tos_mask = cb->val.u8;
123 break;
124 case O_XOR_TOS:
125 info->tos_value = cb->val.u8;
126 info->tos_mask = 0;
127 break;
128 }
129 }
130
tos_tg_check(struct xt_fcheck_call * cb)131 static void tos_tg_check(struct xt_fcheck_call *cb)
132 {
133 if (!(cb->xflags & F_ANY))
134 xtables_error(PARAMETER_PROBLEM,
135 "TOS: An action is required");
136 }
137
tos_tg_print_v0(const void * ip,const struct xt_entry_target * target,int numeric)138 static void tos_tg_print_v0(const void *ip,
139 const struct xt_entry_target *target, int numeric)
140 {
141 const struct ipt_tos_target_info *info = (const void *)target->data;
142
143 printf(" TOS set ");
144 if (numeric || !tos_try_print_symbolic("", info->tos, 0xFF))
145 printf("0x%02x", info->tos);
146 }
147
tos_tg_print(const void * ip,const struct xt_entry_target * target,int numeric)148 static void tos_tg_print(const void *ip, const struct xt_entry_target *target,
149 int numeric)
150 {
151 const struct xt_tos_target_info *info = (const void *)target->data;
152
153 if (numeric)
154 printf(" TOS set 0x%02x/0x%02x",
155 info->tos_value, info->tos_mask);
156 else if (tos_try_print_symbolic(" TOS set",
157 info->tos_value, info->tos_mask))
158 /* already printed by call */
159 return;
160 else if (info->tos_value == 0)
161 printf(" TOS and 0x%02x",
162 (unsigned int)(uint8_t)~info->tos_mask);
163 else if (info->tos_value == info->tos_mask)
164 printf(" TOS or 0x%02x", info->tos_value);
165 else if (info->tos_mask == 0)
166 printf(" TOS xor 0x%02x", info->tos_value);
167 else
168 printf(" TOS set 0x%02x/0x%02x",
169 info->tos_value, info->tos_mask);
170 }
171
tos_tg_save_v0(const void * ip,const struct xt_entry_target * target)172 static void tos_tg_save_v0(const void *ip, const struct xt_entry_target *target)
173 {
174 const struct ipt_tos_target_info *info = (const void *)target->data;
175
176 printf(" --set-tos 0x%02x", info->tos);
177 }
178
tos_tg_save(const void * ip,const struct xt_entry_target * target)179 static void tos_tg_save(const void *ip, const struct xt_entry_target *target)
180 {
181 const struct xt_tos_target_info *info = (const void *)target->data;
182
183 printf(" --set-tos 0x%02x/0x%02x", info->tos_value, info->tos_mask);
184 }
185
__tos_xlate(struct xt_xlate * xl,const char * ip,uint8_t tos,uint8_t tosmask)186 static int __tos_xlate(struct xt_xlate *xl, const char *ip,
187 uint8_t tos, uint8_t tosmask)
188 {
189 xt_xlate_add(xl, "%s dscp set ", ip);
190 if ((tosmask & 0x3f) == 0x3f)
191 xt_xlate_add(xl, "0x%02x", tos >> 2);
192 else if (!tos)
193 xt_xlate_add(xl, "%s dscp and 0x%02x",
194 ip, (uint8_t)~tosmask >> 2);
195 else if (tos == tosmask)
196 xt_xlate_add(xl, "%s dscp or 0x%02x", ip, tos >> 2);
197 else if (!tosmask)
198 xt_xlate_add(xl, "%s dscp xor 0x%02x", ip, tos >> 2);
199 else
200 xt_xlate_add(xl, "%s dscp and 0x%02x xor 0x%02x",
201 ip, (uint8_t)~tosmask >> 2, tos >> 2);
202 return 1;
203 }
204
tos_xlate(struct xt_xlate * xl,const struct xt_xlate_tg_params * params)205 static int tos_xlate(struct xt_xlate *xl,
206 const struct xt_xlate_tg_params *params)
207 {
208 const struct ipt_tos_target_info *info =
209 (struct ipt_tos_target_info *) params->target->data;
210
211 return __tos_xlate(xl, "ip", info->tos, UINT8_MAX);
212 }
213
tos_xlate6(struct xt_xlate * xl,const struct xt_xlate_tg_params * params)214 static int tos_xlate6(struct xt_xlate *xl,
215 const struct xt_xlate_tg_params *params)
216 {
217 const struct xt_tos_target_info *info =
218 (struct xt_tos_target_info *)params->target->data;
219
220 return __tos_xlate(xl, "ip6", info->tos_value, info->tos_mask);
221 }
222
223 static struct xtables_target tos_tg_reg[] = {
224 {
225 .version = XTABLES_VERSION,
226 .name = "TOS",
227 .revision = 0,
228 .family = NFPROTO_IPV4,
229 .size = XT_ALIGN(sizeof(struct xt_tos_target_info)),
230 .userspacesize = XT_ALIGN(sizeof(struct xt_tos_target_info)),
231 .help = tos_tg_help_v0,
232 .print = tos_tg_print_v0,
233 .save = tos_tg_save_v0,
234 .x6_parse = tos_tg_parse_v0,
235 .x6_fcheck = tos_tg_check,
236 .x6_options = tos_tg_opts_v0,
237 .xlate = tos_xlate,
238 },
239 {
240 .version = XTABLES_VERSION,
241 .name = "TOS",
242 .revision = 1,
243 .family = NFPROTO_UNSPEC,
244 .size = XT_ALIGN(sizeof(struct xt_tos_target_info)),
245 .userspacesize = XT_ALIGN(sizeof(struct xt_tos_target_info)),
246 .help = tos_tg_help,
247 .print = tos_tg_print,
248 .save = tos_tg_save,
249 .x6_parse = tos_tg_parse,
250 .x6_fcheck = tos_tg_check,
251 .x6_options = tos_tg_opts,
252 .xlate = tos_xlate6,
253 },
254 };
255
_init(void)256 void _init(void)
257 {
258 xtables_register_targets(tos_tg_reg, ARRAY_SIZE(tos_tg_reg));
259 }
260