Bug Summary

File:src/usr.sbin/sasyncd/net.c
Warning:line 808, column 12
Result of 'calloc' is converted to a pointer of type 'struct sockaddr', which is incompatible with sizeof operand type 'struct sockaddr_storage'

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 net.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/sasyncd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/sasyncd -I /usr/src/usr.sbin/sasyncd/../../sbin/iked -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/sasyncd/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/sasyncd/net.c
1/* $OpenBSD: net.c,v 1.23 2015/12/12 20:04:23 mmcc Exp $ */
2
3/*
4 * Copyright (c) 2005 Håkan Olsson. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * This code was written under funding by Multicom Security AB.
30 */
31
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <sys/time.h>
35#include <netinet/in.h>
36#include <arpa/inet.h>
37#include <ifaddrs.h>
38#include <netdb.h>
39#include <signal.h>
40
41#include <openssl/aes.h>
42#include <openssl/sha.h>
43
44#include <errno(*__errno()).h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49
50#include "sasyncd.h"
51#include "net.h"
52
53struct msg {
54 u_int8_t *buf;
55 u_int32_t len;
56 int refcnt;
57};
58
59struct qmsg {
60 SIMPLEQ_ENTRY(qmsg)struct { struct qmsg *sqe_next; } next;
61 struct msg *msg;
62};
63
64int *listeners;
65AES_KEY aes_key[2];
66#define AES_IV_LEN16 AES_BLOCK_SIZE16
67
68/* We never send (or expect to receive) messages smaller/larger than this. */
69#define MSG_MINLEN12 12
70#define MSG_MAXLEN4096 4096
71
72/* Local prototypes. */
73static u_int8_t *net_read(struct syncpeer *, u_int32_t *, u_int32_t *);
74static int net_set_sa(struct sockaddr *, char *, in_port_t);
75static void net_check_peers(void *);
76
77/* Pretty-print a buffer. */
78void
79dump_buf(int lvl, u_int8_t *b, u_int32_t len, char *title)
80{
81 u_int32_t i, off, blen;
82 u_int8_t *buf;
83 const char def[] = "Buffer:";
84
85 if (cfgstate.verboselevel < lvl)
86 return;
87
88 blen = 2 * (len + len / 36) + 3 + (title ? strlen(title) : sizeof def);
89 if (!(buf = calloc(1, blen)))
90 return;
91
92 snprintf(buf, blen, "%s\n ", title ? title : def);
93 off = strlen(buf);
94 for (i = 0; i < len; i++, off+=2) {
95 snprintf(buf + off, blen - off, "%02x", b[i]);
96 if ((i+1) % 36 == 0) {
97 off += 2;
98 snprintf(buf + off, blen - off, "\n ");
99 }
100 }
101 log_msg(lvl, "%s", buf);
102 free(buf);
103}
104
105/* Add a listening socket. */
106static int
107net_add_listener(struct sockaddr *sa)
108{
109 char host[NI_MAXHOST256], port[NI_MAXSERV32];
110 int r, s;
111
112 s = socket(sa->sa_family, SOCK_STREAM1, 0);
113 if (s < 0) {
114 perror("net_add_listener: socket()");
115 close(s);
116 return -1;
117 }
118
119 r = 1;
120 if (setsockopt(s, SOL_SOCKET0xffff,
121 cfgstate.listen_on ? SO_REUSEADDR0x0004 : SO_REUSEPORT0x0200, (void *)&r,
122 sizeof r)) {
123 perror("net_add_listener: setsockopt()");
124 close(s);
125 return -1;
126 }
127
128 if (bind(s, sa, sa->sa_family == AF_INET2 ? sizeof(struct sockaddr_in) :
129 sizeof (struct sockaddr_in6))) {
130 perror("net_add_listener: bind()");
131 close(s);
132 return -1;
133 }
134
135 if (listen(s, 3)) {
136 perror("net_add_listener: listen()");
137 close(s);
138 return -1;
139 }
140
141 if (getnameinfo(sa, sa->sa_len, host, sizeof host, port, sizeof port,
142 NI_NUMERICHOST1 | NI_NUMERICSERV2))
143 log_msg(2, "listening on port %u fd %d", cfgstate.listen_port,
144 s);
145 else
146 log_msg(2, "listening on %s port %s fd %d", host, port, s);
147
148 return s;
149}
150
151/* Allocate and fill in listeners array. */
152static int
153net_setup_listeners(void)
154{
155 struct sockaddr_storage sa_storage;
156 struct sockaddr *sa = (struct sockaddr *)&sa_storage;
157 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
158 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
159 struct ifaddrs *ifap = 0, *ifa;
160 int i, count;
161
162 /* Setup listening sockets. */
163 memset(&sa_storage, 0, sizeof sa_storage);
164 if (net_set_sa(sa, cfgstate.listen_on, cfgstate.listen_port) == 0) {
165 listeners = calloc(2, sizeof(int));
166 if (!listeners) {
167 perror("net_setup_listeners: calloc()");
168 goto errout;
169 }
170 listeners[1] = -1;
171 listeners[0] = net_add_listener(sa);
172 if (listeners[0] == -1) {
173 log_msg(0, "net_setup_listeners: could not find "
174 "listen address (%s)", cfgstate.listen_on);
175 goto errout;
176 }
177 return 0;
178 }
179
180 /*
181 * If net_set_sa() failed, cfgstate.listen_on is probably an
182 * interface name, so we should listen on all it's addresses.
183 */
184
185 if (getifaddrs(&ifap) != 0) {
186 perror("net_setup_listeners: getifaddrs()");
187 goto errout;
188 }
189
190 /* How many addresses matches? */
191 for (count = 0, ifa = ifap; ifa; ifa = ifa->ifa_next) {
192 if (!ifa->ifa_name || !ifa->ifa_addr ||
193 (ifa->ifa_addr->sa_family != AF_INET2 &&
194 ifa->ifa_addr->sa_family != AF_INET624))
195 continue;
196 if (cfgstate.listen_family &&
197 cfgstate.listen_family != ifa->ifa_addr->sa_family)
198 continue;
199 if (strcmp(ifa->ifa_name, cfgstate.listen_on) != 0)
200 continue;
201 count++;
202 }
203
204 if (!count) {
205 log_msg(0, "net_setup_listeners: no listeners found for %s",
206 cfgstate.listen_on);
207 goto errout;
208 }
209
210 /* Allocate one extra slot and set to -1, marking end of array. */
211 listeners = calloc(count + 1, sizeof(int));
212 if (!listeners) {
213 perror("net_setup_listeners: calloc()");
214 goto errout;
215 }
216 for (i = 0; i <= count; i++)
217 listeners[i] = -1;
218
219 /* Create listening sockets */
220 for (count = 0, ifa = ifap; ifa; ifa = ifa->ifa_next) {
221 if (!ifa->ifa_name || !ifa->ifa_addr ||
222 (ifa->ifa_addr->sa_family != AF_INET2 &&
223 ifa->ifa_addr->sa_family != AF_INET624))
224 continue;
225 if (cfgstate.listen_family &&
226 cfgstate.listen_family != ifa->ifa_addr->sa_family)
227 continue;
228 if (strcmp(ifa->ifa_name, cfgstate.listen_on) != 0)
229 continue;
230
231 memset(&sa_storage, 0, sizeof sa_storage);
232 sa->sa_family = ifa->ifa_addr->sa_family;
233 switch (sa->sa_family) {
234 case AF_INET2:
235 sin->sin_port = htons(cfgstate.listen_port)(__uint16_t)(__builtin_constant_p(cfgstate.listen_port) ? (__uint16_t
)(((__uint16_t)(cfgstate.listen_port) & 0xffU) << 8
| ((__uint16_t)(cfgstate.listen_port) & 0xff00U) >>
8) : __swap16md(cfgstate.listen_port))
;
236 sin->sin_len = sizeof *sin;
237 memcpy(&sin->sin_addr,
238 &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
239 sizeof sin->sin_addr);
240 break;
241 case AF_INET624:
242 sin6->sin6_port = htons(cfgstate.listen_port)(__uint16_t)(__builtin_constant_p(cfgstate.listen_port) ? (__uint16_t
)(((__uint16_t)(cfgstate.listen_port) & 0xffU) << 8
| ((__uint16_t)(cfgstate.listen_port) & 0xff00U) >>
8) : __swap16md(cfgstate.listen_port))
;
243 sin6->sin6_len = sizeof *sin6;
244 memcpy(&sin6->sin6_addr,
245 &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
246 sizeof sin6->sin6_addr);
247 break;
248 }
249
250 listeners[count] = net_add_listener(sa);
251 if (listeners[count] == -1) {
252 log_msg(2, "net_setup_listeners(setup): failed to "
253 "add listener, count = %d", count);
254 goto errout;
255 }
256 count++;
257 }
258 freeifaddrs(ifap);
259 return 0;
260
261 errout:
262 if (ifap)
263 freeifaddrs(ifap);
264 if (listeners) {
265 for (i = 0; listeners[i] != -1; i++)
266 close(listeners[i]);
267 free(listeners);
268 }
269 return -1;
270}
271
272int
273net_init(void)
274{
275 struct syncpeer *p;
276
277 if (AES_set_encrypt_key(cfgstate.sharedkey, cfgstate.sharedkey_len,
278 &aes_key[0]) ||
279 AES_set_decrypt_key(cfgstate.sharedkey, cfgstate.sharedkey_len,
280 &aes_key[1])) {
281 fprintf(stderr(&__sF[2]), "Bad AES shared key\n");
282 return -1;
283 }
284
285 if (net_setup_listeners())
286 return -1;
287
288 for (p = LIST_FIRST(&cfgstate.peerlist)((&cfgstate.peerlist)->lh_first); p; p = LIST_NEXT(p, link)((p)->link.le_next)) {
289 p->socket = -1;
290 SIMPLEQ_INIT(&p->msgs)do { (&p->msgs)->sqh_first = ((void*)0); (&p->
msgs)->sqh_last = &(&p->msgs)->sqh_first; } while
(0)
;
291 }
292
293 net_check_peers(0);
294 return 0;
295}
296
297static void
298net_enqueue(struct syncpeer *p, struct msg *m)
299{
300 struct qmsg *qm;
301
302 if (p->socket < 0)
303 return;
304
305 qm = calloc(1, sizeof *qm);
306 if (!qm) {
307 log_err("net_enqueue: calloc()");
308 return;
309 }
310
311 qm->msg = m;
312 m->refcnt++;
313
314 SIMPLEQ_INSERT_TAIL(&p->msgs, qm, next)do { (qm)->next.sqe_next = ((void*)0); *(&p->msgs)->
sqh_last = (qm); (&p->msgs)->sqh_last = &(qm)->
next.sqe_next; } while (0)
;
315 return;
316}
317
318/*
319 * Queue a message for transmission to a particular peer,
320 * or to all peers if no peer is specified.
321 */
322int
323net_queue(struct syncpeer *p0, u_int32_t msgtype, u_int8_t *buf, u_int32_t len)
324{
325 struct syncpeer *p = p0;
326 struct msg *m;
327 SHA_CTX ctx;
328 u_int8_t hash[SHA_DIGEST_LENGTH20];
329 u_int8_t iv[AES_IV_LEN16], tmp_iv[AES_IV_LEN16];
330 u_int32_t v, padlen = 0;
331 int i, offset;
332
333 m = calloc(1, sizeof *m);
334 if (!m) {
335 log_err("net_queue: calloc()");
336 free(buf);
337 return -1;
338 }
339
340 /* Generate hash */
341 SHA1_Init(&ctx);
342 SHA1_Update(&ctx, buf, len);
343 SHA1_Final(hash, &ctx);
344 dump_buf(2, hash, sizeof hash, "net_queue: computed hash");
345
346 /* Padding required? */
347 i = len % AES_IV_LEN16;
348 if (i) {
349 u_int8_t *pbuf;
350 i = AES_IV_LEN16 - i;
351 pbuf = realloc(buf, len + i);
352 if (!pbuf) {
353 log_err("net_queue: realloc()");
354 free(buf);
355 free(m);
356 return -1;
357 }
358 padlen = i;
359 while (i > 0)
360 pbuf[len++] = (u_int8_t)i--;
361 buf = pbuf;
362 }
363
364 /* Get random IV */
365 for (i = 0; (size_t)i <= sizeof iv - sizeof v; i += sizeof v) {
366 v = arc4random();
367 memcpy(&iv[i], &v, sizeof v);
368 }
369 dump_buf(2, iv, sizeof iv, "net_queue: IV");
370 memcpy(tmp_iv, iv, sizeof tmp_iv);
371
372 /* Encrypt */
373 dump_buf(2, buf, len, "net_queue: pre encrypt");
374 AES_cbc_encrypt(buf, buf, len, &aes_key[0], tmp_iv, AES_ENCRYPT1);
375 dump_buf(2, buf, len, "net_queue: post encrypt");
376
377 /* Allocate send buffer */
378 m->len = len + sizeof iv + sizeof hash + 3 * sizeof(u_int32_t);
379 m->buf = malloc(m->len);
380 if (!m->buf) {
381 free(m);
382 free(buf);
383 log_err("net_queue: calloc()");
384 return -1;
385 }
386 offset = 0;
387
388 /* Fill it (order must match parsing code in net_read()) */
389 v = htonl(m->len - sizeof(u_int32_t))(__uint32_t)(__builtin_constant_p(m->len - sizeof(u_int32_t
)) ? (__uint32_t)(((__uint32_t)(m->len - sizeof(u_int32_t)
) & 0xff) << 24 | ((__uint32_t)(m->len - sizeof(
u_int32_t)) & 0xff00) << 8 | ((__uint32_t)(m->len
- sizeof(u_int32_t)) & 0xff0000) >> 8 | ((__uint32_t
)(m->len - sizeof(u_int32_t)) & 0xff000000) >> 24
) : __swap32md(m->len - sizeof(u_int32_t)))
;
390 memcpy(m->buf + offset, &v, sizeof v);
391 offset += sizeof v;
392 v = htonl(msgtype)(__uint32_t)(__builtin_constant_p(msgtype) ? (__uint32_t)(((__uint32_t
)(msgtype) & 0xff) << 24 | ((__uint32_t)(msgtype) &
0xff00) << 8 | ((__uint32_t)(msgtype) & 0xff0000) >>
8 | ((__uint32_t)(msgtype) & 0xff000000) >> 24) : __swap32md
(msgtype))
;
393 memcpy(m->buf + offset, &v, sizeof v);
394 offset += sizeof v;
395 v = htonl(padlen)(__uint32_t)(__builtin_constant_p(padlen) ? (__uint32_t)(((__uint32_t
)(padlen) & 0xff) << 24 | ((__uint32_t)(padlen) &
0xff00) << 8 | ((__uint32_t)(padlen) & 0xff0000) >>
8 | ((__uint32_t)(padlen) & 0xff000000) >> 24) : __swap32md
(padlen))
;
396 memcpy(m->buf + offset, &v, sizeof v);
397 offset += sizeof v;
398 memcpy(m->buf + offset, hash, sizeof hash);
399 offset += sizeof hash;
400 memcpy(m->buf + offset, iv, sizeof iv);
401 offset += sizeof iv;
402 memcpy(m->buf + offset, buf, len);
403 free(buf);
404
405 if (p)
406 net_enqueue(p, m);
407 else
408 for (p = LIST_FIRST(&cfgstate.peerlist)((&cfgstate.peerlist)->lh_first); p;
409 p = LIST_NEXT(p, link)((p)->link.le_next))
410 net_enqueue(p, m);
411
412 if (!m->refcnt) {
413 free(m->buf);
414 free(m);
415 }
416
417 return 0;
418}
419
420/* Set all write pending filedescriptors. */
421int
422net_set_pending_wfds(fd_set *fds)
423{
424 struct syncpeer *p;
425 int max_fd = -1;
426
427 for (p = LIST_FIRST(&cfgstate.peerlist)((&cfgstate.peerlist)->lh_first); p; p = LIST_NEXT(p, link)((p)->link.le_next))
428 if (p->socket > -1 && SIMPLEQ_FIRST(&p->msgs)((&p->msgs)->sqh_first)) {
429 FD_SET(p->socket, fds)__fd_set((p->socket), (fds));
430 if (p->socket > max_fd)
431 max_fd = p->socket;
432 }
433 return max_fd + 1;
434}
435
436/*
437 * Set readable filedescriptors. They are basically the same as for write,
438 * plus the listening socket.
439 */
440int
441net_set_rfds(fd_set *fds)
442{
443 struct syncpeer *p;
444 int i, max_fd = -1;
445
446 for (p = LIST_FIRST(&cfgstate.peerlist)((&cfgstate.peerlist)->lh_first); p; p = LIST_NEXT(p, link)((p)->link.le_next)) {
447 if (p->socket > -1)
448 FD_SET(p->socket, fds)__fd_set((p->socket), (fds));
449 if (p->socket > max_fd)
450 max_fd = p->socket;
451 }
452 for (i = 0; listeners[i] != -1; i++) {
453 FD_SET(listeners[i], fds)__fd_set((listeners[i]), (fds));
454 if (listeners[i] > max_fd)
455 max_fd = listeners[i];
456 }
457 return max_fd + 1;
458}
459
460static void
461net_accept(int accept_socket)
462{
463 struct sockaddr_storage sa_storage, sa_storage2;
464 struct sockaddr *sa = (struct sockaddr *)&sa_storage;
465 struct sockaddr *sa2 = (struct sockaddr *)&sa_storage2;
466 struct sockaddr_in *sin, *sin2;
467 struct sockaddr_in6 *sin6, *sin62;
468 struct syncpeer *p;
469 socklen_t socklen;
470 int s, found;
471
472 /* Accept a new incoming connection */
473 socklen = sizeof sa_storage;
474 memset(&sa_storage, 0, socklen);
475 memset(&sa_storage2, 0, socklen);
476 s = accept(accept_socket, sa, &socklen);
477 if (s > -1) {
478 /* Setup the syncpeer structure */
479 found = 0;
480 for (p = LIST_FIRST(&cfgstate.peerlist)((&cfgstate.peerlist)->lh_first); p && !found;
481 p = LIST_NEXT(p, link)((p)->link.le_next)) {
482
483 /* Match? */
484 if (net_set_sa(sa2, p->name, 0))
485 continue;
486 if (sa->sa_family != sa2->sa_family)
487 continue;
488 if (sa->sa_family == AF_INET2) {
489 sin = (struct sockaddr_in *)sa;
490 sin2 = (struct sockaddr_in *)sa2;
491 if (memcmp(&sin->sin_addr, &sin2->sin_addr,
492 sizeof(struct in_addr)))
493 continue;
494 } else {
495 sin6 = (struct sockaddr_in6 *)sa;
496 sin62 = (struct sockaddr_in6 *)sa2;
497 if (memcmp(&sin6->sin6_addr, &sin62->sin6_addr,
498 sizeof(struct in6_addr)))
499 continue;
500 }
501 /* Match! */
502 found++;
503 p->socket = s;
504 log_msg(1, "net: peer \"%s\" connected", p->name);
505 if (cfgstate.runstate == MASTER)
506 timer_add("pfkey_snap", 2, pfkey_snapshot, p);
507 }
508 if (!found) {
509 log_msg(1, "net: found no matching peer for accepted "
510 "socket, closing.");
511 close(s);
512 }
513 } else if (errno(*__errno()) != EWOULDBLOCK35 && errno(*__errno()) != EINTR4 &&
514 errno(*__errno()) != ECONNABORTED53)
515 log_err("net: accept()");
516}
517
518void
519net_handle_messages(fd_set *fds)
520{
521 struct syncpeer *p;
522 u_int8_t *msg;
523 u_int32_t msgtype, msglen;
524 int i;
525
526 for (i = 0; listeners[i] != -1; i++)
527 if (FD_ISSET(listeners[i], fds)__fd_isset((listeners[i]), (fds)))
528 net_accept(listeners[i]);
529
530 for (p = LIST_FIRST(&cfgstate.peerlist)((&cfgstate.peerlist)->lh_first); p; p = LIST_NEXT(p, link)((p)->link.le_next)) {
531 if (p->socket < 0 || !FD_ISSET(p->socket, fds)__fd_isset((p->socket), (fds)))
532 continue;
533 msg = net_read(p, &msgtype, &msglen);
534 if (!msg)
535 continue;
536
537 log_msg(2, "net_handle_messages: got msg type %u len %u from "
538 "peer %s", msgtype, msglen, p->name);
539
540 switch (msgtype) {
541 case MSG_SYNCCTL0:
542 net_ctl_handle_msg(p, msg, msglen);
543 free(msg);
544 break;
545
546 case MSG_PFKEYDATA1:
547 if (p->runstate != MASTER ||
548 cfgstate.runstate == MASTER) {
549 log_msg(1, "net: got PFKEY message from "
550 "non-MASTER peer");
551 free(msg);
552 if (cfgstate.runstate == MASTER)
553 net_ctl_send_state(p);
554 else
555 net_ctl_send_error(p, 0);
556 } else if (pfkey_queue_message(msg, msglen))
557 free(msg);
558 break;
559
560 default:
561 log_msg(0, "net: got unknown message type %u len %u "
562 "from peer %s", msgtype, msglen, p->name);
563 free(msg);
564 net_ctl_send_error(p, 0);
565 }
566 }
567}
568
569void
570net_send_messages(fd_set *fds)
571{
572 struct syncpeer *p;
573 struct qmsg *qm;
574 struct msg *m;
575 ssize_t r;
576
577 for (p = LIST_FIRST(&cfgstate.peerlist)((&cfgstate.peerlist)->lh_first); p; p = LIST_NEXT(p, link)((p)->link.le_next)) {
578 if (p->socket < 0 || !FD_ISSET(p->socket, fds)__fd_isset((p->socket), (fds)))
579 continue;
580 qm = SIMPLEQ_FIRST(&p->msgs)((&p->msgs)->sqh_first);
581 if (!qm) {
582 /* XXX Log */
583 continue;
584 }
585 m = qm->msg;
586
587 log_msg(2, "net_send_messages: msg %p len %u ref %d "
588 "to peer %s", m, m->len, m->refcnt, p->name);
589
590 /* write message */
591 r = write(p->socket, m->buf, m->len);
592 if (r == -1) {
593 net_disconnect_peer(p);
594 log_msg(0, "net_send_messages: write() failed, "
595 "peer disconnected");
596 } else if (r < (ssize_t)m->len) {
597 /* retransmit later */
598 continue;
599 }
600
601 /* cleanup */
602 SIMPLEQ_REMOVE_HEAD(&p->msgs, next)do { if (((&p->msgs)->sqh_first = (&p->msgs)
->sqh_first->next.sqe_next) == ((void*)0)) (&p->
msgs)->sqh_last = &(&p->msgs)->sqh_first; } while
(0)
;
603 free(qm);
604
605 if (--m->refcnt < 1) {
606 log_msg(2, "net_send_messages: freeing msg %p", m);
607 free(m->buf);
608 free(m);
609 }
610 }
611 return;
612}
613
614void
615net_disconnect_peer(struct syncpeer *p)
616{
617 if (p->socket > -1) {
618 log_msg(1, "net_disconnect_peer: peer \"%s\" removed",
619 p->name);
620 close(p->socket);
621 }
622 p->socket = -1;
623}
624
625void
626net_shutdown(void)
627{
628 struct syncpeer *p;
629 struct qmsg *qm;
630 struct msg *m;
631 int i;
632
633 while ((p = LIST_FIRST(&cfgstate.peerlist)((&cfgstate.peerlist)->lh_first))) {
634 while ((qm = SIMPLEQ_FIRST(&p->msgs)((&p->msgs)->sqh_first))) {
635 SIMPLEQ_REMOVE_HEAD(&p->msgs, next)do { if (((&p->msgs)->sqh_first = (&p->msgs)
->sqh_first->next.sqe_next) == ((void*)0)) (&p->
msgs)->sqh_last = &(&p->msgs)->sqh_first; } while
(0)
;
636 m = qm->msg;
637 if (--m->refcnt < 1) {
638 free(m->buf);
639 free(m);
640 }
641 free(qm);
642 }
643 net_disconnect_peer(p);
644 free(p->sa);
645 free(p->name);
646 LIST_REMOVE(p, link)do { if ((p)->link.le_next != ((void*)0)) (p)->link.le_next
->link.le_prev = (p)->link.le_prev; *(p)->link.le_prev
= (p)->link.le_next; ; ; } while (0)
;
647 cfgstate.peercnt--;
648 free(p);
649 }
650
651 if (listeners) {
652 for (i = 0; listeners[i] != -1; i++)
653 close(listeners[i]);
654 free(listeners);
655 listeners = 0;
656 }
657}
658
659/*
660 * Helper functions (local) below here.
661 */
662
663static u_int8_t *
664net_read(struct syncpeer *p, u_int32_t *msgtype, u_int32_t *msglen)
665{
666 u_int8_t *msg, *blob, *rhash, *iv, hash[SHA_DIGEST_LENGTH20];
667 u_int32_t v, blob_len, pos = 0;
668 int padlen = 0, offset = 0;
669 ssize_t r;
670 SHA_CTX ctx;
671
672 /* Read blob length */
673 r = read(p->socket, &v, sizeof v);
674 if (r != (ssize_t)sizeof v) {
675 if (r < 1)
676 net_disconnect_peer(p);
677 return NULL((void*)0);
678 }
679
680 blob_len = ntohl(v)(__uint32_t)(__builtin_constant_p(v) ? (__uint32_t)(((__uint32_t
)(v) & 0xff) << 24 | ((__uint32_t)(v) & 0xff00)
<< 8 | ((__uint32_t)(v) & 0xff0000) >> 8 | (
(__uint32_t)(v) & 0xff000000) >> 24) : __swap32md(v
))
;
681 if (blob_len < sizeof hash + AES_IV_LEN16 + 2 * sizeof(u_int32_t))
682 return NULL((void*)0);
683 *msglen = blob_len - sizeof hash - AES_IV_LEN16 - 2 * sizeof(u_int32_t);
684 if (*msglen < MSG_MINLEN12 || *msglen > MSG_MAXLEN4096)
685 return NULL((void*)0);
686
687 /* Read message blob */
688 blob = malloc(blob_len);
689 if (!blob) {
690 log_err("net_read: malloc()");
691 return NULL((void*)0);
692 }
693
694 while (blob_len > pos) {
695 switch (r = read(p->socket, blob + pos, blob_len - pos)) {
696 case -1:
697 if (errno(*__errno()) == EINTR4 || errno(*__errno()) == EAGAIN35)
698 continue;
699 /* FALLTHROUGH */
700 case 0:
701 net_disconnect_peer(p);
702 free(blob);
703 return NULL((void*)0);
704 /* NOTREACHED */
705 default:
706 pos += r;
707 }
708 }
709
710 offset = 0;
711 memcpy(&v, blob + offset, sizeof v);
712 *msgtype = ntohl(v)(__uint32_t)(__builtin_constant_p(v) ? (__uint32_t)(((__uint32_t
)(v) & 0xff) << 24 | ((__uint32_t)(v) & 0xff00)
<< 8 | ((__uint32_t)(v) & 0xff0000) >> 8 | (
(__uint32_t)(v) & 0xff000000) >> 24) : __swap32md(v
))
;
713 offset += sizeof v;
714
715 if (*msgtype > MSG_MAXTYPE1) {
716 free(blob);
717 return NULL((void*)0);
718 }
719
720 memcpy(&v, blob + offset, sizeof v);
721 padlen = ntohl(v)(__uint32_t)(__builtin_constant_p(v) ? (__uint32_t)(((__uint32_t
)(v) & 0xff) << 24 | ((__uint32_t)(v) & 0xff00)
<< 8 | ((__uint32_t)(v) & 0xff0000) >> 8 | (
(__uint32_t)(v) & 0xff000000) >> 24) : __swap32md(v
))
;
722 offset += sizeof v;
723
724 rhash = blob + offset;
725 iv = rhash + sizeof hash;
726 msg = malloc(*msglen);
727 if (!msg) {
728 free(blob);
729 return NULL((void*)0);
730 }
731 memcpy(msg, iv + AES_IV_LEN16, *msglen);
732
733 dump_buf(2, rhash, sizeof hash, "net_read: got hash");
734 dump_buf(2, iv, AES_IV_LEN16, "net_read: got IV");
735 dump_buf(2, msg, *msglen, "net_read: pre decrypt");
736 AES_cbc_encrypt(msg, msg, *msglen, &aes_key[1], iv, AES_DECRYPT0);
737 dump_buf(2, msg, *msglen, "net_read: post decrypt");
738 *msglen -= padlen;
739
740 SHA1_Init(&ctx);
741 SHA1_Update(&ctx, msg, *msglen);
742 SHA1_Final(hash, &ctx);
743 dump_buf(2, hash, sizeof hash, "net_read: computed hash");
744
745 if (memcmp(hash, rhash, sizeof hash) != 0) {
746 free(blob);
747 free(msg);
748 log_msg(0, "net_read: got bad message (typo in shared key?)");
749 return NULL((void*)0);
750 }
751 free(blob);
752 return msg;
753}
754
755static int
756net_set_sa(struct sockaddr *sa, char *name, in_port_t port)
757{
758 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
759 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
760
761 if (!name) {
762 /* XXX Assume IPv4 */
763 sa->sa_family = AF_INET2;
764 sin->sin_port = htons(port)(__uint16_t)(__builtin_constant_p(port) ? (__uint16_t)(((__uint16_t
)(port) & 0xffU) << 8 | ((__uint16_t)(port) & 0xff00U
) >> 8) : __swap16md(port))
;
765 sin->sin_len = sizeof *sin;
766 return 0;
767 }
768
769 if (inet_pton(AF_INET2, name, &sin->sin_addr) == 1) {
770 sa->sa_family = AF_INET2;
771 sin->sin_port = htons(port)(__uint16_t)(__builtin_constant_p(port) ? (__uint16_t)(((__uint16_t
)(port) & 0xffU) << 8 | ((__uint16_t)(port) & 0xff00U
) >> 8) : __swap16md(port))
;
772 sin->sin_len = sizeof *sin;
773 return 0;
774 }
775
776 if (inet_pton(AF_INET624, name, &sin6->sin6_addr) == 1) {
777 sa->sa_family = AF_INET624;
778 sin6->sin6_port = htons(port)(__uint16_t)(__builtin_constant_p(port) ? (__uint16_t)(((__uint16_t
)(port) & 0xffU) << 8 | ((__uint16_t)(port) & 0xff00U
) >> 8) : __swap16md(port))
;
779 sin6->sin6_len = sizeof *sin6;
780 return 0;
781 }
782
783 return -1;
784}
785
786static void
787got_sigalrm(int s)
788{
789 return;
790}
791
792void
793net_connect(void)
794{
795 struct itimerval iv;
796 struct syncpeer *p;
797
798 signal(SIGALRM14, got_sigalrm);
799 memset(&iv, 0, sizeof iv);
800 iv.it_value.tv_sec = 5;
801 iv.it_interval.tv_sec = 5;
802 setitimer(ITIMER_REAL0, &iv, NULL((void*)0));
803
804 for (p = LIST_FIRST(&cfgstate.peerlist)((&cfgstate.peerlist)->lh_first); p; p = LIST_NEXT(p, link)((p)->link.le_next)) {
805 if (p->socket > -1)
806 continue;
807 if (!p->sa) {
808 p->sa = calloc(1, sizeof(struct sockaddr_storage));
Result of 'calloc' is converted to a pointer of type 'struct sockaddr', which is incompatible with sizeof operand type 'struct sockaddr_storage'
809 if (!p->sa)
810 return;
811 if (net_set_sa(p->sa, p->name, cfgstate.listen_port))
812 continue;
813 }
814 p->socket = socket(p->sa->sa_family, SOCK_STREAM1, 0);
815 if (p->socket < 0) {
816 log_err("peer \"%s\": socket()", p->name);
817 continue;
818 }
819 if (connect(p->socket, p->sa, p->sa->sa_len)) {
820 log_msg(1, "net_connect: peer \"%s\" not ready yet",
821 p->name);
822 net_disconnect_peer(p);
823 continue;
824 }
825 if (net_ctl_send_state(p)) {
826 log_msg(0, "net_connect: peer \"%s\" failed", p->name);
827 net_disconnect_peer(p);
828 continue;
829 }
830 log_msg(1, "net_connect: peer \"%s\" connected, fd %d",
831 p->name, p->socket);
832
833 /* Schedule a pfkey sync to the newly connected peer. */
834 if (cfgstate.runstate == MASTER)
835 timer_add("pfkey_snapshot", 2, pfkey_snapshot, p);
836 }
837
838 timerclear(&iv.it_value)(&iv.it_value)->tv_sec = (&iv.it_value)->tv_usec
= 0
;
839 timerclear(&iv.it_interval)(&iv.it_interval)->tv_sec = (&iv.it_interval)->
tv_usec = 0
;
840 setitimer(ITIMER_REAL0, &iv, NULL((void*)0));
841 signal(SIGALRM14, SIG_IGN(void (*)(int))1);
842
843 return;
844}
845
846static void
847net_check_peers(void *arg)
848{
849 net_connect();
850 (void)timer_add("peer recheck", 600, net_check_peers, 0);
851}