The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
fd_open.c
Go to the documentation of this file.
1/*
2 * This program 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: ede00faf88e2d8920694d92c71d6aa201cb98654 $
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#include <freeradius-devel/util/rand.h>
29
30#include <sys/stat.h>
31#include <net/if.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 socket.
147 *
148 */
149static int fr_bio_fd_common_udp(int fd, fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
150{
151#ifdef SO_REUSEPORT
152 /*
153 * Servers re-use ports by default. And clients, too, if they ask nicely.
154 */
155 if (cfg->reuse_port) {
156 int on = 1;
157
158 /*
159 * Set SO_REUSEPORT before bind, so that all sockets can
160 * listen on the same destination IP address.
161 */
162 if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) {
163 fr_strerror_printf("Failed setting SO_REUSEPORT: %s", fr_syserror(errno));
164 return -1;
165 }
166 }
167#endif
168
169 /*
170 * IPv4 fragments packets. IPv6 does not.
171 *
172 * Many systems set the "don't fragment" bit by default for IPv4. This setting means that "too
173 * large" packets are silently discarded in the network.
174 *
175 * Many local networks support UDP fragmentation, so we just send packets and hope for the best.
176 * In order to support local networks, we disable the "don't fragment" bit.
177 *
178 * The wider Internet does not support UDP fragmentation. This means that fragmented packets are
179 * silently discarded.
180 *
181 * @todo - add more code to properly handle EMSGSIZE for PMTUD. We can then also do
182 * getsockopt(fd,IP_MTU,&integer) to get the current path MTU. It can only be used after the
183 * socket has been connected. It should also be called after an EMSGSIZE error is returned.
184 *
185 * getsockopt(fd,IP_MTU,&integer) can also be used for unconnected sockets, if we also set
186 * IP_RECVERR. In which case the errors are put into an error queue. This is only for Linux.
187 */
188 if ((sock->af == AF_INET) && cfg->exceed_mtu) {
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 {
195 int flag = IP_PMTUDISC_DONT;
196
197 if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &flag, sizeof(flag)) < 0) {
198 fr_strerror_printf("Failed setting IP_MTU_DISCOVER: %s", fr_syserror(errno));
199 return -1;
200 }
201 }
202#endif
203
204#if defined(IP_DONTFRAG)
205 /*
206 * Ensure that the "don't fragment" flag is zero.
207 */
208 {
209 int off = 0;
210
211 if (setsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &off, sizeof(off)) < 0) {
212 fr_strerror_printf("Failed setting IP_DONTFRAG: %s", fr_syserror(errno));
213 return -1;
214 }
215 }
216#endif
217 }
218
219 return fr_bio_fd_common_datagram(fd, sock, cfg);
220}
221
222/** Initialize a TCP server socket.
223 *
224 */
225static int fr_bio_fd_server_tcp(int fd, UNUSED fr_socket_t const *sock)
226{
227 int on = 1;
228
229 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
230 fr_strerror_printf("Failed setting SO_REUSEADDR: %s", fr_syserror(errno));
231 return -1;
232 }
233
234 return 0;
235}
236
237/** Initialize an IPv4 server socket.
238 *
239 */
240static int fr_bio_fd_server_ipv4(int fd, fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
241{
242 /*
243 * And set up any UDP / TCP specific information.
244 */
245 if (sock->type == SOCK_DGRAM) return fr_bio_fd_common_udp(fd, sock, cfg);
246
247 return fr_bio_fd_server_tcp(fd, sock);
248}
249
250/** Initialize an IPv6 server socket.
251 *
252 */
253static int fr_bio_fd_server_ipv6(int fd, fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
254{
255#ifdef IPV6_V6ONLY
256 /*
257 * Don't allow v4 packets on v6 connections.
258 */
259 if (IN6_IS_ADDR_UNSPECIFIED(UNCONST(struct in6_addr *, &sock->inet.src_ipaddr.addr.v6))) {
260 int on = 1;
261
262 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) < 0) {
263 fr_strerror_printf("Failed setting IPV6_ONLY: %s", fr_syserror(errno));
264 return -1;
265 }
266 }
267#endif /* IPV6_V6ONLY */
268
269 /*
270 * And set up any UDP / TCP specific information.
271 */
272 if (sock->type == SOCK_DGRAM) return fr_bio_fd_common_udp(fd, sock, cfg);
273
274 return fr_bio_fd_server_tcp(fd, sock);
275}
276
277/** Verify or clean up a pre-existing domain socket.
278 *
279 */
280static int fr_bio_fd_socket_unix_verify(int dirfd, char const *filename, fr_bio_fd_config_t const *cfg)
281{
282 int fd;
283 struct stat buf;
284
285 /*
286 * See if the socket exits. If there's an error opening it, that's an issue.
287 *
288 * If it doesn't exist, that's fine.
289 */
290 if (fstatat(dirfd, filename, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
291 if (errno != ENOENT) {
292 fr_strerror_printf("Failed opening domain socket %s: %s", cfg->path, fr_syserror(errno));
293 return -1;
294 }
295
296 return 0;
297 }
298
299 /*
300 * If it exists, it must be a socket.
301 */
302 if (!S_ISSOCK(buf.st_mode)) {
303 fr_strerror_printf("Failed open domain socket %s: it is not a socket", filename);
304 return -1;
305 }
306
307 /*
308 * Refuse to open sockets not owned by us. This prevents configurations from stomping on each
309 * other.
310 */
311 if (buf.st_uid != cfg->uid) {
312 fr_strerror_printf("Failed opening domain socket %s: incorrect UID", cfg->path);
313 return -1;
314 }
315
316 /*
317 * The file exists,and someone is listening. We can't claim it for ourselves.
318 *
319 * Note that this function calls connect(), but connect() always returns immediately for domain
320 * sockets.
321 *
322 * @todo - redo that function here, with separate checks for permission errors vs anything else.
323 */
324 fd = fr_socket_client_unix(cfg->path, false);
325 if (fd >= 0) {
326 close(fd);
327 fr_strerror_printf("Failed creating domain socket %s: It is currently active", cfg->path);
328 return -1;
329 }
330
331 /*
332 * It exists, but no one is listening. Delete it so that we can re-bind to it.
333 */
334 if (unlinkat(dirfd, filename, 0) < 0) {
335 fr_strerror_printf("Failed removing pre-existing domain socket %s: %s",
336 cfg->path, fr_syserror(errno));
337 return -1;
338 }
339
340 return 0;
341}
342
343/*
344 * We normally can't call fchmod() or fchown() on sockets, as they don't really exist in the file system.
345 * Instead, we enforce those permissions on the parent directory of the socket.
346 */
347static int fr_bio_fd_socket_unix_mkdir(int *dirfd, char const **filename, fr_bio_fd_config_t const *cfg)
348{
349 mode_t perm;
350 int parent_fd, fd;
351 char const *path = cfg->path;
352 char *p, *dir = NULL;
353 char *slashes[2];
354
355 perm = S_IREAD | S_IWRITE | S_IEXEC;
356 perm |= S_IRGRP | S_IWGRP | S_IXGRP;
357
358 /*
359 * The parent directory exists. Ensure that it has the correct ownership and permissions.
360 *
361 * If the parent directory exists, then it enforces access, and we can create the domain socket
362 * within it.
363 */
364 if (fr_dirfd(dirfd, filename, path) == 0) {
365 struct stat buf;
366
367 fr_assert(*filename);
368 fr_assert(*dirfd >= 0);
369
370 if (fstat(*dirfd, &buf) < 0) {
371 fr_strerror_printf("Failed reading parent directory for file %s: %s", path, fr_syserror(errno));
372 fail:
373 talloc_free(dir);
374 close(*dirfd);
375 return -1;
376 }
377
378 if (buf.st_uid != cfg->uid) {
379 fr_strerror_printf("Failed reading parent directory for file %s: Incorrect UID", path);
380 goto fail;
381 }
382
383 if (buf.st_gid != cfg->gid) {
384 fr_strerror_printf("Failed reading parent directory for file %s: Incorrect GID", path);
385 goto fail;
386 }
387
388 /*
389 * We don't have the correct permissions on the directory, so we fix them.
390 *
391 * @todo - allow for "other" to read/write if we do authentication on the socket?
392 */
393 if (fchmod(*dirfd, perm) < 0) {
394 fr_strerror_printf("Failed setting parent directory permissions for file %s: %s", path, fr_syserror(errno));
395 goto fail;
396 }
397
398 return 0;
399 }
400
401 /*
402 * We have to create the directories.
403 */
404 dir = talloc_strdup(NULL, path);
405 if (!dir) goto fail;
406
407 /*
408 * Find the last two directory separators.
409 */
410 slashes[0] = slashes[1] = NULL;
411 for (p = dir; *p != '\0'; p++) {
412 if (*p == '/') {
413 slashes[0] = slashes[1];
414 slashes[1] = p;
415 }
416 }
417
418 /*
419 * There's only one / in the path, we can't do anything.
420 *
421 * Opening 'foo/bar.sock' might be useful, but isn't normally a good idea.
422 */
423 if (!slashes[0]) {
424 fr_strerror_printf("Failed parsing filename %s: it is not absolute", path);
425 goto fail;
426 }
427
428 /*
429 * Ensure that the grandparent directory exists.
430 *
431 * /var/run/radiusd/foo.sock
432 *
433 * slashes[0] points to the slash after 'run'.
434 *
435 * slashes[1] points to the slash after 'radiusd', which doesn't exist.
436 */
437 *slashes[0] = '\0';
438
439 /*
440 * If the grandparent doesn't exist, then we don't create it.
441 *
442 * These checks minimize the possibility that a misconfiguration by user "radiusd" can cause a
443 * suid-root binary top create a directory in the wrong place. These checks are only necessary
444 * if the unix domain socket is opened as root.
445 */
446 parent_fd = open(dir, O_DIRECTORY | O_NOFOLLOW);
447 if (parent_fd < 0) {
448 fr_strerror_printf("Failed opening directory %s: %s", dir, fr_syserror(errno));
449 goto fail;
450 }
451
452 /*
453 * Create the parent directory.
454 */
455 *slashes[0] = '/';
456 *slashes[1] = '\0';
457 if (mkdirat(parent_fd, slashes[0] + 1, 0700) < 0) {
458 fr_strerror_printf("Failed creating directory %s: %s", slashes[0], fr_syserror(errno));
459 close_parent:
460 close(parent_fd);
461 goto fail;
462 }
463
464 fd = openat(parent_fd, slashes[0] + 1, O_DIRECTORY);
465 if (fd < 0) {
466 fr_strerror_printf("Failed opening directory %s: %s", slashes[0] + 1, fr_syserror(errno));
467 goto close_parent;
468 }
469
470 if (fchmod(fd, perm) < 0) {
471 fr_strerror_printf("Failed changing permission for directory %s: %s", dir, fr_syserror(errno));
472 close_fd:
473 close(fd);
474 goto close_parent;
475 }
476
477 /*
478 * This is a NOOP if we're chowning a file owned by ourselves to our own UID / GID.
479 *
480 * Otherwise if we're running as root, it will set ownership to the correct user.
481 */
482 if (fchown(fd, cfg->uid, cfg->gid) < 0) {
483 fr_strerror_printf("Failed changing ownership for directory %s: %s", dir, fr_syserror(errno));
484 goto close_fd;
485 }
486
487 *dirfd = fd;
488 path = strrchr(cfg->path, '/');
489 if (path) path++;
490
491 *filename = path;
492
493 talloc_free(dir);
494 close(parent_fd);
495
496 return 0;
497}
498
500{
501 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
502
503 /*
504 * This is called after fr_bio_fd_close() - which marks the bio state as closed
505 *
506 * Unix domain sockets are deleted when the bio is closed.
507 *
508 * Unix domain sockets are never in the "connecting" state, because connect() always returns
509 * immediately.
510 */
511 fr_assert(my->info.state == FR_BIO_FD_STATE_CLOSED);
512
513 /*
514 * Run the user shutdown before we run ours.
515 */
516 if (my->user_shutdown) {
517 int rcode;
518
519 rcode = my->user_shutdown(bio);
520 if (rcode < 0) return rcode;
521 }
522
523 if (unlink(my->info.socket.unix.path) < 0) return fr_bio_error(GENERIC);
524
525 return 0;
526}
527
528/** Bind to a Unix domain socket.
529 *
530 * @todo - this function only does a tiny bit of what fr_server_domain_socket_peercred() and
531 * fr_server_domain_socket_perm() do. Those functions do a lot more sanity checks.
532 *
533 * The main question is whether or not those checks are useful. In many cases, fchmod() and fchown() are not
534 * possible on Unix sockets, so we shouldn't bother doing them,
535 *
536 * Note that the listeners generally call these functions with wrappers of fr_suid_up() and fr_suid_down().
537 * So these functions are running as "root", and will create files owned as "root".
538 */
540{
541 int dirfd, rcode;
542 char const *filename, *p;
543 socklen_t sunlen;
544 struct sockaddr_un sun;
545
546 if (!cfg->path) {
547 fr_strerror_const("Failed to specify path");
548 return -1;
549 }
550
551 /*
552 * The UID and GID should be taken automatically from the "user" and "group" settings in
553 * mainconfig. There is no reason to set them to anything else.
554 */
555 if (cfg->uid == (uid_t) -1) {
556 fr_strerror_printf("Failed opening domain socket %s: no UID specified", cfg->path);
557 return -1;
558 }
559
560 if (cfg->gid == (gid_t) -1) {
561 fr_strerror_printf("Failed opening domain socket %s: no GID specified", cfg->path);
562 return -1;
563 }
564
565 /*
566 * Opening 'foo.sock' is OK.
567 */
568 p = strrchr(cfg->path, '/');
569 if (!p) {
570 dirfd = AT_FDCWD;
571 filename = cfg->path;
572
573 } else if (p == cfg->path) {
574 /*
575 * Opening '/foo.sock' is dumb.
576 */
577 fr_strerror_printf("Failed opening domain socket %s: cannot exist at file system root", p);
578 return -1;
579
580 } else if (fr_bio_fd_socket_unix_mkdir(&dirfd, &filename, cfg) < 0) {
581 return -1;
582 }
583
584 /*
585 * Verify and/or clean up the domain socket.
586 */
587 if (fr_bio_fd_socket_unix_verify(dirfd, filename, cfg) < 0) {
588 fail:
589 if (dirfd != AT_FDCWD) close(dirfd);
590 return -1;
591 }
592
593#ifdef HAVE_BINDAT
594 /*
595 * The best function to use here is bindat(), but only quite recent versions of FreeBSD actually
596 * have it, and it's definitely not POSIX.
597 *
598 * If we use bindat(), we pass a relative pathname.
599 */
600 if (fr_filename_to_sockaddr(&sun, &sunlen, filename) < 0) goto fail;
601
602 rcode = bindat(dirfd, my->info.socket.fd, (struct sockaddr *) &sun, sunlen);
603#else
604 /*
605 * For bind(), we pass the full path.
606 */
607 if (fr_filename_to_sockaddr(&sun, &sunlen, cfg->path) < 0) goto fail;
608
609 rcode = bind(my->info.socket.fd, (struct sockaddr *) &sun, sunlen);
610#endif
611 if (rcode < 0) {
612 /*
613 * @todo - if EADDRINUSE, then the socket exists. Try connect(), and if that fails,
614 * delete the socket and try again. This may be simpler than the checks above.
615 */
616 fr_strerror_printf("Failed binding to domain socket %s: %s", cfg->path, fr_syserror(errno));
617 goto fail;
618 }
619
620#ifdef __linux__
621 /*
622 * Linux supports chown && chmod for sockets.
623 */
624 if (fchmod(my->info.socket.fd, S_IREAD | S_IWRITE | S_IEXEC | S_IRGRP | S_IWGRP | S_IXGRP) < 0) {
625 fr_strerror_printf("Failed changing permission for domain socket %s: %s", cfg->path, fr_syserror(errno));
626 goto fail;
627 }
628
629 /*
630 * This is a NOOP if we're chowning a file owned by ourselves to our own UID / GID.
631 *
632 * Otherwise if we're running as root, it will set ownership to the correct user.
633 */
634 if (fchown(my->info.socket.fd, cfg->uid, cfg->gid) < 0) {
635 fr_strerror_printf("Failed changing ownershipt for domain directory %s: %s", cfg->path, fr_syserror(errno));
636 goto fail;
637 }
638
639#endif
640
641 /*
642 * Socket is open. We need to clean it up on shutdown.
643 */
644 if (my->cb.shutdown) my->user_shutdown = my->cb.shutdown;
645 my->cb.shutdown = fr_bio_fd_unix_shutdown;
646 if (dirfd != AT_FDCWD) close(dirfd);
647
648 return 0;
649}
650
651/*
652 * Use the OSX native versions on OSX.
653 */
654#ifdef __APPLE__
655#undef SO_BINDTODEVICE
656#endif
657
658#ifdef SO_BINDTODEVICE
659/** Linux bind to device by name.
660 *
661 */
663{
664 /*
665 * ifindex isn't set, do nothing.
666 */
667 if (!my->info.socket.inet.ifindex) return 0;
668
669 if (!cfg->interface) return 0;
670
671 /*
672 * The internet hints that CAP_NET_RAW is required to use SO_BINDTODEVICE.
673 *
674 * This function also sets fr_strerror() on failure, which will be seen if the bind fails. If
675 * the bind succeeds, then we don't really care that the capability change has failed. We must
676 * already have that capability.
677 */
678#ifdef HAVE_CAPABILITY_H
679 (void)fr_cap_enable(CAP_NET_RAW, CAP_EFFECTIVE);
680#endif
681
682 if (setsockopt(my->info.socket.fd, SOL_SOCKET, SO_BINDTODEVICE, cfg->interface, strlen(cfg->interface)) < 0) {
683 fr_strerror_printf("Failed setting SO_BINDTODEVICE for %s: %s", cfg->interface, fr_syserror(errno));
684 return -1;
685 }
686
687 return 0;
688}
689
690#elif defined(IP_BOUND_IF) || defined(IPV6_BOUND_IF)
691/** OSX bind to interface by index.
692 *
693 */
695{
696 int opt, rcode;
697
698 if (!my->info.socket.inet.ifindex) return 0;
699
700 opt = my->info.socket.inet.ifindex;
701
702 switch (my->info.socket.af) {
703 case AF_INET:
704 rcode = setsockopt(my->info.socket.fd, IPPROTO_IP, IP_BOUND_IF, &opt, sizeof(opt));
705 break;
706
707 case AF_INET6:
708 rcode = setsockopt(my->info.socket.fd, IPPROTO_IPV6, IPV6_BOUND_IF, &opt, sizeof(opt));
709 break;
710
711 default:
712 rcode = -1;
713 errno = EAFNOSUPPORT;
714 break;
715 }
716
717 if (rcode < 0) fr_strerror_printf("Failed setting IP_BOUND_IF: %s", fr_syserror(errno));
718 return rcode;
719}
720#else
721
722/** This system is missing SO_BINDTODEVICE, IP_BOUND_IF, IPV6_BOUND_IF
723 *
724 * @todo - FreeBSD IP_RECVIF and IP_SENDIF
725 *
726 * Except that has to be done in recvmsg() and sendmsg(). And it only works on datagram sockets.
727 *
728 * cmsg_len = sizeof(struct sockaddr_dl)
729 * cmsg_level = IPPROTO_IP
730 * cmsg_type = IP_RECVIF
731 */
733{
734 if (!my->info.socket.inet.ifindex) return 0;
735
736 fr_strerror_const("Bind to interface is not supported on this platform");
737 return -1;
738}
739
740/* bind to device */
741#endif
742
744{
745 bool do_suid;
746 int rcode;
747 socklen_t salen;
748 struct sockaddr_storage salocal;
749
750 fr_assert((my->info.socket.af == AF_INET) || (my->info.socket.af == AF_INET6));
751
752 /*
753 * Ranges must be a high value.
754 */
755 if (my->info.cfg->src_port_start) {
756 if (my->info.cfg->src_port_start < 1024) {
757 fr_strerror_const("Cannot set src_port_start in the range 1..1023");
758 return -1;
759 }
760
761 if (my->info.cfg->src_port_end <= my->info.cfg->src_port_start) {
762 fr_strerror_const("Invalid range src_port_end <= src_port_start");
763 return -1;
764 }
765 }
766
767 /*
768 * Source port is in the restricted range, and we're not root, update permissions / capabilities
769 * so that the bind is permitted.
770 */
771 do_suid = (my->info.socket.inet.src_port > 0) && (my->info.socket.inet.src_port < 1024) && (geteuid() != 0);
772
773#ifdef HAVE_CAPABILITY_H
774 /*
775 * If we can set the capabilities, then we don't need to do SUID.
776 */
777 if (do_suid) do_suid = (fr_cap_enable(CAP_NET_BIND_SERVICE, CAP_EFFECTIVE) < 0);
778#endif
779
780 /*
781 * SUID up before we bind to the interface. If we can set the capabilities above, then should
782 * also be able to set the capabilities to bind to an interface.
783 */
784 if (do_suid) fr_suid_up();
785
786 if (fr_bio_fd_socket_bind_to_device(my, cfg) < 0) {
787 down:
788 if (do_suid) fr_suid_down();
789 return -1;
790 }
791
792 /*
793 * Get the sockaddr for bind()
794 */
795 if (fr_ipaddr_to_sockaddr(&salocal, &salen, &my->info.socket.inet.src_ipaddr, my->info.socket.inet.src_port) < 0) goto down;
796
797 /*
798 * We don't have a source port range, just bind to whatever source port that we're given.
799 */
800 if (!my->info.cfg->src_port_start) {
801 rcode = bind(my->info.socket.fd, (struct sockaddr *) &salocal, salen);
802 if (do_suid) fr_suid_down();
803
804 if (rcode < 0) {
805 fr_strerror_printf("Failed binding to socket: %s", fr_syserror(errno));
806 return -1;
807 }
808
809 } else {
810 uint16_t src_port, current, range;
811 struct sockaddr_in *sin = (struct sockaddr_in *) &salocal;
812
813 fr_assert(my->info.cfg->src_port_start);
814 fr_assert(my->info.cfg->src_port_end);
815 fr_assert(my->info.cfg->src_port_end >= my->info.cfg->src_port_start);
816
817 range = my->info.cfg->src_port_end - my->info.cfg->src_port_start;
818 src_port = fr_rand() % range;
819
820 /*
821 * We only care about sin_port, which is in the same location for sockaddr_in and sockaddr_in6.
822 */
823 fr_assert(sin->sin_port == 0);
824
825 sin->sin_port = htons(my->info.cfg->src_port_start + src_port);
826
827 /*
828 * We've picked a random port in what is hopefully a large range. If that works, we're
829 * done.
830 */
831 rcode = bind(my->info.socket.fd, (struct sockaddr *) &salocal, salen);
832 if (rcode == 0) {
833 if (do_suid) fr_suid_down();
834 goto done;
835 }
836
837 /*
838 * Hunt & peck. Which is horrible.
839 */
840 current = src_port;
841 while (true) {
842 if (current == range) {
843 current = 0;
844 } else {
845 current++;
846 }
847
848 /*
849 * We've already checked this, so stop.
850 */
851 if (current == src_port) break;
852
853 sin->sin_port = htons(my->info.cfg->src_port_start + current);
854
855 rcode = bind(my->info.socket.fd, (struct sockaddr *) &salocal, salen);
856 if (rcode == 0) {
857 if (do_suid) fr_suid_down();
858 goto done;
859 }
860 }
861
862 /*
863 * The error is a good hint at _why_ we failed to bind.
864 * We expect errno to be EADDRINUSE, anything else is a surprise.
865 */
866 if (do_suid) fr_suid_down();
867 fr_strerror_printf("Failed binding port between 'src_port_start' and 'src_port_end': %s", fr_syserror(errno));
868 return -1;
869 }
870
871 /*
872 * The IP and/or port may have changed, so get the new one.
873 */
874done:
876}
877
878/** Set the name of an FD BIO
879 *
880 */
882{
883 fr_bio_fd_config_t const *cfg = my->info.cfg;
884
885 switch (my->info.type) {
887 return;
888
890 fr_assert(cfg->socket_type == SOCK_DGRAM);
891
892 switch (my->info.socket.af) {
893 case AF_INET:
894 case AF_INET6:
895 my->info.name = fr_asprintf(my, "proto udp local %pV port %u",
896 fr_box_ipaddr(my->info.socket.inet.src_ipaddr),
897 my->info.socket.inet.src_port);
898 break;
899
900 case AF_LOCAL:
901 my->info.name = fr_asprintf(my, "proto unix (datagram) filename %s",
902 cfg->path);
903 break;
904
905 default:
906 fr_assert(0);
907 my->info.name = "??? invalid BIO ???";
908 break;
909 }
910 break;
911
913 switch (my->info.socket.af) {
914 case AF_INET:
915 case AF_INET6:
916 my->info.name = fr_asprintf(my, "proto %s local %pV port %u remote %pV port %u",
917 (cfg->socket_type == SOCK_DGRAM) ? "udp" : "tcp",
918 fr_box_ipaddr(my->info.socket.inet.src_ipaddr),
919 my->info.socket.inet.src_port,
920 fr_box_ipaddr(my->info.socket.inet.dst_ipaddr),
921 my->info.socket.inet.dst_port);
922 break;
923
924 case AF_LOCAL:
925 my->info.name = fr_asprintf(my, "proto unix %sfilename %s",
926 (cfg->socket_type == SOCK_DGRAM) ? "(datagram) " : "",
927 cfg->path);
928 break;
929
930 case AF_FILE_BIO:
931 fr_assert(cfg->socket_type == SOCK_STREAM);
932
933 if (cfg->flags == O_RDONLY) {
934 my->info.name = fr_asprintf(my, "proto file (read-only) filename %s ",
935 cfg->filename);
936
937 } else if (cfg->flags == O_WRONLY) {
938 my->info.name = fr_asprintf(my, "proto file (write-only) filename %s",
939 cfg->filename);
940 } else {
941 my->info.name = fr_asprintf(my, "proto file (read-write) filename %s",
942 cfg->filename);
943 }
944 break;
945
946 default:
947 fr_assert(0);
948 my->info.name = "??? invalid BIO ???";
949 break;
950 }
951 break;
952
953 case FR_BIO_FD_LISTEN:
954 switch (my->info.socket.af) {
955 case AF_INET:
956 case AF_INET6:
957 my->info.name = fr_asprintf(my, "proto %s local %pV port %u",
958 (cfg->socket_type == SOCK_DGRAM) ? "udp" : "tcp",
959 fr_box_ipaddr(my->info.socket.inet.src_ipaddr),
960 my->info.socket.inet.src_port);
961 break;
962
963 case AF_LOCAL:
964 my->info.name = fr_asprintf(my, "proto unix filename %s",
965 cfg->path);
966 break;
967
968 default:
969 fr_assert(0);
970 my->info.name = "??? invalid BIO ???";
971 break;
972 }
973 break;
974 }
975}
976
977/** Checks the configuration without modifying anything.
978 *
979 */
981{
982 /*
983 * Sanitize the IP addresses.
984 *
985 */
986 switch (cfg->type) {
988 fr_strerror_const("No connection type was specified");
989 return -1;
990
992 /*
993 * Ensure that we have a destination address.
994 */
995 if (cfg->dst_ipaddr.af == AF_UNSPEC) {
996 fr_strerror_const("No destination IP address was specified");
997 return -1;
998 }
999
1000 if (!cfg->dst_port) {
1001 fr_strerror_const("No destination port was specified");
1002 return -1;
1003 }
1004
1005 /*
1006 * The source IP has to be the same address family as the destination IP.
1007 */
1008 if ((cfg->src_ipaddr.af != AF_UNSPEC) && (cfg->src_ipaddr.af != cfg->dst_ipaddr.af)) {
1009 fr_strerror_printf("Source and destination IP addresses are not from the same IP address family");
1010 return -1;
1011 }
1012 break;
1013
1014 case FR_BIO_FD_LISTEN:
1015 if (!cfg->src_port) {
1016 fr_strerror_const("No source port was specified");
1017 return -1;
1018 }
1020
1021 /*
1022 * Unconnected sockets can use a source port, but don't need one.
1023 */
1025 if (cfg->path && cfg->filename) {
1026 fr_strerror_const("Unconnected sockets cannot be used with Unix sockets or files");
1027 return -1;
1028 }
1029
1030 if (cfg->src_ipaddr.af == AF_UNSPEC) {
1031 fr_strerror_const("No source IP address was specified");
1032 return -1;
1033 }
1034 break;
1035 }
1036
1037 return 0;
1038}
1039
1040/** Opens a socket and updates sock->fd
1041 *
1042 * If the socket is asynchronous, it also calls connect()
1043 */
1045{
1046 int fd;
1047 int rcode = -1;
1048 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1049
1051
1052 my->info = (fr_bio_fd_info_t) {
1053 .socket = {
1054 .type = cfg->socket_type,
1055 .fd = -1,
1056 },
1057 .cfg = cfg,
1058 };
1059
1060 if (!cfg->path && !cfg->filename) {
1061 int protocol;
1062
1063 my->info.socket.af = cfg->src_ipaddr.af;
1064 my->info.socket.inet.src_ipaddr = cfg->src_ipaddr;
1065 my->info.socket.inet.dst_ipaddr = cfg->dst_ipaddr;
1066 my->info.socket.inet.src_port = cfg->src_port;
1067 my->info.socket.inet.dst_port = cfg->dst_port;
1068
1069 if (fr_bio_fd_check_config(cfg) < 0) return -1;
1070
1071 /*
1072 * Sanitize the IP addresses.
1073 *
1074 */
1075 switch (cfg->type) {
1076 case FR_BIO_FD_INVALID:
1077 return -1;
1078
1080 /*
1081 * No source specified, just bootstrap it from the destination.
1082 */
1083 if (my->info.socket.inet.src_ipaddr.af == AF_UNSPEC) {
1084 my->info.socket.inet.src_ipaddr = (fr_ipaddr_t) {
1085 .af = my->info.socket.inet.dst_ipaddr.af,
1086 .prefix = (my->info.socket.inet.dst_ipaddr.af == AF_INET) ? 32 : 128,
1087 };
1088
1089 /*
1090 * Set the main socket AF too.
1091 */
1092 my->info.socket.af = my->info.socket.inet.dst_ipaddr.af;
1093 }
1094
1095 /*
1096 * The source IP has to be the same address family as the destination IP.
1097 */
1098 if (my->info.socket.inet.src_ipaddr.af != my->info.socket.inet.dst_ipaddr.af) {
1099 fr_strerror_const("Source and destination IP addresses are not from the same IP address family");
1100 return -1;
1101 }
1102
1103#ifdef SO_REUSEPORT
1104 /*
1105 * Connected UDP sockets really only matter when writing packets. They allow the
1106 * system to use write() instead of sendto().
1107 *
1108 * However for reading packets, the kernel does NOT check the source IP.
1109 * Instead, it just delivers any packet with the correct dst IP/port. Even
1110 * worse, if multiple sockets re-use the same dst IP/port, packets are delivered
1111 * to a _random_ socket.
1112 *
1113 * As a result, we cannot use wildcard sockets with SO_REUSEPORT, and UDP.
1114 */
1115 if (cfg->reuse_port && (cfg->socket_type == SOCK_DGRAM) &&
1116 fr_ipaddr_is_inaddr_any(&my->info.socket.inet.dst_ipaddr)) { /* checks AF, so we're OK */
1117 fr_strerror_const("Cannot set 'reuse_port' for connected UDP sockets with wildcard IP");
1118 return -1;
1119 }
1120#endif
1121
1122 break;
1123
1125 case FR_BIO_FD_LISTEN:
1126 fr_assert(my->info.socket.inet.src_ipaddr.af != AF_UNSPEC);
1127 break;
1128 }
1129
1130 if (cfg->socket_type == SOCK_STREAM) {
1131 protocol = IPPROTO_TCP;
1132 } else {
1133 protocol = IPPROTO_UDP;
1134 }
1135
1136 if (cfg->interface) {
1137 my->info.socket.inet.ifindex = if_nametoindex(cfg->interface);
1138
1139 if (!my->info.socket.inet.ifindex) {
1140 fr_strerror_printf_push("Failed finding interface %s: %s", cfg->interface, fr_syserror(errno));
1141 return -1;
1142 }
1143 }
1144
1145 fd = socket(my->info.socket.af, my->info.socket.type, protocol);
1146 if (fd < 0) {
1147 fr_strerror_printf("Failed opening socket: %s", fr_syserror(errno));
1148 return fr_bio_error(GENERIC);
1149 }
1150
1151 } else if (cfg->path) {
1152 my->info.socket.af = AF_LOCAL;
1153 my->info.socket.type = SOCK_STREAM;
1154 my->info.socket.unix.path = cfg->path;
1155
1156 fd = socket(my->info.socket.af, my->info.socket.type, 0);
1157 if (fd < 0) {
1158 fr_strerror_printf("Failed opening domain socket %s: %s", cfg->path, fr_syserror(errno));
1159 return fr_bio_error(GENERIC);
1160 }
1161
1162 } else {
1163 if (cfg->type != FR_BIO_FD_CONNECTED) {
1164 fr_strerror_printf("Can only use connected sockets for file IO");
1165 return -1;
1166 }
1167
1168 /*
1169 * Filenames overload the #fr_socket_t for now.
1170 */
1171 my->info.socket.af = AF_FILE_BIO;
1172 my->info.socket.type = SOCK_STREAM;
1173 my->info.socket.unix.path = cfg->filename;
1174
1175 /*
1176 * Allow hacks for stdout and stderr
1177 */
1178 if (strcmp(cfg->filename, "/dev/stdout") == 0) {
1179 if (cfg->flags != O_WRONLY) {
1180 fail_dev:
1181 fr_strerror_printf("Cannot read from %s", cfg->filename);
1182 return -1;
1183 }
1184
1185 fd = dup(STDOUT_FILENO);
1186
1187 } else if (strcmp(cfg->filename, "/dev/stderr") == 0) {
1188 if (cfg->flags != O_WRONLY) goto fail_dev;
1189
1190 fd = dup(STDERR_FILENO);
1191
1192 } else if (strcmp(cfg->filename, "/dev/stdin") == 0) {
1193 if (cfg->flags != O_RDONLY) {
1194 fr_strerror_printf("Cannot write to %s", cfg->filename);
1195 return -1;
1196 }
1197
1198 fd = dup(STDIN_FILENO);
1199
1200 } else {
1201 /*
1202 * Minor hacks so that we have only _one_ source of open / mkdir
1203 */
1204 my->info.socket.fd = -1;
1205
1206 fd = fr_bio_fd_reopen(bio);
1207 }
1208 if (fd < 0) {
1209 fr_strerror_printf("Failed opening file %s: %s", cfg->filename, fr_syserror(errno));
1210 return fr_bio_error(GENERIC);
1211 }
1212 }
1213
1214 /*
1215 * Set it to be non-blocking if required.
1216 */
1217 if (cfg->async && (fr_nonblock(fd) < 0)) {
1218 fr_strerror_printf("Failed setting O_NONBLOCK: %s", fr_syserror(errno));
1219 rcode = fr_bio_error(GENERIC);
1220
1221 fail:
1222 my->info.socket = (fr_socket_t) {
1223 .fd = -1,
1224 };
1225 my->info.state = FR_BIO_FD_STATE_CLOSED;
1226 my->info.cfg = NULL;
1227 close(fd);
1228 return rcode;
1229 }
1230
1231 if (fr_cloexec(fd) < 0) goto fail;
1232
1233 /*
1234 * Initialize the bio information before calling the various setup functions.
1235 */
1236 my->info.state = FR_BIO_FD_STATE_CONNECTING;
1237
1238 /*
1239 * Set the FD so that the subsequent calls can use it.
1240 */
1241 my->info.socket.fd = fd;
1242
1243 /*
1244 * Set the type, too.
1245 */
1246 my->info.type = cfg->type;
1247
1248 /*
1249 * Do sanity checks, bootstrap common socket options, bind to the socket, and initialize the read
1250 * / write functions.
1251 */
1252 switch (cfg->type) {
1253 case FR_BIO_FD_INVALID:
1254 goto fail;
1255
1256 /*
1257 * Unconnected UDP or datagram AF_LOCAL server sockets.
1258 */
1260 if (my->info.socket.type != SOCK_DGRAM) {
1261 fr_strerror_const("Failed configuring socket: unconnected sockets must be UDP");
1262 goto fail;
1263 }
1264
1265 switch (my->info.socket.af) {
1266 case AF_INET:
1267 case AF_INET6:
1268 if ((rcode = fr_bio_fd_common_udp(fd, &my->info.socket, cfg)) < 0) goto fail;
1269 break;
1270
1271 case AF_LOCAL:
1272 if ((rcode = fr_bio_fd_common_datagram(fd, &my->info.socket, cfg)) < 0) goto fail;
1273 break;
1274
1275 case AF_FILE_BIO:
1276 fr_strerror_const("Filenames must use the connected API");
1277 goto fail;
1278
1279 default:
1280 fr_strerror_const("Unsupported address family for unconnected sockets");
1281 goto fail;
1282 }
1283
1284 if ((rcode = fr_bio_fd_socket_bind(my, cfg)) < 0) goto fail;
1285
1286 if ((rcode = fr_bio_fd_init_common(my)) < 0) goto fail;
1287 break;
1288
1289 /*
1290 * A connected client: UDP, TCP, AF_LOCAL, or AF_FILE_BIO
1291 */
1293 if (my->info.socket.type == SOCK_DGRAM) {
1294 switch (my->info.socket.af) {
1295 case AF_INET:
1296 case AF_INET6:
1297 if ((rcode = fr_bio_fd_common_udp(fd, &my->info.socket, cfg)) < 0) goto fail;
1298 break;
1299 default:
1300 if ((rcode = fr_bio_fd_common_datagram(fd, &my->info.socket, cfg)) < 0) goto fail;
1301 break;
1302 }
1303
1304 } else if ((my->info.socket.af == AF_INET) || (my->info.socket.af == AF_INET6)) {
1305 rcode = fr_bio_fd_common_tcp(fd, &my->info.socket, cfg);
1306 if (rcode < 0) goto fail;
1307 }
1308
1309 switch (my->info.socket.af) {
1310 case AF_LOCAL:
1311 if ((rcode = fr_bio_fd_socket_bind_unix(my, cfg)) < 0) goto fail;
1312 break;
1313
1314 case AF_FILE_BIO:
1315 break;
1316
1317 case AF_INET:
1318 case AF_INET6:
1319 if ((rcode = fr_bio_fd_socket_bind(my, cfg)) < 0) goto fail;
1320 break;
1321
1322 default:
1323 goto fail;
1324 }
1325
1326 if ((rcode = fr_bio_fd_init_connected(my)) < 0) goto fail;
1327 break;
1328
1329 /*
1330 * Server socket which listens for new stream connections
1331 */
1332 case FR_BIO_FD_LISTEN:
1333 if ((my->info.socket.type == SOCK_DGRAM) && !cfg->reuse_port) {
1334 fr_strerror_const("reuseport must be set for datagram sockets");
1335 rcode = -1;
1336 goto fail;
1337 }
1338
1339 switch (my->info.socket.af) {
1340 case AF_INET:
1341 if ((rcode = fr_bio_fd_server_ipv4(fd, &my->info.socket, cfg)) < 0) goto fail;
1342
1343 if ((rcode = fr_bio_fd_socket_bind(my, cfg)) < 0) goto fail;
1344 break;
1345
1346 case AF_INET6:
1347 if ((rcode = fr_bio_fd_server_ipv6(fd, &my->info.socket, cfg)) < 0) goto fail;
1348
1349 if ((rcode = fr_bio_fd_socket_bind(my, cfg)) < 0) goto fail;
1350 break;
1351
1352 case AF_LOCAL:
1353 if ((rcode = fr_bio_fd_socket_bind_unix(my, cfg)) < 0) goto fail;
1354 break;
1355
1356 default:
1357 fr_strerror_const("Unsupported address family for accept() socket");
1358 rcode = -1;
1359 goto fail;
1360 }
1361
1362 if ((rcode = fr_bio_fd_init_listen(my)) < 0) goto fail;
1363 break;
1364 }
1365
1366 /*
1367 * Set the name of the BIO.
1368 */
1370
1371 return 0;
1372}
1373
1374/** Reopen a file BIO
1375 *
1376 * e.g. for log files.
1377 */
1379{
1380 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1381 fr_bio_fd_config_t const *cfg = my->info.cfg;
1382 int fd, flags;
1383
1384 if (my->info.socket.af != AF_FILE_BIO) {
1385 fr_strerror_const("Cannot reopen a non-file BIO");
1386 return -1;
1387 }
1388
1389 /*
1390 * Create it if necessary.
1391 */
1392 flags = cfg->flags;
1393 if (flags != O_RDONLY) flags |= O_CREAT;
1394
1395 if (!cfg->mkdir) {
1396 /*
1397 * Client BIOs writing to a file, and therefore need to create it.
1398 */
1399 do_open:
1400 fd = open(cfg->filename, flags, cfg->perm);
1401 if (fd < 0) {
1402 failed_open:
1403 fr_strerror_printf("Failed opening file %s: %s", cfg->filename, fr_syserror(errno));
1404 return -1;
1405 }
1406
1407 } else {
1408 /*
1409 * We make the parent directory if told to, AND if there's a '/' in the path.
1410 */
1411 char *p = strrchr(cfg->filename, '/');
1412 int dir_fd;
1413
1414 if (!p) goto do_open;
1415
1416 if (fr_mkdir(&dir_fd, cfg->filename, (size_t) (p - cfg->filename), cfg->perm, fr_mkdir_chown,
1417 &(fr_mkdir_chown_t) {
1418 .uid = cfg->uid,
1419 .gid = cfg->gid,
1420 }) < 0) {
1421 return -1;
1422 }
1423
1424 fd = openat(dir_fd, p + 1, flags, cfg->perm);
1425 if (fd < 0) {
1426 close(dir_fd);
1427 goto failed_open;
1428 }
1429
1430 close(dir_fd);
1431 }
1432
1433 /*
1434 * We're boot-strapping, just set the new FD and return.
1435 */
1436 if (my->info.socket.fd < 0) {
1437 return fd;
1438 }
1439
1440 /*
1441 * Replace the FD rather than swapping it out with a new one. This is potentially more
1442 * thread-safe.
1443 */
1444 if (dup2(fd, my->info.socket.fd) < 0) {
1445 close(fd);
1446 fr_strerror_printf("Failed reopening file - %s", fr_syserror(errno));
1447 return -1;
1448 }
1449
1450 close(fd);
1451 return my->info.socket.fd;
1452}
#define fr_bio_error(_x)
Definition base.h:200
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:186
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:343
#define UNUSED
Definition build.h:336
#define CAP_EFFECTIVE
Definition cap.h:48
int fr_bio_fd_socket_name(fr_bio_fd_t *my)
Definition fd.c:659
int fr_bio_fd_init_connected(fr_bio_fd_t *my)
Definition fd.c:817
int fr_filename_to_sockaddr(struct sockaddr_un *sun, socklen_t *sunlen, char const *filename)
Definition fd.c:641
int fr_bio_fd_init_listen(fr_bio_fd_t *my)
Definition fd.c:921
int fr_bio_fd_init_common(fr_bio_fd_t *my)
Definition fd.c:880
uint16_t src_port
our port
Definition fd.h:91
@ 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:101
bool mkdir
make intermediate directories
Definition fd.h:108
@ FR_BIO_FD_STATE_CLOSED
Definition fd.h:58
@ FR_BIO_FD_STATE_CONNECTING
Definition fd.h:60
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:81
char const * path
for Unix domain sockets
Definition fd.h:104
uint32_t send_buff
How big the kernel's send buffer should be.
Definition fd.h:102
char const * filename
for files
Definition fd.h:110
uid_t uid
who owns the socket
Definition fd.h:106
gid_t gid
who owns the socket
Definition fd.h:107
char const * interface
for binding to an interface
Definition fd.h:97
mode_t perm
permissions for domain sockets
Definition fd.h:105
#define AF_FILE_BIO
Definition fd.h:40
int socket_type
SOCK_STREAM or SOCK_DGRAM.
Definition fd.h:83
uint16_t dst_port
their port
Definition fd.h:92
bool tcp_delay
We do tcp_nodelay by default.
Definition fd.h:114
bool reuse_port
whether or not we re-use the same destination port for datagram sockets
Definition fd.h:86
bool exceed_mtu
Whether we allow packets which exceed the local MTU.
Definition fd.h:115
bool async
is it async
Definition fd.h:113
int flags
O_RDONLY, etc.
Definition fd.h:111
fr_ipaddr_t src_ipaddr
our IP address
Definition fd.h:88
Configuration for sockets.
Definition fd.h:80
Run-time status of the socket.
Definition fd.h:131
void fr_bio_shutdown & my
Definition fd_errno.h:70
static int fr_bio_fd_socket_unix_mkdir(int *dirfd, char const **filename, fr_bio_fd_config_t const *cfg)
Definition fd_open.c:347
static int fr_bio_fd_socket_bind_to_device(fr_bio_fd_t *my, UNUSED fr_bio_fd_config_t const *cfg)
This system is missing SO_BINDTODEVICE, IP_BOUND_IF, IPV6_BOUND_IF.
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:280
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:253
static int fr_bio_fd_common_udp(int fd, fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
Initialize a UDP socket.
Definition fd_open.c:149
int fr_bio_fd_reopen(fr_bio_t *bio)
Reopen a file BIO.
Definition fd_open.c:1378
static int fr_bio_fd_server_tcp(int fd, UNUSED fr_socket_t const *sock)
Initialize a TCP server socket.
Definition fd_open.c:225
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:539
void fr_bio_fd_name(fr_bio_fd_t *my)
Set the name of an FD BIO.
Definition fd_open.c:881
static int fr_bio_fd_socket_bind(fr_bio_fd_t *my, fr_bio_fd_config_t const *cfg)
Definition fd_open.c:743
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:240
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_unix_shutdown(fr_bio_t *bio)
Definition fd_open.c:499
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:1044
int fr_bio_fd_check_config(fr_bio_fd_config_t const *cfg)
Checks the configuration without modifying anything.
Definition fd_open.c:980
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
talloc_free(hp)
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
Definition inet.c:62
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:1399
int af
Address family.
Definition inet.h:63
IPv4/6 prefix.
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:218
int fr_mkdir_chown(int fd, char const *path, void *uctx)
Callback for the common case of chown() of the directory.
Definition file.c:38
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:411
unsigned short uint16_t
unsigned int mode_t
int fr_nonblock(UNUSED int fd)
Definition misc.c:293
fr_suid_t fr_suid_up
Definition misc.c:568
int fr_cloexec(UNUSED int fd)
Definition misc.c:331
fr_suid_t fr_suid_down
Definition misc.c:569
char * fr_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Special version of asprintf which implements custom format specifiers.
Definition print.c:883
#define fr_assert(_expr)
Definition rad_assert.h:37
static bool done
Definition radclient.c:80
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:104
int fr_socket_client_unix(UNUSED char const *path, UNUSED bool async)
Definition socket.c:543
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define talloc_strdup(_ctx, _str)
Definition talloc.h:142
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition socket.h:75
int type
SOCK_STREAM, SOCK_DGRAM, etc.
Definition socket.h:76
Holds information necessary for binding or connecting to a socket.
Definition socket.h:60
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:576
#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:317