Bug Summary

File:src/usr.sbin/bgpd/rtr_proto.c
Warning:line 523, column 3
Potential leak of memory pointed to by 'roa'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name rtr_proto.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -fno-rounding-math -mconstructor-aliases -munwind-tables -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/lib/clang/13.0.0 -I /usr/src/usr.sbin/bgpd -internal-isystem /usr/local/lib/clang/13.0.0/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 -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/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/bgpd/rtr_proto.c
1/* $OpenBSD: rtr_proto.c,v 1.4 2021/08/02 16:42:13 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};
37
38#define RTR_MAX_LEN2048 2048
39#define RTR_DEFAULT_REFRESH3600 3600
40#define RTR_DEFAULT_RETRY600 600
41#define RTR_DEFAULT_EXPIRE7200 7200
42
43enum rtr_pdu_type {
44 SERIAL_NOTIFY = 0,
45 SERIAL_QUERY,
46 RESET_QUERY,
47 CACHE_RESPONSE,
48 IPV4_PREFIX,
49 IPV6_PREFIX = 6,
50 END_OF_DATA = 7,
51 CACHE_RESET = 8,
52 ROUTER_KEY = 9,
53 ERROR_REPORT = 10,
54};
55
56#define FLAG_ANNOUNCE0x1 0x1
57#define FLAG_MASK0x1 FLAG_ANNOUNCE0x1
58struct rtr_ipv4 {
59 uint8_t flags;
60 uint8_t prefixlen;
61 uint8_t maxlen;
62 uint8_t zero;
63 uint32_t prefix;
64 uint32_t asnum;
65};
66
67struct rtr_ipv6 {
68 uint8_t flags;
69 uint8_t prefixlen;
70 uint8_t maxlen;
71 uint8_t zero;
72 uint32_t prefix[4];
73 uint32_t asnum;
74};
75
76struct rtr_endofdata {
77 uint32_t serial;
78 uint32_t refresh;
79 uint32_t retry;
80 uint32_t expire;
81};
82
83enum rtr_event {
84 RTR_EVNT_START,
85 RTR_EVNT_CON_OPEN,
86 RTR_EVNT_CON_CLOSED,
87 RTR_EVNT_TIMER_REFRESH,
88 RTR_EVNT_TIMER_RETRY,
89 RTR_EVNT_TIMER_EXPIRE,
90 RTR_EVNT_SEND_ERROR,
91 RTR_EVNT_SERIAL_NOTIFY,
92 RTR_EVNT_CACHE_RESPONSE,
93 RTR_EVNT_END_OF_DATA,
94 RTR_EVNT_CACHE_RESET,
95 RTR_EVNT_NO_DATA,
96};
97
98static const char *rtr_eventnames[] = {
99 "start",
100 "connection open",
101 "connection closed",
102 "refresh timer expired",
103 "retry timer expired",
104 "expire timer expired",
105 "sent error",
106 "serial notify received",
107 "cache response received",
108 "end of data received",
109 "cache reset received",
110 "no data"
111};
112
113enum rtr_state {
114 RTR_STATE_CLOSED,
115 RTR_STATE_ERROR,
116 RTR_STATE_IDLE,
117 RTR_STATE_ACTIVE,
118};
119
120static const char *rtr_statenames[] = {
121 "closed",
122 "error",
123 "idle",
124 "active"
125};
126
127struct rtr_session {
128 TAILQ_ENTRY(rtr_session)struct { struct rtr_session *tqe_next; struct rtr_session **tqe_prev
; }
entry;
129 char descr[PEER_DESCR_LEN32];
130 struct roa_tree roa_set;
131 struct ibuf_read r;
132 struct msgbuf w;
133 struct timer_head timers;
134 uint32_t id; /* rtr_config id */
135 uint32_t serial;
136 uint32_t refresh;
137 uint32_t retry;
138 uint32_t expire;
139 int session_id;
140 int fd;
141 enum rtr_state state;
142 enum reconf_action reconf_action;
143 enum rtr_error last_sent_error;
144 enum rtr_error last_recv_error;
145 char last_sent_msg[REASON_LEN256];
146 char last_recv_msg[REASON_LEN256];
147};
148
149TAILQ_HEAD(, rtr_session)struct { struct rtr_session *tqh_first; struct rtr_session **
tqh_last; }
rtrs = TAILQ_HEAD_INITIALIZER(rtrs){ ((void *)0), &(rtrs).tqh_first };
150
151static void rtr_fsm(struct rtr_session *, enum rtr_event);
152
153static const char *
154log_rtr(struct rtr_session *rs)
155{
156 return rs->descr;
157}
158
159static const char *
160log_rtr_type(enum rtr_pdu_type type)
161{
162 static char buf[20];
163
164 switch (type) {
165 case SERIAL_NOTIFY:
166 return "serial notify";
167 case SERIAL_QUERY:
168 return "serial query";
169 case RESET_QUERY:
170 return "reset query";
171 case CACHE_RESPONSE:
172 return "cache response";
173 case IPV4_PREFIX:
174 return "IPv4 prefix";
175 case IPV6_PREFIX:
176 return "IPv6 prefix";
177 case END_OF_DATA:
178 return "end of data";
179 case CACHE_RESET:
180 return "cache reset";
181 case ROUTER_KEY:
182 return "router key";
183 case ERROR_REPORT:
184 return "error report";
185 default:
186 snprintf(buf, sizeof(buf), "unknown %u", type);
187 return buf;
188 }
189};
190
191static struct ibuf *
192rtr_newmsg(enum rtr_pdu_type type, uint32_t len, u_int16_t session_id)
193{
194 struct ibuf *buf;
195 struct rtr_header rh;
196
197 if (len > RTR_MAX_LEN2048) {
198 errno(*__errno()) = ERANGE34;
199 return NULL((void *)0);
200 }
201 len += sizeof(rh);
202 if ((buf = ibuf_open(len)) == NULL((void *)0))
203 return NULL((void *)0);
204
205 memset(&rh, 0, sizeof(rh));
206 rh.version = 1;
207 rh.type = type;
208 rh.session_id = htons(session_id)(__uint16_t)(__builtin_constant_p(session_id) ? (__uint16_t)(
((__uint16_t)(session_id) & 0xffU) << 8 | ((__uint16_t
)(session_id) & 0xff00U) >> 8) : __swap16md(session_id
))
;
209 rh.length = htonl(len)(__uint32_t)(__builtin_constant_p(len) ? (__uint32_t)(((__uint32_t
)(len) & 0xff) << 24 | ((__uint32_t)(len) & 0xff00
) << 8 | ((__uint32_t)(len) & 0xff0000) >> 8 |
((__uint32_t)(len) & 0xff000000) >> 24) : __swap32md
(len))
;
210
211 /* can not fail with fixed buffers */
212 ibuf_add(buf, &rh, sizeof(rh));
213 return buf;
214}
215
216/*
217 * Try to send an error PDU to cache, put connection into error
218 * state.
219 */
220static void
221rtr_send_error(struct rtr_session *rs, enum rtr_error err, char *msg,
222 void *pdu, size_t len)
223{
224 struct ibuf *buf;
225 size_t mlen = 0;
226 uint32_t hdrlen;
227
228 rs->last_sent_error = err;
229 if (msg) {
230 mlen = strlen(msg);
231 strlcpy(rs->last_sent_msg, msg, sizeof(rs->last_sent_msg));
232 } else
233 memset(rs->last_sent_msg, 0, sizeof(rs->last_sent_msg));
234
235 rtr_fsm(rs, RTR_EVNT_SEND_ERROR);
236
237 buf = rtr_newmsg(ERROR_REPORT, 2 * sizeof(hdrlen) + len + mlen, err);
238 if (buf == NULL((void *)0)) {
239 log_warn("rtr %s: send error report", log_rtr(rs));
240 return;
241 }
242
243 /* can not fail with fixed buffers */
244 hdrlen = ntohl(len)(__uint32_t)(__builtin_constant_p(len) ? (__uint32_t)(((__uint32_t
)(len) & 0xff) << 24 | ((__uint32_t)(len) & 0xff00
) << 8 | ((__uint32_t)(len) & 0xff0000) >> 8 |
((__uint32_t)(len) & 0xff000000) >> 24) : __swap32md
(len))
;
245 ibuf_add(buf, &hdrlen, sizeof(hdrlen));
246 ibuf_add(buf, pdu, len);
247 hdrlen = ntohl(mlen)(__uint32_t)(__builtin_constant_p(mlen) ? (__uint32_t)(((__uint32_t
)(mlen) & 0xff) << 24 | ((__uint32_t)(mlen) & 0xff00
) << 8 | ((__uint32_t)(mlen) & 0xff0000) >> 8
| ((__uint32_t)(mlen) & 0xff000000) >> 24) : __swap32md
(mlen))
;
248 ibuf_add(buf, &hdrlen, sizeof(hdrlen));
249 ibuf_add(buf, msg, mlen);
250 ibuf_close(&rs->w, buf);
251
252 log_warnx("%s: sending error report[%u] %s", log_rtr(rs), err,
253 msg ? msg : "");
254}
255
256static void
257rtr_reset_query(struct rtr_session *rs)
258{
259 struct ibuf *buf;
260
261 buf = rtr_newmsg(RESET_QUERY, 0, 0);
262 if (buf == NULL((void *)0)) {
263 log_warn("rtr %s: send reset query", log_rtr(rs));
264 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL((void *)0), 0);
265 return;
266 }
267 ibuf_close(&rs->w, buf);
268}
269
270static void
271rtr_serial_query(struct rtr_session *rs)
272{
273 struct ibuf *buf;
274 uint32_t s;
275
276 buf = rtr_newmsg(SERIAL_QUERY, sizeof(s), rs->session_id);
277 if (buf == NULL((void *)0)) {
278 log_warn("rtr %s: send serial query", log_rtr(rs));
279 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL((void *)0), 0);
280 return;
281 }
282
283 /* can not fail with fixed buffers */
284 s = htonl(rs->serial)(__uint32_t)(__builtin_constant_p(rs->serial) ? (__uint32_t
)(((__uint32_t)(rs->serial) & 0xff) << 24 | ((__uint32_t
)(rs->serial) & 0xff00) << 8 | ((__uint32_t)(rs->
serial) & 0xff0000) >> 8 | ((__uint32_t)(rs->serial
) & 0xff000000) >> 24) : __swap32md(rs->serial))
;
285 ibuf_add(buf, &s, sizeof(s));
286 ibuf_close(&rs->w, buf);
287}
288
289/*
290 * Validate the common rtr header (first 8 bytes) including the
291 * included length field.
292 * Returns -1 on failure. On success msgtype and msglen are set
293 * and the function return 0.
294 */
295static int
296rtr_parse_header(struct rtr_session *rs, void *buf,
297 size_t *msglen, enum rtr_pdu_type *msgtype)
298{
299 struct rtr_header rh;
300 uint32_t len = 16; /* default for ERROR_REPORT */
301 int session_id;
302
303 memcpy(&rh, buf, sizeof(rh));
304
305 if (rh.version != 1) {
306 log_warnx("rtr %s: received message with unsupported version",
307 log_rtr(rs));
308 rtr_send_error(rs, UNEXP_PROTOCOL_VERS, NULL((void *)0), &rh, sizeof(rh));
309 return -1;
310 }
311
312 *msgtype = rh.type;
313 *msglen = 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))
;
314
315 switch (*msgtype) {
316 case SERIAL_NOTIFY:
317 session_id = rs->session_id;
318 len = 12;
319 break;
320 case CACHE_RESPONSE:
321 /* set session_id if not yet happened */
322 if (rs->session_id == -1)
323 rs->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
))
;
324 session_id = rs->session_id;
325 len = 8;
326 break;
327 case IPV4_PREFIX:
328 session_id = 0;
329 len = 20;
330 break;
331 case IPV6_PREFIX:
332 session_id = 0;
333 len = 32;
334 break;
335 case END_OF_DATA:
336 session_id = rs->session_id;
337 len = 24;
338 break;
339 case CACHE_RESET:
340 session_id = 0;
341 len = 8;
342 break;
343 case ROUTER_KEY:
344 len = 36; /* XXX probably too small, but we ignore it */
345 /* FALLTHROUGH */
346 case ERROR_REPORT:
347 if (*msglen > RTR_MAX_LEN2048) {
348 log_warnx("rtr %s: received %s: msg too big: %zu byte",
349 log_rtr(rs), log_rtr_type(*msgtype), *msglen);
350 rtr_send_error(rs, CORRUPT_DATA, "too big",
351 &rh, sizeof(rh));
352 return -1;
353 }
354 if (*msglen < len) {
355 log_warnx("rtr %s: received %s: msg too small: "
356 "%zu byte", log_rtr(rs), log_rtr_type(*msgtype),
357 *msglen);
358 rtr_send_error(rs, CORRUPT_DATA, "too small",
359 &rh, sizeof(rh));
360 return -1;
361 }
362 /*
363 * session_id check ommitted since ROUTER_KEY and ERROR_REPORT
364 * use the field for different things.
365 */
366 return 0;
367 default:
368 log_warnx("rtr %s: received unknown message: type %u",
369 log_rtr(rs), *msgtype);
370 rtr_send_error(rs, UNSUPP_PDU_TYPE, NULL((void *)0), &rh, sizeof(rh));
371 return -1;
372 }
373
374 if (len != *msglen) {
375 log_warnx("rtr %s: received %s: illegal len: %zu byte not %u",
376 log_rtr(rs), log_rtr_type(*msgtype), *msglen, len);
377 rtr_send_error(rs, CORRUPT_DATA, "bad length",
378 &rh, sizeof(rh));
379 return -1;
380 }
381
382 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
))
) {
383 /* ignore SERIAL_NOTIFY during startup */
384 if (rs->session_id == -1 && *msgtype == SERIAL_NOTIFY)
385 return 0;
386
387 log_warnx("rtr %s: received %s: bad session_id: %d != %d",
388 log_rtr(rs), log_rtr_type(*msgtype), 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
))
,
389 session_id);
390 rtr_send_error(rs, CORRUPT_DATA, "bad session_id",
391 &rh, sizeof(rh));
392 return -1;
393 }
394
395 return 0;
396}
397
398static int
399rtr_parse_notify(struct rtr_session *rs, uint8_t *buf, size_t len)
400{
401 if (rs->state == RTR_STATE_ACTIVE) {
402 log_warnx("rtr %s: received %s: while active (ignored)",
403 log_rtr(rs), log_rtr_type(SERIAL_NOTIFY));
404 return 0;
405 }
406
407 rtr_fsm(rs, RTR_EVNT_SERIAL_NOTIFY);
408 return 0;
409}
410
411static int
412rtr_parse_cache_response(struct rtr_session *rs, uint8_t *buf, size_t len)
413{
414 if (rs->state != RTR_STATE_IDLE) {
415 log_warnx("rtr %s: received %s: out of context",
416 log_rtr(rs), log_rtr_type(CACHE_RESPONSE));
417 return -1;
418 }
419
420 rtr_fsm(rs, RTR_EVNT_CACHE_RESPONSE);
421 return 0;
422}
423
424static int
425rtr_parse_ipv4_prefix(struct rtr_session *rs, uint8_t *buf, size_t len)
426{
427 struct rtr_ipv4 ip4;
428 struct roa *roa;
429
430 if (len != sizeof(struct rtr_header) + sizeof(ip4)) {
431 log_warnx("rtr %s: received %s: bad pdu len",
432 log_rtr(rs), log_rtr_type(IPV4_PREFIX));
433 rtr_send_error(rs, CORRUPT_DATA, "bad len", buf, len);
434 return -1;
435 }
436
437 if (rs->state != RTR_STATE_ACTIVE) {
438 log_warnx("rtr %s: received %s: out of context",
439 log_rtr(rs), log_rtr_type(IPV4_PREFIX));
440 rtr_send_error(rs, CORRUPT_DATA, NULL((void *)0), buf, len);
441 return -1;
442 }
443
444 memcpy(&ip4, buf + sizeof(struct rtr_header), sizeof(ip4));
445
446 if ((roa = calloc(1, sizeof(*roa))) == NULL((void *)0)) {
447 log_warn("rtr %s: received %s",
448 log_rtr(rs), log_rtr_type(IPV4_PREFIX));
449 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL((void *)0), 0);
450 return -1;
451 }
452 if (ip4.prefixlen > 32 || ip4.maxlen > 32 ||
453 ip4.prefixlen > ip4.maxlen) {
454 log_warnx("rtr: %s: received %s: bad prefixlen / maxlen",
455 log_rtr(rs), log_rtr_type(IPV4_PREFIX));
456 rtr_send_error(rs, CORRUPT_DATA, "bad prefixlen / maxlen",
457 buf, len);
458 return -1;
459 }
460 roa->aid = AID_INET1;
461 roa->prefixlen = ip4.prefixlen;
462 roa->maxlen = ip4.maxlen;
463 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))
;
464 roa->prefix.inet.s_addr = ip4.prefix;
465
466 if (ip4.flags & FLAG_ANNOUNCE0x1) {
467 if (RB_INSERT(roa_tree, &rs->roa_set, roa)roa_tree_RB_INSERT(&rs->roa_set, roa) != NULL((void *)0)) {
468 log_warnx("rtr %s: received %s: duplicate announcement",
469 log_rtr(rs), log_rtr_type(IPV4_PREFIX));
470 rtr_send_error(rs, DUP_REC_RECV, NULL((void *)0), buf, len);
471 free(roa);
472 return -1;
473 }
474 } else {
475 struct roa *r;
476
477 r = RB_FIND(roa_tree, &rs->roa_set, roa)roa_tree_RB_FIND(&rs->roa_set, roa);
478 if (r == NULL((void *)0)) {
479 log_warnx("rtr %s: received %s: unknown withdrawl",
480 log_rtr(rs), log_rtr_type(IPV4_PREFIX));
481 rtr_send_error(rs, UNK_REC_WDRAWL, NULL((void *)0), buf, len);
482 free(roa);
483 return -1;
484 }
485 RB_REMOVE(roa_tree, &rs->roa_set, r)roa_tree_RB_REMOVE(&rs->roa_set, r);
486 free(r);
487 free(roa);
488 }
489
490 return 0;
491}
492
493static int
494rtr_parse_ipv6_prefix(struct rtr_session *rs, uint8_t *buf, size_t len)
495{
496 struct rtr_ipv6 ip6;
497 struct roa *roa;
498
499 if (len != sizeof(struct rtr_header) + sizeof(ip6)) {
39
Assuming the condition is false
40
Taking false branch
500 log_warnx("rtr %s: received %s: bad pdu len",
501 log_rtr(rs), log_rtr_type(IPV6_PREFIX));
502 rtr_send_error(rs, CORRUPT_DATA, "bad len", buf, len);
503 return -1;
504 }
505
506 if (rs->state != RTR_STATE_ACTIVE) {
41
Assuming field 'state' is equal to RTR_STATE_ACTIVE
42
Taking false branch
507 log_warnx("rtr %s: received %s: out of context",
508 log_rtr(rs), log_rtr_type(IPV6_PREFIX));
509 rtr_send_error(rs, CORRUPT_DATA, NULL((void *)0), buf, len);
510 return -1;
511 }
512
513 memcpy(&ip6, buf + sizeof(struct rtr_header), sizeof(ip6));
514
515 if ((roa = calloc(1, sizeof(*roa))) == NULL((void *)0)) {
43
Memory is allocated
44
Assuming the condition is false
45
Taking false branch
516 log_warn("rtr %s: received %s",
517 log_rtr(rs), log_rtr_type(IPV6_PREFIX));
518 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL((void *)0), 0);
519 return -1;
520 }
521 if (ip6.prefixlen > 128 || ip6.maxlen > 128 ||
46
Assuming field 'prefixlen' is > 128
522 ip6.prefixlen > ip6.maxlen) {
523 log_warnx("rtr: %s: received %s: bad prefixlen / maxlen",
47
Potential leak of memory pointed to by 'roa'
524 log_rtr(rs), log_rtr_type(IPV6_PREFIX));
525 rtr_send_error(rs, CORRUPT_DATA, "bad prefixlen / maxlen",
526 buf, len);
527 return -1;
528 }
529 roa->aid = AID_INET62;
530 roa->prefixlen = ip6.prefixlen;
531 roa->maxlen = ip6.maxlen;
532 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))
;
533 memcpy(&roa->prefix.inet6, ip6.prefix, sizeof(roa->prefix.inet6));
534
535 if (ip6.flags & FLAG_ANNOUNCE0x1) {
536 if (RB_INSERT(roa_tree, &rs->roa_set, roa)roa_tree_RB_INSERT(&rs->roa_set, roa) != NULL((void *)0)) {
537 log_warnx("rtr %s: received %s: duplicate announcement",
538 log_rtr(rs), log_rtr_type(IPV6_PREFIX));
539 rtr_send_error(rs, DUP_REC_RECV, NULL((void *)0), buf, len);
540 free(roa);
541 return -1;
542 }
543 } else {
544 struct roa *r;
545
546 r = RB_FIND(roa_tree, &rs->roa_set, roa)roa_tree_RB_FIND(&rs->roa_set, roa);
547 if (r == NULL((void *)0)) {
548 log_warnx("rtr %s: received %s: unknown withdrawl",
549 log_rtr(rs), log_rtr_type(IPV6_PREFIX));
550 rtr_send_error(rs, UNK_REC_WDRAWL, NULL((void *)0), buf, len);
551 free(roa);
552 return -1;
553 }
554 RB_REMOVE(roa_tree, &rs->roa_set, r)roa_tree_RB_REMOVE(&rs->roa_set, r);
555 free(r);
556 free(roa);
557 }
558 return 0;
559}
560
561static int
562rtr_parse_end_of_data(struct rtr_session *rs, uint8_t *buf, size_t len)
563{
564 struct rtr_endofdata eod;
565 uint32_t t;
566
567 buf += sizeof(struct rtr_header);
568 len -= sizeof(struct rtr_header);
569
570 if (len != sizeof(eod)) {
571 log_warnx("rtr %s: received %s: bad pdu len",
572 log_rtr(rs), log_rtr_type(END_OF_DATA));
573 return -1;
574 }
575
576 memcpy(&eod, buf, sizeof(eod));
577
578 if (rs->state != RTR_STATE_ACTIVE) {
579 log_warnx("rtr %s: received %s: out of context",
580 log_rtr(rs), log_rtr_type(END_OF_DATA));
581 return -1;
582 }
583
584 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))
;
585 /* validate timer values to be in the right range */
586 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))
;
587 if (t < 1 || t > 86400)
588 goto bad;
589 rs->refresh = t;
590 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))
;
591 if (t < 1 || t > 7200)
592 goto bad;
593 rs->retry = t;
594 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))
;
595 if (t < 600 || t > 172800)
596 goto bad;
597 if (t <= rs->retry || t <= rs->refresh)
598 goto bad;
599 rs->expire = t;
600
601 rtr_fsm(rs, RTR_EVNT_END_OF_DATA);
602 return 0;
603
604bad:
605 log_warnx("rtr %s: received %s: bad timeout values",
606 log_rtr(rs), log_rtr_type(END_OF_DATA));
607 return -1;
608}
609
610static int
611rtr_parse_cache_reset(struct rtr_session *rs, uint8_t *buf, size_t len)
612{
613 if (rs->state != RTR_STATE_IDLE) {
614 log_warnx("rtr %s: received %s: out of context",
615 log_rtr(rs), log_rtr_type(CACHE_RESET));
616 return -1;
617 }
618
619 rtr_fsm(rs, RTR_EVNT_CACHE_RESET);
620 return 0;
621}
622
623/*
624 * Parse an Error Response message. This function behaves a bit different
625 * from other parse functions since on error the connection needs to be
626 * dropped without sending an error response back.
627 */
628static int
629rtr_parse_error(struct rtr_session *rs, uint8_t *buf, size_t len)
630{
631 struct rtr_header rh;
632 uint32_t pdu_len, msg_len;
633 uint8_t *msg;
634 char *str = NULL((void *)0);
635 uint16_t errcode;
636
637 memcpy(&rh, buf, sizeof(rh));
638 buf += sizeof(struct rtr_header);
639 len -= sizeof(struct rtr_header);
640 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
))
;
641
642 memcpy(&pdu_len, buf, sizeof(pdu_len));
643 pdu_len = ntohs(pdu_len)(__uint16_t)(__builtin_constant_p(pdu_len) ? (__uint16_t)(((__uint16_t
)(pdu_len) & 0xffU) << 8 | ((__uint16_t)(pdu_len) &
0xff00U) >> 8) : __swap16md(pdu_len))
;
644
645 if (len < pdu_len + sizeof(pdu_len)) {
646 log_warnx("rtr %s: received %s: bad pdu len: %u byte",
647 log_rtr(rs), log_rtr_type(ERROR_REPORT), pdu_len);
648 rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
649 return -1;
650 }
651
652 /* for now just ignore the embedded pdu */
653 buf += pdu_len + sizeof(pdu_len);
654 len -= pdu_len + sizeof(pdu_len);
655
656 memcpy(&msg_len, buf, sizeof(msg_len));
657 msg_len = ntohs(msg_len)(__uint16_t)(__builtin_constant_p(msg_len) ? (__uint16_t)(((__uint16_t
)(msg_len) & 0xffU) << 8 | ((__uint16_t)(msg_len) &
0xff00U) >> 8) : __swap16md(msg_len))
;
658
659 if (len < msg_len + sizeof(msg_len)) {
660 log_warnx("rtr %s: received %s: bad msg len: %u byte",
661 log_rtr(rs), log_rtr_type(ERROR_REPORT), msg_len);
662 rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
663 return -1;
664 }
665
666 msg = buf + sizeof(msg_len);
667 if (msg_len != 0)
668 /* optional error msg, no need to check for failure */
669 str = strndup(msg, msg_len);
670
671 log_warnx("rtr %s: received error: %s%s%s", log_rtr(rs),
672 log_rtr_error(errcode), str ? ": " : "", str ? str : "");
673
674 if (errcode == NO_DATA_AVAILABLE) {
675 rtr_fsm(rs, RTR_EVNT_NO_DATA);
676 } else {
677 rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
678 rs->last_recv_error = errcode;
679 if (str)
680 strlcpy(rs->last_recv_msg, str,
681 sizeof(rs->last_recv_msg));
682 else
683 memset(rs->last_recv_msg, 0,
684 sizeof(rs->last_recv_msg));
685
686 free(str);
687 return -1;
688 }
689 free(str);
690
691 return 0;
692}
693
694/*
695 * Try to process received rtr message, it is possible that not a full
696 * message is in the buffer. In that case stop, once new data is available
697 * a retry will be done.
698 */
699static void
700rtr_process_msg(struct rtr_session *rs)
701{
702 size_t rpos, av, left;
703 void *rptr;
704 size_t msglen;
705 enum rtr_pdu_type msgtype;
706
707 rpos = 0;
708 av = rs->r.wpos;
709
710 for (;;) {
30
Loop condition is true. Entering loop body
711 if (rpos + sizeof(struct rtr_header) > av)
31
Assuming the condition is false
32
Taking false branch
712 break;
713 rptr = rs->r.buf + rpos;
714 if (rtr_parse_header(rs, rptr, &msglen, &msgtype) == -1)
33
Assuming the condition is false
34
Taking false branch
715 return;
716
717 /* missing data */
718 if (rpos + msglen > av)
35
Assuming the condition is false
36
Taking false branch
719 break;
720
721 switch (msgtype) {
37
Control jumps to 'case IPV6_PREFIX:' at line 741
722 case SERIAL_NOTIFY:
723 if (rtr_parse_notify(rs, rptr, msglen) == -1) {
724 rtr_send_error(rs, CORRUPT_DATA, NULL((void *)0),
725 rptr, msglen);
726 return;
727 }
728 break;
729 case CACHE_RESPONSE:
730 if (rtr_parse_cache_response(rs, rptr, msglen) == -1) {
731 rtr_send_error(rs, CORRUPT_DATA, NULL((void *)0),
732 rptr, msglen);
733 return;
734 }
735 break;
736 case IPV4_PREFIX:
737 if (rtr_parse_ipv4_prefix(rs, rptr, msglen) == -1) {
738 return;
739 }
740 break;
741 case IPV6_PREFIX:
742 if (rtr_parse_ipv6_prefix(rs, rptr, msglen) == -1) {
38
Calling 'rtr_parse_ipv6_prefix'
743 return;
744 }
745 break;
746 case END_OF_DATA:
747 if (rtr_parse_end_of_data(rs, rptr, msglen) == -1) {
748 rtr_send_error(rs, CORRUPT_DATA, NULL((void *)0),
749 rptr, msglen);
750 return;
751 }
752 break;
753 case CACHE_RESET:
754 if (rtr_parse_cache_reset(rs, rptr, msglen) == -1) {
755 rtr_send_error(rs, CORRUPT_DATA, NULL((void *)0),
756 rptr, msglen);
757 return;
758 }
759 break;
760 case ROUTER_KEY:
761 /* silently ignore router key */
762 break;
763 case ERROR_REPORT:
764 if (rtr_parse_error(rs, rptr, msglen) == -1)
765 /* no need to send back an error */
766 return;
767 break;
768 default:
769 log_warnx("rtr %s: received %s: unexpected pdu type",
770 log_rtr(rs), log_rtr_type(msgtype));
771 rtr_send_error(rs, INVALID_REQUEST, NULL((void *)0), rptr, msglen);
772 return;
773 }
774 rpos += msglen;
775 }
776
777 left = av - rpos;
778 memmove(&rs->r.buf, rs->r.buf + rpos, left);
779 rs->r.wpos = left;
780}
781
782/*
783 * Simple FSM for RTR sessions
784 */
785static void
786rtr_fsm(struct rtr_session *rs, enum rtr_event event)
787{
788 enum rtr_state prev_state = rs->state;
789
790 switch (event) {
791 case RTR_EVNT_CON_CLOSED:
792 if (rs->state != RTR_STATE_CLOSED) {
793 /* flush buffers */
794 msgbuf_clear(&rs->w);
795 rs->r.wpos = 0;
796 close(rs->fd);
797 rs->fd = -1;
798 }
799 rs->state = RTR_STATE_CLOSED;
800 /* try to reopen session */
801 timer_set(&rs->timers, Timer_Rtr_Retry,
802 arc4random_uniform(10));
803 break;
804 case RTR_EVNT_START:
805 case RTR_EVNT_TIMER_RETRY:
806 switch (rs->state) {
807 case RTR_STATE_ERROR:
808 rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
809 return;
810 case RTR_STATE_CLOSED:
811 timer_set(&rs->timers, Timer_Rtr_Retry, rs->retry);
812 rtr_imsg_compose(IMSG_SOCKET_CONN, rs->id, 0, NULL((void *)0), 0);
813 return;
814 default:
815 break;
816 }
817 /* FALLTHROUGH */
818 case RTR_EVNT_CON_OPEN:
819 timer_stop(&rs->timers, Timer_Rtr_Retry);
820 if (rs->session_id == -1)
821 rtr_reset_query(rs);
822 else
823 rtr_serial_query(rs);
824 break;
825 case RTR_EVNT_SERIAL_NOTIFY:
826 /* schedule a refresh after a quick wait */
827 timer_set(&rs->timers, Timer_Rtr_Refresh,
828 arc4random_uniform(10));
829 break;
830 case RTR_EVNT_TIMER_REFRESH:
831 /* send serial query */
832 rtr_serial_query(rs);
833 break;
834 case RTR_EVNT_TIMER_EXPIRE:
835 free_roatree(&rs->roa_set);
836 rtr_recalc();
837 break;
838 case RTR_EVNT_CACHE_RESPONSE:
839 rs->state = RTR_STATE_ACTIVE;
840 timer_stop(&rs->timers, Timer_Rtr_Refresh);
841 timer_stop(&rs->timers, Timer_Rtr_Retry);
842 break;
843 case RTR_EVNT_END_OF_DATA:
844 /* start refresh and expire timers */
845 timer_set(&rs->timers, Timer_Rtr_Refresh, rs->refresh);
846 timer_set(&rs->timers, Timer_Rtr_Expire, rs->expire);
847 rs->state = RTR_STATE_IDLE;
848 rtr_recalc();
849 break;
850 case RTR_EVNT_CACHE_RESET:
851 /* reset session and retry after a quick wait */
852 rs->session_id = -1;
853 free_roatree(&rs->roa_set);
854 timer_set(&rs->timers, Timer_Rtr_Retry,
855 arc4random_uniform(10));
856 break;
857 case RTR_EVNT_NO_DATA:
858 /* start retry timer */
859 timer_set(&rs->timers, Timer_Rtr_Retry, rs->retry);
860 /* stop refresh timer just to be sure */
861 timer_stop(&rs->timers, Timer_Rtr_Refresh);
862 break;
863 case RTR_EVNT_SEND_ERROR:
864 rs->state = RTR_STATE_ERROR;
865 /* flush receive buffer */
866 rs->r.wpos = 0;
867 break;
868 }
869
870 log_info("rtr %s: state change %s -> %s, reason: %s",
871 log_rtr(rs), rtr_statenames[prev_state], rtr_statenames[rs->state],
872 rtr_eventnames[event]);
873}
874
875/*
876 * IO handler for RTR sessions
877 */
878static void
879rtr_dispatch_msg(struct pollfd *pfd, struct rtr_session *rs)
880{
881 ssize_t n;
882 int error;
883
884 if (pfd->revents & POLLHUP0x0010) {
18
Assuming the condition is false
19
Taking false branch
885 log_warnx("rtr %s: Connection closed, hangup", log_rtr(rs));
886 rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
887 return;
888 }
889 if (pfd->revents & (POLLERR0x0008|POLLNVAL0x0020)) {
20
Assuming the condition is false
21
Taking false branch
890 log_warnx("rtr %s: Connection closed, error", log_rtr(rs));
891 rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
892 return;
893 }
894 if (pfd->revents & POLLOUT0x0004 && rs->w.queued) {
22
Assuming the condition is false
895 if ((error = ibuf_write(&rs->w)) <= 0 && errno(*__errno()) != EAGAIN35) {
896 if (error == 0)
897 log_warnx("rtr %s: Connection closed",
898 log_rtr(rs));
899 else if (error == -1)
900 log_warn("rtr %s: write error", log_rtr(rs));
901 rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
902 return;
903 }
904 if (rs->w.queued == 0 && rs->state == RTR_STATE_ERROR)
905 rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
906 }
907 if (pfd->revents & POLLIN0x0001) {
23
Assuming the condition is true
24
Taking true branch
908 if ((n = read(rs->fd, rs->r.buf + rs->r.wpos,
25
Assuming the condition is false
26
Taking false branch
909 sizeof(rs->r.buf) - rs->r.wpos)) == -1) {
910 if (errno(*__errno()) != EINTR4 && errno(*__errno()) != EAGAIN35) {
911 log_warn("rtr %s: read error", log_rtr(rs));
912 rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
913 }
914 return;
915 }
916 if (n == 0) {
27
Assuming 'n' is not equal to 0
28
Taking false branch
917 log_warnx("rtr %s: Connection closed", log_rtr(rs));
918 rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
919 return;
920 }
921 rs->r.wpos += n;
922
923 /* new data arrived, try to process it */
924 rtr_process_msg(rs);
29
Calling 'rtr_process_msg'
925 }
926
927}
928
929void
930rtr_check_events(struct pollfd *pfds, size_t npfds)
931{
932 struct rtr_session *rs;
933 struct timer *t;
934 time_t now;
935 size_t i = 0;
936
937 for (i = 0; i < npfds; i++) {
1
Assuming 'i' is < 'npfds'
2
Loop condition is true. Entering loop body
938 if (pfds[i].revents == 0)
3
Assuming field 'revents' is not equal to 0
4
Taking false branch
939 continue;
940 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
9
Assuming 'rs' is not equal to null
10
Loop condition is true. Entering loop body
13
Assuming 'rs' is not equal to null
14
Loop condition is true. Entering loop body
941 if (rs->fd == pfds[i].fd) {
7
Assuming 'rs->fd' is not equal to 'pfds[i].fd'
8
Taking false branch
11
Assuming 'rs->fd' is not equal to 'pfds[i].fd'
12
Taking false branch
15
Assuming 'rs->fd' is equal to 'pfds[i].fd'
16
Taking true branch
942 rtr_dispatch_msg(&pfds[i], rs);
17
Calling 'rtr_dispatch_msg'
943 break;
944 }
945 if (rs == NULL((void *)0))
946 log_warnx("%s: unknown fd in pollfds", __func__);
947 }
948
949 /* run all timers */
950 now = getmonotime();
951 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
952 if ((t = timer_nextisdue(&rs->timers, now)) != NULL((void *)0)) {
953 log_debug("rtr %s: %s triggered", log_rtr(rs),
954 timernames[t->type]);
955 /* stop timer so it does not trigger again */
956 timer_stop(&rs->timers, t->type);
957 switch (t->type) {
958 case Timer_Rtr_Refresh:
959 rtr_fsm(rs, RTR_EVNT_TIMER_REFRESH);
960 break;
961 case Timer_Rtr_Retry:
962 rtr_fsm(rs, RTR_EVNT_TIMER_RETRY);
963 break;
964 case Timer_Rtr_Expire:
965 rtr_fsm(rs, RTR_EVNT_TIMER_EXPIRE);
966 break;
967 default:
968 fatalx("King Bula lost in time");
969 }
970 }
971}
972
973size_t
974rtr_count(void)
975{
976 struct rtr_session *rs;
977 size_t count = 0;
978
979 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
980 count++;
981 return count;
982}
983
984size_t
985rtr_poll_events(struct pollfd *pfds, size_t npfds, time_t *timeout)
986{
987 struct rtr_session *rs;
988 time_t now = getmonotime();
989 size_t i = 0;
990
991 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
{
992 time_t nextaction;
993 struct pollfd *pfd = pfds + i++;
994
995 if (i > npfds)
996 fatalx("%s: too many sessions for pollfd", __func__);
997
998 if ((nextaction = timer_nextduein(&rs->timers, now)) != -1 &&
999 nextaction < *timeout)
1000 *timeout = nextaction;
1001
1002 if (rs->state == RTR_STATE_CLOSED) {
1003 pfd->fd = -1;
1004 continue;
1005 }
1006
1007 pfd->fd = rs->fd;
1008 pfd->events = 0;
1009
1010 if (rs->w.queued)
1011 pfd->events |= POLLOUT0x0004;
1012 if (rs->state >= RTR_STATE_IDLE)
1013 pfd->events |= POLLIN0x0001;
1014 }
1015
1016 return i;
1017}
1018
1019struct rtr_session *
1020rtr_new(uint32_t id, char *descr)
1021{
1022 struct rtr_session *rs;
1023
1024 if ((rs = calloc(1, sizeof(*rs))) == NULL((void *)0))
1025 fatal("RTR session %s", descr);
1026
1027 RB_INIT(&rs->roa_set)do { (&rs->roa_set)->rbh_root = ((void *)0); } while
(0)
;
1028 TAILQ_INIT(&rs->timers)do { (&rs->timers)->tqh_first = ((void *)0); (&
rs->timers)->tqh_last = &(&rs->timers)->tqh_first
; } while (0)
;
1029 msgbuf_init(&rs->w);
1030
1031 strlcpy(rs->descr, descr, sizeof(rs->descr));
1032 rs->id = id;
1033 rs->session_id = -1;
1034 rs->refresh = RTR_DEFAULT_REFRESH3600;
1035 rs->retry = RTR_DEFAULT_RETRY600;
1036 rs->expire = RTR_DEFAULT_EXPIRE7200;
1037 rs->state = RTR_STATE_CLOSED;
1038 rs->reconf_action = RECONF_REINIT;
1039 rs->last_recv_error = NO_ERROR;
1040 rs->last_sent_error = NO_ERROR;
1041
1042 /* make sure that some timer is running to abort bad sessions */
1043 timer_set(&rs->timers, Timer_Rtr_Expire, rs->expire);
1044
1045 log_debug("rtr %s: new session, start", log_rtr(rs));
1046 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)
;
1047 rtr_fsm(rs, RTR_EVNT_START);
1048
1049 return rs;
1050}
1051
1052struct rtr_session *
1053rtr_get(uint32_t id)
1054{
1055 struct rtr_session *rs;
1056
1057 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
1058 if (rs->id == id)
1059 return rs;
1060 return NULL((void *)0);
1061}
1062
1063void
1064rtr_free(struct rtr_session *rs)
1065{
1066 if (rs == NULL((void *)0))
1067 return;
1068
1069 rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
1070 timer_remove_all(&rs->timers);
1071 free_roatree(&rs->roa_set);
1072 free(rs);
1073}
1074
1075void
1076rtr_open(struct rtr_session *rs, int fd)
1077{
1078 if (rs->state != RTR_STATE_CLOSED) {
1079 log_warnx("rtr %s: bad session state", log_rtr(rs));
1080 rtr_fsm(rs, RTR_EVNT_CON_CLOSED);
1081 }
1082
1083 log_debug("rtr %s: connection opened", log_rtr(rs));
1084
1085 rs->fd = rs->w.fd = fd;
1086 rs->state = RTR_STATE_IDLE;
1087 rtr_fsm(rs, RTR_EVNT_CON_OPEN);
1088}
1089
1090void
1091rtr_config_prep(void)
1092{
1093 struct rtr_session *rs;
1094
1095 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
1096 rs->reconf_action = RECONF_DELETE;
1097}
1098
1099void
1100rtr_config_merge(void)
1101{
1102 struct rtr_session *rs, *nrs;
1103
1104 TAILQ_FOREACH_SAFE(rs, &rtrs, entry, nrs)for ((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0) &&
((nrs) = ((rs)->entry.tqe_next), 1); (rs) = (nrs))
1105 if (rs->reconf_action == RECONF_DELETE) {
1106 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)
;
1107 rtr_free(rs);
1108 }
1109}
1110
1111void
1112rtr_config_keep(struct rtr_session *rs)
1113{
1114 rs->reconf_action = RECONF_KEEP;
1115}
1116
1117void
1118rtr_roa_merge(struct roa_tree *rt)
1119{
1120 struct rtr_session *rs;
1121 struct roa *roa;
1122
1123 TAILQ_FOREACH(rs, &rtrs, entry)for((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0); (
rs) = ((rs)->entry.tqe_next))
{
1124 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))
1125 roa_insert(rt, roa);
1126 }
1127}
1128
1129void
1130rtr_shutdown(void)
1131{
1132 struct rtr_session *rs, *nrs;
1133
1134 TAILQ_FOREACH_SAFE(rs, &rtrs, entry, nrs)for ((rs) = ((&rtrs)->tqh_first); (rs) != ((void *)0) &&
((nrs) = ((rs)->entry.tqe_next), 1); (rs) = (nrs))
1135 rtr_free(rs);
1136}
1137
1138void
1139rtr_show(struct rtr_session *rs, pid_t pid)
1140{
1141 struct ctl_show_rtr msg;
1142 struct ctl_timer ct;
1143 u_int i;
1144 time_t d;
1145
1146 memset(&msg, 0, sizeof(msg));
1147
1148 /* descr, remote_addr, local_addr and remote_port set by parent */
1149 msg.serial = rs->serial;
1150 msg.refresh = rs->refresh;
1151 msg.retry = rs->retry;
1152 msg.expire = rs->expire;
1153 msg.session_id = rs->session_id;
1154 msg.last_sent_error = rs->last_sent_error;
1155 msg.last_recv_error = rs->last_recv_error;
1156 strlcpy(msg.last_sent_msg, rs->last_sent_msg,
1157 sizeof(msg.last_sent_msg));
1158 strlcpy(msg.last_recv_msg, rs->last_recv_msg,
1159 sizeof(msg.last_recv_msg));
1160
1161 /* send back imsg */
1162 rtr_imsg_compose(IMSG_CTL_SHOW_RTR, rs->id, pid, &msg, sizeof(msg));
1163
1164 /* send back timer imsgs */
1165 for (i = 1; i < Timer_Max; i++) {
1166 if (!timer_running(&rs->timers, i, &d))
1167 continue;
1168 ct.type = i;
1169 ct.val = d;
1170 rtr_imsg_compose(IMSG_CTL_SHOW_TIMER, rs->id, pid,
1171 &ct, sizeof(ct));
1172 }
1173}