1 /* $NetBSD: quip_server.c,v 1.4 2001/08/22 08:52:37 itojun Exp $ */
2 /* $KAME: quip_server.c,v 1.6 2001/08/20 06:41:32 kjc Exp $ */
4 * Copyright (C) 1999-2000
5 * Sony Computer Science Laboratories, Inc. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/param.h>
30 #include <sys/socket.h>
31 #include <sys/queue.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
45 #include <altq/altq.h>
46 #include <altq/altq_red.h>
47 #include <altq/altq_rio.h>
50 #include "quip_server.h"
52 extern LIST_HEAD(qop_iflist
, ifinfo
) qop_iflist
;
54 #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
56 static int next_word(char **, char *);
58 static int query_list(const char *, const char *, char *, size_t);
59 static int query_handle2name(const char *, const char *, char *, size_t);
60 static int query_qdisc(const char *, const char *, char *, size_t);
61 static int query_filterspec(const char *, const char *, char *, size_t);
66 char request
[REQ_MAXSIZE
], result
[RES_MAXSIZE
], body
[BODY_MAXSIZE
],
67 w
[REQ_MAXSIZE
], *cp
, *query
;
71 if (fgets(request
, REQ_MAXSIZE
, fp
) == NULL
) /* EOF */
73 /* skip preceding blank lines */
74 if (request
[0] == '\n')
79 /* remove trailing newline and white space */
80 if ((cp
= strrchr(request
, '\n')) != NULL
) {
82 while (*cp
== ' ' || *cp
== '\t')
88 if (!next_word(&cp
, w
)) {
89 snprintf(result
, sizeof(result
), "400 Bad request\n");
92 if (EQUAL(w
, "GET")) {
93 if (!next_word(&cp
, w
)) {
94 snprintf(result
, sizeof(result
), "400 Bad request\n");
97 if ((query
= strchr(w
, '?')) != NULL
) {
98 /* request has a query string */
103 if (EQUAL(w
, "list")) {
104 n
= query_list(w
, query
, body
, BODY_MAXSIZE
);
105 } else if (EQUAL(w
, "handle-to-name")) {
106 n
= query_handle2name(w
, query
, body
, BODY_MAXSIZE
);
107 } else if (EQUAL(w
, "qdisc")) {
108 n
= query_qdisc(w
, query
, body
, BODY_MAXSIZE
);
109 } else if (EQUAL(w
, "filter")) {
110 n
= query_filterspec(w
, query
, body
, BODY_MAXSIZE
);
112 snprintf(result
, sizeof(result
), "400 Bad request\n");
116 snprintf(result
, sizeof(result
), "400 Bad request\n");
121 snprintf(result
, sizeof(result
), "204 No content\n");
123 snprintf(result
, sizeof(result
), "400 Bad request\n");
125 snprintf(result
, sizeof(result
), "200 OK\nContent-Length:%d\n", n
);
129 /* send a result line and a blank line */
130 if (fputs ("QUIP/1.0 ", fp
) != 0 ||
131 fputs(result
, fp
) != 0 || fputs("\n", fp
) != 0)
134 /* send message body */
135 if (fputs(body
, fp
) != 0)
141 * Skip leading blanks, then copy next word (delimited by blank or zero, but
142 * no longer than 63 bytes) into buffer b, set scan pointer to following
143 * non-blank (or end of string), and return 1. If there is no non-blank text,
144 * set scan ptr to point to 0 byte and return 0.
147 next_word(char **cpp
, char *b
)
152 *cpp
+= strspn(*cpp
, " \t");
153 if (**cpp
== '\0' || **cpp
== '\n' || **cpp
== '#')
156 tp
= strpbrk(*cpp
, " \t\n#");
157 L
= MIN((tp
)?(tp
-*cpp
):(int)strlen(*cpp
), 63);
161 *cpp
+= strspn(*cpp
, " \t");
167 * expand_classname creates a long class name.
168 * <ifname>:/<root_name>/../<parent_name>/<class_name>
171 expand_classname(struct classinfo
*clinfo
, char *name
, size_t maxname
)
173 struct classinfo
*ci
= clinfo
;
174 #define CLASSNAMEMAX 256
175 char buf
[2][CLASSNAMEMAX
], *b0
, *b1
, *tmp
;
177 b0
= buf
[0]; b1
= buf
[1];
180 strlcpy(b0
, "/", CLASSNAMEMAX
);
181 strlcat(b0
, ci
->clname
, CLASSNAMEMAX
);
182 strlcat(b0
, b1
, CLASSNAMEMAX
);
185 tmp
= b0
; b0
= b1
; b1
= tmp
;
187 snprintf(b0
, CLASSNAMEMAX
, "%s:", clinfo
->ifinfo
->ifname
);
188 strlcat(b0
, b1
, CLASSNAMEMAX
);
189 strlcpy(name
, b0
, CLASSNAMEMAX
);
190 return (strlen(name
));
195 * expand_filtername creates a long filter name.
196 * <ifname>:/<root_name>/../<parent_name>/<class_name>:<fltr_name>
199 expand_filtername(struct fltrinfo
*fltrinfo
, char *name
, size_t maxname
)
203 len
= expand_classname(fltrinfo
->clinfo
, name
, maxname
);
204 snprintf(name
+ len
, maxname
- len
, ":%s", fltrinfo
->flname
);
205 return (strlen(name
));
209 query_handle2name(const char *cmd
, const char *arg
, char *msg
, size_t maxmsg
)
211 struct ifinfo
*ifinfo
;
212 struct classinfo
*clinfo
;
213 struct fltrinfo
*fltrinfo
;
214 char *ifname
, *class_field
, *fltr_field
, buf
[256], *cp
;
218 strlcpy(buf
, arg
, sizeof(buf
));
220 ifname
= strsep(&cp
, ":");
221 class_field
= strsep(&cp
, ":");
224 if (fltr_field
!= NULL
) {
225 if (sscanf(fltr_field
, "%lx", &handle
) != 1)
227 if ((ifinfo
= ifname2ifinfo(ifname
)) == NULL
)
229 if ((fltrinfo
= flhandle2fltrinfo(ifinfo
, handle
)) == NULL
)
232 len
= expand_filtername(fltrinfo
, msg
, maxmsg
);
234 if (sscanf(class_field
, "%lx", &handle
) != 1)
236 if ((ifinfo
= ifname2ifinfo(ifname
)) == NULL
)
238 if ((clinfo
= clhandle2clinfo(ifinfo
, handle
)) == NULL
)
241 len
= expand_classname(clinfo
, msg
, maxmsg
);
243 strlcat(msg
, "\n", maxmsg
);
244 return (strlen(msg
));
248 query_qdisc(const char *cmd
, const char *arg
, char *msg
, size_t maxmsg
)
250 struct ifinfo
*ifinfo
;
252 if ((ifinfo
= ifname2ifinfo(arg
)) == NULL
)
255 snprintf(msg
, maxmsg
, "%s\nbandwidth:%.2fMbps\nstatus:%s\n",
256 ifinfo
->qdisc
->qname
, (double)ifinfo
->bandwidth
/1000000,
257 (ifinfo
->enabled
? "enabled" : "disabled"));
258 return (strlen(msg
));
262 query_filterspec(const char *cmd
, const char *arg
, char *msg
, size_t maxmsg
)
264 struct ifinfo
*ifinfo
;
265 struct fltrinfo
*fltrinfo
;
266 struct flow_filter
*filt
;
267 char *ifname
, *class_field
, *fltr_field
, buf
[256], *cp
;
270 strlcpy(buf
, arg
, sizeof(buf
));
272 ifname
= strsep(&cp
, ":");
273 class_field
= strsep(&cp
, ":");
276 if (fltr_field
== NULL
)
278 if (sscanf(fltr_field
, "%lx", &handle
) != 1)
281 if ((ifinfo
= ifname2ifinfo(ifname
)) == NULL
)
283 if ((fltrinfo
= flhandle2fltrinfo(ifinfo
, handle
)) == NULL
)
286 filt
= &fltrinfo
->fltr
;
288 if (filt
->ff_flow
.fi_family
== AF_INET
) {
289 char src
[128], dst
[128], smask
[128], dmask
[128], tos
[128];
291 if (filt
->ff_flow
.fi_dst
.s_addr
== 0) {
292 snprintf(dst
, sizeof(dst
), "0");
295 snprintf(dst
, sizeof(dst
), "%s",
296 inet_ntoa(filt
->ff_flow
.fi_dst
));
297 if (filt
->ff_mask
.mask_dst
.s_addr
== 0xffffffff)
300 snprintf(dmask
, sizeof(dmask
), " mask %#x",
301 ntoh32(filt
->ff_mask
.mask_dst
.s_addr
));
303 if (filt
->ff_flow
.fi_src
.s_addr
== 0) {
304 snprintf(src
, sizeof(src
), "0");
307 snprintf(src
, sizeof(src
), "%s",
308 inet_ntoa(filt
->ff_flow
.fi_src
));
309 if (filt
->ff_mask
.mask_src
.s_addr
== 0xffffffff)
312 snprintf(smask
, sizeof(smask
), " mask %#x",
313 ntoh32(filt
->ff_mask
.mask_src
.s_addr
));
315 if (filt
->ff_flow
.fi_tos
== 0)
318 snprintf(tos
, sizeof(tos
), " tos %#x tosmask %#x",
319 filt
->ff_flow
.fi_tos
,
320 filt
->ff_mask
.mask_tos
);
322 snprintf(msg
, maxmsg
, "inet %s%s %d %s%s %d %d%s\n",
324 ntoh16(filt
->ff_flow
.fi_dport
),
326 ntoh16(filt
->ff_flow
.fi_sport
),
327 filt
->ff_flow
.fi_proto
, tos
);
330 else if (filt
->ff_flow
.fi_family
== AF_INET6
) {
331 struct flow_filter6
*filt6
;
332 char dst6
[INET6_ADDRSTRLEN
], dmask6
[INET6_ADDRSTRLEN
];
333 char src6
[INET6_ADDRSTRLEN
], smask6
[INET6_ADDRSTRLEN
];
335 const struct in6_addr mask128
=
336 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
337 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}};
339 filt6
= (struct flow_filter6
*)&fltrinfo
->fltr
;
340 if (IN6_IS_ADDR_UNSPECIFIED(&filt6
->ff_flow6
.fi6_dst
)) {
341 snprintf(dst6
, sizeof(dst6
), "0");
344 inet_ntop(AF_INET6
, &filt6
->ff_flow6
.fi6_dst
,
346 if (IN6_ARE_ADDR_EQUAL(&mask128
,
347 &filt6
->ff_mask6
.mask6_dst
))
350 snprintf(dmask6
, sizeof(dmask6
), " mask ");
351 inet_ntop(AF_INET6
, &filt6
->ff_mask6
.mask6_dst
,
352 dmask6
+ 6, sizeof(dmask6
) -6);
356 if (IN6_IS_ADDR_UNSPECIFIED(&filt6
->ff_flow6
.fi6_src
)) {
357 snprintf(src6
, sizeof(src6
), "0");
360 inet_ntop(AF_INET6
, &filt6
->ff_flow6
.fi6_src
,
362 if (IN6_ARE_ADDR_EQUAL(&mask128
,
363 &filt6
->ff_mask6
.mask6_src
))
366 snprintf(smask6
, sizeof(smask6
), " mask ");
367 inet_ntop(AF_INET6
, &filt6
->ff_mask6
.mask6_src
,
368 smask6
+ 6, sizeof(smask6
) -6);
371 if (filt6
->ff_flow6
.fi6_tclass
== 0)
374 snprintf(tclass6
, sizeof(tclass6
),
375 " tclass %#x tclassmask %#x",
376 filt6
->ff_flow6
.fi6_tclass
,
377 filt6
->ff_mask6
.mask6_tclass
);
379 snprintf(msg
, maxmsg
, "inet6 %s%s %d %s%s %d %d%s\n",
381 ntoh16(filt6
->ff_flow6
.fi6_dport
),
383 ntoh16(filt6
->ff_flow6
.fi6_sport
),
384 filt6
->ff_flow6
.fi6_proto
, tclass6
);
388 return (strlen(msg
));
393 * string_match compares 2 strings and returns 1 when s1 matches s2.
394 * s1: possibly includes wildcards, "*".
395 * s2: must be a full string (should not include "*").
398 string_match(const char *s1
, const char *s2
)
400 char *ap
, *next
, sub
[256];
401 int prefixlen
, sublen
;
403 /* if there's no wild card, compare full string */
404 if ((ap
= strchr(s1
, '*')) == NULL
)
405 return (strcmp(s1
, s2
) == 0);
407 /* compare string prefix */
409 if (strncmp(s1
, s2
, prefixlen
) != 0)
414 * if there is another wildcard in the rest of the string,
415 * compare the substring between the 2 wildcards.
417 while ((next
= strchr(ap
+ 1, '*')) != NULL
) {
418 sublen
= next
- ap
- 1;
419 strncpy(sub
, ap
+1, sublen
);
421 if ((s2
= strstr(s2
, sub
)) == NULL
)
428 /* no more wildcard, compare the rest of the string */
429 return (strcmp(ap
+1, s2
+strlen(s2
)-strlen(ap
+1)) == 0);
433 query_list(const char *cmd
, const char *arg
, char *msg
, size_t maxmsg
)
435 char tmp
[256], *cp
, *ep
;
436 struct ifinfo
*ifinfo
;
437 struct classinfo
*clinfo
;
438 struct fltrinfo
*fltrinfo
;
439 int print_if
, print_class
, print_fltr
, len
;
442 /* no arg, print all */
443 print_if
= print_class
= print_fltr
= 1;
445 print_if
= print_class
= print_fltr
= 0;
446 if ((cp
= strchr(arg
, ':')) == NULL
)
448 else if (strchr(cp
+1, ':') == NULL
)
456 LIST_FOREACH(ifinfo
, &qop_iflist
, next
) {
458 strlcpy(tmp
, ifinfo
->ifname
, sizeof(tmp
));
459 if (arg
== NULL
|| string_match(arg
, tmp
)) {
460 len
= snprintf(cp
, ep
- cp
, "%#010x\t%s\n",
461 ifinfo
->ifindex
, tmp
);
462 if (len
< 0 || len
>= ep
- cp
)
467 if (!print_class
&& !print_fltr
)
469 for (clinfo
= get_rootclass(ifinfo
);
470 clinfo
!= NULL
; clinfo
= get_nextclass(clinfo
)) {
472 expand_classname(clinfo
, tmp
, sizeof(tmp
));
473 if (arg
== NULL
|| string_match(arg
, tmp
)) {
474 len
= snprintf(cp
, ep
- cp
,
476 clinfo
->handle
, tmp
);
477 if (len
< 0 || len
>= ep
- cp
)
484 LIST_FOREACH(fltrinfo
, &clinfo
->fltrlist
, next
) {
485 expand_filtername(fltrinfo
, tmp
, sizeof(tmp
));
486 if (arg
== NULL
|| string_match(arg
, tmp
)) {
487 len
= snprintf(cp
, ep
- cp
, "%#010lx\t%s\n",
488 fltrinfo
->handle
, tmp
);
489 if (len
< 0 || len
>= ep
- cp
)
496 return (strlen(msg
));