Bug Summary

File:src/usr.bin/bgplg/bgpctl/../../../usr.sbin/bgpctl/bgpctl.c
Warning:line 1183, column 10
Although the value stored to 'linelen' is used in the enclosing expression, the value is never actually read from 'linelen'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name bgpctl.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/bgplg/bgpctl/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/usr.bin/bgplg/bgpctl/../../../usr.sbin/bgpctl -I /usr/src/usr.bin/bgplg/bgpctl/../../../usr.sbin/bgpctl/../bgpd -I /usr/src/usr.bin/bgplg/bgpctl -I /usr/src/usr.bin/bgplg/bgpctl/../bgpd -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/bgplg/bgpctl/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.bin/bgplg/bgpctl/../../../usr.sbin/bgpctl/bgpctl.c
1/* $OpenBSD: bgpctl.c,v 1.299 2024/01/08 15:09:14 claudio Exp $ */
2
3/*
4 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 2004-2019 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2016 Job Snijders <job@instituut.net>
7 * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22#include <sys/time.h>
23#include <sys/types.h>
24#include <sys/socket.h>
25#include <sys/stat.h>
26#include <sys/un.h>
27
28#include <endian.h>
29#include <err.h>
30#include <errno(*__errno()).h>
31#include <fcntl.h>
32#include <math.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <time.h>
37#include <unistd.h>
38#include <util.h>
39
40#include "bgpd.h"
41#include "session.h"
42#include "rde.h"
43#include "version.h"
44
45#include "bgpctl.h"
46#include "parser.h"
47#include "mrtparser.h"
48
49int main(int, char *[]);
50int show(struct imsg *, struct parse_result *);
51void send_filterset(struct imsgbuf *, struct filter_set_head *);
52void show_mrt_dump_neighbors(struct mrt_rib *, struct mrt_peer *,
53 void *);
54void show_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *);
55void network_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *);
56void show_mrt_state(struct mrt_bgp_state *, void *);
57void show_mrt_msg(struct mrt_bgp_msg *, void *);
58const char *msg_type(uint8_t);
59void network_bulk(struct parse_result *);
60int match_aspath(void *, uint16_t, struct filter_as *);
61struct flowspec *res_to_flowspec(struct parse_result *);
62
63struct imsgbuf *imsgbuf;
64struct mrt_parser show_mrt = { show_mrt_dump, show_mrt_state, show_mrt_msg };
65struct mrt_parser net_mrt = { network_mrt_dump, NULL((void *)0), NULL((void *)0) };
66const struct output *output = &show_output;
67int tableid;
68int nodescr;
69
70__dead__attribute__((__noreturn__)) void
71usage(void)
72{
73 extern char *__progname;
74
75 fprintf(stderr(&__sF[2]), "usage: %s [-jnV] [-s socket] command [argument ...]\n",
76 __progname);
77 exit(1);
78}
79
80int
81main(int argc, char *argv[])
82{
83 struct sockaddr_un sa_un;
84 int fd, n, done, numdone, ch, verbose = 0;
85 struct imsg imsg;
86 struct network_config net;
87 struct parse_result *res;
88 struct ctl_neighbor neighbor;
89 struct ctl_show_rib_request ribreq;
90 struct flowspec *f;
91 char *sockname;
92 enum imsg_type type;
93
94 if (pledge("stdio rpath wpath cpath unix inet dns", NULL((void *)0)) == -1)
95 err(1, "pledge");
96
97 tableid = getrtable();
98 if (asprintf(&sockname, "%s.%d", SOCKET_NAME"/var/run/bgpd.sock", tableid) == -1)
99 err(1, "asprintf");
100
101 while ((ch = getopt(argc, argv, "jns:V")) != -1) {
102 switch (ch) {
103 case 'n':
104 if (++nodescr > 1)
105 usage();
106 break;
107 case 'j':
108 output = &json_output;
109 break;
110 case 's':
111 sockname = optarg;
112 break;
113 case 'V':
114 fprintf(stderr(&__sF[2]), "OpenBGPD %s\n", BGPD_VERSION"8.3");
115 return 0;
116 default:
117 usage();
118 /* NOTREACHED */
119 }
120 }
121 argc -= optind;
122 argv += optind;
123
124 if ((res = parse(argc, argv)) == NULL((void *)0))
125 exit(1);
126
127 memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr));
128 strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr));
129 neighbor.is_group = res->is_group;
130 strlcpy(neighbor.reason, res->reason, sizeof(neighbor.reason));
131
132 switch (res->action) {
133 case SHOW_MRT:
134 if (pledge("stdio", NULL((void *)0)) == -1)
135 err(1, "pledge");
136
137 memset(&ribreq, 0, sizeof(ribreq));
138 if (res->as.type != AS_UNDEF)
139 ribreq.as = res->as;
140 if (res->addr.aid) {
141 ribreq.prefix = res->addr;
142 ribreq.prefixlen = res->prefixlen;
143 }
144 /* XXX currently no communities support */
145 ribreq.neighbor = neighbor;
146 ribreq.aid = res->aid;
147 ribreq.flags = res->flags;
148 ribreq.validation_state = res->validation_state;
149 show_mrt.arg = &ribreq;
150 if (res->flags & F_CTL_NEIGHBORS0x400000)
151 show_mrt.dump = show_mrt_dump_neighbors;
152 else
153 output->head(res);
154 mrt_parse(res->mrtfd, &show_mrt, 1);
155 exit(0);
156 default:
157 break;
158 }
159
160 if (pledge("stdio unix", NULL((void *)0)) == -1)
161 err(1, "pledge");
162
163 if ((fd = socket(AF_UNIX1, SOCK_STREAM1, 0)) == -1)
164 err(1, "control_init: socket");
165
166 memset(&sa_un, 0, sizeof(sa_un));
167 sa_un.sun_family = AF_UNIX1;
168 if (strlcpy(sa_un.sun_path, sockname, sizeof(sa_un.sun_path)) >=
169 sizeof(sa_un.sun_path))
170 errx(1, "socket name too long");
171 if (connect(fd, (struct sockaddr *)&sa_un, sizeof(sa_un)) == -1)
172 err(1, "connect: %s", sockname);
173
174 if (pledge("stdio", NULL((void *)0)) == -1)
175 err(1, "pledge");
176
177 if ((imsgbuf = malloc(sizeof(struct imsgbuf))) == NULL((void *)0))
178 err(1, NULL((void *)0));
179 imsg_init(imsgbuf, fd);
180 done = 0;
181
182 switch (res->action) {
183 case NONE:
184 case SHOW_MRT:
185 usage();
186 /* NOTREACHED */
187 case SHOW:
188 case SHOW_SUMMARY:
189 imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
190 NULL((void *)0), 0);
191 break;
192 case SHOW_SUMMARY_TERSE:
193 imsg_compose(imsgbuf, IMSG_CTL_SHOW_TERSE, 0, 0, -1, NULL((void *)0), 0);
194 break;
195 case SHOW_FIB:
196 if (!res->addr.aid) {
197 struct ctl_kroute_req req = { 0 };
198
199 req.af = aid2af(res->aid);
200 req.flags = res->flags;
201
202 imsg_compose(imsgbuf, IMSG_CTL_KROUTE, res->rtableid,
203 0, -1, &req, sizeof(req));
204 } else
205 imsg_compose(imsgbuf, IMSG_CTL_KROUTE_ADDR,
206 res->rtableid, 0, -1,
207 &res->addr, sizeof(res->addr));
208 break;
209 case SHOW_FIB_TABLES:
210 imsg_compose(imsgbuf, IMSG_CTL_SHOW_FIB_TABLES, 0, 0, -1,
211 NULL((void *)0), 0);
212 break;
213 case SHOW_NEXTHOP:
214 imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEXTHOP, res->rtableid,
215 0, -1, NULL((void *)0), 0);
216 break;
217 case SHOW_INTERFACE:
218 imsg_compose(imsgbuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
219 NULL((void *)0), 0);
220 break;
221 case SHOW_SET:
222 imsg_compose(imsgbuf, IMSG_CTL_SHOW_SET, 0, 0, -1, NULL((void *)0), 0);
223 break;
224 case SHOW_RTR:
225 imsg_compose(imsgbuf, IMSG_CTL_SHOW_RTR, 0, 0, -1, NULL((void *)0), 0);
226 break;
227 case SHOW_NEIGHBOR:
228 case SHOW_NEIGHBOR_TIMERS:
229 case SHOW_NEIGHBOR_TERSE:
230 neighbor.show_timers = (res->action == SHOW_NEIGHBOR_TIMERS);
231 if (res->peeraddr.aid || res->peerdesc[0])
232 imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
233 &neighbor, sizeof(neighbor));
234 else
235 imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
236 NULL((void *)0), 0);
237 break;
238 case SHOW_RIB:
239 memset(&ribreq, 0, sizeof(ribreq));
240 type = IMSG_CTL_SHOW_RIB;
241 if (res->addr.aid) {
242 ribreq.prefix = res->addr;
243 ribreq.prefixlen = res->prefixlen;
244 type = IMSG_CTL_SHOW_RIB_PREFIX;
245 }
246 if (res->as.type != AS_UNDEF)
247 ribreq.as = res->as;
248 if (res->community.flags != 0)
249 ribreq.community = res->community;
250 ribreq.neighbor = neighbor;
251 strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
252 ribreq.aid = res->aid;
253 ribreq.path_id = res->pathid;
254 ribreq.flags = res->flags;
255 imsg_compose(imsgbuf, type, 0, 0, -1, &ribreq, sizeof(ribreq));
256 break;
257 case SHOW_RIB_MEM:
258 imsg_compose(imsgbuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL((void *)0), 0);
259 break;
260 case SHOW_METRICS:
261 output = &ometric_output;
262 numdone = 2;
263 imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
264 NULL((void *)0), 0);
265 imsg_compose(imsgbuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL((void *)0), 0);
266 break;
267 case RELOAD:
268 imsg_compose(imsgbuf, IMSG_CTL_RELOAD, 0, 0, -1,
269 res->reason, sizeof(res->reason));
270 if (res->reason[0])
271 printf("reload request sent: %s\n", res->reason);
272 else
273 printf("reload request sent.\n");
274 break;
275 case FIB:
276 errx(1, "action==FIB");
277 break;
278 case FIB_COUPLE:
279 imsg_compose(imsgbuf, IMSG_CTL_FIB_COUPLE, res->rtableid, 0, -1,
280 NULL((void *)0), 0);
281 printf("couple request sent.\n");
282 done = 1;
283 break;
284 case FIB_DECOUPLE:
285 imsg_compose(imsgbuf, IMSG_CTL_FIB_DECOUPLE, res->rtableid,
286 0, -1, NULL((void *)0), 0);
287 printf("decouple request sent.\n");
288 done = 1;
289 break;
290 case NEIGHBOR:
291 errx(1, "action==NEIGHBOR");
292 break;
293 case NEIGHBOR_UP:
294 imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_UP, 0, 0, -1,
295 &neighbor, sizeof(neighbor));
296 break;
297 case NEIGHBOR_DOWN:
298 imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_DOWN, 0, 0, -1,
299 &neighbor, sizeof(neighbor));
300 break;
301 case NEIGHBOR_CLEAR:
302 imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_CLEAR, 0, 0, -1,
303 &neighbor, sizeof(neighbor));
304 break;
305 case NEIGHBOR_RREFRESH:
306 imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_RREFRESH, 0, 0, -1,
307 &neighbor, sizeof(neighbor));
308 break;
309 case NEIGHBOR_DESTROY:
310 imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_DESTROY, 0, 0, -1,
311 &neighbor, sizeof(neighbor));
312 break;
313 case NETWORK_BULK_ADD:
314 case NETWORK_BULK_REMOVE:
315 network_bulk(res);
316 printf("requests sent.\n");
317 done = 1;
318 break;
319 case NETWORK_ADD:
320 case NETWORK_REMOVE:
321 memset(&net, 0, sizeof(net));
322 net.prefix = res->addr;
323 net.prefixlen = res->prefixlen;
324 net.rd = res->rd;
325 /* attribute sets are not supported */
326 if (res->action == NETWORK_ADD) {
327 imsg_compose(imsgbuf, IMSG_NETWORK_ADD, 0, 0, -1,
328 &net, sizeof(net));
329 send_filterset(imsgbuf, &res->set);
330 imsg_compose(imsgbuf, IMSG_NETWORK_DONE, 0, 0, -1,
331 NULL((void *)0), 0);
332 } else
333 imsg_compose(imsgbuf, IMSG_NETWORK_REMOVE, 0, 0, -1,
334 &net, sizeof(net));
335 printf("request sent.\n");
336 done = 1;
337 break;
338 case NETWORK_FLUSH:
339 imsg_compose(imsgbuf, IMSG_NETWORK_FLUSH, 0, 0, -1, NULL((void *)0), 0);
340 printf("request sent.\n");
341 done = 1;
342 break;
343 case NETWORK_SHOW:
344 memset(&ribreq, 0, sizeof(ribreq));
345 ribreq.aid = res->aid;
346 strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
347 imsg_compose(imsgbuf, IMSG_CTL_SHOW_NETWORK, 0, 0, -1,
348 &ribreq, sizeof(ribreq));
349 break;
350 case NETWORK_MRT:
351 memset(&ribreq, 0, sizeof(ribreq));
352 if (res->as.type != AS_UNDEF)
353 ribreq.as = res->as;
354 if (res->addr.aid) {
355 ribreq.prefix = res->addr;
356 ribreq.prefixlen = res->prefixlen;
357 }
358 /* XXX currently no community support */
359 ribreq.neighbor = neighbor;
360 ribreq.aid = res->aid;
361 ribreq.flags = res->flags;
362 net_mrt.arg = &ribreq;
363 mrt_parse(res->mrtfd, &net_mrt, 1);
364 done = 1;
365 break;
366 case FLOWSPEC_ADD:
367 case FLOWSPEC_REMOVE:
368 f = res_to_flowspec(res);
369 /* attribute sets are not supported */
370 if (res->action == FLOWSPEC_ADD) {
371 imsg_compose(imsgbuf, IMSG_FLOWSPEC_ADD, 0, 0, -1,
372 f, FLOWSPEC_SIZE(__builtin_offsetof(struct flowspec, data)) + f->len);
373 send_filterset(imsgbuf, &res->set);
374 imsg_compose(imsgbuf, IMSG_FLOWSPEC_DONE, 0, 0, -1,
375 NULL((void *)0), 0);
376 } else
377 imsg_compose(imsgbuf, IMSG_FLOWSPEC_REMOVE, 0, 0, -1,
378 f, FLOWSPEC_SIZE(__builtin_offsetof(struct flowspec, data)) + f->len);
379 printf("request sent.\n");
380 done = 1;
381 break;
382 case FLOWSPEC_FLUSH:
383 imsg_compose(imsgbuf, IMSG_FLOWSPEC_FLUSH, 0, 0, -1, NULL((void *)0), 0);
384 printf("request sent.\n");
385 done = 1;
386 break;
387 case FLOWSPEC_SHOW:
388 memset(&ribreq, 0, sizeof(ribreq));
389 switch (res->aid) {
390 case AID_INET1:
391 ribreq.aid = AID_FLOWSPECv45;
392 break;
393 case AID_INET62:
394 ribreq.aid = AID_FLOWSPECv66;
395 break;
396 case AID_UNSPEC0:
397 ribreq.aid = res->aid;
398 break;
399 default:
400 errx(1, "flowspec family %s currently not supported",
401 aid2str(res->aid));
402 }
403 strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
404 imsg_compose(imsgbuf, IMSG_CTL_SHOW_FLOWSPEC, 0, 0, -1,
405 &ribreq, sizeof(ribreq));
406 break;
407 case LOG_VERBOSE:
408 verbose = 1;
409 /* FALLTHROUGH */
410 case LOG_BRIEF:
411 imsg_compose(imsgbuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
412 &verbose, sizeof(verbose));
413 printf("logging request sent.\n");
414 done = 1;
415 break;
416 }
417
418 output->head(res);
419
420 again:
421 while (imsgbuf->w.queued)
422 if (msgbuf_write(&imsgbuf->w) <= 0)
423 err(1, "write error");
424
425 while (!done) {
426 while (!done) {
427 if ((n = imsg_get(imsgbuf, &imsg)) == -1)
428 err(1, "imsg_get error");
429 if (n == 0)
430 break;
431
432 done = show(&imsg, res);
433 imsg_free(&imsg);
434 }
435
436 if (done)
437 break;
438
439 if ((n = imsg_read(imsgbuf)) == -1)
440 err(1, "imsg_read error");
441 if (n == 0)
442 errx(1, "pipe closed");
443
444 }
445
446 if (res->action == SHOW_METRICS && --numdone > 0) {
447 done = 0;
448 goto again;
449 }
450
451 output->tail();
452
453 close(fd);
454 free(imsgbuf);
455
456 exit(0);
457}
458
459int
460show(struct imsg *imsg, struct parse_result *res)
461{
462 struct peer *p;
463 struct ctl_timer t;
464 struct ctl_show_interface *iface;
465 struct ctl_show_nexthop *nh;
466 struct ctl_show_set set;
467 struct ctl_show_rtr rtr;
468 struct kroute_full *kf;
469 struct ktable *kt;
470 struct flowspec *f;
471 struct ctl_show_rib rib;
472 struct rde_memstats stats;
473 u_char *asdata;
474 u_int rescode, ilen;
475 size_t aslen;
476
477 switch (imsg->hdr.type) {
478 case IMSG_CTL_SHOW_NEIGHBOR:
479 if (output->neighbor == NULL((void *)0))
480 break;
481 p = imsg->data;
482 output->neighbor(p, res);
483 break;
484 case IMSG_CTL_SHOW_TIMER:
485 if (imsg->hdr.len < IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(t))
486 errx(1, "wrong imsg len");
487 if (output->timer == NULL((void *)0))
488 break;
489 memcpy(&t, imsg->data, sizeof(t));
490 if (t.type > 0 && t.type < Timer_Max)
491 output->timer(&t);
492 break;
493 case IMSG_CTL_SHOW_INTERFACE:
494 if (output->interface == NULL((void *)0))
495 break;
496 iface = imsg->data;
497 output->interface(iface);
498 break;
499 case IMSG_CTL_SHOW_NEXTHOP:
500 if (output->nexthop == NULL((void *)0))
501 break;
502 nh = imsg->data;
503 output->nexthop(nh);
504 break;
505 case IMSG_CTL_KROUTE:
506 case IMSG_CTL_SHOW_NETWORK:
507 if (imsg->hdr.len < IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*kf))
508 errx(1, "wrong imsg len");
509 if (output->fib == NULL((void *)0))
510 break;
511 kf = imsg->data;
512 output->fib(kf);
513 break;
514 case IMSG_CTL_SHOW_FLOWSPEC:
515 if (imsg->hdr.len < IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*f))
516 errx(1, "wrong imsg len");
517 if (output->flowspec == NULL((void *)0))
518 break;
519 f = imsg->data;
520 output->flowspec(f);
521 break;
522 case IMSG_CTL_SHOW_FIB_TABLES:
523 if (imsg->hdr.len < IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(*kt))
524 errx(1, "wrong imsg len");
525 if (output->fib_table == NULL((void *)0))
526 break;
527 kt = imsg->data;
528 output->fib_table(kt);
529 break;
530 case IMSG_CTL_SHOW_RIB:
531 if (imsg->hdr.len < IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(rib))
532 errx(1, "wrong imsg len");
533 if (output->rib == NULL((void *)0))
534 break;
535 memcpy(&rib, imsg->data, sizeof(rib));
536 aslen = imsg->hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) - sizeof(rib);
537 asdata = imsg->data;
538 asdata += sizeof(rib);
539 output->rib(&rib, asdata, aslen, res);
540 break;
541 case IMSG_CTL_SHOW_RIB_COMMUNITIES:
542 ilen = imsg->hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr);
543 if (ilen % sizeof(struct community)) {
544 warnx("bad IMSG_CTL_SHOW_RIB_COMMUNITIES received");
545 break;
546 }
547 if (output->communities == NULL((void *)0))
548 break;
549 output->communities(imsg->data, ilen, res);
550 break;
551 case IMSG_CTL_SHOW_RIB_ATTR:
552 ilen = imsg->hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr);
553 if (ilen < 3) {
554 warnx("bad IMSG_CTL_SHOW_RIB_ATTR received");
555 break;
556 }
557 if (output->attr == NULL((void *)0))
558 break;
559 output->attr(imsg->data, ilen, res->flags, 0);
560 break;
561 case IMSG_CTL_SHOW_RIB_MEM:
562 if (imsg->hdr.len < IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(stats))
563 errx(1, "wrong imsg len");
564 if (output->rib_mem == NULL((void *)0))
565 break;
566 memcpy(&stats, imsg->data, sizeof(stats));
567 output->rib_mem(&stats);
568 return (1);
569 case IMSG_CTL_SHOW_SET:
570 if (imsg->hdr.len < IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(set))
571 errx(1, "wrong imsg len");
572 if (output->set == NULL((void *)0))
573 break;
574 memcpy(&set, imsg->data, sizeof(set));
575 output->set(&set);
576 break;
577 case IMSG_CTL_SHOW_RTR:
578 if (imsg->hdr.len < IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(rtr))
579 errx(1, "wrong imsg len");
580 if (output->rtr == NULL((void *)0))
581 break;
582 memcpy(&rtr, imsg->data, sizeof(rtr));
583 output->rtr(&rtr);
584 break;
585 case IMSG_CTL_RESULT:
586 if (imsg->hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof(rescode)) {
587 warnx("got IMSG_CTL_RESULT with wrong len");
588 break;
589 }
590 if (output->result == NULL((void *)0))
591 break;
592 memcpy(&rescode, imsg->data, sizeof(rescode));
593 output->result(rescode);
594 return (1);
595 case IMSG_CTL_END:
596 return (1);
597 default:
598 warnx("unknown imsg %d received", imsg->hdr.type);
599 break;
600 }
601
602 return (0);
603}
604
605time_t
606get_monotime(time_t t)
607{
608 struct timespec ts;
609
610 if (t == 0)
611 return -1;
612 if (clock_gettime(CLOCK_MONOTONIC3, &ts) != 0)
613 err(1, "clock_gettime");
614 if (t > ts.tv_sec) /* time in the future is not possible */
615 t = ts.tv_sec;
616 return (ts.tv_sec - t);
617}
618
619char *
620fmt_peer(const char *descr, const struct bgpd_addr *remote_addr,
621 int masklen)
622{
623 const char *ip;
624 char *p;
625
626 if (descr && descr[0] && !nodescr) {
627 if ((p = strdup(descr)) == NULL((void *)0))
628 err(1, NULL((void *)0));
629 return (p);
630 }
631
632 ip = log_addr(remote_addr);
633 if (masklen != -1 && ((remote_addr->aid == AID_INET1 && masklen != 32) ||
634 (remote_addr->aid == AID_INET62 && masklen != 128))) {
635 if (asprintf(&p, "%s/%u", ip, masklen) == -1)
636 err(1, NULL((void *)0));
637 } else {
638 if ((p = strdup(ip)) == NULL((void *)0))
639 err(1, NULL((void *)0));
640 }
641
642 return (p);
643}
644
645const char *
646fmt_auth_method(enum auth_method method)
647{
648 switch (method) {
649 case AUTH_MD5SIG:
650 return ", using md5sig";
651 case AUTH_IPSEC_MANUAL_ESP:
652 return ", using ipsec manual esp";
653 case AUTH_IPSEC_MANUAL_AH:
654 return ", using ipsec manual ah";
655 case AUTH_IPSEC_IKE_ESP:
656 return ", using ipsec ike esp";
657 case AUTH_IPSEC_IKE_AH:
658 return ", using ipsec ike ah";
659 case AUTH_NONE: /* FALLTHROUGH */
660 default:
661 return "";
662 }
663}
664
665#define TF_LEN16 16
666
667const char *
668fmt_timeframe(time_t t)
669{
670 static char buf[TF_LEN16];
671 unsigned int sec, min, hrs, day;
672 unsigned long long week;
673
674 if (t < 0)
675 t = 0;
676 week = t;
677
678 sec = week % 60;
679 week /= 60;
680 min = week % 60;
681 week /= 60;
682 hrs = week % 24;
683 week /= 24;
684 day = week % 7;
685 week /= 7;
686
687 if (week >= 1000)
688 snprintf(buf, TF_LEN16, "%02lluw", week);
689 else if (week > 0)
690 snprintf(buf, TF_LEN16, "%02lluw%01ud%02uh", week, day, hrs);
691 else if (day > 0)
692 snprintf(buf, TF_LEN16, "%01ud%02uh%02um", day, hrs, min);
693 else
694 snprintf(buf, TF_LEN16, "%02u:%02u:%02u", hrs, min, sec);
695
696 return (buf);
697}
698
699const char *
700fmt_monotime(time_t t)
701{
702 t = get_monotime(t);
703
704 if (t == -1)
705 return ("Never");
706
707 return (fmt_timeframe(t));
708}
709
710const char *
711fmt_fib_flags(uint16_t flags)
712{
713 static char buf[8];
714
715 if (flags & F_BGPD0x0001)
716 strlcpy(buf, "B", sizeof(buf));
717 else if (flags & F_CONNECTED0x0004)
718 strlcpy(buf, "C", sizeof(buf));
719 else if (flags & F_STATIC0x0008)
720 strlcpy(buf, "S", sizeof(buf));
721 else
722 strlcpy(buf, " ", sizeof(buf));
723
724 if (flags & F_NEXTHOP0x0010)
725 strlcat(buf, "N", sizeof(buf));
726 else
727 strlcat(buf, " ", sizeof(buf));
728
729 if (flags & F_REJECT0x0020 && flags & F_BLACKHOLE0x0040)
730 strlcat(buf, "f", sizeof(buf));
731 else if (flags & F_REJECT0x0020)
732 strlcat(buf, "r", sizeof(buf));
733 else if (flags & F_BLACKHOLE0x0040)
734 strlcat(buf, "b", sizeof(buf));
735 else
736 strlcat(buf, " ", sizeof(buf));
737
738 return buf;
739}
740
741const char *
742fmt_origin(uint8_t origin, int sum)
743{
744 switch (origin) {
745 case ORIGIN_IGP0:
746 return (sum ? "i" : "IGP");
747 case ORIGIN_EGP1:
748 return (sum ? "e" : "EGP");
749 case ORIGIN_INCOMPLETE2:
750 return (sum ? "?" : "incomplete");
751 default:
752 return (sum ? "X" : "bad origin");
753 }
754}
755
756const char *
757fmt_flags(uint32_t flags, int sum)
758{
759 static char buf[80];
760 char flagstr[5];
761 char *p = flagstr;
762
763 if (sum) {
764 if (flags & F_PREF_INVALID0x020)
765 *p++ = 'E';
766 if (flags & F_PREF_OTC_LEAK0x080)
767 *p++ = 'L';
768 if (flags & F_PREF_ANNOUNCE0x008)
769 *p++ = 'A';
770 if (flags & F_PREF_INTERNAL0x004)
771 *p++ = 'I';
772 if (flags & F_PREF_STALE0x010)
773 *p++ = 'S';
774 if (flags & F_PREF_ELIGIBLE0x001)
775 *p++ = '*';
776 if (flags & F_PREF_BEST0x002)
777 *p++ = '>';
778 if (flags & F_PREF_ECMP0x100)
779 *p++ = 'm';
780 if (flags & F_PREF_AS_WIDE0x200)
781 *p++ = 'w';
782 *p = '\0';
783 snprintf(buf, sizeof(buf), "%-5s", flagstr);
784 } else {
785 if (flags & F_PREF_INTERNAL0x004)
786 strlcpy(buf, "internal", sizeof(buf));
787 else
788 strlcpy(buf, "external", sizeof(buf));
789
790 if (flags & F_PREF_INVALID0x020)
791 strlcat(buf, ", invalid", sizeof(buf));
792 if (flags & F_PREF_OTC_LEAK0x080)
793 strlcat(buf, ", otc leak", sizeof(buf));
794 if (flags & F_PREF_STALE0x010)
795 strlcat(buf, ", stale", sizeof(buf));
796 if (flags & F_PREF_ELIGIBLE0x001)
797 strlcat(buf, ", valid", sizeof(buf));
798 if (flags & F_PREF_BEST0x002)
799 strlcat(buf, ", best", sizeof(buf));
800 if (flags & F_PREF_ECMP0x100)
801 strlcat(buf, ", ecmp", sizeof(buf));
802 if (flags & F_PREF_AS_WIDE0x200)
803 strlcat(buf, ", as-wide", sizeof(buf));
804 if (flags & F_PREF_ANNOUNCE0x008)
805 strlcat(buf, ", announced", sizeof(buf));
806 if (strlen(buf) >= sizeof(buf) - 1)
807 errx(1, "%s buffer too small", __func__);
808 }
809
810 return buf;
811}
812
813const char *
814fmt_ovs(uint8_t validation_state, int sum)
815{
816 switch (validation_state) {
817 case ROA_INVALID0x1:
818 return (sum ? "!" : "invalid");
819 case ROA_VALID0x2:
820 return (sum ? "V" : "valid");
821 default:
822 return (sum ? "N" : "not-found");
823 }
824}
825
826const char *
827fmt_avs(uint8_t validation_state, int sum)
828{
829 switch (validation_state) {
830 case ASPA_INVALID0x01:
831 return (sum ? "!" : "invalid");
832 case ASPA_VALID0x02:
833 return (sum ? "V" : "valid");
834 default:
835 return (sum ? "?" : "unknown");
836 }
837}
838
839const char *
840fmt_mem(long long num)
841{
842 static char buf[16];
843
844 if (fmt_scaled(num, buf) == -1)
845 snprintf(buf, sizeof(buf), "%lldB", num);
846
847 return (buf);
848}
849
850const char *
851fmt_errstr(uint8_t errcode, uint8_t subcode)
852{
853 static char errbuf[256];
854 const char *errstr = NULL((void *)0);
855 const char *suberr = NULL((void *)0);
856 int uk = 0;
857
858 if (errcode == 0) /* no error */
859 return NULL((void *)0);
860
861 if (errcode < sizeof(errnames)/sizeof(char *))
862 errstr = errnames[errcode];
863
864 switch (errcode) {
865 case ERR_HEADER:
866 if (subcode < sizeof(suberr_header_names)/sizeof(char *))
867 suberr = suberr_header_names[subcode];
868 else
869 uk = 1;
870 break;
871 case ERR_OPEN:
872 if (subcode < sizeof(suberr_open_names)/sizeof(char *))
873 suberr = suberr_open_names[subcode];
874 else
875 uk = 1;
876 break;
877 case ERR_UPDATE:
878 if (subcode < sizeof(suberr_update_names)/sizeof(char *))
879 suberr = suberr_update_names[subcode];
880 else
881 uk = 1;
882 break;
883 case ERR_HOLDTIMEREXPIRED:
884 if (subcode != 0)
885 uk = 1;
886 break;
887 case ERR_FSM:
888 if (subcode < sizeof(suberr_fsm_names)/sizeof(char *))
889 suberr = suberr_fsm_names[subcode];
890 else
891 uk = 1;
892 break;
893 case ERR_CEASE:
894 if (subcode < sizeof(suberr_cease_names)/sizeof(char *))
895 suberr = suberr_cease_names[subcode];
896 else
897 uk = 1;
898 break;
899 default:
900 snprintf(errbuf, sizeof(errbuf),
901 "unknown error code %u subcode %u", errcode, subcode);
902 return (errbuf);
903 }
904
905 if (uk)
906 snprintf(errbuf, sizeof(errbuf),
907 "%s, unknown subcode %u", errstr, subcode);
908 else if (suberr == NULL((void *)0))
909 return (errstr);
910 else
911 snprintf(errbuf, sizeof(errbuf),
912 "%s, %s", errstr, suberr);
913
914 return (errbuf);
915}
916
917const char *
918fmt_attr(uint8_t type, int flags)
919{
920#define CHECK_FLAGS(s, t, m) \
921 if (((s) & ~(ATTR_DEFMASK(0x0f | 0x10) | (m))) != (t)) pflags = 1
922
923 static char cstr[48];
924 int pflags = 0;
925
926 switch (type) {
927 case ATTR_ORIGIN:
928 CHECK_FLAGS(flags, ATTR_WELL_KNOWN0x40, 0);
929 strlcpy(cstr, "Origin", sizeof(cstr));
930 break;
931 case ATTR_ASPATH:
932 CHECK_FLAGS(flags, ATTR_WELL_KNOWN0x40, 0);
933 strlcpy(cstr, "AS-Path", sizeof(cstr));
934 break;
935 case ATTR_AS4_PATH:
936 CHECK_FLAGS(flags, ATTR_WELL_KNOWN0x40, 0);
937 strlcpy(cstr, "AS4-Path", sizeof(cstr));
938 break;
939 case ATTR_NEXTHOP:
940 CHECK_FLAGS(flags, ATTR_WELL_KNOWN0x40, 0);
941 strlcpy(cstr, "Nexthop", sizeof(cstr));
942 break;
943 case ATTR_MED:
944 CHECK_FLAGS(flags, ATTR_OPTIONAL0x80, 0);
945 strlcpy(cstr, "Med", sizeof(cstr));
946 break;
947 case ATTR_LOCALPREF:
948 CHECK_FLAGS(flags, ATTR_WELL_KNOWN0x40, 0);
949 strlcpy(cstr, "Localpref", sizeof(cstr));
950 break;
951 case ATTR_ATOMIC_AGGREGATE:
952 CHECK_FLAGS(flags, ATTR_WELL_KNOWN0x40, 0);
953 strlcpy(cstr, "Atomic Aggregate", sizeof(cstr));
954 break;
955 case ATTR_AGGREGATOR:
956 CHECK_FLAGS(flags, ATTR_OPTIONAL0x80|ATTR_TRANSITIVE0x40, ATTR_PARTIAL0x20);
957 strlcpy(cstr, "Aggregator", sizeof(cstr));
958 break;
959 case ATTR_AS4_AGGREGATOR:
960 CHECK_FLAGS(flags, ATTR_OPTIONAL0x80|ATTR_TRANSITIVE0x40, ATTR_PARTIAL0x20);
961 strlcpy(cstr, "AS4-Aggregator", sizeof(cstr));
962 break;
963 case ATTR_COMMUNITIES:
964 CHECK_FLAGS(flags, ATTR_OPTIONAL0x80|ATTR_TRANSITIVE0x40, ATTR_PARTIAL0x20);
965 strlcpy(cstr, "Communities", sizeof(cstr));
966 break;
967 case ATTR_ORIGINATOR_ID:
968 CHECK_FLAGS(flags, ATTR_OPTIONAL0x80, 0);
969 strlcpy(cstr, "Originator Id", sizeof(cstr));
970 break;
971 case ATTR_CLUSTER_LIST:
972 CHECK_FLAGS(flags, ATTR_OPTIONAL0x80, 0);
973 strlcpy(cstr, "Cluster Id List", sizeof(cstr));
974 break;
975 case ATTR_MP_REACH_NLRI:
976 CHECK_FLAGS(flags, ATTR_OPTIONAL0x80, 0);
977 strlcpy(cstr, "MP Reach NLRI", sizeof(cstr));
978 break;
979 case ATTR_MP_UNREACH_NLRI:
980 CHECK_FLAGS(flags, ATTR_OPTIONAL0x80, 0);
981 strlcpy(cstr, "MP Unreach NLRI", sizeof(cstr));
982 break;
983 case ATTR_EXT_COMMUNITIES:
984 CHECK_FLAGS(flags, ATTR_OPTIONAL0x80|ATTR_TRANSITIVE0x40, ATTR_PARTIAL0x20);
985 strlcpy(cstr, "Ext. Communities", sizeof(cstr));
986 break;
987 case ATTR_LARGE_COMMUNITIES:
988 CHECK_FLAGS(flags, ATTR_OPTIONAL0x80|ATTR_TRANSITIVE0x40, ATTR_PARTIAL0x20);
989 strlcpy(cstr, "Large Communities", sizeof(cstr));
990 break;
991 case ATTR_OTC:
992 CHECK_FLAGS(flags, ATTR_OPTIONAL0x80|ATTR_TRANSITIVE0x40, ATTR_PARTIAL0x20);
993 strlcpy(cstr, "OTC", sizeof(cstr));
994 break;
995 default:
996 /* ignore unknown attributes */
997 snprintf(cstr, sizeof(cstr), "Unknown Attribute #%u", type);
998 pflags = 1;
999 break;
1000 }
1001 if (flags != -1 && pflags) {
1002 strlcat(cstr, " flags [", sizeof(cstr));
1003 if (flags & ATTR_OPTIONAL0x80)
1004 strlcat(cstr, "O", sizeof(cstr));
1005 if (flags & ATTR_TRANSITIVE0x40)
1006 strlcat(cstr, "T", sizeof(cstr));
1007 if (flags & ATTR_PARTIAL0x20)
1008 strlcat(cstr, "P", sizeof(cstr));
1009 strlcat(cstr, "]", sizeof(cstr));
1010 }
1011 return (cstr);
1012
1013#undef CHECK_FLAGS
1014}
1015
1016const char *
1017fmt_community(uint16_t a, uint16_t v)
1018{
1019 static char buf[12];
1020
1021 if (a == COMMUNITY_WELLKNOWN0xffff)
1022 switch (v) {
1023 case COMMUNITY_GRACEFUL_SHUTDOWN0x0000:
1024 return "GRACEFUL_SHUTDOWN";
1025 case COMMUNITY_NO_EXPORT0xff01:
1026 return "NO_EXPORT";
1027 case COMMUNITY_NO_ADVERTISE0xff02:
1028 return "NO_ADVERTISE";
1029 case COMMUNITY_NO_EXPSUBCONFED0xff03:
1030 return "NO_EXPORT_SUBCONFED";
1031 case COMMUNITY_NO_PEER0xff04:
1032 return "NO_PEER";
1033 case COMMUNITY_BLACKHOLE0x029A:
1034 return "BLACKHOLE";
1035 default:
1036 break;
1037 }
1038
1039 snprintf(buf, sizeof(buf), "%hu:%hu", a, v);
1040 return buf;
1041}
1042
1043const char *
1044fmt_large_community(uint32_t d1, uint32_t d2, uint32_t d3)
1045{
1046 static char buf[33];
1047
1048 snprintf(buf, sizeof(buf), "%u:%u:%u", d1, d2, d3);
1049 return buf;
1050}
1051
1052const char *
1053fmt_ext_community(uint8_t *data)
1054{
1055 static char buf[32];
1056 uint64_t ext;
1057 struct in_addr ip;
1058 uint32_t as4, u32;
1059 uint16_t as2, u16;
1060 uint8_t type, subtype;
1061
1062 type = data[0];
1063 subtype = data[1];
1064
1065 switch (type) {
1066 case EXT_COMMUNITY_TRANS_TWO_AS0x00:
1067 case EXT_COMMUNITY_GEN_TWO_AS0x80:
1068 memcpy(&as2, data + 2, sizeof(as2));
1069 memcpy(&u32, data + 4, sizeof(u32));
1070 snprintf(buf, sizeof(buf), "%s %s:%u",
1071 log_ext_subtype(type, subtype),
1072 log_as(ntohs(as2)(__uint16_t)(__builtin_constant_p(as2) ? (__uint16_t)(((__uint16_t
)(as2) & 0xffU) << 8 | ((__uint16_t)(as2) & 0xff00U
) >> 8) : __swap16md(as2))
), ntohl(u32)(__uint32_t)(__builtin_constant_p(u32) ? (__uint32_t)(((__uint32_t
)(u32) & 0xff) << 24 | ((__uint32_t)(u32) & 0xff00
) << 8 | ((__uint32_t)(u32) & 0xff0000) >> 8 |
((__uint32_t)(u32) & 0xff000000) >> 24) : __swap32md
(u32))
);
1073 return buf;
1074 case EXT_COMMUNITY_TRANS_IPV40x01:
1075 case EXT_COMMUNITY_GEN_IPV40x81:
1076 memcpy(&ip, data + 2, sizeof(ip));
1077 memcpy(&u16, data + 6, sizeof(u16));
1078 snprintf(buf, sizeof(buf), "%s %s:%hu",
1079 log_ext_subtype(type, subtype),
1080 inet_ntoa(ip), ntohs(u16)(__uint16_t)(__builtin_constant_p(u16) ? (__uint16_t)(((__uint16_t
)(u16) & 0xffU) << 8 | ((__uint16_t)(u16) & 0xff00U
) >> 8) : __swap16md(u16))
);
1081 return buf;
1082 case EXT_COMMUNITY_TRANS_FOUR_AS0x02:
1083 case EXT_COMMUNITY_GEN_FOUR_AS0x82:
1084 memcpy(&as4, data + 2, sizeof(as4));
1085 memcpy(&u16, data + 6, sizeof(u16));
1086 snprintf(buf, sizeof(buf), "%s %s:%hu",
1087 log_ext_subtype(type, subtype),
1088 log_as(ntohl(as4)(__uint32_t)(__builtin_constant_p(as4) ? (__uint32_t)(((__uint32_t
)(as4) & 0xff) << 24 | ((__uint32_t)(as4) & 0xff00
) << 8 | ((__uint32_t)(as4) & 0xff0000) >> 8 |
((__uint32_t)(as4) & 0xff000000) >> 24) : __swap32md
(as4))
), ntohs(u16)(__uint16_t)(__builtin_constant_p(u16) ? (__uint16_t)(((__uint16_t
)(u16) & 0xffU) << 8 | ((__uint16_t)(u16) & 0xff00U
) >> 8) : __swap16md(u16))
);
1089 return buf;
1090 case EXT_COMMUNITY_TRANS_OPAQUE0x03:
1091 case EXT_COMMUNITY_TRANS_EVPN0x06:
1092 memcpy(&ext, data, sizeof(ext));
1093 ext = be64toh(ext)(__uint64_t)(__builtin_constant_p(ext) ? (__uint64_t)((((__uint64_t
)(ext) & 0xff) << 56) | ((__uint64_t)(ext) & 0xff00ULL
) << 40 | ((__uint64_t)(ext) & 0xff0000ULL) <<
24 | ((__uint64_t)(ext) & 0xff000000ULL) << 8 | ((
__uint64_t)(ext) & 0xff00000000ULL) >> 8 | ((__uint64_t
)(ext) & 0xff0000000000ULL) >> 24 | ((__uint64_t)(ext
) & 0xff000000000000ULL) >> 40 | ((__uint64_t)(ext)
& 0xff00000000000000ULL) >> 56) : __swap64md(ext))
& 0xffffffffffffLL;
1094 snprintf(buf, sizeof(buf), "%s 0x%llx",
1095 log_ext_subtype(type, subtype), (unsigned long long)ext);
1096 return buf;
1097 case EXT_COMMUNITY_NON_TRANS_OPAQUE0x43:
1098 memcpy(&ext, data, sizeof(ext));
1099 ext = be64toh(ext)(__uint64_t)(__builtin_constant_p(ext) ? (__uint64_t)((((__uint64_t
)(ext) & 0xff) << 56) | ((__uint64_t)(ext) & 0xff00ULL
) << 40 | ((__uint64_t)(ext) & 0xff0000ULL) <<
24 | ((__uint64_t)(ext) & 0xff000000ULL) << 8 | ((
__uint64_t)(ext) & 0xff00000000ULL) >> 8 | ((__uint64_t
)(ext) & 0xff0000000000ULL) >> 24 | ((__uint64_t)(ext
) & 0xff000000000000ULL) >> 40 | ((__uint64_t)(ext)
& 0xff00000000000000ULL) >> 56) : __swap64md(ext))
& 0xffffffffffffLL;
1100 if (subtype == EXT_COMMUNITY_SUBTYPE_OVS0) {
1101 switch (ext) {
1102 case EXT_COMMUNITY_OVS_VALID0:
1103 snprintf(buf, sizeof(buf), "%s valid",
1104 log_ext_subtype(type, subtype));
1105 return buf;
1106 case EXT_COMMUNITY_OVS_NOTFOUND1:
1107 snprintf(buf, sizeof(buf), "%s not-found",
1108 log_ext_subtype(type, subtype));
1109 return buf;
1110 case EXT_COMMUNITY_OVS_INVALID2:
1111 snprintf(buf, sizeof(buf), "%s invalid",
1112 log_ext_subtype(type, subtype));
1113 return buf;
1114 default:
1115 snprintf(buf, sizeof(buf), "%s 0x%llx",
1116 log_ext_subtype(type, subtype),
1117 (unsigned long long)ext);
1118 return buf;
1119 }
1120 } else {
1121 snprintf(buf, sizeof(buf), "%s 0x%llx",
1122 log_ext_subtype(type, subtype),
1123 (unsigned long long)ext);
1124 return buf;
1125 }
1126 break;
1127 default:
1128 memcpy(&ext, data, sizeof(ext));
1129 snprintf(buf, sizeof(buf), "%s 0x%llx",
1130 log_ext_subtype(type, subtype),
1131 (unsigned long long)be64toh(ext)(__uint64_t)(__builtin_constant_p(ext) ? (__uint64_t)((((__uint64_t
)(ext) & 0xff) << 56) | ((__uint64_t)(ext) & 0xff00ULL
) << 40 | ((__uint64_t)(ext) & 0xff0000ULL) <<
24 | ((__uint64_t)(ext) & 0xff000000ULL) << 8 | ((
__uint64_t)(ext) & 0xff00000000ULL) >> 8 | ((__uint64_t
)(ext) & 0xff0000000000ULL) >> 24 | ((__uint64_t)(ext
) & 0xff000000000000ULL) >> 40 | ((__uint64_t)(ext)
& 0xff00000000000000ULL) >> 56) : __swap64md(ext))
);
1132 return buf;
1133 }
1134}
1135
1136const char *
1137fmt_set_type(struct ctl_show_set *set)
1138{
1139 switch (set->type) {
1140 case ASPA_SET:
1141 return "ASPA";
1142 case ROA_SET:
1143 return "ROA";
1144 case PREFIX_SET:
1145 return "PREFIX";
1146 case ORIGIN_SET:
1147 return "ORIGIN";
1148 case ASNUM_SET:
1149 return "ASNUM";
1150 default:
1151 return "BULA";
1152 }
1153}
1154
1155void
1156send_filterset(struct imsgbuf *i, struct filter_set_head *set)
1157{
1158 struct filter_set *s;
1159
1160 while ((s = TAILQ_FIRST(set)((set)->tqh_first)) != NULL((void *)0)) {
1161 imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s,
1162 sizeof(struct filter_set));
1163 TAILQ_REMOVE(set, s, entry)do { if (((s)->entry.tqe_next) != ((void *)0)) (s)->entry
.tqe_next->entry.tqe_prev = (s)->entry.tqe_prev; else (
set)->tqh_last = (s)->entry.tqe_prev; *(s)->entry.tqe_prev
= (s)->entry.tqe_next; ; ; } while (0)
;
1164 free(s);
1165 }
1166}
1167
1168void
1169network_bulk(struct parse_result *res)
1170{
1171 struct network_config net;
1172 struct filter_set *s = NULL((void *)0);
1173 struct bgpd_addr h;
1174 char *line = NULL((void *)0);
1175 size_t linesize = 0;
1176 ssize_t linelen;
1177 uint8_t len;
1178 FILE *f;
1179
1180 if ((f = fdopen(STDIN_FILENO0, "r")) == NULL((void *)0))
1181 err(1, "Failed to open stdin\n");
1182
1183 while ((linelen = getline(&line, &linesize, f)) != -1) {
Although the value stored to 'linelen' is used in the enclosing expression, the value is never actually read from 'linelen'
1184 char *b, *buf = line;
1185 while ((b = strsep(&buf, " \t\n")) != NULL((void *)0)) {
1186 if (*b == '\0') /* skip empty tokens */
1187 continue;
1188 /* Stop processing after a comment */
1189 if (*b == '#')
1190 break;
1191 memset(&net, 0, sizeof(net));
1192 if (parse_prefix(b, strlen(b), &h, &len) != 1)
1193 errx(1, "bad prefix: %s", b);
1194 net.prefix = h;
1195 net.prefixlen = len;
1196 net.rd = res->rd;
1197
1198 if (res->action == NETWORK_BULK_ADD) {
1199 imsg_compose(imsgbuf, IMSG_NETWORK_ADD,
1200 0, 0, -1, &net, sizeof(net));
1201 /*
1202 * can't use send_filterset since that
1203 * would free the set.
1204 */
1205 TAILQ_FOREACH(s, &res->set, entry)for((s) = ((&res->set)->tqh_first); (s) != ((void *
)0); (s) = ((s)->entry.tqe_next))
{
1206 imsg_compose(imsgbuf,
1207 IMSG_FILTER_SET,
1208 0, 0, -1, s, sizeof(*s));
1209 }
1210 imsg_compose(imsgbuf, IMSG_NETWORK_DONE,
1211 0, 0, -1, NULL((void *)0), 0);
1212 } else
1213 imsg_compose(imsgbuf, IMSG_NETWORK_REMOVE,
1214 0, 0, -1, &net, sizeof(net));
1215 }
1216 }
1217 free(line);
1218 if (ferror(f)(!__isthreaded ? (((f)->_flags & 0x0040) != 0) : (ferror
)(f))
)
1219 err(1, "getline");
1220 fclose(f);
1221}
1222
1223void
1224show_mrt_dump_neighbors(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
1225{
1226 struct mrt_peer_entry *p;
1227 struct in_addr ina;
1228 uint16_t i;
1229
1230 ina.s_addr = htonl(mp->bgp_id)(__uint32_t)(__builtin_constant_p(mp->bgp_id) ? (__uint32_t
)(((__uint32_t)(mp->bgp_id) & 0xff) << 24 | ((__uint32_t
)(mp->bgp_id) & 0xff00) << 8 | ((__uint32_t)(mp->
bgp_id) & 0xff0000) >> 8 | ((__uint32_t)(mp->bgp_id
) & 0xff000000) >> 24) : __swap32md(mp->bgp_id))
;
1231 printf("view: %s BGP ID: %s Number of peers: %u\n\n",
1232 mp->view, inet_ntoa(ina), mp->npeers);
1233 printf("%-30s %8s %15s\n", "Neighbor", "AS", "BGP ID");
1234 for (i = 0; i < mp->npeers; i++) {
1235 p = &mp->peers[i];
1236 ina.s_addr = htonl(p->bgp_id)(__uint32_t)(__builtin_constant_p(p->bgp_id) ? (__uint32_t
)(((__uint32_t)(p->bgp_id) & 0xff) << 24 | ((__uint32_t
)(p->bgp_id) & 0xff00) << 8 | ((__uint32_t)(p->
bgp_id) & 0xff0000) >> 8 | ((__uint32_t)(p->bgp_id
) & 0xff000000) >> 24) : __swap32md(p->bgp_id))
;
1237 printf("%-30s %8u %15s\n", log_addr(&p->addr), p->asnum,
1238 inet_ntoa(ina));
1239 }
1240 /* we only print the first message */
1241 exit(0);
1242}
1243
1244void
1245show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
1246{
1247 struct ctl_show_rib ctl;
1248 struct parse_result res;
1249 struct ctl_show_rib_request *req = arg;
1250 struct mrt_rib_entry *mre;
1251 time_t now;
1252 uint16_t i, j;
1253
1254 memset(&res, 0, sizeof(res));
1255 res.flags = req->flags;
1256 now = time(NULL((void *)0));
1257
1258 for (i = 0; i < mr->nentries; i++) {
1259 mre = &mr->entries[i];
1260 memset(&ctl, 0, sizeof(ctl));
1261 ctl.prefix = mr->prefix;
1262 ctl.prefixlen = mr->prefixlen;
1263 if (mre->originated <= now)
1264 ctl.age = now - mre->originated;
1265 ctl.true_nexthop = mre->nexthop;
1266 ctl.exit_nexthop = mre->nexthop;
1267 ctl.origin = mre->origin;
1268 ctl.local_pref = mre->local_pref;
1269 ctl.med = mre->med;
1270 /* weight is not part of the mrt dump so it can't be set */
1271 if (mr->add_path) {
1272 ctl.flags |= F_PREF_PATH_ID0x040;
1273 ctl.path_id = mre->path_id;
1274 }
1275
1276 if (mre->peer_idx < mp->npeers) {
1277 ctl.remote_addr = mp->peers[mre->peer_idx].addr;
1278 ctl.remote_id = mp->peers[mre->peer_idx].bgp_id;
1279 }
1280
1281 /* filter by neighbor */
1282 if (req->neighbor.addr.aid != AID_UNSPEC0 &&
1283 memcmp(&req->neighbor.addr, &ctl.remote_addr,
1284 sizeof(ctl.remote_addr)) != 0)
1285 continue;
1286 /* filter by AF */
1287 if (req->aid && req->aid != ctl.prefix.aid)
1288 return;
1289 /* filter by prefix */
1290 if (req->prefix.aid != AID_UNSPEC0) {
1291 if (req->flags & F_LONGER0x0200) {
1292 if (req->prefixlen > ctl.prefixlen)
1293 return;
1294 if (prefix_compare(&req->prefix, &ctl.prefix,
1295 req->prefixlen))
1296 return;
1297 } else if (req->flags & F_SHORTER0x0400) {
1298 if (req->prefixlen < ctl.prefixlen)
1299 return;
1300 if (prefix_compare(&req->prefix, &ctl.prefix,
1301 ctl.prefixlen))
1302 return;
1303 } else {
1304 if (req->prefixlen != ctl.prefixlen)
1305 return;
1306 if (prefix_compare(&req->prefix, &ctl.prefix,
1307 req->prefixlen))
1308 return;
1309 }
1310 }
1311 /* filter by AS */
1312 if (req->as.type != AS_UNDEF &&
1313 !match_aspath(mre->aspath, mre->aspath_len, &req->as))
1314 continue;
1315
1316 output->rib(&ctl, mre->aspath, mre->aspath_len, &res);
1317 if (req->flags & F_CTL_DETAIL0x1000) {
1318 for (j = 0; j < mre->nattrs; j++)
1319 output->attr(mre->attrs[j].attr,
1320 mre->attrs[j].attr_len, req->flags, 0);
1321 }
1322 }
1323}
1324
1325void
1326network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
1327{
1328 struct ctl_show_rib ctl;
1329 struct network_config net;
1330 struct ctl_show_rib_request *req = arg;
1331 struct mrt_rib_entry *mre;
1332 struct ibuf *msg;
1333 time_t now;
1334 uint16_t i, j;
1335
1336 /* can't announce more than one path so ignore add-path */
1337 if (mr->add_path)
1338 return;
1339
1340 now = time(NULL((void *)0));
1341 for (i = 0; i < mr->nentries; i++) {
1342 mre = &mr->entries[i];
1343 memset(&ctl, 0, sizeof(ctl));
1344 ctl.prefix = mr->prefix;
1345 ctl.prefixlen = mr->prefixlen;
1346 if (mre->originated <= now)
1347 ctl.age = now - mre->originated;
1348 ctl.true_nexthop = mre->nexthop;
1349 ctl.exit_nexthop = mre->nexthop;
1350 ctl.origin = mre->origin;
1351 ctl.local_pref = mre->local_pref;
1352 ctl.med = mre->med;
1353
1354 if (mre->peer_idx < mp->npeers) {
1355 ctl.remote_addr = mp->peers[mre->peer_idx].addr;
1356 ctl.remote_id = mp->peers[mre->peer_idx].bgp_id;
1357 }
1358
1359 /* filter by neighbor */
1360 if (req->neighbor.addr.aid != AID_UNSPEC0 &&
1361 memcmp(&req->neighbor.addr, &ctl.remote_addr,
1362 sizeof(ctl.remote_addr)) != 0)
1363 continue;
1364 /* filter by AF */
1365 if (req->aid && req->aid != ctl.prefix.aid)
1366 return;
1367 /* filter by prefix */
1368 if (req->prefix.aid != AID_UNSPEC0) {
1369 if (!prefix_compare(&req->prefix, &ctl.prefix,
1370 req->prefixlen)) {
1371 if (req->flags & F_LONGER0x0200) {
1372 if (req->prefixlen > ctl.prefixlen)
1373 return;
1374 } else if (req->prefixlen != ctl.prefixlen)
1375 return;
1376 } else
1377 return;
1378 }
1379 /* filter by AS */
1380 if (req->as.type != AS_UNDEF &&
1381 !match_aspath(mre->aspath, mre->aspath_len, &req->as))
1382 continue;
1383
1384 memset(&net, 0, sizeof(net));
1385 net.prefix = ctl.prefix;
1386 net.prefixlen = ctl.prefixlen;
1387 net.type = NETWORK_MRTCLONE;
1388 /* XXX rd can't be set and will be 0 */
1389
1390 imsg_compose(imsgbuf, IMSG_NETWORK_ADD, 0, 0, -1,
1391 &net, sizeof(net));
1392 if ((msg = imsg_create(imsgbuf, IMSG_NETWORK_ASPATH,
1393 0, 0, sizeof(ctl) + mre->aspath_len)) == NULL((void *)0))
1394 errx(1, "imsg_create failure");
1395 if (imsg_add(msg, &ctl, sizeof(ctl)) == -1 ||
1396 imsg_add(msg, mre->aspath, mre->aspath_len) == -1)
1397 errx(1, "imsg_add failure");
1398 imsg_close(imsgbuf, msg);
1399 for (j = 0; j < mre->nattrs; j++)
1400 imsg_compose(imsgbuf, IMSG_NETWORK_ATTR, 0, 0, -1,
1401 mre->attrs[j].attr, mre->attrs[j].attr_len);
1402 imsg_compose(imsgbuf, IMSG_NETWORK_DONE, 0, 0, -1, NULL((void *)0), 0);
1403
1404 while (imsgbuf->w.queued) {
1405 if (msgbuf_write(&imsgbuf->w) <= 0 && errno(*__errno()) != EAGAIN35)
1406 err(1, "write error");
1407 }
1408 }
1409}
1410
1411static const char *
1412fmt_time(struct timespec *t)
1413{
1414 static char timebuf[32];
1415 static struct timespec prevtime;
1416 struct timespec temp;
1417
1418 timespecsub(t, &prevtime, &temp)do { (&temp)->tv_sec = (t)->tv_sec - (&prevtime
)->tv_sec; (&temp)->tv_nsec = (t)->tv_nsec - (&
prevtime)->tv_nsec; if ((&temp)->tv_nsec < 0) { (
&temp)->tv_sec--; (&temp)->tv_nsec += 1000000000L
; } } while (0)
;
1419 snprintf(timebuf, sizeof(timebuf), "%lld.%06ld",
1420 (long long)temp.tv_sec, temp.tv_nsec / 1000);
1421 prevtime = *t;
1422 return (timebuf);
1423}
1424
1425void
1426show_mrt_state(struct mrt_bgp_state *ms, void *arg)
1427{
1428 printf("%s %s[%u] -> ", fmt_time(&ms->time),
1429 log_addr(&ms->src), ms->src_as);
1430 printf("%s[%u]: %s -> %s\n", log_addr(&ms->dst), ms->dst_as,
1431 statenames[ms->old_state], statenames[ms->new_state]);
1432}
1433
1434static void
1435print_afi(u_char *p, uint8_t len)
1436{
1437 uint16_t afi;
1438 uint8_t safi, aid;
1439
1440 if (len != 4) {
1441 printf("bad length");
1442 return;
1443 }
1444
1445 /* afi, 2 byte */
1446 memcpy(&afi, p, sizeof(afi));
1447 afi = ntohs(afi)(__uint16_t)(__builtin_constant_p(afi) ? (__uint16_t)(((__uint16_t
)(afi) & 0xffU) << 8 | ((__uint16_t)(afi) & 0xff00U
) >> 8) : __swap16md(afi))
;
1448 p += 2;
1449 /* reserved, 1 byte */
1450 p += 1;
1451 /* safi, 1 byte */
1452 memcpy(&safi, p, sizeof(safi));
1453 if (afi2aid(afi, safi, &aid) == -1)
1454 printf("unknown afi %u safi %u", afi, safi);
1455 else
1456 printf("%s", aid2str(aid));
1457}
1458
1459static void
1460print_capability(uint8_t capa_code, u_char *p, uint8_t len)
1461{
1462 switch (capa_code) {
1463 case CAPA_MP:
1464 printf("multiprotocol capability: ");
1465 print_afi(p, len);
1466 break;
1467 case CAPA_REFRESH:
1468 printf("route refresh capability");
1469 break;
1470 case CAPA_RESTART:
1471 printf("graceful restart capability");
1472 /* XXX there is more needed here */
1473 break;
1474 case CAPA_AS4BYTE:
1475 printf("4-byte AS num capability: ");
1476 if (len == 4) {
1477 uint32_t as;
1478 memcpy(&as, p, sizeof(as));
1479 as = ntohl(as)(__uint32_t)(__builtin_constant_p(as) ? (__uint32_t)(((__uint32_t
)(as) & 0xff) << 24 | ((__uint32_t)(as) & 0xff00
) << 8 | ((__uint32_t)(as) & 0xff0000) >> 8 |
((__uint32_t)(as) & 0xff000000) >> 24) : __swap32md
(as))
;
1480 printf("AS %u", as);
1481 } else
1482 printf("bad length");
1483 break;
1484 case CAPA_ADD_PATH:
1485 printf("add-path capability");
1486 /* XXX there is more needed here */
1487 break;
1488 case CAPA_ENHANCED_RR:
1489 printf("enhanced route refresh capability");
1490 break;
1491 default:
1492 printf("unknown capability %u length %u", capa_code, len);
1493 break;
1494 }
1495}
1496
1497static void
1498print_notification(uint8_t errcode, uint8_t subcode)
1499{
1500 const char *suberrname = NULL((void *)0);
1501 int uk = 0;
1502
1503 switch (errcode) {
1504 case ERR_HEADER:
1505 if (subcode >= sizeof(suberr_header_names)/sizeof(char *))
1506 uk = 1;
1507 else
1508 suberrname = suberr_header_names[subcode];
1509 break;
1510 case ERR_OPEN:
1511 if (subcode >= sizeof(suberr_open_names)/sizeof(char *))
1512 uk = 1;
1513 else
1514 suberrname = suberr_open_names[subcode];
1515 break;
1516 case ERR_UPDATE:
1517 if (subcode >= sizeof(suberr_update_names)/sizeof(char *))
1518 uk = 1;
1519 else
1520 suberrname = suberr_update_names[subcode];
1521 break;
1522 case ERR_CEASE:
1523 if (subcode >= sizeof(suberr_cease_names)/sizeof(char *))
1524 uk = 1;
1525 else
1526 suberrname = suberr_cease_names[subcode];
1527 break;
1528 case ERR_HOLDTIMEREXPIRED:
1529 if (subcode != 0)
1530 uk = 1;
1531 break;
1532 case ERR_FSM:
1533 if (subcode >= sizeof(suberr_fsm_names)/sizeof(char *))
1534 uk = 1;
1535 else
1536 suberrname = suberr_fsm_names[subcode];
1537 break;
1538 default:
1539 printf("unknown errcode %u, subcode %u",
1540 errcode, subcode);
1541 return;
1542 }
1543
1544 if (uk)
1545 printf("%s, unknown subcode %u", errnames[errcode], subcode);
1546 else {
1547 if (suberrname == NULL((void *)0))
1548 printf("%s", errnames[errcode]);
1549 else
1550 printf("%s, %s", errnames[errcode], suberrname);
1551 }
1552}
1553
1554static int
1555show_mrt_capabilities(u_char *p, uint16_t len)
1556{
1557 uint16_t totlen = len;
1558 uint8_t capa_code, capa_len;
1559
1560 while (len > 2) {
1561 memcpy(&capa_code, p, sizeof(capa_code));
1562 p += sizeof(capa_code);
1563 len -= sizeof(capa_code);
1564 memcpy(&capa_len, p, sizeof(capa_len));
1565 p += sizeof(capa_len);
1566 len -= sizeof(capa_len);
1567 if (len < capa_len) {
1568 printf("capa_len %u exceeds remaining length",
1569 capa_len);
1570 return (-1);
1571 }
1572 printf("\n ");
1573 print_capability(capa_code, p, capa_len);
1574 p += capa_len;
1575 len -= capa_len;
1576 }
1577 if (len != 0) {
1578 printf("length mismatch while capability parsing");
1579 return (-1);
1580 }
1581 return (totlen);
1582}
1583
1584static void
1585show_mrt_open(u_char *p, uint16_t len)
1586{
1587 uint16_t short_as, holdtime;
1588 uint8_t version, optparamlen;
1589 struct in_addr bgpid;
1590
1591 /* length check up to optparamlen already happened */
1592 memcpy(&version, p, sizeof(version));
1593 p += sizeof(version);
1594 len -= sizeof(version);
1595 memcpy(&short_as, p, sizeof(short_as));
1596 p += sizeof(short_as);
1597 len -= sizeof(short_as);
1598 short_as = ntohs(short_as)(__uint16_t)(__builtin_constant_p(short_as) ? (__uint16_t)(((
__uint16_t)(short_as) & 0xffU) << 8 | ((__uint16_t)
(short_as) & 0xff00U) >> 8) : __swap16md(short_as))
;
1599 memcpy(&holdtime, p, sizeof(holdtime));
1600 holdtime = ntohs(holdtime)(__uint16_t)(__builtin_constant_p(holdtime) ? (__uint16_t)(((
__uint16_t)(holdtime) & 0xffU) << 8 | ((__uint16_t)
(holdtime) & 0xff00U) >> 8) : __swap16md(holdtime))
;
1601 p += sizeof(holdtime);
1602 len -= sizeof(holdtime);
1603 memcpy(&bgpid, p, sizeof(bgpid));
1604 p += sizeof(bgpid);
1605 len -= sizeof(bgpid);
1606 memcpy(&optparamlen, p, sizeof(optparamlen));
1607 p += sizeof(optparamlen);
1608 len -= sizeof(optparamlen);
1609
1610 printf("\n ");
1611 printf("Version: %d AS: %u Holdtime: %u BGP Id: %s Paramlen: %u",
1612 version, short_as, holdtime, inet_ntoa(bgpid), optparamlen);
1613 if (optparamlen != len) {
1614 printf("optional parameter length mismatch");
1615 return;
1616 }
1617 while (len > 2) {
1618 uint8_t op_type, op_len;
1619 int r;
1620
1621 memcpy(&op_type, p, sizeof(op_type));
1622 p += sizeof(op_type);
1623 len -= sizeof(op_type);
1624 memcpy(&op_len, p, sizeof(op_len));
1625 p += sizeof(op_len);
1626 len -= sizeof(op_len);
1627
1628 printf("\n ");
1629 switch (op_type) {
1630 case OPT_PARAM_CAPABILITIES:
1631 printf("Capabilities: size %u", op_len);
1632 r = show_mrt_capabilities(p, op_len);
1633 if (r == -1)
1634 return;
1635 p += r;
1636 len -= r;
1637 break;
1638 case OPT_PARAM_AUTH:
1639 default:
1640 printf("unsupported optional parameter: type %u",
1641 op_type);
1642 return;
1643 }
1644 }
1645 if (len != 0) {
1646 printf("optional parameter encoding error");
1647 return;
1648 }
1649}
1650
1651static void
1652show_mrt_notification(u_char *p, uint16_t len)
1653{
1654 uint16_t i;
1655 uint8_t errcode, subcode;
1656 size_t reason_len;
1657 char reason[REASON_LEN256];
1658
1659 memcpy(&errcode, p, sizeof(errcode));
1660 p += sizeof(errcode);
1661 len -= sizeof(errcode);
1662
1663 memcpy(&subcode, p, sizeof(subcode));
1664 p += sizeof(subcode);
1665 len -= sizeof(subcode);
1666
1667 printf("\n ");
1668 print_notification(errcode, subcode);
1669
1670 if (errcode == ERR_CEASE && (subcode == ERR_CEASE_ADMIN_DOWN ||
1671 subcode == ERR_CEASE_ADMIN_RESET)) {
1672 if (len > 1) {
1673 reason_len = *p++;
1674 len--;
1675 if (len < reason_len) {
1676 printf("truncated shutdown reason");
1677 return;
1678 }
1679 if (reason_len > REASON_LEN256 - 1) {
1680 printf("overly long shutdown reason");
1681 return;
1682 }
1683 memcpy(reason, p, reason_len);
1684 reason[reason_len] = '\0';
1685 printf("shutdown reason: \"%s\"",
1686 log_reason(reason));
1687 p += reason_len;
1688 len -= reason_len;
1689 }
1690 }
1691 if (errcode == ERR_OPEN && subcode == ERR_OPEN_CAPA) {
1692 int r;
1693
1694 r = show_mrt_capabilities(p, len);
1695 if (r == -1)
1696 return;
1697 p += r;
1698 len -= r;
1699 }
1700
1701 if (len > 0) {
1702 printf("\n additional data %u bytes", len);
1703 for (i = 0; i < len; i++) {
1704 if (i % 16 == 0)
1705 printf("\n ");
1706 if (i % 8 == 0)
1707 printf(" ");
1708 printf(" %02X", *p++);
1709 }
1710 }
1711}
1712
1713/* XXX this function does not handle JSON output */
1714static void
1715show_mrt_update(u_char *p, uint16_t len, int reqflags, int addpath)
1716{
1717 struct bgpd_addr prefix;
1718 int pos;
1719 uint32_t pathid;
1720 uint16_t wlen, alen;
1721 uint8_t prefixlen;
1722
1723 if (len < sizeof(wlen)) {
1724 printf("bad length");
1725 return;
1726 }
1727 memcpy(&wlen, p, sizeof(wlen));
1728 wlen = ntohs(wlen)(__uint16_t)(__builtin_constant_p(wlen) ? (__uint16_t)(((__uint16_t
)(wlen) & 0xffU) << 8 | ((__uint16_t)(wlen) & 0xff00U
) >> 8) : __swap16md(wlen))
;
1729 p += sizeof(wlen);
1730 len -= sizeof(wlen);
1731
1732 if (len < wlen) {
1733 printf("bad withdraw length");
1734 return;
1735 }
1736 if (wlen > 0) {
1737 printf("\n Withdrawn prefixes:");
1738 while (wlen > 0) {
1739 if (addpath) {
1740 if (wlen <= sizeof(pathid)) {
1741 printf("bad withdraw prefix");
1742 return;
1743 }
1744 memcpy(&pathid, p, sizeof(pathid));
1745 pathid = ntohl(pathid)(__uint32_t)(__builtin_constant_p(pathid) ? (__uint32_t)(((__uint32_t
)(pathid) & 0xff) << 24 | ((__uint32_t)(pathid) &
0xff00) << 8 | ((__uint32_t)(pathid) & 0xff0000) >>
8 | ((__uint32_t)(pathid) & 0xff000000) >> 24) : __swap32md
(pathid))
;
1746 p += sizeof(pathid);
1747 len -= sizeof(pathid);
1748 wlen -= sizeof(pathid);
1749 }
1750 if ((pos = nlri_get_prefix(p, wlen, &prefix,
1751 &prefixlen)) == -1) {
1752 printf("bad withdraw prefix");
1753 return;
1754 }
1755 printf(" %s/%u", log_addr(&prefix), prefixlen);
1756 if (addpath)
1757 printf(" path-id %u", pathid);
1758 p += pos;
1759 len -= pos;
1760 wlen -= pos;
1761 }
1762 }
1763
1764 if (len < sizeof(alen)) {
1765 printf("bad length");
1766 return;
1767 }
1768 memcpy(&alen, p, sizeof(alen));
1769 alen = ntohs(alen)(__uint16_t)(__builtin_constant_p(alen) ? (__uint16_t)(((__uint16_t
)(alen) & 0xffU) << 8 | ((__uint16_t)(alen) & 0xff00U
) >> 8) : __swap16md(alen))
;
1770 p += sizeof(alen);
1771 len -= sizeof(alen);
1772
1773 if (len < alen) {
1774 printf("bad attribute length");
1775 return;
1776 }
1777 printf("\n");
1778 /* alen attributes here */
1779 while (alen > 3) {
1780 uint8_t flags;
1781 uint16_t attrlen;
1782
1783 flags = p[0];
1784 /* type = p[1]; */
1785
1786 /* get the attribute length */
1787 if (flags & ATTR_EXTLEN0x10) {
1788 if (len < sizeof(attrlen) + 2)
1789 printf("bad attribute length");
1790 memcpy(&attrlen, &p[2], sizeof(attrlen));
1791 attrlen = ntohs(attrlen)(__uint16_t)(__builtin_constant_p(attrlen) ? (__uint16_t)(((__uint16_t
)(attrlen) & 0xffU) << 8 | ((__uint16_t)(attrlen) &
0xff00U) >> 8) : __swap16md(attrlen))
;
1792 attrlen += sizeof(attrlen) + 2;
1793 } else {
1794 attrlen = p[2];
1795 attrlen += 1 + 2;
1796 }
1797
1798 output->attr(p, attrlen, reqflags, addpath);
1799 p += attrlen;
1800 alen -= attrlen;
1801 len -= attrlen;
1802 }
1803
1804 if (len > 0) {
1805 printf(" NLRI prefixes:");
1806 while (len > 0) {
1807 if (addpath) {
1808 if (len <= sizeof(pathid)) {
1809 printf(" bad nlri prefix: pathid, "
1810 "len %d", len);
1811 return;
1812 }
1813 memcpy(&pathid, p, sizeof(pathid));
1814 pathid = ntohl(pathid)(__uint32_t)(__builtin_constant_p(pathid) ? (__uint32_t)(((__uint32_t
)(pathid) & 0xff) << 24 | ((__uint32_t)(pathid) &
0xff00) << 8 | ((__uint32_t)(pathid) & 0xff0000) >>
8 | ((__uint32_t)(pathid) & 0xff000000) >> 24) : __swap32md
(pathid))
;
1815 p += sizeof(pathid);
1816 len -= sizeof(pathid);
1817 }
1818 if ((pos = nlri_get_prefix(p, len, &prefix,
1819 &prefixlen)) == -1) {
1820 printf(" bad nlri prefix");
1821 return;
1822 }
1823 printf(" %s/%u", log_addr(&prefix), prefixlen);
1824 if (addpath)
1825 printf(" path-id %u", pathid);
1826 p += pos;
1827 len -= pos;
1828 }
1829 }
1830}
1831
1832void
1833show_mrt_msg(struct mrt_bgp_msg *mm, void *arg)
1834{
1835 static const uint8_t marker[MSGSIZE_HEADER_MARKER16] = {
1836 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1837 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1838 u_char *p;
1839 uint16_t len;
1840 uint8_t type;
1841 struct ctl_show_rib_request *req = arg;
1842
1843 printf("%s %s[%u] -> ", fmt_time(&mm->time),
1844 log_addr(&mm->src), mm->src_as);
1845 printf("%s[%u]: size %u%s ", log_addr(&mm->dst), mm->dst_as,
1846 mm->msg_len, mm->add_path ? " addpath" : "");
1847 p = mm->msg;
1848 len = mm->msg_len;
1849
1850 if (len < MSGSIZE_HEADER19) {
1851 printf("illegal header length: %u byte\n", len);
1852 return;
1853 }
1854
1855 /* parse BGP message header */
1856 if (memcmp(p, marker, sizeof(marker))) {
1857 printf("incorrect marker in BGP message\n");
1858 return;
1859 }
1860 p += MSGSIZE_HEADER_MARKER16;
1861
1862 memcpy(&len, p, 2);
1863 len = ntohs(len)(__uint16_t)(__builtin_constant_p(len) ? (__uint16_t)(((__uint16_t
)(len) & 0xffU) << 8 | ((__uint16_t)(len) & 0xff00U
) >> 8) : __swap16md(len))
;
1864 p += 2;
1865 memcpy(&type, p, 1);
1866 p += 1;
1867
1868 if (len < MSGSIZE_HEADER19 || len > MAX_PKTSIZE4096) {
1869 printf("illegal header length: %u byte\n", len);
1870 return;
1871 }
1872
1873 switch (type) {
1874 case OPEN:
1875 printf("%s ", msgtypenames[type]);
1876 if (len < MSGSIZE_OPEN_MIN29) {
1877 printf("illegal length: %u byte\n", len);
1878 return;
1879 }
1880 show_mrt_open(p, len - MSGSIZE_HEADER19);
1881 break;
1882 case NOTIFICATION:
1883 printf("%s ", msgtypenames[type]);
1884 if (len < MSGSIZE_NOTIFICATION_MIN21) {
1885 printf("illegal length: %u byte\n", len);
1886 return;
1887 }
1888 show_mrt_notification(p, len - MSGSIZE_HEADER19);
1889 break;
1890 case UPDATE:
1891 printf("%s ", msgtypenames[type]);
1892 if (len < MSGSIZE_UPDATE_MIN23) {
1893 printf("illegal length: %u byte\n", len);
1894 return;
1895 }
1896 show_mrt_update(p, len - MSGSIZE_HEADER19, req->flags,
1897 mm->add_path);
1898 break;
1899 case KEEPALIVE:
1900 printf("%s ", msgtypenames[type]);
1901 if (len != MSGSIZE_KEEPALIVE19) {
1902 printf("illegal length: %u byte\n", len);
1903 return;
1904 }
1905 /* nothing */
1906 break;
1907 case RREFRESH:
1908 printf("%s ", msgtypenames[type]);
1909 if (len != MSGSIZE_RREFRESH(19 + 4)) {
1910 printf("illegal length: %u byte\n", len);
1911 return;
1912 }
1913 print_afi(p, len);
1914 break;
1915 default:
1916 printf("unknown type %u\n", type);
1917 return;
1918 }
1919 printf("\n");
1920}
1921
1922const char *
1923msg_type(uint8_t type)
1924{
1925 if (type >= sizeof(msgtypenames)/sizeof(msgtypenames[0]))
1926 return "BAD";
1927 return (msgtypenames[type]);
1928}
1929
1930int
1931match_aspath(void *data, uint16_t len, struct filter_as *f)
1932{
1933 uint8_t *seg;
1934 int final;
1935 uint16_t seg_size;
1936 uint8_t i, seg_len;
1937 uint32_t as = 0;
1938
1939 if (f->type == AS_EMPTY) {
1940 if (len == 0)
1941 return (1);
1942 else
1943 return (0);
1944 }
1945
1946 seg = data;
1947
1948 /* just check the leftmost AS */
1949 if (f->type == AS_PEER && len >= 6) {
1950 as = aspath_extract(seg, 0);
1951 if (f->as_min == as)
1952 return (1);
1953 else
1954 return (0);
1955 }
1956
1957 for (; len >= 6; len -= seg_size, seg += seg_size) {
1958 seg_len = seg[1];
1959 seg_size = 2 + sizeof(uint32_t) * seg_len;
1960
1961 final = (len == seg_size);
1962
1963 if (f->type == AS_SOURCE) {
1964 /*
1965 * Just extract the rightmost AS
1966 * but if that segment is an AS_SET then the rightmost
1967 * AS of a previous AS_SEQUENCE segment should be used.
1968 * Because of that just look at AS_SEQUENCE segments.
1969 */
1970 if (seg[0] == AS_SEQUENCE2)
1971 as = aspath_extract(seg, seg_len - 1);
1972 /* not yet in the final segment */
1973 if (!final)
1974 continue;
1975 if (f->as_min == as)
1976 return (1);
1977 else
1978 return (0);
1979 }
1980 /* AS_TRANSIT or AS_ALL */
1981 for (i = 0; i < seg_len; i++) {
1982 /*
1983 * the source (rightmost) AS is excluded from
1984 * AS_TRANSIT matches.
1985 */
1986 if (final && i == seg_len - 1 && f->type == AS_TRANSIT)
1987 return (0);
1988 as = aspath_extract(seg, i);
1989 if (f->as_min == as)
1990 return (1);
1991 }
1992 }
1993 return (0);
1994}
1995
1996static void
1997component_finish(int type, uint8_t *data, int len)
1998{
1999 uint8_t *last;
2000 int i;
2001
2002 switch (type) {
2003 case FLOWSPEC_TYPE_DEST1:
2004 case FLOWSPEC_TYPE_SOURCE2:
2005 /* nothing todo */
2006 return;
2007 default:
2008 break;
2009 }
2010
2011 i = 0;
2012 do {
2013 last = data + i;
2014 i += FLOWSPEC_OP_LEN(*last)(1 << (((*last) & 0x30) >> 4)) + 1;
2015 } while (i < len);
2016 *last |= FLOWSPEC_OP_EOL0x80;
2017}
2018
2019static void
2020push_prefix(struct parse_result *r, int type, struct bgpd_addr *addr,
2021 uint8_t len)
2022{
2023 void *data;
2024 uint8_t *comp;
2025 int complen, l;
2026
2027 switch (addr->aid) {
2028 case AID_UNSPEC0:
2029 return;
2030 case AID_INET1:
2031 complen = PREFIX_SIZE(len)(((len) + 7) / 8 + 1);
2032 data = &addr->v4ba.v4;
2033 break;
2034 case AID_INET62:
2035 /* IPv6 includes an offset byte */
2036 complen = PREFIX_SIZE(len)(((len) + 7) / 8 + 1) + 1;
2037 data = &addr->v6ba.v6;
2038 break;
2039 default:
2040 errx(1, "unsupported address family for flowspec address");
2041 }
2042 comp = malloc(complen);
2043 if (comp == NULL((void *)0))
2044 err(1, NULL((void *)0));
2045
2046 l = 0;
2047 comp[l++] = len;
2048 if (addr->aid == AID_INET62)
2049 comp[l++] = 0;
2050 memcpy(comp + l, data, complen - l);
2051
2052 r->flow.complen[type] = complen;
2053 r->flow.components[type] = comp;
2054}
2055
2056
2057struct flowspec *
2058res_to_flowspec(struct parse_result *r)
2059{
2060 struct flowspec *f;
2061 int i, len = 0;
2062 uint8_t aid;
2063
2064 switch (r->aid) {
2065 case AID_INET1:
2066 aid = AID_FLOWSPECv45;
2067 break;
2068 case AID_INET62:
2069 aid = AID_FLOWSPECv66;
2070 break;
2071 default:
2072 errx(1, "unsupported AFI %s for flowspec rule",
2073 aid2str(r->aid));
2074 }
2075
2076 push_prefix(r, FLOWSPEC_TYPE_DEST1, &r->flow.dst, r->flow.dstlen);
2077 push_prefix(r, FLOWSPEC_TYPE_SOURCE2, &r->flow.src, r->flow.srclen);
2078
2079 for (i = FLOWSPEC_TYPE_MIN1; i < FLOWSPEC_TYPE_MAX14; i++)
2080 if (r->flow.components[i] != NULL((void *)0))
2081 len += r->flow.complen[i] + 1;
2082
2083 if (len == 0)
2084 errx(1, "no flowspec rule defined");
2085
2086 f = malloc(FLOWSPEC_SIZE(__builtin_offsetof(struct flowspec, data)) + len);
2087 if (f == NULL((void *)0))
2088 err(1, NULL((void *)0));
2089 memset(f, 0, FLOWSPEC_SIZE(__builtin_offsetof(struct flowspec, data)));
2090
2091 f->aid = aid;
2092 f->len = len;
2093
2094 len = 0;
2095 for (i = FLOWSPEC_TYPE_MIN1; i < FLOWSPEC_TYPE_MAX14; i++)
2096 if (r->flow.components[i] != NULL((void *)0)) {
2097 f->data[len++] = i;
2098 component_finish(i, r->flow.components[i],
2099 r->flow.complen[i]);
2100 memcpy(f->data + len, r->flow.components[i],
2101 r->flow.complen[i]);
2102 len += r->flow.complen[i];
2103 }
2104
2105 return f;
2106}