2 * q_rsvp.c RSVP filter.
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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
27 static void explain(void)
29 fprintf(stderr
, "Usage: ... rsvp ipproto PROTOCOL session DST[/PORT | GPI ]\n");
30 fprintf(stderr
, " [ sender SRC[/PORT | GPI ]\n");
31 fprintf(stderr
, " [ classid CLASSID ] [ action ACTION_SPEC ]\n");
32 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");
35 fprintf(stderr
, " ACTION_SPEC := ... look at individual actions\n");
36 fprintf(stderr
, " FILTERID := X:Y\n");
37 fprintf(stderr
, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
40 static int get_addr_and_pi(int *argc_p
, char ***argv_p
, inet_prefix
* addr
,
41 struct tc_rsvp_pinfo
*pinfo
, int dir
, int family
)
44 char **argv
= *argv_p
;
45 char *p
= strchr(*argv
, '/');
46 struct tc_rsvp_gpi
*pi
= dir
? &pinfo
->dpi
: &pinfo
->spi
;
51 if (get_u16(&tmp
, p
+1, 0))
55 /* Source port: u16 at offset 0 */
56 pi
->key
= htonl(((__u32
)tmp
)<<16);
57 pi
->mask
= htonl(0xFFFF0000);
59 /* Destination port: u16 at offset 2 */
60 pi
->key
= htonl(((__u32
)tmp
));
61 pi
->mask
= htonl(0x0000FFFF);
66 if (get_addr_1(addr
, *argv
, family
))
73 if (pi
->mask
|| argc
<= 0)
76 if (strcmp(*argv
, "spi/ah") == 0 ||
77 strcmp(*argv
, "gpi/ah") == 0) {
80 if (get_u32(&gpi
, *argv
, 0))
82 pi
->mask
= htonl(0xFFFFFFFF);
85 if (pinfo
->protocol
== 0)
86 pinfo
->protocol
= IPPROTO_AH
;
88 } else if (strcmp(*argv
, "spi/esp") == 0 ||
89 strcmp(*argv
, "gpi/esp") == 0) {
92 if (get_u32(&gpi
, *argv
, 0))
94 pi
->mask
= htonl(0xFFFFFFFF);
97 if (pinfo
->protocol
== 0)
98 pinfo
->protocol
= IPPROTO_ESP
;
100 } else if (strcmp(*argv
, "flowlabel") == 0) {
103 if (get_u32(&flabel
, *argv
, 0))
105 if (family
!= AF_INET6
)
107 pi
->mask
= htonl(0x000FFFFF);
108 pi
->key
= htonl(flabel
) & pi
->mask
;
111 } else if (strcmp(*argv
, "u32") == 0 ||
112 strcmp(*argv
, "u16") == 0 ||
113 strcmp(*argv
, "u8") == 0) {
117 if (strcmp(*argv
, "u32") == 0) {
120 } else if (strcmp(*argv
, "u16") == 0) {
125 if (get_u32(&tmp
, *argv
, 0))
128 if (strcmp(*argv
, "mask") == 0) {
130 if (get_u32(&mask
, *argv
, 16))
134 if (strcmp(*argv
, "at") == 0) {
136 if (get_integer(&pi
->offset
, *argv
, 0))
141 if ((pi
->offset
& 3) == 0) {
144 } else if ((pi
->offset
& 3) == 1) {
147 } else if ((pi
->offset
& 3) == 3) {
151 } else if (sz
== 2) {
152 if ((pi
->offset
& 3) == 0) {
158 pi
->mask
= htonl(mask
);
159 pi
->key
= htonl(tmp
) & pi
->mask
;
169 static int rsvp_parse_opt(struct filter_util
*qu
, char *handle
, int argc
, char **argv
, struct nlmsghdr
*n
)
171 int family
= strcmp(qu
->id
, "rsvp") == 0 ? AF_INET
: AF_INET6
;
172 struct tc_rsvp_pinfo pinfo
;
174 struct tcmsg
*t
= NLMSG_DATA(n
);
178 memset(&pinfo
, 0, sizeof(pinfo
));
179 memset(&tp
, 0, sizeof(tp
));
182 if (get_u32(&t
->tcm_handle
, handle
, 0)) {
183 fprintf(stderr
, "Illegal \"handle\"\n");
191 tail
= NLMSG_TAIL(n
);
192 addattr_l(n
, 4096, TCA_OPTIONS
, NULL
, 0);
195 if (matches(*argv
, "session") == 0) {
198 if (get_addr_and_pi(&argc
, &argv
, &addr
, &pinfo
, 1, family
)) {
199 fprintf(stderr
, "Illegal \"session\"\n");
202 addattr_l(n
, 4096, TCA_RSVP_DST
, &addr
.data
, addr
.bytelen
);
203 if (pinfo
.dpi
.mask
|| pinfo
.protocol
)
206 } else if (matches(*argv
, "sender") == 0 ||
207 matches(*argv
, "flowspec") == 0) {
210 if (get_addr_and_pi(&argc
, &argv
, &addr
, &pinfo
, 0, family
)) {
211 fprintf(stderr
, "Illegal \"sender\"\n");
214 addattr_l(n
, 4096, TCA_RSVP_SRC
, &addr
.data
, addr
.bytelen
);
215 if (pinfo
.spi
.mask
|| pinfo
.protocol
)
218 } else if (matches("ipproto", *argv
) == 0) {
221 num
= inet_proto_a2n(*argv
);
223 fprintf(stderr
, "Illegal \"ipproto\"\n");
226 pinfo
.protocol
= num
;
228 } else if (matches(*argv
, "classid") == 0 ||
229 strcmp(*argv
, "flowid") == 0) {
232 if (get_tc_classid(&handle
, *argv
)) {
233 fprintf(stderr
, "Illegal \"classid\"\n");
236 addattr_l(n
, 4096, TCA_RSVP_CLASSID
, &handle
, 4);
237 } else if (strcmp(*argv
, "tunnelid") == 0) {
240 if (get_unsigned(&tid
, *argv
, 0)) {
241 fprintf(stderr
, "Illegal \"tunnelid\"\n");
244 pinfo
.tunnelid
= tid
;
246 } else if (strcmp(*argv
, "tunnel") == 0) {
249 if (get_unsigned(&tid
, *argv
, 0)) {
250 fprintf(stderr
, "Illegal \"tunnel\"\n");
253 addattr_l(n
, 4096, TCA_RSVP_CLASSID
, &tid
, 4);
255 if (strcmp(*argv
, "skip") == 0) {
258 if (get_unsigned(&tid
, *argv
, 0)) {
259 fprintf(stderr
, "Illegal \"skip\"\n");
262 pinfo
.tunnelhdr
= tid
;
264 } else if (matches(*argv
, "action") == 0) {
266 if (parse_action(&argc
, &argv
, TCA_RSVP_ACT
, n
)) {
267 fprintf(stderr
, "Illegal \"action\"\n");
271 } else if (matches(*argv
, "police") == 0) {
273 if (parse_police(&argc
, &argv
, TCA_RSVP_POLICE
, n
)) {
274 fprintf(stderr
, "Illegal \"police\"\n");
278 } else if (strcmp(*argv
, "help") == 0) {
282 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
290 addattr_l(n
, 4096, TCA_RSVP_PINFO
, &pinfo
, sizeof(pinfo
));
291 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
295 static char * sprint_spi(struct tc_rsvp_gpi
*pi
, int dir
, char *buf
)
297 if (pi
->offset
== 0) {
298 if (dir
&& pi
->mask
== htonl(0xFFFF)) {
299 snprintf(buf
, SPRINT_BSIZE
-1, "/%d", htonl(pi
->key
));
302 if (!dir
&& pi
->mask
== htonl(0xFFFF0000)) {
303 snprintf(buf
, SPRINT_BSIZE
-1, "/%d", htonl(pi
->key
)>>16);
306 if (pi
->mask
== htonl(0xFFFFFFFF)) {
307 snprintf(buf
, SPRINT_BSIZE
-1, " spi/esp 0x%08x", htonl(pi
->key
));
310 } else if (pi
->offset
== 4 && pi
->mask
== htonl(0xFFFFFFFF)) {
311 snprintf(buf
, SPRINT_BSIZE
-1, " spi/ah 0x%08x", htonl(pi
->key
));
313 } else if (pi
->offset
== -40 && pi
->mask
== htonl(0x000FFFFF)) {
314 snprintf(buf
, SPRINT_BSIZE
-1, " flowlabel 0x%05x", htonl(pi
->key
));
317 snprintf(buf
, SPRINT_BSIZE
-1, " u32 0x%08x mask %08x at %d",
318 htonl(pi
->key
), htonl(pi
->mask
), pi
->offset
);
322 static int rsvp_print_opt(struct filter_util
*qu
, FILE *f
, struct rtattr
*opt
, __u32 handle
)
324 int family
= strcmp(qu
->id
, "rsvp") == 0 ? AF_INET
: AF_INET6
;
325 struct rtattr
*tb
[TCA_RSVP_MAX
+1];
326 struct tc_rsvp_pinfo
*pinfo
= NULL
;
331 parse_rtattr_nested(tb
, TCA_RSVP_MAX
, opt
);
334 fprintf(f
, "fh 0x%08x ", handle
);
336 if (tb
[TCA_RSVP_PINFO
]) {
337 if (RTA_PAYLOAD(tb
[TCA_RSVP_PINFO
]) < sizeof(*pinfo
))
340 pinfo
= RTA_DATA(tb
[TCA_RSVP_PINFO
]);
343 if (tb
[TCA_RSVP_CLASSID
]) {
345 if (!pinfo
|| pinfo
->tunnelhdr
== 0)
346 fprintf(f
, "flowid %s ", sprint_tc_classid(rta_getattr_u32(tb
[TCA_RSVP_CLASSID
]), b1
));
348 fprintf(f
, "tunnel %d skip %d ", rta_getattr_u32(tb
[TCA_RSVP_CLASSID
]), pinfo
->tunnelhdr
);
349 } else if (pinfo
&& pinfo
->tunnelhdr
)
350 fprintf(f
, "tunnel [BAD] skip %d ", pinfo
->tunnelhdr
);
352 if (tb
[TCA_RSVP_DST
]) {
354 fprintf(f
, "session ");
355 if (inet_ntop(family
, RTA_DATA(tb
[TCA_RSVP_DST
]), buf
, sizeof(buf
)) == 0)
356 fprintf(f
, " [INVALID DADDR] ");
358 fprintf(f
, "%s", buf
);
359 if (pinfo
&& pinfo
->dpi
.mask
) {
361 fprintf(f
, "%s ", sprint_spi(&pinfo
->dpi
, 1, b2
));
365 if (pinfo
&& pinfo
->dpi
.mask
) {
367 fprintf(f
, "session [NONE]%s ", sprint_spi(&pinfo
->dpi
, 1, b2
));
369 fprintf(f
, "session NONE ");
372 if (pinfo
&& pinfo
->protocol
) {
374 fprintf(f
, "ipproto %s ", inet_proto_n2a(pinfo
->protocol
, b1
, sizeof(b1
)));
376 if (pinfo
&& pinfo
->tunnelid
)
377 fprintf(f
, "tunnelid %d ", pinfo
->tunnelid
);
378 if (tb
[TCA_RSVP_SRC
]) {
380 fprintf(f
, "sender ");
381 if (inet_ntop(family
, RTA_DATA(tb
[TCA_RSVP_SRC
]), buf
, sizeof(buf
)) == 0) {
384 fprintf(f
, " %s", buf
);
386 if (pinfo
&& pinfo
->spi
.mask
) {
388 fprintf(f
, "%s ", sprint_spi(&pinfo
->spi
, 0, b2
));
391 } else if (pinfo
&& pinfo
->spi
.mask
) {
393 fprintf(f
, "sender [NONE]%s ", sprint_spi(&pinfo
->spi
, 0, b2
));
396 if (tb
[TCA_RSVP_ACT
]) {
397 tc_print_action(f
, tb
[TCA_RSVP_ACT
]);
399 if (tb
[TCA_RSVP_POLICE
])
400 tc_print_police(f
, tb
[TCA_RSVP_POLICE
]);
404 struct filter_util rsvp_filter_util
= {
406 .parse_fopt
= rsvp_parse_opt
,
407 .print_fopt
= rsvp_print_opt
,
410 struct filter_util rsvp6_filter_util
= {
412 .parse_fopt
= rsvp_parse_opt
,
413 .print_fopt
= rsvp_print_opt
,