blob: e7dcc774cd3f3c3480fb411db33a3322028f6090 [file] [log] [blame]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001/*
2 * q_rsvp.c RSVP filter.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <syslog.h>
17#include <fcntl.h>
18#include <sys/socket.h>
19#include <netinet/in.h>
20#include <arpa/inet.h>
21#include <string.h>
22
23#include "rt_names.h"
24#include "utils.h"
25#include "tc_util.h"
26
27static void explain(void)
28{
29 fprintf(stderr, "Usage: ... rsvp ipproto PROTOCOL session DST[/PORT | GPI ]\n");
Phil Sutter0a83e1e2015-10-23 19:21:17 +020030 fprintf(stderr, " [ sender SRC[/PORT | GPI ] ]\n");
Jamal Hadi Salim863ecb02014-10-06 07:41:21 -040031 fprintf(stderr, " [ classid CLASSID ] [ action ACTION_SPEC ]\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000032 fprintf(stderr, " [ tunnelid ID ] [ tunnel ID skip NUMBER ]\n");
33 fprintf(stderr, "Where: GPI := { flowlabel NUMBER | spi/ah SPI | spi/esp SPI |\n");
34 fprintf(stderr, " u{8|16|32} NUMBER mask MASK at OFFSET}\n");
Jamal Hadi Salim863ecb02014-10-06 07:41:21 -040035 fprintf(stderr, " ACTION_SPEC := ... look at individual actions\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000036 fprintf(stderr, " FILTERID := X:Y\n");
PJ Waskiewicze9acc242008-02-13 03:49:09 -080037 fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000038}
39
Stephen Hemminger32a121c2016-03-21 11:48:36 -070040static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix *addr,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000041 struct tc_rsvp_pinfo *pinfo, int dir, int family)
42{
43 int argc = *argc_p;
44 char **argv = *argv_p;
45 char *p = strchr(*argv, '/');
46 struct tc_rsvp_gpi *pi = dir ? &pinfo->dpi : &pinfo->spi;
47
48 if (p) {
49 __u16 tmp;
50
51 if (get_u16(&tmp, p+1, 0))
52 return -1;
53
54 if (dir == 0) {
55 /* Source port: u16 at offset 0 */
56 pi->key = htonl(((__u32)tmp)<<16);
57 pi->mask = htonl(0xFFFF0000);
58 } else {
59 /* Destination port: u16 at offset 2 */
60 pi->key = htonl(((__u32)tmp));
61 pi->mask = htonl(0x0000FFFF);
62 }
63 pi->offset = 0;
64 *p = 0;
65 }
66 if (get_addr_1(addr, *argv, family))
67 return -1;
68 if (p)
69 *p = '/';
70
71 argc--; argv++;
72
73 if (pi->mask || argc <= 0)
74 goto done;
75
76 if (strcmp(*argv, "spi/ah") == 0 ||
77 strcmp(*argv, "gpi/ah") == 0) {
78 __u32 gpi;
Stephen Hemminger32a121c2016-03-21 11:48:36 -070079
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000080 NEXT_ARG();
81 if (get_u32(&gpi, *argv, 0))
82 return -1;
83 pi->mask = htonl(0xFFFFFFFF);
84 pi->key = htonl(gpi);
85 pi->offset = 4;
86 if (pinfo->protocol == 0)
87 pinfo->protocol = IPPROTO_AH;
88 argc--; argv++;
89 } else if (strcmp(*argv, "spi/esp") == 0 ||
90 strcmp(*argv, "gpi/esp") == 0) {
91 __u32 gpi;
Stephen Hemminger32a121c2016-03-21 11:48:36 -070092
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000093 NEXT_ARG();
94 if (get_u32(&gpi, *argv, 0))
95 return -1;
96 pi->mask = htonl(0xFFFFFFFF);
97 pi->key = htonl(gpi);
98 pi->offset = 0;
99 if (pinfo->protocol == 0)
100 pinfo->protocol = IPPROTO_ESP;
101 argc--; argv++;
102 } else if (strcmp(*argv, "flowlabel") == 0) {
103 __u32 flabel;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700104
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000105 NEXT_ARG();
106 if (get_u32(&flabel, *argv, 0))
107 return -1;
108 if (family != AF_INET6)
109 return -1;
110 pi->mask = htonl(0x000FFFFF);
111 pi->key = htonl(flabel) & pi->mask;
112 pi->offset = -40;
113 argc--; argv++;
114 } else if (strcmp(*argv, "u32") == 0 ||
115 strcmp(*argv, "u16") == 0 ||
116 strcmp(*argv, "u8") == 0) {
117 int sz = 1;
118 __u32 tmp;
119 __u32 mask = 0xff;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700120
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000121 if (strcmp(*argv, "u32") == 0) {
122 sz = 4;
123 mask = 0xffff;
124 } else if (strcmp(*argv, "u16") == 0) {
125 mask = 0xffffffff;
126 sz = 2;
127 }
128 NEXT_ARG();
129 if (get_u32(&tmp, *argv, 0))
130 return -1;
131 argc--; argv++;
132 if (strcmp(*argv, "mask") == 0) {
133 NEXT_ARG();
134 if (get_u32(&mask, *argv, 16))
135 return -1;
136 argc--; argv++;
137 }
138 if (strcmp(*argv, "at") == 0) {
139 NEXT_ARG();
140 if (get_integer(&pi->offset, *argv, 0))
141 return -1;
142 argc--; argv++;
143 }
144 if (sz == 1) {
145 if ((pi->offset & 3) == 0) {
146 mask <<= 24;
147 tmp <<= 24;
148 } else if ((pi->offset & 3) == 1) {
149 mask <<= 16;
150 tmp <<= 16;
151 } else if ((pi->offset & 3) == 3) {
152 mask <<= 8;
153 tmp <<= 8;
154 }
155 } else if (sz == 2) {
156 if ((pi->offset & 3) == 0) {
157 mask <<= 16;
158 tmp <<= 16;
159 }
160 }
161 pi->offset &= ~3;
162 pi->mask = htonl(mask);
163 pi->key = htonl(tmp) & pi->mask;
164 }
165
166done:
167 *argc_p = argc;
168 *argv_p = argv;
169 return 0;
170}
171
172
173static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n)
174{
175 int family = strcmp(qu->id, "rsvp") == 0 ? AF_INET : AF_INET6;
176 struct tc_rsvp_pinfo pinfo;
177 struct tc_police tp;
178 struct tcmsg *t = NLMSG_DATA(n);
179 int pinfo_ok = 0;
180 struct rtattr *tail;
181
182 memset(&pinfo, 0, sizeof(pinfo));
183 memset(&tp, 0, sizeof(tp));
184
185 if (handle) {
186 if (get_u32(&t->tcm_handle, handle, 0)) {
187 fprintf(stderr, "Illegal \"handle\"\n");
188 return -1;
189 }
190 }
191
192 if (argc == 0)
193 return 0;
194
4!tgraf228569c2005-01-18 01:24:18 +0000195 tail = NLMSG_TAIL(n);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000196 addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
197
198 while (argc > 0) {
199 if (matches(*argv, "session") == 0) {
200 inet_prefix addr;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700201
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000202 NEXT_ARG();
203 if (get_addr_and_pi(&argc, &argv, &addr, &pinfo, 1, family)) {
204 fprintf(stderr, "Illegal \"session\"\n");
205 return -1;
206 }
207 addattr_l(n, 4096, TCA_RSVP_DST, &addr.data, addr.bytelen);
208 if (pinfo.dpi.mask || pinfo.protocol)
209 pinfo_ok++;
210 continue;
211 } else if (matches(*argv, "sender") == 0 ||
212 matches(*argv, "flowspec") == 0) {
213 inet_prefix addr;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700214
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000215 NEXT_ARG();
216 if (get_addr_and_pi(&argc, &argv, &addr, &pinfo, 0, family)) {
217 fprintf(stderr, "Illegal \"sender\"\n");
218 return -1;
219 }
220 addattr_l(n, 4096, TCA_RSVP_SRC, &addr.data, addr.bytelen);
221 if (pinfo.spi.mask || pinfo.protocol)
222 pinfo_ok++;
223 continue;
224 } else if (matches("ipproto", *argv) == 0) {
225 int num;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700226
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000227 NEXT_ARG();
228 num = inet_proto_a2n(*argv);
229 if (num < 0) {
230 fprintf(stderr, "Illegal \"ipproto\"\n");
231 return -1;
232 }
233 pinfo.protocol = num;
234 pinfo_ok++;
235 } else if (matches(*argv, "classid") == 0 ||
236 strcmp(*argv, "flowid") == 0) {
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700237 unsigned int handle;
238
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000239 NEXT_ARG();
240 if (get_tc_classid(&handle, *argv)) {
241 fprintf(stderr, "Illegal \"classid\"\n");
242 return -1;
243 }
244 addattr_l(n, 4096, TCA_RSVP_CLASSID, &handle, 4);
245 } else if (strcmp(*argv, "tunnelid") == 0) {
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700246 unsigned int tid;
247
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000248 NEXT_ARG();
249 if (get_unsigned(&tid, *argv, 0)) {
250 fprintf(stderr, "Illegal \"tunnelid\"\n");
251 return -1;
252 }
253 pinfo.tunnelid = tid;
254 pinfo_ok++;
255 } else if (strcmp(*argv, "tunnel") == 0) {
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700256 unsigned int tid;
257
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000258 NEXT_ARG();
259 if (get_unsigned(&tid, *argv, 0)) {
260 fprintf(stderr, "Illegal \"tunnel\"\n");
261 return -1;
262 }
263 addattr_l(n, 4096, TCA_RSVP_CLASSID, &tid, 4);
264 NEXT_ARG();
265 if (strcmp(*argv, "skip") == 0) {
266 NEXT_ARG();
267 }
268 if (get_unsigned(&tid, *argv, 0)) {
269 fprintf(stderr, "Illegal \"skip\"\n");
270 return -1;
271 }
272 pinfo.tunnelhdr = tid;
273 pinfo_ok++;
Jamal Hadi Salim10f5a372014-09-28 12:49:53 -0400274 } else if (matches(*argv, "action") == 0) {
275 NEXT_ARG();
276 if (parse_action(&argc, &argv, TCA_RSVP_ACT, n)) {
277 fprintf(stderr, "Illegal \"action\"\n");
278 return -1;
279 }
280 continue;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000281 } else if (matches(*argv, "police") == 0) {
282 NEXT_ARG();
283 if (parse_police(&argc, &argv, TCA_RSVP_POLICE, n)) {
284 fprintf(stderr, "Illegal \"police\"\n");
285 return -1;
286 }
287 continue;
288 } else if (strcmp(*argv, "help") == 0) {
289 explain();
290 return -1;
291 } else {
292 fprintf(stderr, "What is \"%s\"?\n", *argv);
293 explain();
294 return -1;
295 }
296 argc--; argv++;
297 }
298
299 if (pinfo_ok)
300 addattr_l(n, 4096, TCA_RSVP_PINFO, &pinfo, sizeof(pinfo));
4!tgraf228569c2005-01-18 01:24:18 +0000301 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000302 return 0;
303}
304
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700305static char *sprint_spi(struct tc_rsvp_gpi *pi, int dir, char *buf)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000306{
307 if (pi->offset == 0) {
308 if (dir && pi->mask == htonl(0xFFFF)) {
309 snprintf(buf, SPRINT_BSIZE-1, "/%d", htonl(pi->key));
310 return buf;
311 }
312 if (!dir && pi->mask == htonl(0xFFFF0000)) {
313 snprintf(buf, SPRINT_BSIZE-1, "/%d", htonl(pi->key)>>16);
314 return buf;
315 }
316 if (pi->mask == htonl(0xFFFFFFFF)) {
317 snprintf(buf, SPRINT_BSIZE-1, " spi/esp 0x%08x", htonl(pi->key));
318 return buf;
319 }
320 } else if (pi->offset == 4 && pi->mask == htonl(0xFFFFFFFF)) {
321 snprintf(buf, SPRINT_BSIZE-1, " spi/ah 0x%08x", htonl(pi->key));
322 return buf;
323 } else if (pi->offset == -40 && pi->mask == htonl(0x000FFFFF)) {
324 snprintf(buf, SPRINT_BSIZE-1, " flowlabel 0x%05x", htonl(pi->key));
325 return buf;
326 }
327 snprintf(buf, SPRINT_BSIZE-1, " u32 0x%08x mask %08x at %d",
328 htonl(pi->key), htonl(pi->mask), pi->offset);
329 return buf;
330}
331
332static int rsvp_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 handle)
333{
334 int family = strcmp(qu->id, "rsvp") == 0 ? AF_INET : AF_INET6;
335 struct rtattr *tb[TCA_RSVP_MAX+1];
336 struct tc_rsvp_pinfo *pinfo = NULL;
337
338 if (opt == NULL)
339 return 0;
340
4!tgraf3b3ecd32005-01-18 22:11:58 +0000341 parse_rtattr_nested(tb, TCA_RSVP_MAX, opt);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000342
343 if (handle)
344 fprintf(f, "fh 0x%08x ", handle);
345
346 if (tb[TCA_RSVP_PINFO]) {
347 if (RTA_PAYLOAD(tb[TCA_RSVP_PINFO]) < sizeof(*pinfo))
348 return -1;
349
350 pinfo = RTA_DATA(tb[TCA_RSVP_PINFO]);
351 }
352
353 if (tb[TCA_RSVP_CLASSID]) {
354 SPRINT_BUF(b1);
355 if (!pinfo || pinfo->tunnelhdr == 0)
Stephen Hemmingerff247462012-04-10 08:47:55 -0700356 fprintf(f, "flowid %s ", sprint_tc_classid(rta_getattr_u32(tb[TCA_RSVP_CLASSID]), b1));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000357 else
Stephen Hemmingerff247462012-04-10 08:47:55 -0700358 fprintf(f, "tunnel %d skip %d ", rta_getattr_u32(tb[TCA_RSVP_CLASSID]), pinfo->tunnelhdr);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000359 } else if (pinfo && pinfo->tunnelhdr)
360 fprintf(f, "tunnel [BAD] skip %d ", pinfo->tunnelhdr);
361
362 if (tb[TCA_RSVP_DST]) {
363 char buf[128];
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700364
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000365 fprintf(f, "session ");
366 if (inet_ntop(family, RTA_DATA(tb[TCA_RSVP_DST]), buf, sizeof(buf)) == 0)
367 fprintf(f, " [INVALID DADDR] ");
368 else
369 fprintf(f, "%s", buf);
370 if (pinfo && pinfo->dpi.mask) {
371 SPRINT_BUF(b2);
372 fprintf(f, "%s ", sprint_spi(&pinfo->dpi, 1, b2));
373 } else
374 fprintf(f, " ");
375 } else {
376 if (pinfo && pinfo->dpi.mask) {
377 SPRINT_BUF(b2);
378 fprintf(f, "session [NONE]%s ", sprint_spi(&pinfo->dpi, 1, b2));
379 } else
380 fprintf(f, "session NONE ");
381 }
382
383 if (pinfo && pinfo->protocol) {
384 SPRINT_BUF(b1);
385 fprintf(f, "ipproto %s ", inet_proto_n2a(pinfo->protocol, b1, sizeof(b1)));
386 }
387 if (pinfo && pinfo->tunnelid)
388 fprintf(f, "tunnelid %d ", pinfo->tunnelid);
389 if (tb[TCA_RSVP_SRC]) {
390 char buf[128];
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700391
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000392 fprintf(f, "sender ");
393 if (inet_ntop(family, RTA_DATA(tb[TCA_RSVP_SRC]), buf, sizeof(buf)) == 0) {
394 fprintf(f, "[BAD]");
395 } else {
396 fprintf(f, " %s", buf);
397 }
398 if (pinfo && pinfo->spi.mask) {
399 SPRINT_BUF(b2);
400 fprintf(f, "%s ", sprint_spi(&pinfo->spi, 0, b2));
401 } else
402 fprintf(f, " ");
403 } else if (pinfo && pinfo->spi.mask) {
404 SPRINT_BUF(b2);
405 fprintf(f, "sender [NONE]%s ", sprint_spi(&pinfo->spi, 0, b2));
406 }
Jamal Hadi Salim10f5a372014-09-28 12:49:53 -0400407
408 if (tb[TCA_RSVP_ACT]) {
409 tc_print_action(f, tb[TCA_RSVP_ACT]);
410 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000411 if (tb[TCA_RSVP_POLICE])
412 tc_print_police(f, tb[TCA_RSVP_POLICE]);
413 return 0;
414}
415
osdl.net!shemminger6b7dff12004-09-28 18:35:49 +0000416struct filter_util rsvp_filter_util = {
417 .id = "rsvp",
418 .parse_fopt = rsvp_parse_opt,
419 .print_fopt = rsvp_print_opt,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000420};
421
osdl.net!shemminger6b7dff12004-09-28 18:35:49 +0000422struct filter_util rsvp6_filter_util = {
423 .id = "rsvp6",
424 .parse_fopt = rsvp_parse_opt,
425 .print_fopt = rsvp_print_opt,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000426};