Bug Summary

File:src/usr.sbin/bgpd/rtr_proto.c
Warning:line 788, column 2
Potential leak of memory pointed to by 'aspa'

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 rtr_proto.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.sbin/bgpd/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/usr.sbin/bgpd -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/bgpd/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.sbin/bgpd/rtr_proto.c
1/* $OpenBSD: rtr_proto.c,v 1.28 2024/01/10 16:08:36 claudio Exp $ */
2
3/*
4 * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18#include <sys/tree.h>
19#include <errno(*__errno()).h>
20#include <stdint.h>
21#include <poll.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26
27#include "bgpd.h"
28#include "session.h"
29#include "log.h"
30
31struct rtr_header {
32 uint8_t version;
33 uint8_t type;
34 uint16_t session_id; /* or error code */
35 uint32_t length;
36} __packed__attribute__((__packed__));
37
38#define RTR_MAX_VERSION2 2
39#define RTR_MAX_LEN2048 2048
40#define RTR_DEFAULT_REFRESH3600 3600
41#define RTR_DEFAULT_RETRY600 600
42#define RTR_DEFAULT_EXPIRE7200 7200
43#define RTR_DEFAULT_ACTIVE60 60
44
45enum rtr_pdu_type {
46 SERIAL_NOTIFY = 0,
47 SERIAL_QUERY,
48 RESET_QUERY,
49 CACHE_RESPONSE,
50 IPV4_PREFIX,
51 IPV6_PREFIX = 6,
52 END_OF_DATA = 7,
53 CACHE_RESET = 8,
54 ROUTER_KEY = 9,
55 ERROR_REPORT = 10,
56 ASPA = 11,
57};
58
59struct rtr_notify {
60 struct rtr_header hdr;
61 uint32_t serial;
62} __packed__attribute__((__packed__));
63
64struct rtr_query {
65 struct rtr_header hdr;
66 uint32_t serial;
67} __packed__attribute__((__packed__));
68
69struct rtr_reset {
70 struct rtr_header hdr;
71} __packed__attribute__((__packed__));
72
73struct rtr_response {
74 struct rtr_header hdr;
75} __packed__attribute__((__packed__));
76
77#define FLAG_ANNOUNCE0x1 0x1
78#define FLAG_MASK0x1 FLAG_ANNOUNCE0x1
79struct rtr_ipv4 {
80 struct rtr_header hdr;
81 uint8_t flags;
82 uint8_t prefixlen;
83 uint8_t maxlen;
84 uint8_t zero;
85 uint32_t prefix;
86 uint32_t asnum;
87} __packed__attribute__((__packed__));
88
89struct rtr_ipv6 {
90 struct rtr_header hdr;
91 uint8_t flags;
92 uint8_t prefixlen;
93 uint8_t maxlen;
94 uint8_t zero;
95 uint32_t prefix[4];
96 uint32_t asnum;
97} __packed__attribute__((__packed__));
98
99struct rtr_routerkey {
100 struct rtr_header hdr;
101 uint8_t ski[20];
102 uint32_t asnum;
103 /* followed by Subject Public Key Info */
104} __packed__attribute__((__packed__));
105
106#define FLAG_AFI_V60x1 0x1
107#define FLAG_AFI_MASK0x1 FLAG_AFI_V60x1
108struct rtr_aspa {
109 struct rtr_header hdr;
110 uint8_t flags;
111 uint8_t afi_flags;
112 uint16_t cnt;
113 uint32_t cas;
114 /* array of spas with cnt elements follows */
115} __packed__attribute__((__packed__));
116
117struct rtr_endofdata {
118 struct rtr_header hdr;
119 uint32_t serial;
120 uint32_t refresh;
121 uint32_t retry;
122 uint32_t expire;
123} __packed__attribute__((__packed__));
124
125struct rtr_endofdata_v0 {
126 struct rtr_header hdr;
127 uint32_t serial;
128} __packed__attribute__((__packed__));
129
130enum rtr_event {
131 RTR_EVNT_START,
132 RTR_EVNT_CON_OPEN,
133 RTR_EVNT_CON_CLOSE,
134 RTR_EVNT_TIMER_REFRESH,
135 RTR_EVNT_TIMER_RETRY,
136 RTR_EVNT_TIMER_EXPIRE,
137 RTR_EVNT_TIMER_ACTIVE,
138 RTR_EVNT_SEND_ERROR,
139 RTR_EVNT_SERIAL_NOTIFY,
140 RTR_EVNT_CACHE_RESPONSE,
141 RTR_EVNT_END_OF_DATA,
142 RTR_EVNT_CACHE_RESET,
143 RTR_EVNT_NO_DATA,
144 RTR_EVNT_RESET_AND_CLOSE,
145 RTR_EVNT_UNSUPP_PROTO_VERSION,
146 RTR_EVNT_NEGOTIATION_DONE,
147};
148
149static const char *rtr_eventnames[] = {
150 "start",
151 "connection open",
152 "connection closed",
153 "refresh timer expired",
154 "retry timer expired",
155 "expire timer expired",
156 "activity timer expired",
157 "sent error",
158 "serial notify received",
159 "cache response received",
160 "end of data received",
161 "cache reset received",
162 "no data",
163 "connection closed with reset",
164 "unsupported protocol version",
165 "negotiation done",
166};
167
168enum rtr_state {
169 RTR_STATE_CLOSED,
170 RTR_STATE_ERROR,
171 /* sessions with a state below this line will poll for incoming data */
172 RTR_STATE_ESTABLISHED,
173 RTR_STATE_EXCHANGE,
174 RTR_STATE_NEGOTIATION,
175};
176
177static const char *rtr_statenames[] = {
178 "closed",
179 "error",
180 "established",
181 "exchange",
182 "negotiation",
183};
184
185struct rtr_session {
186 TAILQ_ENTRY(rtr_session)struct { struct rtr_session *tqe_next; struct rtr_session **tqe_prev
; }
entry;
187 char descr[PEER_DESCR_LEN32];
188 struct roa_tree roa_set;
189 struct aspa_tree aspa;
190 struct aspa_tree aspa_oldv6;
191 struct ibuf_read r;
192 struct msgbuf w;
193 struct timer_head timers;
194 uint32_t id; /* rtr_config id */
195 uint32_t serial;
196 uint32_t refresh;
197 uint32_t retry;
198 uint32_t expire;
199 uint32_t active;
200 int session_id;
201 int fd;
202 int active_lock;
203 enum rtr_state state;
204 enum reconf_action reconf_action;
205 enum rtr_error last_sent_error;
206 enum rtr_error last_recv_error;
207 char last_sent_msg[REASON_LEN256];
208 char last_recv_msg[REASON_LEN256];
209 uint8_t version;
210};
211
212TAILQ_HEAD(, rtr_session)struct { struct rtr_session *tqh_first; struct rtr_session **
tqh_last; }
rtrs = TAILQ_HEAD_INITIALIZER(rtrs){ ((void *)0), &(rtrs).tqh_first };
213
214static void rtr_fsm(struct rtr_session *, enum rtr_event);
215
216static const char *
217log_rtr(struct rtr_session *rs)
218{
219 return rs->descr;
220}
221
222static const char *
223log_rtr_type(enum rtr_pdu_type type)
224{
225 static char buf[20];
226
227 switch (type) {
228 case SERIAL_NOTIFY:
229 return "serial notify";
230 case SERIAL_QUERY:
231 return "serial query";
232 case RESET_QUERY:
233 return "reset query";
234 case CACHE_RESPONSE:
235 return "cache response";
236 case IPV4_PREFIX:
237 return "IPv4 prefix";
238 case IPV6_PREFIX:
239 return "IPv6 prefix";
240 case END_OF_DATA:
241 return "end of data";
242 case CACHE_RESET:
243 return "cache reset";
244 case ROUTER_KEY:
245 return "router key";
246 case ERROR_REPORT:
247 return "error report";
248 case ASPA:
249 return "aspa";
250 default:
251 snprintf(buf, sizeof(buf), "unknown %u", type);
252 return buf;
253 }
254};
255
256static void
257rtr_reset_cache(struct rtr_session *rs)
258{
259 /* reset session */
260 rs->session_id = -1;
261 timer_stop(&rs->timers, Timer_Rtr_Expire);
262 free_roatree(&rs->roa_set);
263 free_aspatree(&rs->aspa);
264 free_aspatree(&rs->aspa_oldv6);
265}
266
267static struct ibuf *
268rtr_newmsg(struct rtr_session *rs, enum rtr_pdu_type type, uint32_t len,
269 uint16_t session_id)
270{
271 struct ibuf *buf;
272 int saved_errno;
273
274 if (len > RTR_MAX_LEN2048) {
275 errno(*__errno()) = ERANGE34;
276 return NULL((void *)0);
277 }
278 len += sizeof(struct rtr_header);
279 if ((buf = ibuf_open(len)) == NULL((void *)0))
280 goto fail;
281 if (ibuf_add_n8(buf, rs->version) == -1)
282 goto fail;
283 if (ibuf_add_n8(buf, type) == -1)
284 goto fail;
285 if (ibuf_add_n16(buf, session_id) == -1)
286 goto fail;
287 if (ibuf_add_n32(buf, len) == -1)
288 goto fail;
289
290 return buf;
291
292 fail:
293 saved_errno = errno(*__errno());
294 ibuf_free(buf);
295 errno(*__errno()) = saved_errno;
296 return NULL((void *)0);
297}
298
299static void rtr_send_error(struct rtr_session *, struct ibuf *, enum rtr_error,
300 const char *, ...) __attribute__((__format__ (printf, 4, 5)));
301
302/*
303 * Try to send an error PDU to cache, put connection into error
304 * state.
305 */
306static void
307rtr_send_error(struct rtr_session *rs, struct ibuf *pdu, enum rtr_error err,
308 const char *fmt, ...)
309{
310 struct ibuf *buf;
311 va_list ap;
312 size_t len = 0, mlen = 0;
313
314 rs->last_sent_error = err;
315 memset(rs->last_sent_msg, 0, sizeof(rs->last_sent_msg));
316 if (fmt != NULL((void *)0)) {
317 va_start(ap, fmt)__builtin_va_start((ap), fmt);
318 vsnprintf(rs->last_sent_msg, sizeof(rs->last_sent_msg),
319 fmt, ap);
320 mlen = strlen(rs->last_sent_msg);
321 va_end(ap)__builtin_va_end((ap));
322 }
323
324 log_warnx("rtr %s: sending error: %s%s%s", log_rtr(rs),
325 log_rtr_error(err), mlen > 0 ? ": " : "", rs->last_sent_msg);
326
327 if (pdu != NULL((void *)0)) {
328 ibuf_rewind(pdu);
329 len = ibuf_size(pdu);
330 }
331
332 buf = rtr_newmsg(rs, ERROR_REPORT, 2 * sizeof(uint32_t) + len + mlen,
333 err);
334 if (buf == NULL((void *)0))
335 goto fail;
336 if (ibuf_add_n32(buf, len) == -1)
337 goto fail;
338 if (pdu != NULL((void *)0)) {
339 if (ibuf_add_ibuf(buf, pdu) == -1)
340 goto fail;
341 }
342 if (ibuf_add_n32(buf, mlen) == -1)
343 goto fail;
344 if (ibuf_add(buf, rs->last_sent_msg, mlen) == -1)
345 goto fail;
346 ibuf_close(&rs->w, buf);
347
348 rtr_fsm(rs, RTR_EVNT_SEND_ERROR);
349 return;
350
351 fail:
352 log_warn("rtr %s: send error report", log_rtr(rs));
353 ibuf_free(buf);
354}
355
356static void
357rtr_send_reset_query(struct rtr_session *rs)
358{
359 struct ibuf *buf;
360
361 buf = rtr_newmsg(rs, RESET_QUERY, 0, 0);
362 if (buf == NULL((void *)0))
363 goto fail;
364 ibuf_close(&rs->w, buf);
365 return;
366
367 fail:
368 rtr_send_error(rs, NULL((void *)0), INTERNAL_ERROR,
369 "send %s: %s", log_rtr_type(RESET_QUERY), strerror(errno(*__errno())));
370 ibuf_free(buf);
371}
372
373static void
374rtr_send_serial_query(struct rtr_session *rs)
375{
376 struct ibuf *buf;
377
378 buf = rtr_newmsg(rs, SERIAL_QUERY, sizeof(uint32_t), rs->session_id);
379 if (buf == NULL((void *)0))
380 goto fail;
381 if (ibuf_add_n32(buf, rs->serial) == -1)
382 goto fail;
383 ibuf_close(&rs->w, buf);
384 return;
385
386 fail:
387 rtr_send_error(rs, NULL((void *)0), INTERNAL_ERROR,
388 "send %s: %s", log_rtr_type(SERIAL_QUERY), strerror(errno(*__errno())));
389 ibuf_free(buf);
390}
391
392/*
393 * Check the session_id of the rtr_header to match the expected value.
394 * Returns -1 on failure and 0 on success.
395 */
396static int
397rtr_check_session_id(struct rtr_session *rs, uint16_t session_id,
398 struct rtr_header *rh, struct ibuf *pdu)
399{
400 if (session_id != ntohs(rh->session_id)(__uint16_t)(__builtin_constant_p(rh->session_id) ? (__uint16_t
)(((__uint16_t)(rh->session_id) & 0xffU) << 8 | (
(__uint16_t)(rh->session_id) & 0xff00U) >> 8) : __swap16md
(rh->session_id))
) {
401 rtr_send_error(rs, pdu, CORRUPT_DATA,
402 "%s: bad session_id %d (expected %d)",
403 log_rtr_type(rh->type), ntohs(rh->session_id)(__uint16_t)(__builtin_constant_p(rh->session_id) ? (__uint16_t
)(((__uint16_t)(rh->session_id) & 0xffU) << 8 | (
(__uint16_t)(rh->session_id) & 0xff00U) >> 8) : __swap16md
(rh->session_id))
, session_id);
404 return -1;
405 }
406 return 0;
407}
408
409/*
410 * Parse the common rtr header (first 8 bytes) including the
411 * included length field.
412 * Returns -1 on failure. On success msgtype and msglen are set
413 * and the function return 0.
414 */
415static int
416rtr_parse_header(struct rtr_session *rs, struct ibuf *hdr,
417 size_t *msglen, enum rtr_pdu_type *msgtype)
418{
419 struct rtr_header rh;
420 size_t len;
421
422 if (ibuf_get(hdr, &rh, sizeof(rh)) == -1)
423 fatal("%s: ibuf_get", __func__);
424
425 len = ntohl(rh.length)(__uint32_t)(__builtin_constant_p(rh.length) ? (__uint32_t)((
(__uint32_t)(rh.length) & 0xff) << 24 | ((__uint32_t
)(rh.length) & 0xff00) << 8 | ((__uint32_t)(rh.length
) & 0xff0000) >> 8 | ((__uint32_t)(rh.length) &
0xff000000) >> 24) : __swap32md(rh.length))
;
426
427 if (len > RTR_MAX_LEN2048) {
428 rtr_send_error(rs, hdr, CORRUPT_DATA, "%s: too big: %zu bytes",
429 log_rtr_type(rh.type), len);
430 return -1;
431 }
432
433 if (rs->state == RTR_STATE_NEGOTIATION) {
434 switch (rh.type) {
435 case CACHE_RESPONSE:
436 case CACHE_RESET:
437 case ERROR_REPORT:
438 if (rh.version < rs->version)
439 rs->version = rh.version;
440 rtr_fsm(rs, RTR_EVNT_NEGOTIATION_DONE);
441 break;
442 case SERIAL_NOTIFY:
443 /* ignore SERIAL_NOTIFY */
444 break;
445 default:
446 rtr_send_error(rs, hdr, CORRUPT_DATA,
447 "%s: out of context", log_rtr_type(rh.type));
448 return -1;
449 }
450 } else if (rh.version != rs->version && rh.type != ERROR_REPORT) {
451 goto badversion;
452 }
453
454 switch (rh.type) {
455 case SERIAL_NOTIFY:
456 if (len != sizeof(struct rtr_notify))
457 goto badlen;
458 break;
459 case CACHE_RESPONSE:
460 if (len != sizeof(struct rtr_response))
461 goto badlen;
462 break;
463 case IPV4_PREFIX:
464 if (len != sizeof(struct rtr_ipv4))
465 goto badlen;
466 break;
467 case IPV6_PREFIX:
468 if (len != sizeof(struct rtr_ipv6))
469 goto badlen;
470 break;
471 case END_OF_DATA:
472 if (rs->version == 0) {
473 if (len != sizeof(struct rtr_endofdata_v0))
474 goto badlen;
475 } else {
476 if (len != sizeof(struct rtr_endofdata))
477 goto badlen;
478 }
479 break;
480 case CACHE_RESET:
481 if (len != sizeof(struct rtr_reset))
482 goto badlen;
483 break;
484 case ROUTER_KEY:
485 if (rs->version < 1)
486 goto badversion;
487 if (len < sizeof(struct rtr_routerkey))
488 goto badlen;
489 break;
490 case ERROR_REPORT:
491 if (len < 16)
492 goto badlen;
493 break;
494 case ASPA:
495 if (rs->version < 2)
496 goto badversion;
497 if (len < sizeof(struct rtr_aspa) || (len % 4) != 0)
498 goto badlen;
499 break;
500 default:
501 rtr_send_error(rs, hdr, UNSUPP_PDU_TYPE, "type %s",
502 log_rtr_type(rh.type));
503 return -1;
504 }
505
506 *msglen = len;
507 *msgtype = rh.type;
508
509 return 0;
510
511 badlen:
512 rtr_send_error(rs, hdr, CORRUPT_DATA, "%s: bad length: %zu bytes",
513 log_rtr_type(rh.type), len);
514 return -1;
515
516 badversion:
517 rtr_send_error(rs, hdr, UNEXP_PROTOCOL_VERS, "%s: version %d",
518 log_rtr_type(rh.type), rh.version);
519 return -1;
520}
521
522static int
523rtr_parse_notify(struct rtr_session *rs, struct ibuf *pdu)
524{
525 struct rtr_notify notify;
526
527 /* ignore SERIAL_NOTIFY during startup */
528 if (rs->state == RTR_STATE_NEGOTIATION)
529 return 0;
530
531 if (ibuf_get(pdu, &notify, sizeof(notify)) == -1)
532 goto badlen;
533
534 if (rtr_check_session_id(rs, rs->session_id, &notify.hdr, pdu) == -1)
535 return -1;
536
537 if (rs->state != RTR_STATE_ESTABLISHED) {
538 log_warnx("rtr %s: received %s: while in state %s (ignored)",
539 log_rtr(rs), log_rtr_type(SERIAL_NOTIFY),
540 rtr_statenames[rs->state]);
541 return 0;
542 }
543
544 rtr_fsm(rs, RTR_EVNT_SERIAL_NOTIFY);
545 return 0;
546
547 badlen:
548 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: bad length",
549 log_rtr_type(SERIAL_NOTIFY));
550 return -1;
551}
552
553static int
554rtr_parse_cache_response(struct rtr_session *rs, struct ibuf *pdu)
555{
556 struct rtr_response resp;
557
558 if (ibuf_get(pdu, &resp, sizeof(resp)) == -1)
559 goto badlen;
560
561 /* set session_id if not yet happened */
562 if (rs->session_id == -1)
563 rs->session_id = ntohs(resp.hdr.session_id)(__uint16_t)(__builtin_constant_p(resp.hdr.session_id) ? (__uint16_t
)(((__uint16_t)(resp.hdr.session_id) & 0xffU) << 8 |
((__uint16_t)(resp.hdr.session_id) & 0xff00U) >> 8
) : __swap16md(resp.hdr.session_id))
;
564
565 if (rtr_check_session_id(rs, rs->session_id, &resp.hdr, pdu) == -1)
566 return -1;
567
568 if (rs->state != RTR_STATE_ESTABLISHED) {
569 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: out of context",
570 log_rtr_type(CACHE_RESPONSE));
571 return -1;
572 }
573
574 rtr_fsm(rs, RTR_EVNT_CACHE_RESPONSE);
575 return 0;
576
577 badlen:
578 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: bad length",
579 log_rtr_type(CACHE_RESPONSE));
580 return -1;
581}
582
583static int
584rtr_parse_ipv4_prefix(struct rtr_session *rs, struct ibuf *pdu)
585{
586 struct rtr_ipv4 ip4;
587 struct roa *roa;
588
589 if (ibuf_get(pdu, &ip4, sizeof(ip4)) == -1)
590 goto badlen;
591
592 if (rtr_check_session_id(rs, 0, &ip4.hdr, pdu) == -1)
593 return -1;
594
595 if (rs->state != RTR_STATE_EXCHANGE) {
596 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: out of context",
597 log_rtr_type(IPV4_PREFIX));
598 return -1;
599 }
600
601 if (ip4.prefixlen > 32 || ip4.maxlen > 32 ||
602 ip4.prefixlen > ip4.maxlen) {
603 rtr_send_error(rs, pdu, CORRUPT_DATA,
604 "%s: bad prefixlen / maxlen", log_rtr_type(IPV4_PREFIX));
605 return -1;
606 }
607
608 if ((roa = calloc(1, sizeof(*roa))) == NULL((void *)0)) {
609 rtr_send_error(rs, NULL((void *)0), INTERNAL_ERROR, "out of memory");
610 return -1;
611 }
612 roa->aid = AID_INET1;
613 roa->prefixlen = ip4.prefixlen;
614 roa->maxlen = ip4.maxlen;
615 roa->asnum = ntohl(ip4.asnum)(__uint32_t)(__builtin_constant_p(ip4.asnum) ? (__uint32_t)((
(__uint32_t)(ip4.asnum) & 0xff) << 24 | ((__uint32_t
)(ip4.asnum) & 0xff00) << 8 | ((__uint32_t)(ip4.asnum
) & 0xff0000) >> 8 | ((__uint32_t)(ip4.asnum) &
0xff000000) >> 24) : __swap32md(ip4.asnum))
;
616 roa->prefix.inet.s_addr = ip4.prefix;
617
618 if (ip4.flags & FLAG_ANNOUNCE0x1) {
619 if (RB_INSERT(roa_tree, &rs->roa_set, roa)roa_tree_RB_INSERT(&rs->roa_set, roa) != NULL((void *)0)) {
620 rtr_send_error(rs, pdu, DUP_REC_RECV, "%s %s",
621 log_rtr_type(IPV4_PREFIX), log_roa(roa));
622 free(roa);
623 return -1;
624 }
625 } else {
626 struct roa *r;
627
628 r = RB_FIND(roa_tree, &rs->roa_set, roa)roa_tree_RB_FIND(&rs->roa_set, roa);
629 if (r == NULL((void *)0)) {
630 rtr_send_error(rs, pdu, UNK_REC_WDRAWL, "%s %s",
631 log_rtr_type(IPV4_PREFIX), log_roa(roa));
632 free(roa);
633 return -1;
634 }
635 RB_REMOVE(roa_tree, &rs->roa_set, r)roa_tree_RB_REMOVE(&rs->roa_set, r);
636 free(r);
637 free(roa);
638 }
639
640 return 0;
641
642 badlen:
643 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: bad length",
644 log_rtr_type(IPV4_PREFIX));
645 return -1;
646}
647
648static int
649rtr_parse_ipv6_prefix(struct rtr_session *rs, struct ibuf *pdu)
650{
651 struct rtr_ipv6 ip6;
652 struct roa *roa;
653
654 if (ibuf_get(pdu, &ip6, sizeof(ip6)) == -1)
655 goto badlen;
656
657 if (rtr_check_session_id(rs, 0, &ip6.hdr, pdu) == -1)
658 return -1;
659
660 if (rs->state != RTR_STATE_EXCHANGE) {
661 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: out of context",
662 log_rtr_type(IPV6_PREFIX));
663 return -1;
664 }
665
666 if (ip6.prefixlen > 128 || ip6.maxlen > 128 ||
667 ip6.prefixlen > ip6.maxlen) {
668 rtr_send_error(rs, pdu, CORRUPT_DATA,
669 "%s: bad prefixlen / maxlen", log_rtr_type(IPV6_PREFIX));
670 return -1;
671 }
672
673 if ((roa = calloc(1, sizeof(*roa))) == NULL((void *)0)) {
674 rtr_send_error(rs, NULL((void *)0), INTERNAL_ERROR, "out of memory");
675 return -1;
676 }
677 roa->aid = AID_INET62;
678 roa->prefixlen = ip6.prefixlen;
679 roa->maxlen = ip6.maxlen;
680 roa->asnum = ntohl(ip6.asnum)(__uint32_t)(__builtin_constant_p(ip6.asnum) ? (__uint32_t)((
(__uint32_t)(ip6.asnum) & 0xff) << 24 | ((__uint32_t
)(ip6.asnum) & 0xff00) << 8 | ((__uint32_t)(ip6.asnum
) & 0xff0000) >> 8 | ((__uint32_t)(ip6.asnum) &
0xff000000) >> 24) : __swap32md(ip6.asnum))
;
681 memcpy(&roa->prefix.inet6, ip6.prefix, sizeof(roa->prefix.inet6));
682
683 if (ip6.flags & FLAG_ANNOUNCE0x1) {
684 if (RB_INSERT(roa_tree, &rs->roa_set, roa)roa_tree_RB_INSERT(&rs->roa_set, roa) != NULL((void *)0)) {
685 rtr_send_error(rs, pdu, DUP_REC_RECV, "%s %s",
686 log_rtr_type(IPV6_PREFIX), log_roa(roa));
687 free(roa);
688 return -1;
689 }
690 } else {
691 struct roa *r;
692
693 r = RB_FIND(roa_tree, &rs->roa_set, roa)roa_tree_RB_FIND(&rs->roa_set, roa);
694 if (r == NULL((void *)0)) {
695 rtr_send_error(rs, pdu, UNK_REC_WDRAWL, "%s %s",
696 log_rtr_type(IPV6_PREFIX), log_roa(roa));
697 free(roa);
698 return -1;
699 }
700 RB_REMOVE(roa_tree, &rs->roa_set, r)roa_tree_RB_REMOVE(&rs->roa_set, r);
701 free(r);
702 free(roa);
703 }
704 return 0;
705
706 badlen:
707 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: bad length",
708 log_rtr_type(IPV6_PREFIX));
709 return -1;
710}
711
712static int
713rtr_parse_aspa(struct rtr_session *rs, struct ibuf *pdu)
714{
715 struct rtr_aspa rtr_aspa;
716 struct aspa_tree *aspatree;
717 struct aspa_set *aspa, *a;
718 uint16_t cnt, i;
719
720 if (ibuf_get(pdu, &rtr_aspa, sizeof(rtr_aspa)) == -1)
29
Assuming the condition is false
721 goto badlen;
722
723 cnt = ntohs(rtr_aspa.cnt)(__uint16_t)(__builtin_constant_p(rtr_aspa.cnt) ? (__uint16_t
)(((__uint16_t)(rtr_aspa.cnt) & 0xffU) << 8 | ((__uint16_t
)(rtr_aspa.cnt) & 0xff00U) >> 8) : __swap16md(rtr_aspa
.cnt))
;
30
Taking false branch
31
'?' condition is false
724 if (ibuf_size(pdu) != cnt * sizeof(uint32_t))
32
Assuming the condition is false
33
Taking false branch
725 goto badlen;
726
727 if (rs->state != RTR_STATE_EXCHANGE) {
34
Assuming field 'state' is equal to RTR_STATE_EXCHANGE
35
Taking false branch
728 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: out of context",
729 log_rtr_type(ASPA));
730 return -1;
731 }
732
733 if (rtr_aspa.afi_flags & FLAG_AFI_V60x1) {
36
Assuming the condition is false
37
Taking false branch
734 aspatree = &rs->aspa_oldv6;
735 } else {
736 aspatree = &rs->aspa;
737 }
738
739 /* create aspa_set entry from the rtr aspa pdu */
740 if ((aspa = calloc(1, sizeof(*aspa))) == NULL((void *)0)) {
38
Memory is allocated
39
Assuming the condition is false
741 rtr_send_error(rs, NULL((void *)0), INTERNAL_ERROR, "out of memory");
742 return -1;
743 }
744 aspa->as = ntohl(rtr_aspa.cas)(__uint32_t)(__builtin_constant_p(rtr_aspa.cas) ? (__uint32_t
)(((__uint32_t)(rtr_aspa.cas) & 0xff) << 24 | ((__uint32_t
)(rtr_aspa.cas) & 0xff00) << 8 | ((__uint32_t)(rtr_aspa
.cas) & 0xff0000) >> 8 | ((__uint32_t)(rtr_aspa.cas
) & 0xff000000) >> 24) : __swap32md(rtr_aspa.cas))
;
40
Taking false branch
41
'?' condition is false
745 aspa->num = cnt;
746 if (cnt > 0) {
42
Assuming 'cnt' is > 0
43
Taking true branch
747 if ((aspa->tas = calloc(cnt, sizeof(uint32_t))) == NULL((void *)0)) {
44
Assuming the condition is false
45
Taking false branch
748 free_aspa(aspa);
749 rtr_send_error(rs, NULL((void *)0), INTERNAL_ERROR,
750 "out of memory");
751 return -1;
752 }
753 for (i = 0; i
45.1
'i' is < 'cnt'
< cnt; i++) {
46
Loop condition is true. Entering loop body
754 if (ibuf_get_n32(pdu, &aspa->tas[i]) == -1)
47
Assuming the condition is true
48
Taking true branch
755 goto badlen;
49
Control jumps to line 788
756 }
757 }
758
759 if (rtr_aspa.flags & FLAG_ANNOUNCE0x1) {
760 a = RB_INSERT(aspa_tree, aspatree, aspa)aspa_tree_RB_INSERT(aspatree, aspa);
761 if (a != NULL((void *)0)) {
762 RB_REMOVE(aspa_tree, aspatree, a)aspa_tree_RB_REMOVE(aspatree, a);
763 free_aspa(a);
764
765 if (RB_INSERT(aspa_tree, aspatree, aspa)aspa_tree_RB_INSERT(aspatree, aspa) != NULL((void *)0)) {
766 rtr_send_error(rs, NULL((void *)0), INTERNAL_ERROR,
767 "corrupt aspa tree");
768 free_aspa(aspa);
769 return -1;
770 }
771 }
772 } else {
773 a = RB_FIND(aspa_tree, aspatree, aspa)aspa_tree_RB_FIND(aspatree, aspa);
774 if (a == NULL((void *)0)) {
775 rtr_send_error(rs, pdu, UNK_REC_WDRAWL, "%s %s",
776 log_rtr_type(ASPA), log_aspa(aspa));
777 free_aspa(aspa);
778 return -1;
779 }
780 RB_REMOVE(aspa_tree, aspatree, a)aspa_tree_RB_REMOVE(aspatree, a);
781 free_aspa(a);
782 free_aspa(aspa);
783 }
784
785 return 0;
786
787 badlen:
788 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: bad length",
50
Potential leak of memory pointed to by 'aspa'
789 log_rtr_type(ASPA));
790 return -1;
791}
792
793static int
794rtr_parse_end_of_data_v0(struct rtr_session *rs, struct ibuf *pdu)
795{
796 struct rtr_endofdata_v0 eod;
797
798 if (ibuf_get(pdu, &eod, sizeof(eod)) == -1)
799 goto badlen;
800
801 if (rtr_check_session_id(rs, rs->session_id, &eod.hdr, pdu) == -1)
802 return -1;
803
804 if (rs->state != RTR_STATE_EXCHANGE) {
805 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: out of context",
806 log_rtr_type(END_OF_DATA));
807 return -1;
808 }
809
810 rs->serial = ntohl(eod.serial)(__uint32_t)(__builtin_constant_p(eod.serial) ? (__uint32_t)(
((__uint32_t)(eod.serial) & 0xff) << 24 | ((__uint32_t
)(eod.serial) & 0xff00) << 8 | ((__uint32_t)(eod.serial
) & 0xff0000) >> 8 | ((__uint32_t)(eod.serial) &
0xff000000) >> 24) : __swap32md(eod.serial))
;
811
812 rtr_fsm(rs, RTR_EVNT_END_OF_DATA);
813 return 0;
814
815 badlen:
816 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: bad length",
817 log_rtr_type(END_OF_DATA));
818 return -1;
819}
820
821static int
822rtr_parse_end_of_data(struct rtr_session *rs, struct ibuf *pdu)
823{
824 struct rtr_endofdata eod;
825 uint32_t t;
826
827 /* version 0 does not have the timing values */
828 if (rs->version == 0)
829 return rtr_parse_end_of_data_v0(rs, pdu);
830
831 if (ibuf_get(pdu, &eod, sizeof(eod)) == -1)
832 goto badlen;
833
834 if (rtr_check_session_id(rs, rs->session_id, &eod.hdr, pdu) == -1)
835 return -1;
836
837 if (rs->state != RTR_STATE_EXCHANGE) {
838 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: out of context",
839 log_rtr_type(END_OF_DATA));
840 return -1;
841 }
842
843 rs->serial = ntohl(eod.serial)(__uint32_t)(__builtin_constant_p(eod.serial) ? (__uint32_t)(
((__uint32_t)(eod.serial) & 0xff) << 24 | ((__uint32_t
)(eod.serial) & 0xff00) << 8 | ((__uint32_t)(eod.serial
) & 0xff0000) >> 8 | ((__uint32_t)(eod.serial) &
0xff000000) >> 24) : __swap32md(eod.serial))
;
844 /* validate timer values to be in the right range */
845 t = ntohl(eod.refresh)(__uint32_t)(__builtin_constant_p(eod.refresh) ? (__uint32_t)
(((__uint32_t)(eod.refresh) & 0xff) << 24 | ((__uint32_t
)(eod.refresh) & 0xff00) << 8 | ((__uint32_t)(eod.refresh
) & 0xff0000) >> 8 | ((__uint32_t)(eod.refresh) &
0xff000000) >> 24) : __swap32md(eod.refresh))
;
846 if (t < 1 || t > 86400)
847 goto bad;
848 rs->refresh = t;
849 t = ntohl(eod.retry)(__uint32_t)(__builtin_constant_p(eod.retry) ? (__uint32_t)((
(__uint32_t)(eod.retry) & 0xff) << 24 | ((__uint32_t
)(eod.retry) & 0xff00) << 8 | ((__uint32_t)(eod.retry
) & 0xff0000) >> 8 | ((__uint32_t)(eod.retry) &
0xff000000) >> 24) : __swap32md(eod.retry))
;
850 if (t < 1 || t > 7200)
851 goto bad;
852 rs->retry = t;
853 t = ntohl(eod.expire)(__uint32_t)(__builtin_constant_p(eod.expire) ? (__uint32_t)(
((__uint32_t)(eod.expire) & 0xff) << 24 | ((__uint32_t
)(eod.expire) & 0xff00) << 8 | ((__uint32_t)(eod.expire
) & 0xff0000) >> 8 | ((__uint32_t)(eod.expire) &
0xff000000) >> 24) : __swap32md(eod.expire))
;
854 if (t < 600 || t > 172800)
855 goto bad;
856 if (t <= rs->retry || t <= rs->refresh)
857 goto bad;
858 rs->expire = t;
859
860 rtr_fsm(rs, RTR_EVNT_END_OF_DATA);
861 return 0;
862
863bad:
864 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: bad timeout values",
865 log_rtr_type(END_OF_DATA));
866 return -1;
867
868badlen:
869 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: bad length",
870 log_rtr_type(END_OF_DATA));
871 return -1;
872}
873
874static int
875rtr_parse_cache_reset(struct rtr_session *rs, struct ibuf *pdu)
876{
877 struct rtr_reset reset;
878
879 if (ibuf_get(pdu, &reset, sizeof(reset)) == -1)
880 goto badlen;
881
882 if (rtr_check_session_id(rs, 0, &reset.hdr, pdu) == -1)
883 return -1;
884
885 if (rs->state != RTR_STATE_ESTABLISHED) {
886 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: out of context",
887 log_rtr_type(CACHE_RESET));
888 return -1;
889 }
890
891 rtr_fsm(rs, RTR_EVNT_CACHE_RESET);
892 return 0;
893
894 badlen:
895 rtr_send_error(rs, pdu, CORRUPT_DATA, "%s: bad length",
896 log_rtr_type(CACHE_RESET));
897 return -1;
898}
899
900static char *
901ibuf_get_string(struct ibuf *buf, size_t len)
902{
903 char *str;
904
905 if (ibuf_size(buf) < len) {
906 errno(*__errno()) = EBADMSG92;
907 return (NULL((void *)0));
908 }
909 str = strndup(ibuf_data(buf), len);
910 if (str == NULL((void *)0))
911 return (NULL((void *)0));
912 ibuf_skip(buf, len);
913 return (str);
914}
915
916/*
917 * Parse an Error Response message. This function behaves a bit different
918 * from other parse functions since on error the connection needs to be
919 * dropped without sending an error response back.
920 */
921static int
922rtr_parse_error(struct rtr_session *rs, struct ibuf *pdu)
923{
924 struct rtr_header rh;
925 struct ibuf err_pdu;
926 uint32_t pdu_len, msg_len;
927 char *str = NULL((void *)0);
928 uint16_t errcode;
929 int rv = -1;
930
931 if (ibuf_get(pdu, &rh, sizeof(rh)) == -1)
932 goto fail;
933 errcode = ntohs(rh.session_id)(__uint16_t)(__builtin_constant_p(rh.session_id) ? (__uint16_t
)(((__uint16_t)(rh.session_id) & 0xffU) << 8 | ((__uint16_t
)(rh.session_id) & 0xff00U) >> 8) : __swap16md(rh.session_id
))
;
934
935 if (ibuf_get_n32(pdu, &pdu_len) == -1)
936 goto fail;
937
938 /* for now just ignore the embedded pdu */
939 if (ibuf_get_ibuf(pdu, pdu_len, &err_pdu) == -1)
940 goto fail;
941
942 if (ibuf_get_n32(pdu, &msg_len) == -1)
943 goto fail;
944
945 /* optional error msg */
946 if (msg_len != 0)
947 if ((str = ibuf_get_string(pdu, msg_len)) == NULL((void *)0))
948 goto fail;
949
950 log_warnx("rtr %s: received error: %s%s%s", log_rtr(rs),
951 log_rtr_error(errcode), str ? ": " : "", str ? str : "");
952
953 if (errcode == NO_DATA_AVAILABLE) {
954 rtr_fsm(rs, RTR_EVNT_NO_DATA);
955 rv = 0;
956 } else if (errcode == UNSUPP_PROTOCOL_VERS)
957 rtr_fsm(rs, RTR_EVNT_UNSUPP_PROTO_VERSION);
958 else
959 rtr_fsm(rs, RTR_EVNT_RESET_AND_CLOSE);
960
961 rs->last_recv_error = errcode;
962 if (str)
963 strlcpy(rs->last_recv_msg, str, sizeof(rs->last_recv_msg));
964 else
965 memset(rs->last_recv_msg, 0, sizeof(rs->last_recv_msg));
966
967 free(str);
968 return rv;
969
970 fail:
971 log_warnx("rtr %s: received %s: bad encoding", log_rtr(rs),
972 log_rtr_type(ERROR_REPORT));
973 rtr_fsm(rs, RTR_EVNT_RESET_AND_CLOSE);
974 return -1;
975}
976
977/*
978 * Try to process received rtr message, it is possible that not a full
979 * message is in the buffer. In that case stop, once new data is available
980 * a retry will be done.
981 */
982static void
983rtr_process_msg(struct rtr_session *rs)
984{
985 struct ibuf rbuf, hdr, msg;
986 size_t msglen;
987 enum rtr_pdu_type msgtype;
988
989 ibuf_from_buffer(&rbuf, rs->r.buf, rs->r.wpos);
990
991 for (;;) {
21
Loop condition is true. Entering loop body
992 if (ibuf_size(&rbuf) < sizeof(struct rtr_header))
22
Assuming the condition is false
23
Taking false branch
993 break;
994
995 /* parse header */
996 ibuf_from_buffer(&hdr, ibuf_data(&rbuf),
997 sizeof(struct rtr_header));
998 if (rtr_parse_header(rs, &hdr, &msglen, &msgtype) == -1)
24
Taking false branch
999 return;
1000
1001 /* extract message */
1002 if (ibuf_get_ibuf(&rbuf, msglen, &msg) == -1)
25
Assuming the condition is false
26
Taking false branch
1003 break;
1004
1005 switch (msgtype) {
27
Control jumps to 'case ASPA:' at line 1039
1006 case SERIAL_NOTIFY:
1007 if (rtr_parse_notify(rs, &msg) == -1)
1008 return;
1009 break;
1010 case CACHE_RESPONSE:
1011 if (rtr_parse_cache_response(rs, &msg) == -1)
1012 return;
1013 break;
1014 case IPV4_PREFIX:
1015 if (rtr_parse_ipv4_prefix(rs, &msg) == -1)
1016 return;
1017 break;
1018 case IPV6_PREFIX:
1019 if (rtr_parse_ipv6_prefix(rs, &msg) == -1)
1020 return;
1021 break;
1022 case END_OF_DATA:
1023 if (rtr_parse_end_of_data(rs, &msg) == -1)
1024 return;
1025 break;
1026 case CACHE_RESET:
1027 if (rtr_parse_cache_reset(rs, &msg) == -1)
1028 return;
1029 break;
1030 case ROUTER_KEY:
1031 /* silently ignore router key */
1032 break;
1033 case ERROR_REPORT:
1034 if (rtr_parse_error(rs, &msg) == -1) {
1035 /* no need to send back an error */
1036 return;
1037 }
1038 break;
1039 case ASPA:
1040 if (rtr_parse_aspa(rs, &msg) == -1)
28
Calling 'rtr_parse_aspa'
1041 return;
1042 break;
1043 default:
1044 /* unreachable, checked in rtr_parse_header() */
1045 rtr_send_error(rs, &msg, UNSUPP_PDU_TYPE, "type %s",
1046 log_rtr_type(msgtype));
1047 return;
1048 }
1049 }
1050
1051 memmove(&rs->r.buf, ibuf_data(&rbuf), ibuf_size(&rbuf));
1052 rs->r.wpos = ibuf_size(&rbuf);
1053}
1054
1055/*
1056 * Simple FSM for RTR sessions
1057 */
1058static void
1059rtr_fsm(struct rtr_session *rs, enum rtr_event event)
1060{
1061 enum rtr_state prev_state = rs->state;
1062
1063 switch (event) {
1064 case RTR_EVNT_UNSUPP_PROTO_VERSION:
1065 if (rs->state == RTR_STATE_NEGOTIATION) {
1066 if (rs->version > 0)
1067 rs->version--;
1068 else {
1069 /*
1070 * can't downgrade anymore, fail connection
1071 * RFC requires to send the error with our
1072 * highest version number.
1073 */
1074 rs->version = RTR_MAX_VERSION2;
1075 rtr_send_error(rs, NULL((void *)0), UNSUPP_PROTOCOL_VERS,
1076 "negotiation failed");
1077 return;
1078 }
1079
1080 if (rs->fd != -1) {
1081 /* flush buffers */
1082 msgbuf_clear(&rs->w);
1083 rs->r.wpos = 0;
1084 close(rs->fd);
1085 rs->fd = -1;
1086 }
1087
1088 /* retry connection with lower version */
1089 timer_set(&rs->timers, Timer_Rtr_Retry, rs->retry);
1090 rtr_imsg_compose(IMSG_SOCKET_CONN, rs->id, 0, NULL((void *)0), 0);
1091 break;
1092 }
1093 /* FALLTHROUGH */
1094 case RTR_EVNT_RESET_AND_CLOSE:
1095 rtr_reset_cache(rs);
1096 rtr_recalc();
1097 /* FALLTHROUGH */
1098 case RTR_EVNT_CON_CLOSE:
1099 if (rs->state == RTR_STATE_NEGOTIATION) {
1100 /* consider any close event as a version failure. */
1101 rtr_fsm(rs, RTR_EVNT_UNSUPP_PROTO_VERSION);
1102 break;
1103 }
1104 if (rs->fd != -1) {
1105 /* flush buffers */
1106 msgbuf_clear(&rs->w);
1107 rs->r.wpos = 0;
1108 close(rs->fd);
1109 rs->fd = -1;
1110 }
1111 rs->state = RTR_STATE_CLOSED;
1112 /* try to reopen session */
1113 timer_set(&rs->timers, Timer_Rtr_Retry,
1114 arc4random_uniform(10));
1115 break;
1116 case RTR_EVNT_START:
1117 case RTR_EVNT_TIMER_RETRY:
1118 switch (rs->state) {
1119 case RTR_STATE_ERROR:
1120 rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
1121 return;
1122 case RTR_STATE_CLOSED:
1123 timer_set(&rs->timers, Timer_Rtr_Retry, rs->retry);
1124 rtr_imsg_compose(IMSG_SOCKET_CONN, rs->id, 0, NULL((void *)0), 0);
1125 return;
1126 default:
1127 break;
1128 }
1129 /* FALLTHROUGH */
1130 case RTR_EVNT_CON_OPEN:
1131 timer_stop(&rs->timers, Timer_Rtr_Retry);
1132 if (rs->session_id == -1)
1133 rtr_send_reset_query(rs);
1134 else
1135 rtr_send_serial_query(rs);
1136 break;
1137 case RTR_EVNT_SERIAL_NOTIFY:
1138 /* schedule a refresh after a quick wait */
1139 timer_set(&rs->timers, Timer_Rtr_Refresh,
1140 arc4random_uniform(10));
1141 break;
1142 case RTR_EVNT_TIMER_REFRESH:
1143 /* send serial query */
1144 rtr_send_serial_query(rs);
1145 break;
1146 case RTR_EVNT_TIMER_EXPIRE:
1147 rtr_reset_cache(rs);
1148 rtr_recalc();
1149 break;
1150 case RTR_EVNT_TIMER_ACTIVE:
1151 log_warnx("rtr %s: activity timer fired", log_rtr(rs));
1152 rtr_sem_release(rs->active_lock);
1153 rtr_recalc();
1154 rs->active_lock = 0;
1155 break;
1156 case RTR_EVNT_CACHE_RESPONSE:
1157 rs->state = RTR_STATE_EXCHANGE;
1158 timer_stop(&rs->timers, Timer_Rtr_Refresh);
1159 timer_stop(&rs->timers, Timer_Rtr_Retry);
1160 timer_set(&rs->timers, Timer_Rtr_Active, rs->active);
1161 /* prevent rtr_recalc from running while active */
1162 rs->active_lock = 1;
1163 rtr_sem_acquire(rs->active_lock);
1164 break;
1165 case RTR_EVNT_END_OF_DATA:
1166 /* start refresh and expire timers */
1167 timer_set(&rs->timers, Timer_Rtr_Refresh, rs->refresh);
1168 timer_set(&rs->timers, Timer_Rtr_Expire, rs->expire);
1169 timer_stop(&rs->timers, Timer_Rtr_Active);
1170 rs->state = RTR_STATE_ESTABLISHED;
1171 rtr_sem_release(rs->active_lock);
1172 rtr_recalc();
1173 rs->active_lock = 0;
1174 break;
1175 case RTR_EVNT_CACHE_RESET:
1176 rtr_reset_cache(rs);
1177 rtr_recalc();
1178 /* retry after a quick wait */
1179 timer_set(&rs->timers, Timer_Rtr_Retry,
1180 arc4random_uniform(10));
1181 break;
1182 case RTR_EVNT_NO_DATA:
1183 /* start retry timer */
1184 timer_set(&rs->timers, Timer_Rtr_Retry, rs->retry);
1185 /* stop refresh timer just to be sure */
1186 timer_stop(&rs->timers, Timer_Rtr_Refresh);
1187 rs->state = RTR_STATE_ESTABLISHED;
1188 break;
1189 case RTR_EVNT_SEND_ERROR:
1190 rtr_reset_cache(rs);
1191 rtr_recalc();
1192 rs->state = RTR_STATE_ERROR;
1193 /* flush receive buffer */
1194 rs->r.wpos = 0;
1195 break;
1196 case RTR_EVNT_NEGOTIATION_DONE:
1197 rs->state = RTR_STATE_ESTABLISHED;
1198 break;
1199 }
1200
1201 log_debug("rtr %s: state change %s -> %s, reason: %s",
1202 log_rtr(rs), rtr_statenames[prev_state], rtr_statenames[rs->state],
1203 rtr_eventnames[event]);
1204}
1205
1206/*
1207 * IO handler for RTR sessions
1208 */
1209static void
1210rtr_dispatch_msg(struct pollfd *pfd, struct rtr_session *rs)
1211{
1212 ssize_t n;
1213 int error;
1214
1215 if (pfd->revents & POLLHUP0x0010) {
10
Assuming the condition is false
11
Taking false branch
1216 log_warnx("rtr %s: Connection closed, hangup", log_rtr(rs));
1217 rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
1218 return;
1219 }
1220 if (pfd->revents & (POLLERR0x0008|POLLNVAL0x0020)) {
12
Assuming the condition is false
1221 log_warnx("rtr %s: Connection closed, error", log_rtr(rs));
1222 rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
1223 return;
1224 }
1225 if (pfd->revents & POLLOUT0x0004 && rs->w.queued) {
13
Assuming the condition is false
1226 if ((error = ibuf_write(&rs->w)) == -1) {
1227 if (errno(*__errno()) != EAGAIN35) {
1228 log_warn("rtr %s: write error", log_rtr(rs));
1229 rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
1230 }
1231 }
1232 if (error == 0)
1233 rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
1234 if (rs->w.queued == 0 && rs->state == RTR_STATE_ERROR)
1235 rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
1236 }
1237 if (pfd->revents & POLLIN0x0001) {
14
Assuming the condition is true
15
Taking true branch
1238 if ((n = read(rs->fd, rs->r.buf + rs->r.wpos,
16
Assuming the condition is false
17
Taking false branch
1239 sizeof(rs->r.buf) - rs->r.wpos)) == -1) {
1240 if (errno(*__errno()) != EINTR4 && errno(*__errno()) != EAGAIN35) {
1241 log_warn("rtr %s: read error", log_rtr(rs));
1242 rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
1243 }
1244 return;
1245 }
1246 if (n == 0) {
18
Assuming 'n' is not equal to 0
19
Taking false branch
1247 rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
1248 return;
1249 }
1250 rs->r.wpos += n;
1251
1252 /* new data arrived, try to process it */
1253 rtr_process_msg(rs);
20
Calling 'rtr_process_msg'
1254 }
1255
1256}
1257
1258void
1259rtr_check_events(struct pollfd *pfds, size_t npfds)
1260{
1261 struct rtr_session *rs;
1262 struct timer *t;
1263 time_t now;
1264 size_t i = 0;
1265
1266 for (i = 0; i < npfds; i++) {
1
Assuming 'i' is < 'npfds'
2
Loop condition is true. Entering loop body
1267 if (pfds[i].revents == 0)
3
Assuming field 'revents' is not equal to 0
4
Taking false branch
1268 continue;
1269 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
5
Assuming 'rs' is not equal to null
6
Loop condition is true. Entering loop body
1270 if (rs->fd == pfds[i].fd) {
7
Assuming 'rs->fd' is equal to 'pfds[i].fd'
8
Taking true branch
1271 rtr_dispatch_msg(&pfds[i], rs);
9
Calling 'rtr_dispatch_msg'
1272 break;
1273 }
1274 if (rs == NULL((void *)0))
1275 log_warnx("%s: unknown fd in pollfds", __func__);
1276 }
1277
1278 /* run all timers */
1279 now = getmonotime();
1280 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
1281 if ((t = timer_nextisdue(&rs->timers, now)) != NULL((void *)0)) {
1282 log_debug("rtr %s: %s triggered", log_rtr(rs),
1283 timernames[t->type]);
1284 /* stop timer so it does not trigger again */
1285 timer_stop(&rs->timers, t->type);
1286 switch (t->type) {
1287 case Timer_Rtr_Refresh:
1288 rtr_fsm(rs, RTR_EVNT_TIMER_REFRESH);
1289 break;
1290 case Timer_Rtr_Retry:
1291 rtr_fsm(rs, RTR_EVNT_TIMER_RETRY);
1292 break;
1293 case Timer_Rtr_Expire:
1294 rtr_fsm(rs, RTR_EVNT_TIMER_EXPIRE);
1295 break;
1296 case Timer_Rtr_Active:
1297 rtr_fsm(rs, RTR_EVNT_TIMER_ACTIVE);
1298 break;
1299 default:
1300 fatalx("King Bula lost in time");
1301 }
1302 }
1303}
1304
1305size_t
1306rtr_count(void)
1307{
1308 struct rtr_session *rs;
1309 size_t count = 0;
1310
1311 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
1312 count++;
1313 return count;
1314}
1315
1316size_t
1317rtr_poll_events(struct pollfd *pfds, size_t npfds, time_t *timeout)
1318{
1319 struct rtr_session *rs;
1320 time_t now = getmonotime();
1321 size_t i = 0;
1322
1323 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
{
1324 time_t nextaction;
1325 struct pollfd *pfd = pfds + i++;
1326
1327 if (i > npfds)
1328 fatalx("%s: too many sessions for pollfd", __func__);
1329
1330 if ((nextaction = timer_nextduein(&rs->timers, now)) != -1 &&
1331 nextaction < *timeout)
1332 *timeout = nextaction;
1333
1334 if (rs->state == RTR_STATE_CLOSED) {
1335 pfd->fd = -1;
1336 continue;
1337 }
1338
1339 pfd->fd = rs->fd;
1340 pfd->events = 0;
1341
1342 if (rs->w.queued)
1343 pfd->events |= POLLOUT0x0004;
1344 if (rs->state >= RTR_STATE_ESTABLISHED)
1345 pfd->events |= POLLIN0x0001;
1346 }
1347
1348 return i;
1349}
1350
1351struct rtr_session *
1352rtr_new(uint32_t id, char *descr)
1353{
1354 struct rtr_session *rs;
1355
1356 if ((rs = calloc(1, sizeof(*rs))) == NULL((void *)0))
1357 fatal("RTR session %s", descr);
1358
1359 RB_INIT(&rs->roa_set)do { (&rs->roa_set)->rbh_root = ((void *)0); } while
(0)
;
1360 RB_INIT(&rs->aspa)do { (&rs->aspa)->rbh_root = ((void *)0); } while (
0)
;
1361 RB_INIT(&rs->aspa_oldv6)do { (&rs->aspa_oldv6)->rbh_root = ((void *)0); } while
(0)
;
1362 TAILQ_INIT(&rs->timers)do { (&rs->timers)->tqh_first = ((void *)0); (&
rs->timers)->tqh_last = &(&rs->timers)->tqh_first
; } while (0)
;
1363 msgbuf_init(&rs->w);
1364
1365 strlcpy(rs->descr, descr, sizeof(rs->descr));
1366 rs->id = id;
1367 rs->session_id = -1;
1368 rs->version = RTR_MAX_VERSION2;
1369 rs->refresh = RTR_DEFAULT_REFRESH3600;
1370 rs->retry = RTR_DEFAULT_RETRY600;
1371 rs->expire = RTR_DEFAULT_EXPIRE7200;
1372 rs->active = RTR_DEFAULT_ACTIVE60;
1373 rs->state = RTR_STATE_CLOSED;
1374 rs->reconf_action = RECONF_REINIT;
1375 rs->last_recv_error = NO_ERROR;
1376 rs->last_sent_error = NO_ERROR;
1377
1378 /* make sure that some timer is running to abort bad sessions */
1379 timer_set(&rs->timers, Timer_Rtr_Expire, rs->expire);
1380
1381 log_debug("rtr %s: new session, start", log_rtr(rs));
1382 TAILQ_INSERT_TAIL(&rtrs, rs, entry)do { (rs)->entry.tqe_next = ((void *)0); (rs)->entry.tqe_prev
= (&rtrs)->tqh_last; *(&rtrs)->tqh_last = (rs)
; (&rtrs)->tqh_last = &(rs)->entry.tqe_next; } while
(0)
;
1383 rtr_fsm(rs, RTR_EVNT_START);
1384
1385 return rs;
1386}
1387
1388struct rtr_session *
1389rtr_get(uint32_t id)
1390{
1391 struct rtr_session *rs;
1392
1393 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
1394 if (rs->id == id)
1395 return rs;
1396 return NULL((void *)0);
1397}
1398
1399void
1400rtr_free(struct rtr_session *rs)
1401{
1402 if (rs == NULL((void *)0))
1403 return;
1404
1405 rtr_reset_cache(rs);
1406 rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
1407 timer_remove_all(&rs->timers);
1408 free(rs);
1409}
1410
1411void
1412rtr_open(struct rtr_session *rs, int fd)
1413{
1414 if (rs->state != RTR_STATE_CLOSED &&
1415 rs->state != RTR_STATE_NEGOTIATION) {
1416 log_warnx("rtr %s: bad session state", log_rtr(rs));
1417 rtr_fsm(rs, RTR_EVNT_CON_CLOSE);
1418 }
1419
1420 if (rs->state == RTR_STATE_CLOSED)
1421 rs->version = RTR_MAX_VERSION2;
1422
1423 rs->fd = rs->w.fd = fd;
1424 rs->state = RTR_STATE_NEGOTIATION;
1425 rtr_fsm(rs, RTR_EVNT_CON_OPEN);
1426}
1427
1428void
1429rtr_config_prep(void)
1430{
1431 struct rtr_session *rs;
1432
1433 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
1434 rs->reconf_action = RECONF_DELETE;
1435}
1436
1437void
1438rtr_config_merge(void)
1439{
1440 struct rtr_session *rs, *nrs;
1441
1442 TAILQ_FOREACH_SAFE(rs, &rtrs, entry, nrs)for ((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0) &&
((nrs) = ((rs)->entry.tqe_next), 1); (rs) = (nrs))
1443 if (rs->reconf_action == RECONF_DELETE) {
1444 TAILQ_REMOVE(&rtrs, rs, entry)do { if (((rs)->entry.tqe_next) != ((void *)0)) (rs)->entry
.tqe_next->entry.tqe_prev = (rs)->entry.tqe_prev; else (
&rtrs)->tqh_last = (rs)->entry.tqe_prev; *(rs)->
entry.tqe_prev = (rs)->entry.tqe_next; ; ; } while (0)
;
1445 rtr_free(rs);
1446 }
1447}
1448
1449void
1450rtr_config_keep(struct rtr_session *rs)
1451{
1452 rs->reconf_action = RECONF_KEEP;
1453}
1454
1455void
1456rtr_roa_merge(struct roa_tree *rt)
1457{
1458 struct rtr_session *rs;
1459 struct roa *roa;
1460
1461 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
{
1462 RB_FOREACH(roa, roa_tree, &rs->roa_set)for ((roa) = roa_tree_RB_MINMAX(&rs->roa_set, -1); (roa
) != ((void *)0); (roa) = roa_tree_RB_NEXT(roa))
1463 rtr_roa_insert(rt, roa);
1464 }
1465}
1466
1467void
1468rtr_aspa_merge(struct aspa_tree *at)
1469{
1470 struct rtr_session *rs;
1471 struct aspa_set *aspa;
1472
1473 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
{
1474 RB_FOREACH(aspa, aspa_tree, &rs->aspa)for ((aspa) = aspa_tree_RB_MINMAX(&rs->aspa, -1); (aspa
) != ((void *)0); (aspa) = aspa_tree_RB_NEXT(aspa))
1475 rtr_aspa_insert(at, aspa);
1476 RB_FOREACH(aspa, aspa_tree, &rs->aspa_oldv6)for ((aspa) = aspa_tree_RB_MINMAX(&rs->aspa_oldv6, -1)
; (aspa) != ((void *)0); (aspa) = aspa_tree_RB_NEXT(aspa))
1477 rtr_aspa_insert(at, aspa);
1478 }
1479}
1480
1481void
1482rtr_shutdown(void)
1483{
1484 struct rtr_session *rs, *nrs;
1485
1486 TAILQ_FOREACH_SAFE(rs, &rtrs, entry, nrs)for ((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0) &&
((nrs) = ((rs)->entry.tqe_next), 1); (rs) = (nrs))
1487 rtr_free(rs);
1488}
1489
1490void
1491rtr_show(struct rtr_session *rs, pid_t pid)
1492{
1493 struct ctl_show_rtr msg;
1494 struct ctl_timer ct;
1495 u_int i;
1496 time_t d;
1497
1498 memset(&msg, 0, sizeof(msg));
1499
1500 /* descr, remote_addr, local_addr and remote_port set by parent */
1501 msg.version = rs->version;
1502 msg.serial = rs->serial;
1503 msg.refresh = rs->refresh;
1504 msg.retry = rs->retry;
1505 msg.expire = rs->expire;
1506 msg.session_id = rs->session_id;
1507 msg.last_sent_error = rs->last_sent_error;
1508 msg.last_recv_error = rs->last_recv_error;
1509 strlcpy(msg.last_sent_msg, rs->last_sent_msg,
1510 sizeof(msg.last_sent_msg));
1511 strlcpy(msg.last_recv_msg, rs->last_recv_msg,
1512 sizeof(msg.last_recv_msg));
1513
1514 /* send back imsg */
1515 rtr_imsg_compose(IMSG_CTL_SHOW_RTR, rs->id, pid, &msg, sizeof(msg));
1516
1517 /* send back timer imsgs */
1518 for (i = 1; i < Timer_Max; i++) {
1519 if (!timer_running(&rs->timers, i, &d))
1520 continue;
1521 ct.type = i;
1522 ct.val = d;
1523 rtr_imsg_compose(IMSG_CTL_SHOW_TIMER, rs->id, pid,
1524 &ct, sizeof(ct));
1525 }
1526}