]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/hastd/proto_tcp.c
bhyvectl(8): Normalize the man page date
[FreeBSD/FreeBSD.git] / sbin / hastd / proto_tcp.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2009-2010 The FreeBSD Foundation
5  * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
6  * All rights reserved.
7  *
8  * This software was developed by Pawel Jakub Dawidek under sponsorship from
9  * the FreeBSD Foundation.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>  /* MAXHOSTNAMELEN */
37 #include <sys/socket.h>
38
39 #include <arpa/inet.h>
40
41 #include <netinet/in.h>
42 #include <netinet/tcp.h>
43
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <netdb.h>
47 #include <stdbool.h>
48 #include <stdint.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <unistd.h>
52
53 #include "pjdlog.h"
54 #include "proto_impl.h"
55 #include "subr.h"
56
57 #define TCP_CTX_MAGIC   0x7c41c
58 struct tcp_ctx {
59         int                     tc_magic;
60         struct sockaddr_storage tc_sa;
61         int                     tc_fd;
62         int                     tc_side;
63 #define TCP_SIDE_CLIENT         0
64 #define TCP_SIDE_SERVER_LISTEN  1
65 #define TCP_SIDE_SERVER_WORK    2
66 };
67
68 static int tcp_connect_wait(void *ctx, int timeout);
69 static void tcp_close(void *ctx);
70
71 /*
72  * Function converts the given string to unsigned number.
73  */
74 static int
75 numfromstr(const char *str, intmax_t minnum, intmax_t maxnum, intmax_t *nump)
76 {
77         intmax_t digit, num;
78
79         if (str[0] == '\0')
80                 goto invalid;   /* Empty string. */
81         num = 0;
82         for (; *str != '\0'; str++) {
83                 if (*str < '0' || *str > '9')
84                         goto invalid;   /* Non-digit character. */
85                 digit = *str - '0';
86                 if (num > num * 10 + digit)
87                         goto invalid;   /* Overflow. */
88                 num = num * 10 + digit;
89                 if (num > maxnum)
90                         goto invalid;   /* Too big. */
91         }
92         if (num < minnum)
93                 goto invalid;   /* Too small. */
94         *nump = num;
95         return (0);
96 invalid:
97         errno = EINVAL;
98         return (-1);
99 }
100
101 static int
102 tcp_addr(const char *addr, int defport, struct sockaddr_storage *sap)
103 {
104         char iporhost[MAXHOSTNAMELEN], portstr[6];
105         struct addrinfo hints;
106         struct addrinfo *res;
107         const char *pp;
108         intmax_t port;
109         size_t size;
110         int error;
111
112         if (addr == NULL)
113                 return (-1);
114
115         bzero(&hints, sizeof(hints));
116         hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
117         hints.ai_family = PF_UNSPEC;
118         hints.ai_socktype = SOCK_STREAM;
119         hints.ai_protocol = IPPROTO_TCP;
120
121         if (strncasecmp(addr, "tcp4://", 7) == 0) {
122                 addr += 7;
123                 hints.ai_family = PF_INET;
124         } else if (strncasecmp(addr, "tcp6://", 7) == 0) {
125                 addr += 7;
126                 hints.ai_family = PF_INET6;
127         } else if (strncasecmp(addr, "tcp://", 6) == 0) {
128                 addr += 6;
129         } else {
130                 /*
131                  * Because TCP is the default assume IP or host is given without
132                  * prefix.
133                  */
134         }
135
136         /*
137          * Extract optional port.
138          * There are three cases to consider.
139          * 1. hostname with port, eg. freefall.freebsd.org:8457
140          * 2. IPv4 address with port, eg. 192.168.0.101:8457
141          * 3. IPv6 address with port, eg. [fe80::1]:8457
142          * We discover IPv6 address by checking for two colons and if port is
143          * given, the address has to start with [.
144          */
145         pp = NULL;
146         if (strchr(addr, ':') != strrchr(addr, ':')) {
147                 if (addr[0] == '[')
148                         pp = strrchr(addr, ':');
149         } else {
150                 pp = strrchr(addr, ':');
151         }
152         if (pp == NULL) {
153                 /* Port not given, use the default. */
154                 port = defport;
155         } else {
156                 if (numfromstr(pp + 1, 1, 65535, &port) == -1)
157                         return (errno);
158         }
159         (void)snprintf(portstr, sizeof(portstr), "%jd", (intmax_t)port);
160         /* Extract host name or IP address. */
161         if (pp == NULL) {
162                 size = sizeof(iporhost);
163                 if (strlcpy(iporhost, addr, size) >= size)
164                         return (ENAMETOOLONG);
165         } else if (addr[0] == '[' && pp[-1] == ']') {
166                 size = (size_t)(pp - addr - 2 + 1);
167                 if (size > sizeof(iporhost))
168                         return (ENAMETOOLONG);
169                 (void)strlcpy(iporhost, addr + 1, size);
170         } else {
171                 size = (size_t)(pp - addr + 1);
172                 if (size > sizeof(iporhost))
173                         return (ENAMETOOLONG);
174                 (void)strlcpy(iporhost, addr, size);
175         }
176
177         error = getaddrinfo(iporhost, portstr, &hints, &res);
178         if (error != 0) {
179                 pjdlog_debug(1, "getaddrinfo(%s, %s) failed: %s.", iporhost,
180                     portstr, gai_strerror(error));
181                 return (EINVAL);
182         }
183         if (res == NULL)
184                 return (ENOENT);
185
186         memcpy(sap, res->ai_addr, res->ai_addrlen);
187
188         freeaddrinfo(res);
189
190         return (0);
191 }
192
193 static int
194 tcp_setup_new(const char *addr, int side, void **ctxp)
195 {
196         struct tcp_ctx *tctx;
197         int ret, nodelay;
198
199         PJDLOG_ASSERT(addr != NULL);
200         PJDLOG_ASSERT(side == TCP_SIDE_CLIENT ||
201             side == TCP_SIDE_SERVER_LISTEN);
202         PJDLOG_ASSERT(ctxp != NULL);
203
204         tctx = malloc(sizeof(*tctx));
205         if (tctx == NULL)
206                 return (errno);
207
208         /* Parse given address. */
209         if ((ret = tcp_addr(addr, PROTO_TCP_DEFAULT_PORT, &tctx->tc_sa)) != 0) {
210                 free(tctx);
211                 return (ret);
212         }
213
214         PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC);
215
216         tctx->tc_fd = socket(tctx->tc_sa.ss_family, SOCK_STREAM, 0);
217         if (tctx->tc_fd == -1) {
218                 ret = errno;
219                 free(tctx);
220                 return (ret);
221         }
222
223         PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC);
224
225         /* Socket settings. */
226         nodelay = 1;
227         if (setsockopt(tctx->tc_fd, IPPROTO_TCP, TCP_NODELAY, &nodelay,
228             sizeof(nodelay)) == -1) {
229                 pjdlog_errno(LOG_WARNING, "Unable to set TCP_NOELAY");
230         }
231
232         tctx->tc_side = side;
233         tctx->tc_magic = TCP_CTX_MAGIC;
234         *ctxp = tctx;
235
236         return (0);
237 }
238
239 static int
240 tcp_setup_wrap(int fd, int side, void **ctxp)
241 {
242         struct tcp_ctx *tctx;
243
244         PJDLOG_ASSERT(fd >= 0);
245         PJDLOG_ASSERT(side == TCP_SIDE_CLIENT ||
246             side == TCP_SIDE_SERVER_WORK);
247         PJDLOG_ASSERT(ctxp != NULL);
248
249         tctx = malloc(sizeof(*tctx));
250         if (tctx == NULL)
251                 return (errno);
252
253         tctx->tc_fd = fd;
254         tctx->tc_sa.ss_family = AF_UNSPEC;
255         tctx->tc_side = side;
256         tctx->tc_magic = TCP_CTX_MAGIC;
257         *ctxp = tctx;
258
259         return (0);
260 }
261
262 static int
263 tcp_client(const char *srcaddr, const char *dstaddr, void **ctxp)
264 {
265         struct tcp_ctx *tctx;
266         struct sockaddr_storage sa;
267         int ret;
268
269         ret = tcp_setup_new(dstaddr, TCP_SIDE_CLIENT, ctxp);
270         if (ret != 0)
271                 return (ret);
272         tctx = *ctxp;
273         if (srcaddr == NULL)
274                 return (0);
275         ret = tcp_addr(srcaddr, 0, &sa);
276         if (ret != 0) {
277                 tcp_close(tctx);
278                 return (ret);
279         }
280         if (bind(tctx->tc_fd, (struct sockaddr *)&sa, sa.ss_len) == -1) {
281                 ret = errno;
282                 tcp_close(tctx);
283                 return (ret);
284         }
285         return (0);
286 }
287
288 static int
289 tcp_connect(void *ctx, int timeout)
290 {
291         struct tcp_ctx *tctx = ctx;
292         int error, flags;
293
294         PJDLOG_ASSERT(tctx != NULL);
295         PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
296         PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_CLIENT);
297         PJDLOG_ASSERT(tctx->tc_fd >= 0);
298         PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC);
299         PJDLOG_ASSERT(timeout >= -1);
300
301         flags = fcntl(tctx->tc_fd, F_GETFL);
302         if (flags == -1) {
303                 pjdlog_common(LOG_DEBUG, 1, errno, "fcntl(F_GETFL) failed");
304                 return (errno);
305         }
306         /*
307          * We make socket non-blocking so we can handle connection timeout
308          * manually.
309          */
310         flags |= O_NONBLOCK;
311         if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) {
312                 pjdlog_common(LOG_DEBUG, 1, errno,
313                     "fcntl(F_SETFL, O_NONBLOCK) failed");
314                 return (errno);
315         }
316
317         if (connect(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa,
318             tctx->tc_sa.ss_len) == 0) {
319                 if (timeout == -1)
320                         return (0);
321                 error = 0;
322                 goto done;
323         }
324         if (errno != EINPROGRESS) {
325                 error = errno;
326                 pjdlog_common(LOG_DEBUG, 1, errno, "connect() failed");
327                 goto done;
328         }
329         if (timeout == -1)
330                 return (0);
331         return (tcp_connect_wait(ctx, timeout));
332 done:
333         flags &= ~O_NONBLOCK;
334         if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) {
335                 if (error == 0)
336                         error = errno;
337                 pjdlog_common(LOG_DEBUG, 1, errno,
338                     "fcntl(F_SETFL, ~O_NONBLOCK) failed");
339         }
340         return (error);
341 }
342
343 static int
344 tcp_connect_wait(void *ctx, int timeout)
345 {
346         struct tcp_ctx *tctx = ctx;
347         struct timeval tv;
348         fd_set fdset;
349         socklen_t esize;
350         int error, flags, ret;
351
352         PJDLOG_ASSERT(tctx != NULL);
353         PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
354         PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_CLIENT);
355         PJDLOG_ASSERT(tctx->tc_fd >= 0);
356         PJDLOG_ASSERT(timeout >= 0);
357
358         tv.tv_sec = timeout;
359         tv.tv_usec = 0;
360 again:
361         FD_ZERO(&fdset);
362         FD_SET(tctx->tc_fd, &fdset);
363         ret = select(tctx->tc_fd + 1, NULL, &fdset, NULL, &tv);
364         if (ret == 0) {
365                 error = ETIMEDOUT;
366                 goto done;
367         } else if (ret == -1) {
368                 if (errno == EINTR)
369                         goto again;
370                 error = errno;
371                 pjdlog_common(LOG_DEBUG, 1, errno, "select() failed");
372                 goto done;
373         }
374         PJDLOG_ASSERT(ret > 0);
375         PJDLOG_ASSERT(FD_ISSET(tctx->tc_fd, &fdset));
376         esize = sizeof(error);
377         if (getsockopt(tctx->tc_fd, SOL_SOCKET, SO_ERROR, &error,
378             &esize) == -1) {
379                 error = errno;
380                 pjdlog_common(LOG_DEBUG, 1, errno,
381                     "getsockopt(SO_ERROR) failed");
382                 goto done;
383         }
384         if (error != 0) {
385                 pjdlog_common(LOG_DEBUG, 1, error,
386                     "getsockopt(SO_ERROR) returned error");
387                 goto done;
388         }
389         error = 0;
390 done:
391         flags = fcntl(tctx->tc_fd, F_GETFL);
392         if (flags == -1) {
393                 if (error == 0)
394                         error = errno;
395                 pjdlog_common(LOG_DEBUG, 1, errno, "fcntl(F_GETFL) failed");
396                 return (error);
397         }
398         flags &= ~O_NONBLOCK;
399         if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) {
400                 if (error == 0)
401                         error = errno;
402                 pjdlog_common(LOG_DEBUG, 1, errno,
403                     "fcntl(F_SETFL, ~O_NONBLOCK) failed");
404         }
405         return (error);
406 }
407
408 static int
409 tcp_server(const char *addr, void **ctxp)
410 {
411         struct tcp_ctx *tctx;
412         int ret, val;
413
414         ret = tcp_setup_new(addr, TCP_SIDE_SERVER_LISTEN, ctxp);
415         if (ret != 0)
416                 return (ret);
417
418         tctx = *ctxp;
419
420         val = 1;
421         /* Ignore failure. */
422         (void)setsockopt(tctx->tc_fd, SOL_SOCKET, SO_REUSEADDR, &val,
423            sizeof(val));
424
425         PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC);
426
427         if (bind(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa,
428             tctx->tc_sa.ss_len) == -1) {
429                 ret = errno;
430                 tcp_close(tctx);
431                 return (ret);
432         }
433         if (listen(tctx->tc_fd, 8) == -1) {
434                 ret = errno;
435                 tcp_close(tctx);
436                 return (ret);
437         }
438
439         return (0);
440 }
441
442 static int
443 tcp_accept(void *ctx, void **newctxp)
444 {
445         struct tcp_ctx *tctx = ctx;
446         struct tcp_ctx *newtctx;
447         socklen_t fromlen;
448         int ret;
449
450         PJDLOG_ASSERT(tctx != NULL);
451         PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
452         PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_SERVER_LISTEN);
453         PJDLOG_ASSERT(tctx->tc_fd >= 0);
454         PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC);
455
456         newtctx = malloc(sizeof(*newtctx));
457         if (newtctx == NULL)
458                 return (errno);
459
460         fromlen = tctx->tc_sa.ss_len;
461         newtctx->tc_fd = accept(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa,
462             &fromlen);
463         if (newtctx->tc_fd == -1) {
464                 ret = errno;
465                 free(newtctx);
466                 return (ret);
467         }
468
469         newtctx->tc_side = TCP_SIDE_SERVER_WORK;
470         newtctx->tc_magic = TCP_CTX_MAGIC;
471         *newctxp = newtctx;
472
473         return (0);
474 }
475
476 static int
477 tcp_wrap(int fd, bool client, void **ctxp)
478 {
479
480         return (tcp_setup_wrap(fd,
481             client ? TCP_SIDE_CLIENT : TCP_SIDE_SERVER_WORK, ctxp));
482 }
483
484 static int
485 tcp_send(void *ctx, const unsigned char *data, size_t size, int fd)
486 {
487         struct tcp_ctx *tctx = ctx;
488
489         PJDLOG_ASSERT(tctx != NULL);
490         PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
491         PJDLOG_ASSERT(tctx->tc_fd >= 0);
492         PJDLOG_ASSERT(fd == -1);
493
494         return (proto_common_send(tctx->tc_fd, data, size, -1));
495 }
496
497 static int
498 tcp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
499 {
500         struct tcp_ctx *tctx = ctx;
501
502         PJDLOG_ASSERT(tctx != NULL);
503         PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
504         PJDLOG_ASSERT(tctx->tc_fd >= 0);
505         PJDLOG_ASSERT(fdp == NULL);
506
507         return (proto_common_recv(tctx->tc_fd, data, size, NULL));
508 }
509
510 static int
511 tcp_descriptor(const void *ctx)
512 {
513         const struct tcp_ctx *tctx = ctx;
514
515         PJDLOG_ASSERT(tctx != NULL);
516         PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
517
518         return (tctx->tc_fd);
519 }
520
521 static bool
522 tcp_address_match(const void *ctx, const char *addr)
523 {
524         const struct tcp_ctx *tctx = ctx;
525         struct sockaddr_storage sa1, sa2;
526         socklen_t salen;
527
528         PJDLOG_ASSERT(tctx != NULL);
529         PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
530
531         if (tcp_addr(addr, PROTO_TCP_DEFAULT_PORT, &sa1) != 0)
532                 return (false);
533
534         salen = sizeof(sa2);
535         if (getpeername(tctx->tc_fd, (struct sockaddr *)&sa2, &salen) == -1)
536                 return (false);
537
538         if (sa1.ss_family != sa2.ss_family || sa1.ss_len != sa2.ss_len)
539                 return (false);
540
541         switch (sa1.ss_family) {
542         case AF_INET:
543             {
544                 struct sockaddr_in *sin1, *sin2;
545
546                 sin1 = (struct sockaddr_in *)&sa1;
547                 sin2 = (struct sockaddr_in *)&sa2;
548
549                 return (memcmp(&sin1->sin_addr, &sin2->sin_addr,
550                     sizeof(sin1->sin_addr)) == 0);
551             }
552         case AF_INET6:
553             {
554                 struct sockaddr_in6 *sin1, *sin2;
555
556                 sin1 = (struct sockaddr_in6 *)&sa1;
557                 sin2 = (struct sockaddr_in6 *)&sa2;
558
559                 return (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
560                     sizeof(sin1->sin6_addr)) == 0);
561             }
562         default:
563                 return (false);
564         }
565 }
566
567 static void
568 tcp_local_address(const void *ctx, char *addr, size_t size)
569 {
570         const struct tcp_ctx *tctx = ctx;
571         struct sockaddr_storage sa;
572         socklen_t salen;
573
574         PJDLOG_ASSERT(tctx != NULL);
575         PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
576
577         salen = sizeof(sa);
578         if (getsockname(tctx->tc_fd, (struct sockaddr *)&sa, &salen) == -1) {
579                 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
580                 return;
581         }
582         PJDLOG_VERIFY(snprintf(addr, size, "tcp://%S", &sa) < (ssize_t)size);
583 }
584
585 static void
586 tcp_remote_address(const void *ctx, char *addr, size_t size)
587 {
588         const struct tcp_ctx *tctx = ctx;
589         struct sockaddr_storage sa;
590         socklen_t salen;
591
592         PJDLOG_ASSERT(tctx != NULL);
593         PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
594
595         salen = sizeof(sa);
596         if (getpeername(tctx->tc_fd, (struct sockaddr *)&sa, &salen) == -1) {
597                 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
598                 return;
599         }
600         PJDLOG_VERIFY(snprintf(addr, size, "tcp://%S", &sa) < (ssize_t)size);
601 }
602
603 static void
604 tcp_close(void *ctx)
605 {
606         struct tcp_ctx *tctx = ctx;
607
608         PJDLOG_ASSERT(tctx != NULL);
609         PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
610
611         if (tctx->tc_fd >= 0)
612                 close(tctx->tc_fd);
613         tctx->tc_magic = 0;
614         free(tctx);
615 }
616
617 static struct proto tcp_proto = {
618         .prt_name = "tcp",
619         .prt_client = tcp_client,
620         .prt_connect = tcp_connect,
621         .prt_connect_wait = tcp_connect_wait,
622         .prt_server = tcp_server,
623         .prt_accept = tcp_accept,
624         .prt_wrap = tcp_wrap,
625         .prt_send = tcp_send,
626         .prt_recv = tcp_recv,
627         .prt_descriptor = tcp_descriptor,
628         .prt_address_match = tcp_address_match,
629         .prt_local_address = tcp_local_address,
630         .prt_remote_address = tcp_remote_address,
631         .prt_close = tcp_close
632 };
633
634 static __constructor void
635 tcp_ctor(void)
636 {
637
638         proto_register(&tcp_proto, true);
639 }