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