1*6668a736Sguenther /* $OpenBSD: net.c,v 1.24 2022/01/28 06:33:27 guenther Exp $ */
27aea46c5Sho
37aea46c5Sho /*
47aea46c5Sho * Copyright (c) 2005 H�kan Olsson. All rights reserved.
57aea46c5Sho *
67aea46c5Sho * Redistribution and use in source and binary forms, with or without
77aea46c5Sho * modification, are permitted provided that the following conditions
87aea46c5Sho * are met:
97aea46c5Sho *
107aea46c5Sho * 1. Redistributions of source code must retain the above copyright
117aea46c5Sho * notice, this list of conditions and the following disclaimer.
127aea46c5Sho * 2. Redistributions in binary form must reproduce the above copyright
137aea46c5Sho * notice, this list of conditions and the following disclaimer in the
147aea46c5Sho * documentation and/or other materials provided with the distribution.
157aea46c5Sho *
167aea46c5Sho * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
177aea46c5Sho * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
187aea46c5Sho * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
197aea46c5Sho * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
207aea46c5Sho * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
217aea46c5Sho * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
227aea46c5Sho * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
237aea46c5Sho * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
247aea46c5Sho * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
257aea46c5Sho * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
267aea46c5Sho */
277aea46c5Sho
287aea46c5Sho /*
297aea46c5Sho * This code was written under funding by Multicom Security AB.
307aea46c5Sho */
317aea46c5Sho
327aea46c5Sho #include <sys/types.h>
337aea46c5Sho #include <sys/socket.h>
347aea46c5Sho #include <sys/time.h>
357aea46c5Sho #include <netinet/in.h>
367aea46c5Sho #include <arpa/inet.h>
376db4730eSho #include <ifaddrs.h>
386db4730eSho #include <netdb.h>
390a4f72c5Smillert #include <signal.h>
407aea46c5Sho
4154626cc1Sho #include <openssl/aes.h>
4254626cc1Sho #include <openssl/sha.h>
4354626cc1Sho
447aea46c5Sho #include <errno.h>
4554626cc1Sho #include <stdio.h>
4654626cc1Sho #include <stdlib.h>
477aea46c5Sho #include <string.h>
487aea46c5Sho #include <unistd.h>
497aea46c5Sho
507aea46c5Sho #include "sasyncd.h"
517aea46c5Sho #include "net.h"
527aea46c5Sho
537aea46c5Sho struct msg {
547aea46c5Sho u_int8_t *buf;
557aea46c5Sho u_int32_t len;
567aea46c5Sho int refcnt;
577aea46c5Sho };
587aea46c5Sho
597aea46c5Sho struct qmsg {
607aea46c5Sho SIMPLEQ_ENTRY(qmsg) next;
617aea46c5Sho struct msg *msg;
627aea46c5Sho };
637aea46c5Sho
64bd7abb77Sho int *listeners;
6554626cc1Sho AES_KEY aes_key[2];
6654626cc1Sho #define AES_IV_LEN AES_BLOCK_SIZE
677aea46c5Sho
681d55a410Sho /* We never send (or expect to receive) messages smaller/larger than this. */
691d55a410Sho #define MSG_MINLEN 12
701d55a410Sho #define MSG_MAXLEN 4096
711d55a410Sho
727aea46c5Sho /* Local prototypes. */
737aea46c5Sho static u_int8_t *net_read(struct syncpeer *, u_int32_t *, u_int32_t *);
747aea46c5Sho static int net_set_sa(struct sockaddr *, char *, in_port_t);
757aea46c5Sho static void net_check_peers(void *);
767aea46c5Sho
771d55a410Sho /* Pretty-print a buffer. */
7894f5df21Sho void
dump_buf(int lvl,u_int8_t * b,u_int32_t len,char * title)7954626cc1Sho dump_buf(int lvl, u_int8_t *b, u_int32_t len, char *title)
8054626cc1Sho {
811d55a410Sho u_int32_t i, off, blen;
821d55a410Sho u_int8_t *buf;
831d55a410Sho const char def[] = "Buffer:";
8454626cc1Sho
851d55a410Sho if (cfgstate.verboselevel < lvl)
8654626cc1Sho return;
8754626cc1Sho
881d55a410Sho blen = 2 * (len + len / 36) + 3 + (title ? strlen(title) : sizeof def);
8935de856eSderaadt if (!(buf = calloc(1, blen)))
901d55a410Sho return;
911d55a410Sho
921d55a410Sho snprintf(buf, blen, "%s\n ", title ? title : def);
9354626cc1Sho off = strlen(buf);
941d55a410Sho for (i = 0; i < len; i++, off+=2) {
9554626cc1Sho snprintf(buf + off, blen - off, "%02x", b[i]);
961d55a410Sho if ((i+1) % 36 == 0) {
971d55a410Sho off += 2;
981d55a410Sho snprintf(buf + off, blen - off, "\n ");
991d55a410Sho }
1001d55a410Sho }
10154626cc1Sho log_msg(lvl, "%s", buf);
10254626cc1Sho free(buf);
10354626cc1Sho }
10454626cc1Sho
105bd7abb77Sho /* Add a listening socket. */
106bd7abb77Sho static int
net_add_listener(struct sockaddr * sa)107bd7abb77Sho net_add_listener(struct sockaddr *sa)
108bd7abb77Sho {
109bd7abb77Sho char host[NI_MAXHOST], port[NI_MAXSERV];
110bd7abb77Sho int r, s;
111bd7abb77Sho
112bd7abb77Sho s = socket(sa->sa_family, SOCK_STREAM, 0);
113bd7abb77Sho if (s < 0) {
114bd7abb77Sho perror("net_add_listener: socket()");
115bd7abb77Sho close(s);
116bd7abb77Sho return -1;
117bd7abb77Sho }
118bd7abb77Sho
119bd7abb77Sho r = 1;
120bd7abb77Sho if (setsockopt(s, SOL_SOCKET,
121bd7abb77Sho cfgstate.listen_on ? SO_REUSEADDR : SO_REUSEPORT, (void *)&r,
122bd7abb77Sho sizeof r)) {
123bd7abb77Sho perror("net_add_listener: setsockopt()");
124bd7abb77Sho close(s);
125bd7abb77Sho return -1;
126bd7abb77Sho }
127bd7abb77Sho
128bd7abb77Sho if (bind(s, sa, sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) :
129bd7abb77Sho sizeof (struct sockaddr_in6))) {
130bd7abb77Sho perror("net_add_listener: bind()");
131bd7abb77Sho close(s);
132bd7abb77Sho return -1;
133bd7abb77Sho }
134bd7abb77Sho
135bd7abb77Sho if (listen(s, 3)) {
136bd7abb77Sho perror("net_add_listener: listen()");
137bd7abb77Sho close(s);
138bd7abb77Sho return -1;
139bd7abb77Sho }
140bd7abb77Sho
141bd7abb77Sho if (getnameinfo(sa, sa->sa_len, host, sizeof host, port, sizeof port,
142bd7abb77Sho NI_NUMERICHOST | NI_NUMERICSERV))
1439353ff65Skjell log_msg(2, "listening on port %u fd %d", cfgstate.listen_port,
144bd7abb77Sho s);
145bd7abb77Sho else
1469353ff65Skjell log_msg(2, "listening on %s port %s fd %d", host, port, s);
147bd7abb77Sho
148bd7abb77Sho return s;
149bd7abb77Sho }
150bd7abb77Sho
151bd7abb77Sho /* Allocate and fill in listeners array. */
152bd7abb77Sho static int
net_setup_listeners(void)153bd7abb77Sho net_setup_listeners(void)
1547aea46c5Sho {
1557aea46c5Sho struct sockaddr_storage sa_storage;
1567aea46c5Sho struct sockaddr *sa = (struct sockaddr *)&sa_storage;
157bd7abb77Sho struct sockaddr_in *sin = (struct sockaddr_in *)sa;
158bd7abb77Sho struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
159bd7abb77Sho struct ifaddrs *ifap = 0, *ifa;
160bd7abb77Sho int i, count;
161bd7abb77Sho
162bd7abb77Sho /* Setup listening sockets. */
163bd7abb77Sho memset(&sa_storage, 0, sizeof sa_storage);
164bd7abb77Sho if (net_set_sa(sa, cfgstate.listen_on, cfgstate.listen_port) == 0) {
16535de856eSderaadt listeners = calloc(2, sizeof(int));
166bd7abb77Sho if (!listeners) {
167bd7abb77Sho perror("net_setup_listeners: calloc()");
168f97e363eSmoritz goto errout;
169bd7abb77Sho }
170bd7abb77Sho listeners[1] = -1;
171bd7abb77Sho listeners[0] = net_add_listener(sa);
172bd7abb77Sho if (listeners[0] == -1) {
173bd7abb77Sho log_msg(0, "net_setup_listeners: could not find "
174bd7abb77Sho "listen address (%s)", cfgstate.listen_on);
175bd7abb77Sho goto errout;
176bd7abb77Sho }
177bd7abb77Sho return 0;
178bd7abb77Sho }
179bd7abb77Sho
180bd7abb77Sho /*
181bd7abb77Sho * If net_set_sa() failed, cfgstate.listen_on is probably an
182*6668a736Sguenther * interface name, so we should listen on all its addresses.
183bd7abb77Sho */
184bd7abb77Sho
185bd7abb77Sho if (getifaddrs(&ifap) != 0) {
186bd7abb77Sho perror("net_setup_listeners: getifaddrs()");
187f97e363eSmoritz goto errout;
188bd7abb77Sho }
189bd7abb77Sho
190bd7abb77Sho /* How many addresses matches? */
191bd7abb77Sho for (count = 0, ifa = ifap; ifa; ifa = ifa->ifa_next) {
192bd7abb77Sho if (!ifa->ifa_name || !ifa->ifa_addr ||
193bd7abb77Sho (ifa->ifa_addr->sa_family != AF_INET &&
194bd7abb77Sho ifa->ifa_addr->sa_family != AF_INET6))
195bd7abb77Sho continue;
196bd7abb77Sho if (cfgstate.listen_family &&
197bd7abb77Sho cfgstate.listen_family != ifa->ifa_addr->sa_family)
198bd7abb77Sho continue;
199bd7abb77Sho if (strcmp(ifa->ifa_name, cfgstate.listen_on) != 0)
200bd7abb77Sho continue;
201bd7abb77Sho count++;
202bd7abb77Sho }
203bd7abb77Sho
204bd7abb77Sho if (!count) {
205bd7abb77Sho log_msg(0, "net_setup_listeners: no listeners found for %s",
206bd7abb77Sho cfgstate.listen_on);
207f97e363eSmoritz goto errout;
208bd7abb77Sho }
209bd7abb77Sho
210bd7abb77Sho /* Allocate one extra slot and set to -1, marking end of array. */
21135de856eSderaadt listeners = calloc(count + 1, sizeof(int));
212bd7abb77Sho if (!listeners) {
213bd7abb77Sho perror("net_setup_listeners: calloc()");
214f97e363eSmoritz goto errout;
215bd7abb77Sho }
216bd7abb77Sho for (i = 0; i <= count; i++)
217bd7abb77Sho listeners[i] = -1;
218bd7abb77Sho
219bd7abb77Sho /* Create listening sockets */
220bd7abb77Sho for (count = 0, ifa = ifap; ifa; ifa = ifa->ifa_next) {
221bd7abb77Sho if (!ifa->ifa_name || !ifa->ifa_addr ||
222bd7abb77Sho (ifa->ifa_addr->sa_family != AF_INET &&
223bd7abb77Sho ifa->ifa_addr->sa_family != AF_INET6))
224bd7abb77Sho continue;
225bd7abb77Sho if (cfgstate.listen_family &&
226bd7abb77Sho cfgstate.listen_family != ifa->ifa_addr->sa_family)
227bd7abb77Sho continue;
228bd7abb77Sho if (strcmp(ifa->ifa_name, cfgstate.listen_on) != 0)
229bd7abb77Sho continue;
230bd7abb77Sho
231bd7abb77Sho memset(&sa_storage, 0, sizeof sa_storage);
232bd7abb77Sho sa->sa_family = ifa->ifa_addr->sa_family;
233bd7abb77Sho switch (sa->sa_family) {
234bd7abb77Sho case AF_INET:
235bd7abb77Sho sin->sin_port = htons(cfgstate.listen_port);
236bd7abb77Sho sin->sin_len = sizeof *sin;
237bd7abb77Sho memcpy(&sin->sin_addr,
238bd7abb77Sho &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
239bd7abb77Sho sizeof sin->sin_addr);
240bd7abb77Sho break;
241bd7abb77Sho case AF_INET6:
242bd7abb77Sho sin6->sin6_port = htons(cfgstate.listen_port);
243bd7abb77Sho sin6->sin6_len = sizeof *sin6;
244bd7abb77Sho memcpy(&sin6->sin6_addr,
245bd7abb77Sho &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
246bd7abb77Sho sizeof sin6->sin6_addr);
247bd7abb77Sho break;
248bd7abb77Sho }
249bd7abb77Sho
250bd7abb77Sho listeners[count] = net_add_listener(sa);
251bd7abb77Sho if (listeners[count] == -1) {
2529353ff65Skjell log_msg(2, "net_setup_listeners(setup): failed to "
253bd7abb77Sho "add listener, count = %d", count);
254bd7abb77Sho goto errout;
255bd7abb77Sho }
256bd7abb77Sho count++;
257bd7abb77Sho }
258bd7abb77Sho freeifaddrs(ifap);
259bd7abb77Sho return 0;
260bd7abb77Sho
261bd7abb77Sho errout:
262bd7abb77Sho if (ifap)
263bd7abb77Sho freeifaddrs(ifap);
264f97e363eSmoritz if (listeners) {
265bd7abb77Sho for (i = 0; listeners[i] != -1; i++)
266bd7abb77Sho close(listeners[i]);
267bd7abb77Sho free(listeners);
268f97e363eSmoritz }
269bd7abb77Sho return -1;
270bd7abb77Sho }
271bd7abb77Sho
272bd7abb77Sho int
net_init(void)273bd7abb77Sho net_init(void)
274bd7abb77Sho {
2757aea46c5Sho struct syncpeer *p;
2767aea46c5Sho
27750b83ccaSmarkus if (AES_set_encrypt_key(cfgstate.sharedkey, cfgstate.sharedkey_len,
27850b83ccaSmarkus &aes_key[0]) ||
27950b83ccaSmarkus AES_set_decrypt_key(cfgstate.sharedkey, cfgstate.sharedkey_len,
28050b83ccaSmarkus &aes_key[1])) {
28154626cc1Sho fprintf(stderr, "Bad AES shared key\n");
28254626cc1Sho return -1;
28354626cc1Sho }
2847aea46c5Sho
285bd7abb77Sho if (net_setup_listeners())
2867aea46c5Sho return -1;
2877aea46c5Sho
2887aea46c5Sho for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
2897aea46c5Sho p->socket = -1;
2907aea46c5Sho SIMPLEQ_INIT(&p->msgs);
2917aea46c5Sho }
2927aea46c5Sho
2937aea46c5Sho net_check_peers(0);
2947aea46c5Sho return 0;
2957aea46c5Sho }
2967aea46c5Sho
2977aea46c5Sho static void
net_enqueue(struct syncpeer * p,struct msg * m)2987aea46c5Sho net_enqueue(struct syncpeer *p, struct msg *m)
2997aea46c5Sho {
3007aea46c5Sho struct qmsg *qm;
3017aea46c5Sho
3027aea46c5Sho if (p->socket < 0)
3037aea46c5Sho return;
3047aea46c5Sho
305cc98d859Sguenther qm = calloc(1, sizeof *qm);
3067aea46c5Sho if (!qm) {
307cc98d859Sguenther log_err("net_enqueue: calloc()");
3087aea46c5Sho return;
3097aea46c5Sho }
3107aea46c5Sho
3117aea46c5Sho qm->msg = m;
3127aea46c5Sho m->refcnt++;
3137aea46c5Sho
3147aea46c5Sho SIMPLEQ_INSERT_TAIL(&p->msgs, qm, next);
3157aea46c5Sho return;
3167aea46c5Sho }
3177aea46c5Sho
3187aea46c5Sho /*
3197aea46c5Sho * Queue a message for transmission to a particular peer,
3207aea46c5Sho * or to all peers if no peer is specified.
3217aea46c5Sho */
3227aea46c5Sho int
net_queue(struct syncpeer * p0,u_int32_t msgtype,u_int8_t * buf,u_int32_t len)32354626cc1Sho net_queue(struct syncpeer *p0, u_int32_t msgtype, u_int8_t *buf, u_int32_t len)
3247aea46c5Sho {
3257aea46c5Sho struct syncpeer *p = p0;
3267aea46c5Sho struct msg *m;
32754626cc1Sho SHA_CTX ctx;
32854626cc1Sho u_int8_t hash[SHA_DIGEST_LENGTH];
32954626cc1Sho u_int8_t iv[AES_IV_LEN], tmp_iv[AES_IV_LEN];
33054626cc1Sho u_int32_t v, padlen = 0;
33154626cc1Sho int i, offset;
3327aea46c5Sho
33335de856eSderaadt m = calloc(1, sizeof *m);
3347aea46c5Sho if (!m) {
335bd7abb77Sho log_err("net_queue: calloc()");
3367aea46c5Sho free(buf);
3377aea46c5Sho return -1;
3387aea46c5Sho }
33954626cc1Sho
34054626cc1Sho /* Generate hash */
34154626cc1Sho SHA1_Init(&ctx);
34254626cc1Sho SHA1_Update(&ctx, buf, len);
34354626cc1Sho SHA1_Final(hash, &ctx);
3449353ff65Skjell dump_buf(2, hash, sizeof hash, "net_queue: computed hash");
34554626cc1Sho
34654626cc1Sho /* Padding required? */
34754626cc1Sho i = len % AES_IV_LEN;
34854626cc1Sho if (i) {
34954626cc1Sho u_int8_t *pbuf;
35054626cc1Sho i = AES_IV_LEN - i;
35154626cc1Sho pbuf = realloc(buf, len + i);
35254626cc1Sho if (!pbuf) {
35354626cc1Sho log_err("net_queue: realloc()");
35454626cc1Sho free(buf);
35554626cc1Sho free(m);
35654626cc1Sho return -1;
35754626cc1Sho }
35854626cc1Sho padlen = i;
35954626cc1Sho while (i > 0)
36054626cc1Sho pbuf[len++] = (u_int8_t)i--;
36154626cc1Sho buf = pbuf;
36254626cc1Sho }
36354626cc1Sho
36454626cc1Sho /* Get random IV */
36522474abcShaesbaert for (i = 0; (size_t)i <= sizeof iv - sizeof v; i += sizeof v) {
36654626cc1Sho v = arc4random();
36754626cc1Sho memcpy(&iv[i], &v, sizeof v);
36854626cc1Sho }
3699353ff65Skjell dump_buf(2, iv, sizeof iv, "net_queue: IV");
37054626cc1Sho memcpy(tmp_iv, iv, sizeof tmp_iv);
37154626cc1Sho
37254626cc1Sho /* Encrypt */
3739353ff65Skjell dump_buf(2, buf, len, "net_queue: pre encrypt");
37454626cc1Sho AES_cbc_encrypt(buf, buf, len, &aes_key[0], tmp_iv, AES_ENCRYPT);
3759353ff65Skjell dump_buf(2, buf, len, "net_queue: post encrypt");
37654626cc1Sho
37754626cc1Sho /* Allocate send buffer */
37854626cc1Sho m->len = len + sizeof iv + sizeof hash + 3 * sizeof(u_int32_t);
37935de856eSderaadt m->buf = malloc(m->len);
38054626cc1Sho if (!m->buf) {
38154626cc1Sho free(m);
38254626cc1Sho free(buf);
38354626cc1Sho log_err("net_queue: calloc()");
38454626cc1Sho return -1;
38554626cc1Sho }
38654626cc1Sho offset = 0;
38754626cc1Sho
38854626cc1Sho /* Fill it (order must match parsing code in net_read()) */
38954626cc1Sho v = htonl(m->len - sizeof(u_int32_t));
39054626cc1Sho memcpy(m->buf + offset, &v, sizeof v);
39154626cc1Sho offset += sizeof v;
39254626cc1Sho v = htonl(msgtype);
39354626cc1Sho memcpy(m->buf + offset, &v, sizeof v);
39454626cc1Sho offset += sizeof v;
39554626cc1Sho v = htonl(padlen);
39654626cc1Sho memcpy(m->buf + offset, &v, sizeof v);
39754626cc1Sho offset += sizeof v;
39854626cc1Sho memcpy(m->buf + offset, hash, sizeof hash);
39954626cc1Sho offset += sizeof hash;
40054626cc1Sho memcpy(m->buf + offset, iv, sizeof iv);
40154626cc1Sho offset += sizeof iv;
40254626cc1Sho memcpy(m->buf + offset, buf, len);
40354626cc1Sho free(buf);
4047aea46c5Sho
4057aea46c5Sho if (p)
4067aea46c5Sho net_enqueue(p, m);
4077aea46c5Sho else
4087aea46c5Sho for (p = LIST_FIRST(&cfgstate.peerlist); p;
4097aea46c5Sho p = LIST_NEXT(p, link))
4107aea46c5Sho net_enqueue(p, m);
4117aea46c5Sho
4127aea46c5Sho if (!m->refcnt) {
41354626cc1Sho free(m->buf);
4147aea46c5Sho free(m);
4157aea46c5Sho }
4167aea46c5Sho
4177aea46c5Sho return 0;
4187aea46c5Sho }
4197aea46c5Sho
4207aea46c5Sho /* Set all write pending filedescriptors. */
4217aea46c5Sho int
net_set_pending_wfds(fd_set * fds)4227aea46c5Sho net_set_pending_wfds(fd_set *fds)
4237aea46c5Sho {
4247aea46c5Sho struct syncpeer *p;
4257aea46c5Sho int max_fd = -1;
4267aea46c5Sho
4277aea46c5Sho for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link))
4287aea46c5Sho if (p->socket > -1 && SIMPLEQ_FIRST(&p->msgs)) {
4297aea46c5Sho FD_SET(p->socket, fds);
4307aea46c5Sho if (p->socket > max_fd)
4317aea46c5Sho max_fd = p->socket;
4327aea46c5Sho }
4337aea46c5Sho return max_fd + 1;
4347aea46c5Sho }
4357aea46c5Sho
4367aea46c5Sho /*
4377aea46c5Sho * Set readable filedescriptors. They are basically the same as for write,
4387aea46c5Sho * plus the listening socket.
4397aea46c5Sho */
4407aea46c5Sho int
net_set_rfds(fd_set * fds)4417aea46c5Sho net_set_rfds(fd_set *fds)
4427aea46c5Sho {
4437aea46c5Sho struct syncpeer *p;
444bd7abb77Sho int i, max_fd = -1;
4457aea46c5Sho
4467aea46c5Sho for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
4477aea46c5Sho if (p->socket > -1)
4487aea46c5Sho FD_SET(p->socket, fds);
4497aea46c5Sho if (p->socket > max_fd)
4507aea46c5Sho max_fd = p->socket;
4517aea46c5Sho }
452bd7abb77Sho for (i = 0; listeners[i] != -1; i++) {
453bd7abb77Sho FD_SET(listeners[i], fds);
454bd7abb77Sho if (listeners[i] > max_fd)
455bd7abb77Sho max_fd = listeners[i];
456bd7abb77Sho }
4577aea46c5Sho return max_fd + 1;
4587aea46c5Sho }
4597aea46c5Sho
460bd7abb77Sho static void
net_accept(int accept_socket)461bd7abb77Sho net_accept(int accept_socket)
4627aea46c5Sho {
4637aea46c5Sho struct sockaddr_storage sa_storage, sa_storage2;
4647aea46c5Sho struct sockaddr *sa = (struct sockaddr *)&sa_storage;
4657aea46c5Sho struct sockaddr *sa2 = (struct sockaddr *)&sa_storage2;
466bd7abb77Sho struct sockaddr_in *sin, *sin2;
467bd7abb77Sho struct sockaddr_in6 *sin6, *sin62;
4687aea46c5Sho struct syncpeer *p;
469bd7abb77Sho socklen_t socklen;
470bd7abb77Sho int s, found;
4717aea46c5Sho
4727aea46c5Sho /* Accept a new incoming connection */
4737aea46c5Sho socklen = sizeof sa_storage;
474bd7abb77Sho memset(&sa_storage, 0, socklen);
475bd7abb77Sho memset(&sa_storage2, 0, socklen);
476bd7abb77Sho s = accept(accept_socket, sa, &socklen);
477bd7abb77Sho if (s > -1) {
4787aea46c5Sho /* Setup the syncpeer structure */
4797aea46c5Sho found = 0;
4807aea46c5Sho for (p = LIST_FIRST(&cfgstate.peerlist); p && !found;
4817aea46c5Sho p = LIST_NEXT(p, link)) {
4827aea46c5Sho
4837aea46c5Sho /* Match? */
4847aea46c5Sho if (net_set_sa(sa2, p->name, 0))
4857aea46c5Sho continue;
4867aea46c5Sho if (sa->sa_family != sa2->sa_family)
4877aea46c5Sho continue;
4887aea46c5Sho if (sa->sa_family == AF_INET) {
4897aea46c5Sho sin = (struct sockaddr_in *)sa;
4907aea46c5Sho sin2 = (struct sockaddr_in *)sa2;
491bd7abb77Sho if (memcmp(&sin->sin_addr, &sin2->sin_addr,
4927aea46c5Sho sizeof(struct in_addr)))
4937aea46c5Sho continue;
4947aea46c5Sho } else {
4957aea46c5Sho sin6 = (struct sockaddr_in6 *)sa;
4967aea46c5Sho sin62 = (struct sockaddr_in6 *)sa2;
497bd7abb77Sho if (memcmp(&sin6->sin6_addr, &sin62->sin6_addr,
4987aea46c5Sho sizeof(struct in6_addr)))
4997aea46c5Sho continue;
5007aea46c5Sho }
5017aea46c5Sho /* Match! */
5027aea46c5Sho found++;
503bd7abb77Sho p->socket = s;
504bd7abb77Sho log_msg(1, "net: peer \"%s\" connected", p->name);
50594f5df21Sho if (cfgstate.runstate == MASTER)
506bd7abb77Sho timer_add("pfkey_snap", 2, pfkey_snapshot, p);
5077aea46c5Sho }
5087aea46c5Sho if (!found) {
509bd7abb77Sho log_msg(1, "net: found no matching peer for accepted "
510bd7abb77Sho "socket, closing.");
511bd7abb77Sho close(s);
5127aea46c5Sho }
51362e3c252Sderaadt } else if (errno != EWOULDBLOCK && errno != EINTR &&
51462e3c252Sderaadt errno != ECONNABORTED)
515bd7abb77Sho log_err("net: accept()");
5167aea46c5Sho }
5177aea46c5Sho
518bd7abb77Sho void
net_handle_messages(fd_set * fds)519bd7abb77Sho net_handle_messages(fd_set *fds)
520bd7abb77Sho {
521bd7abb77Sho struct syncpeer *p;
522bd7abb77Sho u_int8_t *msg;
523bd7abb77Sho u_int32_t msgtype, msglen;
524bd7abb77Sho int i;
525bd7abb77Sho
526bd7abb77Sho for (i = 0; listeners[i] != -1; i++)
527bd7abb77Sho if (FD_ISSET(listeners[i], fds))
528bd7abb77Sho net_accept(listeners[i]);
529bd7abb77Sho
5307aea46c5Sho for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
5317aea46c5Sho if (p->socket < 0 || !FD_ISSET(p->socket, fds))
5327aea46c5Sho continue;
5337aea46c5Sho msg = net_read(p, &msgtype, &msglen);
5347aea46c5Sho if (!msg)
5357aea46c5Sho continue;
5367aea46c5Sho
5379353ff65Skjell log_msg(2, "net_handle_messages: got msg type %u len %u from "
5387aea46c5Sho "peer %s", msgtype, msglen, p->name);
5397aea46c5Sho
5407aea46c5Sho switch (msgtype) {
5417aea46c5Sho case MSG_SYNCCTL:
5427aea46c5Sho net_ctl_handle_msg(p, msg, msglen);
5437aea46c5Sho free(msg);
5447aea46c5Sho break;
5457aea46c5Sho
5467aea46c5Sho case MSG_PFKEYDATA:
5477aea46c5Sho if (p->runstate != MASTER ||
5487aea46c5Sho cfgstate.runstate == MASTER) {
5491d55a410Sho log_msg(1, "net: got PFKEY message from "
5501d55a410Sho "non-MASTER peer");
5517aea46c5Sho free(msg);
5527aea46c5Sho if (cfgstate.runstate == MASTER)
5537aea46c5Sho net_ctl_send_state(p);
5547aea46c5Sho else
5557aea46c5Sho net_ctl_send_error(p, 0);
5567aea46c5Sho } else if (pfkey_queue_message(msg, msglen))
5577aea46c5Sho free(msg);
5587aea46c5Sho break;
5597aea46c5Sho
5607aea46c5Sho default:
5611d55a410Sho log_msg(0, "net: got unknown message type %u len %u "
5621d55a410Sho "from peer %s", msgtype, msglen, p->name);
5637aea46c5Sho free(msg);
5647aea46c5Sho net_ctl_send_error(p, 0);
5657aea46c5Sho }
5667aea46c5Sho }
5677aea46c5Sho }
5687aea46c5Sho
5697aea46c5Sho void
net_send_messages(fd_set * fds)5707aea46c5Sho net_send_messages(fd_set *fds)
5717aea46c5Sho {
5727aea46c5Sho struct syncpeer *p;
5737aea46c5Sho struct qmsg *qm;
5747aea46c5Sho struct msg *m;
57554626cc1Sho ssize_t r;
5767aea46c5Sho
5777aea46c5Sho for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
5787aea46c5Sho if (p->socket < 0 || !FD_ISSET(p->socket, fds))
5797aea46c5Sho continue;
5807aea46c5Sho qm = SIMPLEQ_FIRST(&p->msgs);
5817aea46c5Sho if (!qm) {
5827aea46c5Sho /* XXX Log */
5837aea46c5Sho continue;
5847aea46c5Sho }
5857aea46c5Sho m = qm->msg;
5867aea46c5Sho
5879353ff65Skjell log_msg(2, "net_send_messages: msg %p len %u ref %d "
5881d55a410Sho "to peer %s", m, m->len, m->refcnt, p->name);
5897aea46c5Sho
59054626cc1Sho /* write message */
59154626cc1Sho r = write(p->socket, m->buf, m->len);
5921d55a410Sho if (r == -1) {
5931d55a410Sho net_disconnect_peer(p);
5941d55a410Sho log_msg(0, "net_send_messages: write() failed, "
5951d55a410Sho "peer disconnected");
5961d55a410Sho } else if (r < (ssize_t)m->len) {
5971d55a410Sho /* retransmit later */
5987aea46c5Sho continue;
59954626cc1Sho }
6007aea46c5Sho
60154626cc1Sho /* cleanup */
6027aea46c5Sho SIMPLEQ_REMOVE_HEAD(&p->msgs, next);
6037aea46c5Sho free(qm);
6047aea46c5Sho
6057aea46c5Sho if (--m->refcnt < 1) {
6069353ff65Skjell log_msg(2, "net_send_messages: freeing msg %p", m);
60754626cc1Sho free(m->buf);
6087aea46c5Sho free(m);
6097aea46c5Sho }
6107aea46c5Sho }
6117aea46c5Sho return;
6127aea46c5Sho }
6137aea46c5Sho
6147aea46c5Sho void
net_disconnect_peer(struct syncpeer * p)6157aea46c5Sho net_disconnect_peer(struct syncpeer *p)
6167aea46c5Sho {
6171d55a410Sho if (p->socket > -1) {
6181d55a410Sho log_msg(1, "net_disconnect_peer: peer \"%s\" removed",
6191d55a410Sho p->name);
6207aea46c5Sho close(p->socket);
6211d55a410Sho }
6227aea46c5Sho p->socket = -1;
6237aea46c5Sho }
6247aea46c5Sho
6257aea46c5Sho void
net_shutdown(void)6267aea46c5Sho net_shutdown(void)
6277aea46c5Sho {
6287aea46c5Sho struct syncpeer *p;
6297aea46c5Sho struct qmsg *qm;
6307aea46c5Sho struct msg *m;
631bd7abb77Sho int i;
6327aea46c5Sho
6337aea46c5Sho while ((p = LIST_FIRST(&cfgstate.peerlist))) {
6347aea46c5Sho while ((qm = SIMPLEQ_FIRST(&p->msgs))) {
6357aea46c5Sho SIMPLEQ_REMOVE_HEAD(&p->msgs, next);
6367aea46c5Sho m = qm->msg;
6377aea46c5Sho if (--m->refcnt < 1) {
63854626cc1Sho free(m->buf);
6397aea46c5Sho free(m);
6407aea46c5Sho }
6417aea46c5Sho free(qm);
6427aea46c5Sho }
6437aea46c5Sho net_disconnect_peer(p);
6441bf4baafSho free(p->sa);
6457aea46c5Sho free(p->name);
6467aea46c5Sho LIST_REMOVE(p, link);
6479945a12eSmcbride cfgstate.peercnt--;
6487aea46c5Sho free(p);
6497aea46c5Sho }
6507aea46c5Sho
651bd7abb77Sho if (listeners) {
652bd7abb77Sho for (i = 0; listeners[i] != -1; i++)
653bd7abb77Sho close(listeners[i]);
654bd7abb77Sho free(listeners);
655bd7abb77Sho listeners = 0;
656bd7abb77Sho }
6577aea46c5Sho }
6587aea46c5Sho
6597aea46c5Sho /*
6607aea46c5Sho * Helper functions (local) below here.
6617aea46c5Sho */
6627aea46c5Sho
6637aea46c5Sho static u_int8_t *
net_read(struct syncpeer * p,u_int32_t * msgtype,u_int32_t * msglen)6647aea46c5Sho net_read(struct syncpeer *p, u_int32_t *msgtype, u_int32_t *msglen)
6657aea46c5Sho {
66654626cc1Sho u_int8_t *msg, *blob, *rhash, *iv, hash[SHA_DIGEST_LENGTH];
667f5fcfc77Smoritz u_int32_t v, blob_len, pos = 0;
66885fc6b68Shaesbaert int padlen = 0, offset = 0;
66985fc6b68Shaesbaert ssize_t r;
67054626cc1Sho SHA_CTX ctx;
6717aea46c5Sho
67254626cc1Sho /* Read blob length */
6731d55a410Sho r = read(p->socket, &v, sizeof v);
6741d55a410Sho if (r != (ssize_t)sizeof v) {
6751d55a410Sho if (r < 1)
6761d55a410Sho net_disconnect_peer(p);
6777aea46c5Sho return NULL;
6781d55a410Sho }
6791d55a410Sho
68054626cc1Sho blob_len = ntohl(v);
68154626cc1Sho if (blob_len < sizeof hash + AES_IV_LEN + 2 * sizeof(u_int32_t))
6827aea46c5Sho return NULL;
68354626cc1Sho *msglen = blob_len - sizeof hash - AES_IV_LEN - 2 * sizeof(u_int32_t);
6841d55a410Sho if (*msglen < MSG_MINLEN || *msglen > MSG_MAXLEN)
6851d55a410Sho return NULL;
6867aea46c5Sho
68754626cc1Sho /* Read message blob */
68835de856eSderaadt blob = malloc(blob_len);
68954626cc1Sho if (!blob) {
69054626cc1Sho log_err("net_read: malloc()");
6917aea46c5Sho return NULL;
69254626cc1Sho }
693f5fcfc77Smoritz
694f5fcfc77Smoritz while (blob_len > pos) {
695f5fcfc77Smoritz switch (r = read(p->socket, blob + pos, blob_len - pos)) {
696f5fcfc77Smoritz case -1:
697f5fcfc77Smoritz if (errno == EINTR || errno == EAGAIN)
698f5fcfc77Smoritz continue;
699f5fcfc77Smoritz /* FALLTHROUGH */
700f5fcfc77Smoritz case 0:
7011d55a410Sho net_disconnect_peer(p);
70254626cc1Sho free(blob);
70354626cc1Sho return NULL;
704f5fcfc77Smoritz /* NOTREACHED */
705f5fcfc77Smoritz default:
706f5fcfc77Smoritz pos += r;
707f5fcfc77Smoritz }
7087aea46c5Sho }
7097aea46c5Sho
71054626cc1Sho offset = 0;
71154626cc1Sho memcpy(&v, blob + offset, sizeof v);
71254626cc1Sho *msgtype = ntohl(v);
71354626cc1Sho offset += sizeof v;
71454626cc1Sho
71554626cc1Sho if (*msgtype > MSG_MAXTYPE) {
71654626cc1Sho free(blob);
71754626cc1Sho return NULL;
71854626cc1Sho }
71954626cc1Sho
72054626cc1Sho memcpy(&v, blob + offset, sizeof v);
72154626cc1Sho padlen = ntohl(v);
72254626cc1Sho offset += sizeof v;
72354626cc1Sho
72454626cc1Sho rhash = blob + offset;
72554626cc1Sho iv = rhash + sizeof hash;
72635de856eSderaadt msg = malloc(*msglen);
72754626cc1Sho if (!msg) {
72854626cc1Sho free(blob);
72954626cc1Sho return NULL;
73054626cc1Sho }
73154626cc1Sho memcpy(msg, iv + AES_IV_LEN, *msglen);
73254626cc1Sho
7339353ff65Skjell dump_buf(2, rhash, sizeof hash, "net_read: got hash");
7349353ff65Skjell dump_buf(2, iv, AES_IV_LEN, "net_read: got IV");
7359353ff65Skjell dump_buf(2, msg, *msglen, "net_read: pre decrypt");
73654626cc1Sho AES_cbc_encrypt(msg, msg, *msglen, &aes_key[1], iv, AES_DECRYPT);
7379353ff65Skjell dump_buf(2, msg, *msglen, "net_read: post decrypt");
73854626cc1Sho *msglen -= padlen;
73954626cc1Sho
74054626cc1Sho SHA1_Init(&ctx);
74154626cc1Sho SHA1_Update(&ctx, msg, *msglen);
74254626cc1Sho SHA1_Final(hash, &ctx);
7439353ff65Skjell dump_buf(2, hash, sizeof hash, "net_read: computed hash");
74454626cc1Sho
74554626cc1Sho if (memcmp(hash, rhash, sizeof hash) != 0) {
74654626cc1Sho free(blob);
7478367b0efSjsg free(msg);
7481d55a410Sho log_msg(0, "net_read: got bad message (typo in shared key?)");
74954626cc1Sho return NULL;
75054626cc1Sho }
75154626cc1Sho free(blob);
7527aea46c5Sho return msg;
7537aea46c5Sho }
7547aea46c5Sho
7557aea46c5Sho static int
net_set_sa(struct sockaddr * sa,char * name,in_port_t port)7567aea46c5Sho net_set_sa(struct sockaddr *sa, char *name, in_port_t port)
7577aea46c5Sho {
7587aea46c5Sho struct sockaddr_in *sin = (struct sockaddr_in *)sa;
7597aea46c5Sho struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
7607aea46c5Sho
7616db4730eSho if (!name) {
7626db4730eSho /* XXX Assume IPv4 */
7636db4730eSho sa->sa_family = AF_INET;
7646db4730eSho sin->sin_port = htons(port);
7656db4730eSho sin->sin_len = sizeof *sin;
7666db4730eSho return 0;
7676db4730eSho }
7686db4730eSho
7697aea46c5Sho if (inet_pton(AF_INET, name, &sin->sin_addr) == 1) {
7707aea46c5Sho sa->sa_family = AF_INET;
7717aea46c5Sho sin->sin_port = htons(port);
7727aea46c5Sho sin->sin_len = sizeof *sin;
7737aea46c5Sho return 0;
7747aea46c5Sho }
7757aea46c5Sho
7767aea46c5Sho if (inet_pton(AF_INET6, name, &sin6->sin6_addr) == 1) {
7777aea46c5Sho sa->sa_family = AF_INET6;
7787aea46c5Sho sin6->sin6_port = htons(port);
7797aea46c5Sho sin6->sin6_len = sizeof *sin6;
7807aea46c5Sho return 0;
7817aea46c5Sho }
7826db4730eSho
7836db4730eSho return -1;
7846db4730eSho }
7857aea46c5Sho
7867aea46c5Sho static void
got_sigalrm(int s)7877aea46c5Sho got_sigalrm(int s)
7887aea46c5Sho {
7897aea46c5Sho return;
7907aea46c5Sho }
7917aea46c5Sho
7927aea46c5Sho void
net_connect(void)7931d55a410Sho net_connect(void)
7947aea46c5Sho {
7957aea46c5Sho struct itimerval iv;
7967aea46c5Sho struct syncpeer *p;
7977aea46c5Sho
7987aea46c5Sho signal(SIGALRM, got_sigalrm);
7997aea46c5Sho memset(&iv, 0, sizeof iv);
8007aea46c5Sho iv.it_value.tv_sec = 5;
8017aea46c5Sho iv.it_interval.tv_sec = 5;
8027aea46c5Sho setitimer(ITIMER_REAL, &iv, NULL);
8037aea46c5Sho
8047aea46c5Sho for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
80554626cc1Sho if (p->socket > -1)
8067aea46c5Sho continue;
8071bf4baafSho if (!p->sa) {
80835de856eSderaadt p->sa = calloc(1, sizeof(struct sockaddr_storage));
8091bf4baafSho if (!p->sa)
8101bf4baafSho return;
8111bf4baafSho if (net_set_sa(p->sa, p->name, cfgstate.listen_port))
8127aea46c5Sho continue;
8131bf4baafSho }
8141bf4baafSho p->socket = socket(p->sa->sa_family, SOCK_STREAM, 0);
8157aea46c5Sho if (p->socket < 0) {
8167aea46c5Sho log_err("peer \"%s\": socket()", p->name);
8177aea46c5Sho continue;
8187aea46c5Sho }
8191bf4baafSho if (connect(p->socket, p->sa, p->sa->sa_len)) {
8201d55a410Sho log_msg(1, "net_connect: peer \"%s\" not ready yet",
8211d55a410Sho p->name);
8227aea46c5Sho net_disconnect_peer(p);
8237aea46c5Sho continue;
8247aea46c5Sho }
8257aea46c5Sho if (net_ctl_send_state(p)) {
8261d55a410Sho log_msg(0, "net_connect: peer \"%s\" failed", p->name);
8277aea46c5Sho net_disconnect_peer(p);
8287aea46c5Sho continue;
8297aea46c5Sho }
8301d55a410Sho log_msg(1, "net_connect: peer \"%s\" connected, fd %d",
8311d55a410Sho p->name, p->socket);
83294f5df21Sho
83394f5df21Sho /* Schedule a pfkey sync to the newly connected peer. */
83494f5df21Sho if (cfgstate.runstate == MASTER)
83594f5df21Sho timer_add("pfkey_snapshot", 2, pfkey_snapshot, p);
8367aea46c5Sho }
8377aea46c5Sho
8387aea46c5Sho timerclear(&iv.it_value);
8397aea46c5Sho timerclear(&iv.it_interval);
8407aea46c5Sho setitimer(ITIMER_REAL, &iv, NULL);
8417aea46c5Sho signal(SIGALRM, SIG_IGN);
8427aea46c5Sho
8437aea46c5Sho return;
8447aea46c5Sho }
8457aea46c5Sho
8467aea46c5Sho static void
net_check_peers(void * arg)8477aea46c5Sho net_check_peers(void *arg)
8487aea46c5Sho {
8491d55a410Sho net_connect();
8507aea46c5Sho (void)timer_add("peer recheck", 600, net_check_peers, 0);
8517aea46c5Sho }
852