The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
fd_open.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: fb066f596fa48d1282bbc88589d861cd8856275c $
19 * @file lib/bio/fd_open.c
20 * @brief BIO abstractions for opening file descriptors
21 *
22 * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
23 */
24
25#include <freeradius-devel/bio/fd_priv.h>
26#include <freeradius-devel/util/file.h>
27#include <freeradius-devel/util/cap.h>
28
29#include <sys/stat.h>
30#include <net/if.h>
31#include <fcntl.h>
32#include <libgen.h>
33#include <netinet/tcp.h>
34#include <netinet/in.h>
35
36/** Initialize common datagram information
37 *
38 */
39static int fr_bio_fd_common_tcp(int fd, UNUSED fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
40{
41 int on = 1;
42
43#ifdef SO_KEEPALIVE
44 /*
45 * TCP keepalives are always a good idea. Too many people put firewalls between critical
46 * systems, and then the firewalls drop live TCP streams.
47 */
48 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) {
49 fr_strerror_printf("Failed setting SO_KEEPALIVE: %s", fr_syserror(errno));
50 return -1;
51 }
52#endif
53
54#ifdef TCP_NODELAY
55 /*
56 * Add some defines for *BSD, and Solaris systems.
57 */
58# if !defined(SOL_TCP) && defined(IPPROTO_TCP)
59# define SOL_TCP IPPROTO_TCP
60# endif
61
62 /*
63 * Also set TCP_NODELAY, to force the data to be written quickly.
64 *
65 * We buffer full packets in memory before we write them, so there's no reason for the kernel to
66 * sit around waiting for more data from us.
67 */
68 if (!cfg->tcp_delay) {
69 if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) {
70 fr_strerror_printf("Failed setting TCP_NODELAY: %s", fr_syserror(errno));
71 return -1;
72 }
73 }
74#endif
75
76 return 0;
77}
78
79
80/** Initialize common datagram information
81 *
82 */
83static int fr_bio_fd_common_datagram(int fd, UNUSED fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
84{
85 int on = 1;
86
87#ifdef SO_TIMESTAMPNS
88 /*
89 * Enable receive timestamps, these should reflect
90 * when the packet was received, not when it was read
91 * from the socket.
92 */
93 if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS, &on, sizeof(int)) < 0) {
94 fr_strerror_printf("Failed setting SO_TIMESTAMPNS: %s", fr_syserror(errno));
95 return -1;
96 }
97
98#elif defined(SO_TIMESTAMP)
99 /*
100 * Enable receive timestamps, these should reflect
101 * when the packet was received, not when it was read
102 * from the socket.
103 */
104 if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(int)) < 0) {
105 fr_strerror_printf("Failed setting SO_TIMESTAMP: %s", fr_syserror(errno));
106 return -1;
107 }
108#endif
109
110
111#ifdef SO_RCVBUF
112 if (cfg->recv_buff) {
113 int opt = cfg->recv_buff;
114
115 /*
116 * Clamp value to something reasonable.
117 */
118 if (opt > (1 << 29)) opt = (1 << 29);
119
120 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
121 fr_strerror_printf("Failed setting SO_RCVBUF: %s", fr_syserror(errno));
122 return -1;
123 }
124 }
125#endif
126
127#ifdef SO_SNDBUF
128 if (cfg->send_buff) {
129 int opt = cfg->send_buff;
130
131 /*
132 * Clamp value to something reasonable.
133 */
134 if (opt > (1 << 29)) opt = (1 << 29);
135
136 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
137 fr_strerror_printf("Failed setting SO_SNDBUF: %s", fr_syserror(errno));
138 return -1;
139 }
140 }
141#endif
142
143 return 0;
144}
145
146/** Initialize a UDP server socket.
147 *
148 */
149static int fr_bio_fd_server_udp(int fd, fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
150{
151#ifdef SO_REUSEPORT
152 int on = 1;
153
154 /*
155 * Set SO_REUSEPORT before bind, so that all sockets can
156 * listen on the same destination IP address.
157 */
158 if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) {
159 fr_strerror_printf("Failed setting SO_REUSEPORT: %s", fr_syserror(errno));
160 return -1;
161 }
162#endif
163
164 return fr_bio_fd_common_datagram(fd, sock, cfg);
165}
166
167/** Initialize a TCP server socket.
168 *
169 */
170static int fr_bio_fd_server_tcp(int fd, UNUSED fr_socket_t const *sock)
171{
172 int on = 1;
173
174 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
175 fr_strerror_printf("Failed setting SO_REUSEADDR: %s", fr_syserror(errno));
176 return -1;
177 }
178
179 return 0;
180}
181
182/** Initialize an IPv4 server socket.
183 *
184 */
185static int fr_bio_fd_server_ipv4(int fd, fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
186{
187 int flag;
188
189#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
190 /*
191 * Disable PMTU discovery. On Linux, this also makes sure that the "don't
192 * fragment" flag is zero.
193 */
194 flag = IP_PMTUDISC_DONT;
195
196 if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &flag, sizeof(flag)) < 0) {
197 fr_strerror_printf("Failed setting IP_MTU_DISCOVER: %s", fr_syserror(errno));
198 return -1;
199 }
200#endif
201
202#if defined(IP_DONTFRAG)
203 /*
204 * Ensure that the "don't fragment" flag is zero.
205 */
206 flag = 0;
207
208 if (setsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &flag, sizeof(flag)) < 0) {
209 fr_strerror_printf("Failed setting IP_DONTFRAG: %s", fr_syserror(errno));
210 return -1;
211 }
212#endif
213
214 /*
215 * And set up any UDP / TCP specific information.
216 */
217 if (sock->type == SOCK_DGRAM) return fr_bio_fd_server_udp(fd, sock, cfg);
218
219 return fr_bio_fd_server_tcp(fd, sock);
220}
221
222/** Initialize an IPv6 server socket.
223 *
224 */
225static int fr_bio_fd_server_ipv6(int fd, fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
226{
227#ifdef IPV6_V6ONLY
228 /*
229 * Don't allow v4 packets on v6 connections.
230 */
231 if (IN6_IS_ADDR_UNSPECIFIED(UNCONST(struct in6_addr *, &sock->inet.src_ipaddr.addr.v6))) {
232 int on = 1;
233
234 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) < 0) {
235 fr_strerror_printf("Failed setting IPV6_ONLY: %s", fr_syserror(errno));
236 return -1;
237 }
238 }
239#endif /* IPV6_V6ONLY */
240
241 /*
242 * And set up any UDP / TCP specific information.
243 */
244 if (sock->type == SOCK_DGRAM) return fr_bio_fd_server_udp(fd, sock, cfg);
245
246 return fr_bio_fd_server_tcp(fd, sock);
247}
248
249/** Verify or clean up a pre-existing domain socket.
250 *
251 */
252static int fr_bio_fd_socket_unix_verify(int dirfd, char const *filename, fr_bio_fd_config_t const *cfg)
253{
254 int fd;
255 struct stat buf;
256
257 /*
258 * See if the socket exits. If there's an error opening it, that's an issue.
259 *
260 * If it doesn't exist, that's fine.
261 */
262 if (fstatat(dirfd, filename, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
263 if (errno != ENOENT) {
264 fr_strerror_printf("Failed opening domain socket %s: %s", cfg->path, fr_syserror(errno));
265 return -1;
266 }
267
268 return 0;
269 }
270
271 /*
272 * If it exists, it must be a socket.
273 */
274 if (!S_ISSOCK(buf.st_mode)) {
275 fr_strerror_printf("Failed open domain socket %s: it is not a socket", filename);
276 return -1;
277 }
278
279 /*
280 * Refuse to open sockets not owned by us. This prevents configurations from stomping on each
281 * other.
282 */
283 if (buf.st_uid != cfg->uid) {
284 fr_strerror_printf("Failed opening domain socket %s: incorrect UID", cfg->path);
285 return -1;
286 }
287
288 /*
289 * The file exists,and someone is listening. We can't claim it for ourselves.
290 *
291 * Note that this function calls connect(), but connect() always returns immediately for domain
292 * sockets.
293 *
294 * @todo - redo that function here, with separate checks for permission errors vs anything else.
295 */
296 fd = fr_socket_client_unix(cfg->path, false);
297 if (fd >= 0) {
298 close(fd);
299 fr_strerror_printf("Failed creating domain socket %s: It is currently active", cfg->path);
300 return -1;
301 }
302
303 /*
304 * It exists, but no one is listening. Delete it so that we can re-bind to it.
305 */
306 if (unlinkat(dirfd, filename, 0) < 0) {
307 fr_strerror_printf("Failed removing pre-existing domain socket %s: %s",
308 cfg->path, fr_syserror(errno));
309 return -1;
310 }
311
312 return 0;
313}
314
315/*
316 * We normally can't call fchmod() or fchown() on sockets, as they don't really exist in the file system.
317 * Instead, we enforce those permissions on the parent directory of the socket.
318 */
319static int fr_bio_fd_socket_unix_mkdir(int *dirfd, char const **filename, fr_bio_fd_config_t const *cfg)
320{
321 mode_t perm;
322 int parent_fd, fd;
323 char const *path = cfg->path;
324 char *p, *dir = NULL;
325 char *slashes[2];
326
327 perm = S_IREAD | S_IWRITE | S_IEXEC;
328 perm |= S_IRGRP | S_IWGRP | S_IXGRP;
329
330 /*
331 * The parent directory exists. Ensure that it has the correct ownership and permissions.
332 *
333 * If the parent directory exists, then it enforces access, and we can create the domain socket
334 * within it.
335 */
336 if (fr_dirfd(dirfd, filename, path) == 0) {
337 struct stat buf;
338
339 if (fstat(*dirfd, &buf) < 0) {
340 fr_strerror_printf("Failed reading parent directory for file %s: %s", path, fr_syserror(errno));
341 fail:
342 talloc_free(dir);
343 close(*dirfd);
344 return -1;
345 }
346
347 if (buf.st_uid != cfg->uid) {
348 fr_strerror_printf("Failed reading parent directory for file %s: Incorrect UID", path);
349 goto fail;
350 }
351
352 if (buf.st_gid != cfg->gid) {
353 fr_strerror_printf("Failed reading parent directory for file %s: Incorrect GID", path);
354 goto fail;
355 }
356
357 /*
358 * We don't have the correct permissions on the directory, so we fix them.
359 *
360 * @todo - allow for "other" to read/write if we do authentication on the socket?
361 */
362 if (fchmod(*dirfd, perm) < 0) {
363 fr_strerror_printf("Failed setting parent directory permissions for file %s: %s", path, fr_syserror(errno));
364 goto fail;
365 }
366
367 return 0;
368 }
369
370 dir = talloc_strdup(NULL, path);
371 if (!dir) goto fail;
372
373 /*
374 * Find the last two directory separators.
375 */
376 slashes[0] = slashes[1] = NULL;
377 for (p = dir; *p != '\0'; p++) {
378 if (*p == '/') {
379 slashes[0] = slashes[1];
380 slashes[1] = p;
381 }
382 }
383
384 /*
385 * There's only one / in the path, we can't do anything.
386 *
387 * Opening 'foo/bar.sock' might be useful, but isn't normally a good idea.
388 */
389 if (!slashes[0]) {
390 fr_strerror_printf("Failed parsing filename %s: it is not absolute", path);
391 goto fail;
392 }
393
394 /*
395 * Ensure that the grandparent directory exists.
396 *
397 * /var/run/radiusd/foo.sock
398 *
399 * slashes[0] points to the slash after 'run'.
400 *
401 * slashes[1] points to the slash after 'radiusd', which doesn't exist.
402 */
403 *slashes[0] = '\0';
404
405 /*
406 * If the grandparent doesn't exist, then we don't create it.
407 *
408 * These checks minimize the possibility that a misconfiguration by user "radiusd" can cause a
409 * suid-root binary top create a directory in the wrong place. These checks are only necessary
410 * if the unix domain socket is opened as root.
411 */
412 parent_fd = open(dir, O_DIRECTORY | O_NOFOLLOW);
413 if (parent_fd < 0) {
414 fr_strerror_printf("Failed opening directory %s: %s", dir, fr_syserror(errno));
415 goto fail;
416 }
417
418 /*
419 * Create the parent directory.
420 */
421 *slashes[0] = '/';
422 *slashes[1] = '\0';
423 if (mkdirat(parent_fd, dir, 0700) < 0) {
424 fr_strerror_printf("Failed creating directory %s: %s", dir, fr_syserror(errno));
425 close_parent:
426 close(parent_fd);
427 goto fail;
428 }
429
430 fd = openat(parent_fd, dir, O_DIRECTORY);
431 if (fd < 0) {
432 fr_strerror_printf("Failed opening directory %s: %s", dir, fr_syserror(errno));
433 goto close_parent;
434 }
435
436 if (fchmod(fd, perm) < 0) {
437 fr_strerror_printf("Failed changing permission for directory %s: %s", dir, fr_syserror(errno));
438 close_fd:
439 close(fd);
440 goto close_parent;
441 }
442
443 /*
444 * This is a NOOP if we're chowning a file owned by ourselves to our own UID / GID.
445 *
446 * Otherwise if we're running as root, it will set ownership to the correct user.
447 */
448 if (fchown(fd, cfg->uid, cfg->gid) < 0) {
449 fr_strerror_printf("Failed changing ownershipt for directory %s: %s", dir, fr_syserror(errno));
450 goto close_fd;
451 }
452
453 talloc_free(dir);
454 close(fd);
455 close(parent_fd);
456
457 return 0;
458}
459
461{
462 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
463
464 /*
465 * The bio must be open in order to shut it down.
466 *
467 * Unix domain sockets are deleted when the bio is closed.
468 *
469 * Unix domain sockets are never in the "connecting" state, because connect() always returns
470 * immediately.
471 */
472 fr_assert(my->info.state == FR_BIO_FD_STATE_OPEN);
473
474 /*
475 * Run the user shutdown before we run ours.
476 */
477 if (my->user_shutdown) my->user_shutdown(bio);
478
479 (void) unlink(my->info.socket.unix.path);
480}
481
482/** Bind to a Unix domain socket.
483 *
484 * @todo - this function only does a tiny bit of what fr_server_domain_socket_peercred() and
485 * fr_server_domain_socket_perm() do. Those functions do a lot more sanity checks.
486 *
487 * The main question is whether or not those checks are useful. In many cases, fchmod() and fchown() are not
488 * possible on Unix sockets, so we shouldn't bother doing them,
489 *
490 * Note that the listeners generally call these functions with wrappers of fr_suid_up() and fr_suid_down().
491 * So these functions are running as "root", and will create files owned as "root".
492 */
494{
495 int dirfd, rcode;
496 char const *filename, *p;
497 socklen_t sunlen;
498 struct sockaddr_un sun;
499
500 if (!cfg->path) {
501 fr_strerror_const("Failed to specify path");
502 return -1;
503 }
504
505 /*
506 * The UID and GID should be taken automatically from the "user" and "group" settings in
507 * mainconfig. There is no reason to set them to anything else.
508 */
509 if (cfg->uid == (uid_t) -1) {
510 fr_strerror_printf("Failed opening domain socket %s: no UID specified", cfg->path);
511 return -1;
512 }
513
514 if (cfg->gid == (gid_t) -1) {
515 fr_strerror_printf("Failed opening domain socket %s: no GID specified", cfg->path);
516 return -1;
517 }
518
519 /*
520 * Opening 'foo.sock' is OK.
521 */
522 p = strrchr(cfg->path, '/');
523 if (!p) {
524 dirfd = AT_FDCWD;
525 filename = cfg->path;
526
527 } else if (p == cfg->path) {
528 /*
529 * Opening '/foo.sock' is dumb.
530 */
531 fr_strerror_printf("Failed opening domain socket %s: cannot exist at file system root", p);
532 return -1;
533
534 } else if (fr_bio_fd_socket_unix_mkdir(&dirfd, &filename, cfg) < 0) {
535 return -1;
536 }
537
538 /*
539 * Verify and/or clean up the domain socket.
540 */
541 if (fr_bio_fd_socket_unix_verify(dirfd, filename, cfg) < 0) {
542 fail:
543 if (dirfd != AT_FDCWD) close(dirfd);
544 return -1;
545 }
546
547#ifdef HAVE_BINDAT
548 /*
549 * The best function to use here is bindat(), but only quite recent versions of FreeBSD actually
550 * have it, and it's definitely not POSIX.
551 *
552 * If we use bindat(), we pass a relative pathname.
553 */
554 if (fr_filename_to_sockaddr(&sun, &sunlen, filename) < 0) goto fail;
555
556 rcode = bindat(dirfd, my->info.socket.fd, (struct sockaddr *) &sun, sunlen);
557#else
558 /*
559 * For bind(), we pass the full path.
560 */
561 if (fr_filename_to_sockaddr(&sun, &sunlen, cfg->path) < 0) goto fail;
562
563 rcode = bind(my->info.socket.fd, (struct sockaddr *) &sun, sunlen);
564#endif
565 if (rcode < 0) {
566 /*
567 * @todo - if EADDRINUSE, then the socket exists. Try connect(), and if that fails,
568 * delete the socket and try again. This may be simpler than the checks above.
569 */
570 fr_strerror_printf("Failed binding to domain socket %s: %s", cfg->path, fr_syserror(errno));
571 goto fail;
572 }
573
574#ifdef __linux__
575 /*
576 * Linux supports chown && chmod for sockets.
577 */
578 if (fchmod(my->info.socket.fd, S_IREAD | S_IWRITE | S_IEXEC | S_IRGRP | S_IWGRP | S_IXGRP) < 0) {
579 fr_strerror_printf("Failed changing permission for domain socket %s: %s", cfg->path, fr_syserror(errno));
580 goto fail;
581 }
582
583 /*
584 * This is a NOOP if we're chowning a file owned by ourselves to our own UID / GID.
585 *
586 * Otherwise if we're running as root, it will set ownership to the correct user.
587 */
588 if (fchown(my->info.socket.fd, cfg->uid, cfg->gid) < 0) {
589 fr_strerror_printf("Failed changing ownershipt for domain directory %s: %s", cfg->path, fr_syserror(errno));
590 goto fail;
591 }
592
593#endif
594
595 /*
596 * Socket is open. We need to clean it up on shutdown.
597 */
598 if (my->cb.shutdown) my->user_shutdown = my->cb.shutdown;
599 my->cb.shutdown = fr_bio_fd_unix_shutdown;
600
601 return 0;
602}
603
604/*
605 * Use the OSX native versions on OSX.
606 */
607#ifdef __APPLE__
608#undef SO_BINDTODEVICE
609#endif
610
611#ifdef SO_BINDTODEVICE
612/** Linux bind to device by name.
613 *
614 */
616{
617 /*
618 * ifindex isn't set, do nothing.
619 */
620 if (!my->info.socket.inet.ifindex) return 0;
621
622 if (!cfg->interface) return 0;
623
624 /*
625 * The internet hints that CAP_NET_RAW is required to use SO_BINDTODEVICE.
626 *
627 * This function also sets fr_strerror() on failure, which will be seen if the bind fails. If
628 * the bind succeeds, then we don't really care that the capability change has failed. We must
629 * already have that capability.
630 */
631#ifdef HAVE_CAPABILITY_H
632 (void)fr_cap_enable(CAP_NET_RAW, CAP_EFFECTIVE);
633#endif
634
635 if (setsockopt(my->info.socket.fd, SOL_SOCKET, SO_BINDTODEVICE, cfg->interface, strlen(cfg->interface)) < 0) {
636 fr_strerror_printf("Failed setting SO_BINDTODEVICE for %s: %s", cfg->interface, fr_syserror(errno));
637 return -1;
638 }
639
640 return 0;
641}
642
643#elif defined(IP_BOUND_IF) || defined(IPV6_BOUND_IF)
644/** OSX bind to interface by index.
645 *
646 */
648{
649 int opt, rcode;
650
651 if (!my->info.socket.inet.ifindex) return 0;
652
653 opt = my->info.socket.inet.ifindex;
654
655 switch (my->info.socket.af) {
656 case AF_LOCAL:
657 rcode = setsockopt(my->info.socket.fd, IPPROTO_IP, IP_BOUND_IF, &opt, sizeof(opt));
658 break;
659
660 case AF_INET6:
661 rcode = setsockopt(my->info.socket.fd, IPPROTO_IPV6, IPV6_BOUND_IF, &opt, sizeof(opt));
662 break;
663
664 default:
665 rcode = -1;
666 errno = EAFNOSUPPORT;
667 break;
668 }
669
670 fr_strerror_printf("Failed setting IP_BOUND_IF: %s", fr_syserror(errno));
671 return rcode;
672}
673#else
674
675/** This system is missing SO_BINDTODEVICE, IP_BOUND_IF, IPV6_BOUND_IF
676 *
677 * @todo - FreeBSD IP_RECVIF and IP_SENDIF
678 *
679 * Except that has to be done in recvmsg() and sendmsg(). And it only works on datagram sockets.
680 *
681 * cmsg_len = sizeof(struct sockaddr_dl)
682 * cmsg_level = IPPROTO_IP
683 * cmsg_type = IP_RECVIF
684 */
686{
687 if (!my->info.socket.inet.ifindex) return 0;
688
689 fr_strerror_const("Bind to interface is not supported on this platform");
690 return -1;
691}
692
693/* bind to device */
694#endif
695
697{
698 socklen_t salen;
699 struct sockaddr_storage salocal;
700
701 fr_assert((my->info.socket.af == AF_INET) || (my->info.socket.af == AF_INET6));
702
703#ifdef HAVE_CAPABILITY_H
704 /*
705 * If we're binding to a special port as non-root, then
706 * check capabilities. If we're root, we already have
707 * equivalent capabilities so we don't need to check.
708 */
709 if ((my->info.socket.inet.src_port < 1024) && (geteuid() != 0)) {
710 (void)fr_cap_enable(CAP_NET_BIND_SERVICE, CAP_EFFECTIVE);
711 }
712#endif
713
714 if (fr_bio_fd_socket_bind_to_device(my, cfg) < 0) return -1;
715
716 /*
717 * Bind to the IP + interface.
718 */
719 if (fr_ipaddr_to_sockaddr(&salocal, &salen, &my->info.socket.inet.src_ipaddr, my->info.socket.inet.src_port) < 0) return -1;
720
721 if (bind(my->info.socket.fd, (struct sockaddr *) &salocal, salen) < 0) {
722 fr_strerror_printf("Failed binding to socket: %s", fr_syserror(errno));
723 return -1;
724 }
725
726 /*
727 * The source IP may have changed, so get the new one.
728 */
730}
731
733{
734 fr_bio_fd_config_t const *cfg = my->info.cfg;
735
736 switch (my->info.type) {
738 return;
739
741 fr_assert(cfg->socket_type == SOCK_DGRAM);
742
743 switch (my->info.socket.af) {
744 case AF_INET:
745 case AF_INET6:
746 my->info.name = fr_asprintf(my, "proto udp local %pV port %u",
747 fr_box_ipaddr(my->info.socket.inet.src_ipaddr),
748 my->info.socket.inet.src_port);
749 break;
750
751 case AF_LOCAL:
752 my->info.name = fr_asprintf(my, "proto unix (datagram) filename %s",
753 cfg->path);
754 break;
755
756 default:
757 fr_assert(0);
758 my->info.name = "??? invalid BIO ???";
759 break;
760 }
761 break;
762
765 switch (my->info.socket.af) {
766 case AF_INET:
767 case AF_INET6:
768 my->info.name = fr_asprintf(my, "proto %s local %pV port %u remote %pV port %u",
769 (cfg->socket_type == SOCK_DGRAM) ? "udp" : "tcp",
770 fr_box_ipaddr(my->info.socket.inet.src_ipaddr),
771 my->info.socket.inet.src_port,
772 fr_box_ipaddr(my->info.socket.inet.dst_ipaddr),
773 my->info.socket.inet.dst_port);
774 break;
775
776 case AF_LOCAL:
777 my->info.name = fr_asprintf(my, "proto unix %sfilename %s",
778 (cfg->socket_type == SOCK_DGRAM) ? "(datagram) " : "",
779 cfg->path);
780 break;
781
782 case AF_FILE_BIO:
783 fr_assert(cfg->socket_type == SOCK_STREAM);
784
785 if (cfg->flags == O_RDONLY) {
786 my->info.name = fr_asprintf(my, "proto file (read-only) filename %s ",
787 cfg->filename);
788
789 } else if (cfg->flags == O_WRONLY) {
790 my->info.name = fr_asprintf(my, "proto file (write-only) filename %s",
791 cfg->filename);
792 } else {
793 my->info.name = fr_asprintf(my, "proto file (read-write) filename %s",
794 cfg->filename);
795 }
796 break;
797
798 default:
799 fr_assert(0);
800 my->info.name = "??? invalid BIO ???";
801 break;
802 }
803 break;
804
805 case FR_BIO_FD_LISTEN:
806 fr_assert(cfg->socket_type == SOCK_STREAM);
807
808 switch (my->info.socket.af) {
809 case AF_INET:
810 case AF_INET6:
811 my->info.name = fr_asprintf(my, "proto %s local %pV port %u",
812 (cfg->socket_type == SOCK_DGRAM) ? "udp" : "tcp",
813 fr_box_ipaddr(my->info.socket.inet.src_ipaddr),
814 my->info.socket.inet.src_port);
815 break;
816
817 case AF_LOCAL:
818 my->info.name = fr_asprintf(my, "proto unix filename %s",
819 cfg->path);
820 break;
821
822 default:
823 fr_assert(0);
824 my->info.name = "??? invalid BIO ???";
825 break;
826 }
827 break;
828 }
829}
830
831/** Checks the configuration without modifying anything.
832 *
833 */
835{
836 /*
837 * Unix sockets and files are OK.
838 */
839 if (cfg->path || cfg->filename) return 0;
840
841 /*
842 * Sanitize the IP addresses.
843 *
844 */
845 switch (cfg->type) {
847 fr_strerror_const("No connection type was specified");
848 return -1;
849
851 /*
852 * Ensure that we have a destination address.
853 */
854 if (cfg->dst_ipaddr.af == AF_UNSPEC) {
855 fr_strerror_const("No destination IP address was specified");
856 return -1;
857 }
858
859 if (!cfg->dst_port) {
860 fr_strerror_const("No destination port was specified");
861 return -1;
862 }
863
864 /*
865 * The source IP has to be the same address family as the destination IP.
866 */
867 if ((cfg->src_ipaddr.af != AF_UNSPEC) && (cfg->src_ipaddr.af != cfg->dst_ipaddr.af)) {
868 fr_strerror_printf("Source and destination IP addresses are not from the same IP address family");
869 return -1;
870 }
871 break;
872
873 case FR_BIO_FD_LISTEN:
874 if (!cfg->src_port) {
875 fr_strerror_const("No source port was specified");
876 return -1;
877 }
879
880 /*
881 * Unconnected sockets can use a source port, but don't need one.
882 */
884 if (cfg->path && cfg->filename) {
885 fr_strerror_const("Unconnected sockets cannot be used with Unix sockets or files");
886 return -1;
887 }
888
889 if (cfg->src_ipaddr.af == AF_UNSPEC) {
890 fr_strerror_const("No source IP address was specified");
891 return -1;
892 }
893 break;
894
896 fr_assert(cfg->src_ipaddr.af != AF_UNSPEC);
897 fr_assert(cfg->dst_ipaddr.af != AF_UNSPEC);
898 break;
899 }
900
901 return 0;
902}
903
904/** Opens a socket and updates sock->fd
905 *
906 * If the socket is asynchronous, it also calls connect()
907 */
909{
910 int fd;
911 int rcode;
912 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
913
915
916 my->info = (fr_bio_fd_info_t) {
917 .socket = {
918 .type = cfg->socket_type,
919 },
920 .cfg = cfg,
921 };
922
923 if (!cfg->path && !cfg->filename) {
924 int protocol;
925
926 my->info.socket.af = cfg->src_ipaddr.af;
927 my->info.socket.inet.src_ipaddr = cfg->src_ipaddr;
928 my->info.socket.inet.dst_ipaddr = cfg->dst_ipaddr;
929 my->info.socket.inet.src_port = cfg->src_port;
930 my->info.socket.inet.dst_port = cfg->dst_port;
931
932 if (fr_bio_fd_check_config(cfg) < 0) return -1;
933
934 /*
935 * Sanitize the IP addresses.
936 *
937 */
938 switch (cfg->type) {
940 return -1;
941
943 /*
944 * No source specified, just bootstrap it from the destination.
945 */
946 if (my->info.socket.inet.src_ipaddr.af == AF_UNSPEC) {
947 my->info.socket.inet.src_ipaddr = (fr_ipaddr_t) {
948 .af = my->info.socket.inet.dst_ipaddr.af,
949 .prefix = (my->info.socket.inet.dst_ipaddr.af == AF_INET) ? 32 : 128,
950 };
951
952 /*
953 * Set the main socket AF too.
954 */
955 my->info.socket.af = my->info.socket.inet.dst_ipaddr.af;
956 }
957
958 /*
959 * The source IP has to be the same address family as the destination IP.
960 */
961 if (my->info.socket.inet.src_ipaddr.af != my->info.socket.inet.dst_ipaddr.af) {
962 fr_strerror_const("Source and destination IP addresses are not from the same IP address family");
963 return -1;
964 }
965 break;
966
968 case FR_BIO_FD_LISTEN:
969 fr_assert(my->info.socket.inet.src_ipaddr.af != AF_UNSPEC);
970 break;
971
973 fr_assert(my->info.socket.inet.src_ipaddr.af != AF_UNSPEC);
974 fr_assert(my->info.socket.inet.dst_ipaddr.af != AF_UNSPEC);
975 break;
976 }
977
978 if (cfg->socket_type == SOCK_STREAM) {
979 protocol = IPPROTO_TCP;
980 } else {
981 protocol = IPPROTO_UDP;
982 }
983
984 if (cfg->interface) {
985 my->info.socket.inet.ifindex = if_nametoindex(cfg->interface);
986
987 if (!my->info.socket.inet.ifindex) {
988 fr_strerror_printf_push("Failed finding interface %s: %s", cfg->interface, fr_syserror(errno));
989 return -1;
990 }
991 }
992
993 /*
994 * It's already opened, so we don't need to do that.
995 */
996 if (cfg->type == FR_BIO_FD_ACCEPTED) {
997 fd = my->info.socket.fd;
998 fr_assert(fd >= 0);
999
1000 } else {
1001 fd = socket(my->info.socket.af, my->info.socket.type, protocol);
1002 if (fd < 0) {
1003 fr_strerror_printf("Failed opening socket: %s", fr_syserror(errno));
1004 return -1;
1005 }
1006 }
1007
1008 } else if (cfg->path) {
1009 my->info.socket.af = AF_LOCAL;
1010 my->info.socket.type = SOCK_STREAM;
1011 my->info.socket.unix.path = cfg->path;
1012
1013 fd = socket(my->info.socket.af, my->info.socket.type, 0);
1014 if (fd < 0) {
1015 fr_strerror_printf("Failed opening domain socket %s: %s", cfg->path, fr_syserror(errno));
1016 return -1;
1017 }
1018
1019 } else {
1020 if (cfg->type != FR_BIO_FD_CONNECTED) {
1021 fr_strerror_printf("Can only use connected sockets for file IO");
1022 return -1;
1023 }
1024
1025 /*
1026 * Filenames overload the #fr_socket_t for now.
1027 */
1028 my->info.socket.af = AF_FILE_BIO;
1029 my->info.socket.type = SOCK_STREAM;
1030 my->info.socket.unix.path = cfg->filename;
1031
1032 /*
1033 * Allow hacks for stdout and stderr
1034 */
1035 if (strcmp(cfg->filename, "/dev/stdout") == 0) {
1036 if (cfg->flags != O_WRONLY) {
1037 fail_dev:
1038 fr_strerror_printf("Cannot read from %s", cfg->filename);
1039 return -1;
1040 }
1041
1042 fd = dup(STDOUT_FILENO);
1043
1044 } else if (strcmp(cfg->filename, "/dev/stderr") == 0) {
1045 if (cfg->flags != O_WRONLY) goto fail_dev;
1046
1047 fd = dup(STDERR_FILENO);
1048
1049 } else if (strcmp(cfg->filename, "/dev/stdin") == 0) {
1050 if (cfg->flags != O_RDONLY) {
1051 fr_strerror_printf("Cannot write to %s", cfg->filename);
1052 return -1;
1053 }
1054
1055 fd = dup(STDIN_FILENO);
1056
1057 } else {
1058 /*
1059 * Minor hacks so that we have only _one_ source of open / mkdir
1060 */
1061 my->info.socket.fd = -1;
1062
1063 fd = fr_bio_fd_reopen(bio);
1064 }
1065 if (fd < 0) {
1066 fr_strerror_printf("Failed opening file %s: %s", cfg->filename, fr_syserror(errno));
1067 return -1;
1068 }
1069 }
1070
1071 /*
1072 * Set it to be non-blocking if required.
1073 */
1074 if (cfg->async && (fr_nonblock(fd) < 0)) {
1075 fr_strerror_printf("Failed opening setting O_NONBLOCK: %s", fr_syserror(errno));
1076
1077 fail:
1078 my->info.socket = (fr_socket_t) {
1079 .fd = -1,
1080 };
1081 my->info.state = FR_BIO_FD_STATE_CLOSED;
1082 my->info.cfg = NULL;
1083 close(fd);
1084 return -1;
1085 }
1086
1087#ifdef FD_CLOEXEC
1088 /*
1089 * We don't want child processes inheriting these file descriptors.
1090 */
1091 rcode = fcntl(fd, F_GETFD);
1092 if (rcode >= 0) {
1093 if (fcntl(fd, F_SETFD, rcode | FD_CLOEXEC) < 0) {
1094 fr_strerror_printf("Failed opening setting FD_CLOEXE: %s", fr_syserror(errno));
1095 goto fail;
1096 }
1097 }
1098#endif
1099
1100 /*
1101 * Initialize the bio information before calling the various setup functions.
1102 */
1103 my->info.state = FR_BIO_FD_STATE_CONNECTING;
1104
1105 /*
1106 * Set the FD so that the subsequent calls can use it.
1107 */
1108 my->info.socket.fd = fd;
1109
1110 /*
1111 * Set the type, too.
1112 */
1113 my->info.type = cfg->type;
1114
1115 /*
1116 * Do sanity checks, bootstrap common socket options, bind to the socket, and initialize the read
1117 * / write functions.
1118 */
1119 switch (cfg->type) {
1120 case FR_BIO_FD_INVALID:
1121 return -1;
1122
1123 /*
1124 * Unconnected UDP or datagram AF_LOCAL server sockets.
1125 */
1127 if (my->info.socket.type != SOCK_DGRAM) {
1128 fr_strerror_const("Failed configuring socket: unconnected sockets must be UDP");
1129 return -1;
1130 }
1131
1132 switch (my->info.socket.af) {
1133 case AF_LOCAL:
1134 if (fr_bio_fd_common_datagram(fd, &my->info.socket, cfg) < 0) goto fail;
1135 break;
1136
1137 case AF_FILE_BIO:
1138 fr_strerror_const("Filenames must use the connected API");
1139 goto fail;
1140
1141 case AF_INET:
1142 case AF_INET6:
1143 /* sets SO_REUSEPORT, too */
1144 if (fr_bio_fd_server_udp(fd, &my->info.socket, cfg) < 0) goto fail;
1145 break;
1146
1147 default:
1148 fr_strerror_const("Unsupported address family for unconnected sockets");
1149 goto fail;
1150 }
1151
1152 if (fr_bio_fd_socket_bind(my, cfg) < 0) goto fail;
1153
1154 if (fr_bio_fd_init_common(my) < 0) goto fail;
1155 break;
1156
1157 /*
1158 * A connected client: UDP, TCP, AF_LOCAL, or AF_FILE_BIO
1159 */
1161 if (my->info.socket.type == SOCK_DGRAM) {
1162 rcode = fr_bio_fd_common_datagram(fd, &my->info.socket, cfg); /* we don't use SO_REUSEPORT for clients */
1163 if (rcode < 0) goto fail;
1164
1165 } else if ((my->info.socket.af == AF_INET) || (my->info.socket.af == AF_INET6)) {
1166 rcode = fr_bio_fd_common_tcp(fd, &my->info.socket, cfg);
1167 if (rcode < 0) goto fail;
1168 }
1169
1170 switch (my->info.socket.af) {
1171 case AF_LOCAL:
1172 if (fr_bio_fd_socket_bind_unix(my, cfg) < 0) goto fail;
1173 break;
1174
1175 case AF_FILE_BIO:
1176 break;
1177
1178 case AF_INET:
1179 case AF_INET6:
1180 if (fr_bio_fd_socket_bind(my, cfg) < 0) goto fail;
1181 break;
1182
1183 default:
1184 return -1;
1185 }
1186
1187 if (fr_bio_fd_init_connected(my) < 0) goto fail;
1188 break;
1189
1190 case FR_BIO_FD_ACCEPTED:
1191#ifdef SO_NOSIGPIPE
1192 /*
1193 * Although the server ignore SIGPIPE, some operating systems like BSD and OSX ignore the
1194 * ignoring.
1195 *
1196 * Fortunately, those operating systems usually support SO_NOSIGPIPE. We set that to prevent
1197 * them raising the signal in the first place.
1198 */
1199 {
1200 int on = 1;
1201
1202 setsockopt(my->info.socket.fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
1203 }
1204#endif
1205
1206 my->info.type = FR_BIO_FD_CONNECTED;
1207
1208 if (fr_bio_fd_init_common(my) < 0) goto fail;
1209 break;
1210
1211 /*
1212 * Server socket which listens for new stream connections
1213 */
1214 case FR_BIO_FD_LISTEN:
1215 fr_assert(my->info.socket.type == SOCK_STREAM);
1216
1217 switch (my->info.socket.af) {
1218 case AF_INET:
1219 if (fr_bio_fd_server_ipv4(fd, &my->info.socket, cfg) < 0) goto fail;
1220
1221 if (fr_bio_fd_socket_bind(my, cfg) < 0) goto fail;
1222 break;
1223
1224 case AF_INET6:
1225 if (fr_bio_fd_server_ipv6(fd, &my->info.socket, cfg) < 0) goto fail;
1226
1227 if (fr_bio_fd_socket_bind(my, cfg) < 0) goto fail;
1228 break;
1229
1230 case AF_LOCAL:
1231 if (fr_bio_fd_socket_bind_unix(my, cfg) < 0) goto fail;
1232 break;
1233
1234 default:
1235 fr_strerror_const("Unsupported address family for accept() socket");
1236 goto fail;
1237 }
1238
1239 if (fr_bio_fd_init_listen(my) < 0) goto fail;
1240 break;
1241 }
1242
1243 /*
1244 * Set the name of the BIO.
1245 */
1247
1248 return 0;
1249}
1250
1251/** Reopen a file BIO
1252 *
1253 * e.g. for log files.
1254 */
1256{
1257 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1258 fr_bio_fd_config_t const *cfg = my->info.cfg;
1259 int fd, flags;
1260
1261 if (my->info.socket.af != AF_FILE_BIO) {
1262 fr_strerror_const("Cannot reopen a non-file BIO");
1263 return -1;
1264 }
1265
1266 /*
1267 * Create it if necessary.
1268 */
1269 flags = cfg->flags;
1270 if (flags != O_RDONLY) flags |= O_CREAT;
1271
1272 if (!cfg->mkdir) {
1273 /*
1274 * Client BIOs writing to a file, and therefore need to create it.
1275 */
1276 do_open:
1277 fd = open(cfg->filename, flags, cfg->perm);
1278 if (fd < 0) {
1279 failed_open:
1280 fr_strerror_printf("Failed opening file %s: %s", cfg->filename, fr_syserror(errno));
1281 return -1;
1282 }
1283
1284 } else {
1285 /*
1286 * We make the parent directory if told to, AND if there's a '/' in the path.
1287 */
1288 char *p = strrchr(cfg->filename, '/');
1289 int dir_fd;
1290
1291 if (!p) goto do_open;
1292
1293 if (fr_mkdir(&dir_fd, cfg->filename, (size_t) (p - cfg->filename), cfg->perm, fr_mkdir_chown,
1294 &(fr_mkdir_chown_t) {
1295 .uid = cfg->uid,
1296 .gid = cfg->gid,
1297 }) < 0) {
1298 return -1;
1299 }
1300
1301 fd = openat(dir_fd, p + 1, flags, cfg->perm);
1302 if (fd < 0) {
1303 close(dir_fd);
1304 goto failed_open;
1305 }
1306 }
1307
1308 /*
1309 * We're boot-strapping, just set the new FD and return.
1310 */
1311 if (my->info.socket.fd < 0) {
1312 return fd;
1313 }
1314
1315 /*
1316 * Replace the FD rather than swapping it out with a new one. This is potentially more
1317 * thread-safe.
1318 */
1319 if (dup2(fd, my->info.socket.fd) < 0) {
1320 close(fd);
1321 fr_strerror_printf("Failed reopening file - %s", fr_syserror(errno));
1322 return -1;
1323 }
1324
1325 close(fd);
1326 return my->info.socket.fd;
1327}
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:322
#define UNUSED
Definition build.h:315
int fr_bio_fd_socket_name(fr_bio_fd_t *my)
Definition fd.c:633
int fr_bio_fd_init_connected(fr_bio_fd_t *my)
Definition fd.c:789
int fr_filename_to_sockaddr(struct sockaddr_un *sun, socklen_t *sunlen, char const *filename)
Definition fd.c:615
int fr_bio_fd_init_listen(fr_bio_fd_t *my)
Definition fd.c:970
int fr_bio_fd_init_common(fr_bio_fd_t *my)
Definition fd.c:852
uint16_t src_port
our port
Definition fd.h:91
@ FR_BIO_FD_ACCEPTED
temporarily until it's connected.
Definition fd.h:71
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
Definition fd.h:68
@ FR_BIO_FD_INVALID
not set
Definition fd.h:64
@ FR_BIO_FD_UNCONNECTED
unconnected UDP / datagram only
Definition fd.h:65
@ FR_BIO_FD_LISTEN
returns new fd in buffer on fr_bio_read() or fr_bio_fd_accept()
Definition fd.h:69
uint32_t recv_buff
How big the kernel's receive buffer should be.
Definition fd.h:96
bool mkdir
make intermediate directories
Definition fd.h:103
@ FR_BIO_FD_STATE_CLOSED
Definition fd.h:58
@ FR_BIO_FD_STATE_CONNECTING
Definition fd.h:60
@ FR_BIO_FD_STATE_OPEN
error states must be before this
Definition fd.h:59
fr_ipaddr_t dst_ipaddr
their IP address
Definition fd.h:89
fr_bio_fd_type_t type
accept, connected, unconnected, etc.
Definition fd.h:82
char const * path
for Unix domain sockets
Definition fd.h:99
uint32_t send_buff
How big the kernel's send buffer should be.
Definition fd.h:97
char const * filename
for files
Definition fd.h:105
uid_t uid
who owns the socket
Definition fd.h:101
gid_t gid
who owns the socket
Definition fd.h:102
char const * interface
for binding to an interface
Definition fd.h:94
mode_t perm
permissions for domain sockets
Definition fd.h:100
#define AF_FILE_BIO
Definition fd.h:40
int socket_type
SOCK_STREAM or SOCK_DGRAM.
Definition fd.h:84
uint16_t dst_port
their port
Definition fd.h:92
bool tcp_delay
We do tcp_nodelay by default.
Definition fd.h:109
bool async
is it async
Definition fd.h:108
int flags
O_RDONLY, etc.
Definition fd.h:106
fr_ipaddr_t src_ipaddr
our IP address
Definition fd.h:88
Configuration for sockets.
Definition fd.h:81
Run-time status of the socket.
Definition fd.h:124
fr_bio_shutdown & my
Definition fd_errno.h:59
static int fr_bio_fd_socket_unix_mkdir(int *dirfd, char const **filename, fr_bio_fd_config_t const *cfg)
Definition fd_open.c:319
static void fr_bio_fd_name(fr_bio_fd_t *my)
Definition fd_open.c:732
static int fr_bio_fd_socket_unix_verify(int dirfd, char const *filename, fr_bio_fd_config_t const *cfg)
Verify or clean up a pre-existing domain socket.
Definition fd_open.c:252
static void fr_bio_fd_unix_shutdown(fr_bio_t *bio)
Definition fd_open.c:460
static int fr_bio_fd_server_ipv6(int fd, fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
Initialize an IPv6 server socket.
Definition fd_open.c:225
int fr_bio_fd_reopen(fr_bio_t *bio)
Reopen a file BIO.
Definition fd_open.c:1255
static int fr_bio_fd_server_tcp(int fd, UNUSED fr_socket_t const *sock)
Initialize a TCP server socket.
Definition fd_open.c:170
static int fr_bio_fd_socket_bind_unix(fr_bio_fd_t *my, fr_bio_fd_config_t const *cfg)
Bind to a Unix domain socket.
Definition fd_open.c:493
static int fr_bio_fd_socket_bind(fr_bio_fd_t *my, fr_bio_fd_config_t const *cfg)
Definition fd_open.c:696
static int fr_bio_fd_server_ipv4(int fd, fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
Initialize an IPv4 server socket.
Definition fd_open.c:185
static int fr_bio_fd_common_tcp(int fd, UNUSED fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
Initialize common datagram information.
Definition fd_open.c:39
static int fr_bio_fd_socket_bind_to_device(fr_bio_fd_t *my, fr_bio_fd_config_t const *cfg)
This system is missing SO_BINDTODEVICE, IP_BOUND_IF, IPV6_BOUND_IF.
Definition fd_open.c:685
int fr_bio_fd_open(fr_bio_t *bio, fr_bio_fd_config_t const *cfg)
Opens a socket and updates sock->fd.
Definition fd_open.c:908
int fr_bio_fd_check_config(fr_bio_fd_config_t const *cfg)
Checks the configuration without modifying anything.
Definition fd_open.c:834
static int fr_bio_fd_server_udp(int fd, fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
Initialize a UDP server socket.
Definition fd_open.c:149
static int fr_bio_fd_common_datagram(int fd, UNUSED fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
Initialize common datagram information.
Definition fd_open.c:83
Our FD bio structure.
Definition fd_priv.h:35
ssize_t fr_mkdir(int *fd_out, char const *path, ssize_t len, mode_t mode, fr_mkdir_func_t func, void *uctx)
Create directories that are missing in the specified path.
Definition file.c:219
int fr_mkdir_chown(int fd, char const *path, void *uctx)
Callback for the common case of chown() of the directory.
Definition file.c:39
int fr_dirfd(int *dirfd, char const **filename, char const *pathname)
From a pathname, return fd and filename needed for *at() functions.
Definition file.c:412
int fr_ipaddr_to_sockaddr(struct sockaddr_storage *sa, socklen_t *salen, fr_ipaddr_t const *ipaddr, uint16_t port)
Convert our internal ip address representation to a sockaddr.
Definition inet.c:1392
int af
Address family.
Definition inet.h:64
IPv4/6 prefix.
talloc_free(reap)
unsigned int mode_t
int fr_nonblock(UNUSED int fd)
Definition misc.c:293
char * fr_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Special version of asprintf which implements custom format specifiers.
Definition print.c:874
#define fr_assert(_expr)
Definition rad_assert.h:38
#define FD_CLOEXEC
int fr_socket_client_unix(UNUSED char const *path, UNUSED bool async)
Definition socket.c:564
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
close(uq->fd)
int type
SOCK_STREAM, SOCK_DGRAM, etc.
Definition socket.h:79
Holds information necessary for binding or connecting to a socket.
Definition socket.h:63
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:577
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition strerror.h:84
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_box_ipaddr(_val)
Definition value.h:294