25 #include <freeradius-devel/bio/fd_priv.h>
26 #include <freeradius-devel/util/file.h>
27 #include <freeradius-devel/util/cap.h>
33 #include <netinet/tcp.h>
47 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on,
sizeof(on)) < 0) {
57 # if !defined(SOL_TCP) && defined(IPPROTO_TCP)
58 # define SOL_TCP IPPROTO_TCP
68 if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on,
sizeof(on)) < 0) {
92 if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS, &on,
sizeof(
int)) < 0) {
97 #elif defined(SO_TIMESTAMP)
103 if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, &on,
sizeof(
int)) < 0) {
113 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt,
sizeof(opt)) < 0) {
124 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt,
sizeof(opt)) < 0) {
146 if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on,
sizeof(on)) < 0) {
162 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on,
sizeof(on)) < 0) {
177 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
182 flag = IP_PMTUDISC_DONT;
184 if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &flag,
sizeof(flag)) < 0) {
190 #if defined(IP_DONTFRAG)
196 if (setsockopt(fd, IPPROTO_IP, IP_DONTFRAG, &flag,
sizeof(flag)) < 0) {
219 if (IN6_IS_ADDR_UNSPECIFIED(
UNCONST(
struct in6_addr *, &sock->inet.src_ipaddr.addr.v6))) {
222 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (
char *)&on,
sizeof(on)) < 0) {
250 if (fstatat(dirfd, filename, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
251 if (errno != ENOENT) {
262 if (!S_ISSOCK(buf.st_mode)) {
271 if (buf.st_uid != cfg->
uid) {
294 if (unlinkat(dirfd, filename, 0) < 0) {
311 char const *path = cfg->
path;
312 char *p, *dir = NULL;
315 perm = S_IREAD | S_IWRITE | S_IEXEC;
316 perm |= S_IRGRP | S_IWGRP | S_IXGRP;
324 if (
fr_dirfd(dirfd, filename, path) == 0) {
327 if (fstat(*dirfd, &buf) < 0) {
335 if (buf.st_uid != cfg->
uid) {
336 fr_strerror_printf(
"Failed reading parent directory for file %s: Incorrect UID", path);
340 if (buf.st_gid != cfg->
gid) {
341 fr_strerror_printf(
"Failed reading parent directory for file %s: Incorrect GID", path);
350 if (fchmod(*dirfd, perm) < 0) {
358 dir = talloc_strdup(NULL, path);
364 slashes[0] = slashes[1] = NULL;
365 for (p = dir; *p !=
'\0'; p++) {
367 slashes[0] = slashes[1];
400 parent_fd = open(dir, O_DIRECTORY | O_NOFOLLOW);
411 if (mkdirat(parent_fd, dir, 0700) < 0) {
418 fd = openat(parent_fd, dir, O_DIRECTORY);
424 if (fchmod(fd, perm) < 0) {
436 if (fchown(fd, cfg->
uid, cfg->
gid) < 0) {
486 char const *filename, *p;
488 struct sockaddr_un sun;
499 if (cfg->
uid == (uid_t) -1) {
504 if (cfg->
gid == (gid_t) -1) {
512 p = strrchr(cfg->
path,
'/');
515 filename = cfg->
path;
517 }
else if (p == cfg->
path) {
521 fr_strerror_printf(
"Failed opening domain socket %s: cannot exist at file system root", p);
533 if (dirfd != AT_FDCWD)
close(dirfd);
546 rcode = bindat(dirfd, my->
info.
socket.
fd, (
struct sockaddr *) &sun, sunlen);
553 rcode = bind(my->
info.
socket.
fd, (
struct sockaddr *) &sun, sunlen);
568 if (fchmod(my->
info.
socket.
fd, S_IREAD | S_IWRITE | S_IEXEC | S_IRGRP | S_IWGRP | S_IXGRP) < 0) {
594 #ifdef SO_BINDTODEVICE
614 #ifdef HAVE_CAPABILITY_H
615 (void)fr_cap_enable(CAP_NET_RAW, CAP_EFFECTIVE);
626 #elif defined(IP_BOUND_IF) || defined(IPV6_BOUND_IF)
640 rcode = setsockopt(my->
info.
socket.
fd, IPPROTO_IP, IP_BOUND_IF, &opt,
sizeof(opt));
644 rcode = setsockopt(my->
info.
socket.
fd, IPPROTO_IPV6, IPV6_BOUND_IF, &opt,
sizeof(opt));
649 errno = EAFNOSUPPORT;
680 struct sockaddr_storage salocal;
684 #ifdef HAVE_CAPABILITY_H
690 if ((my->
info.
socket.inet.src_port < 1024) && (geteuid() != 0)) {
691 (void)fr_cap_enable(CAP_NET_BIND_SERVICE, CAP_EFFECTIVE);
702 if (bind(my->
info.
socket.
fd, (
struct sockaddr *) &salocal, salen) < 0) {
742 protocol = IPPROTO_TCP;
744 protocol = IPPROTO_UDP;
762 }
else if (cfg->
path) {
789 if (strcmp(cfg->
filename,
"/dev/stdout") == 0) {
790 if (cfg->
flags != O_WRONLY) {
796 fd = dup(STDOUT_FILENO);
798 }
else if (strcmp(cfg->
filename,
"/dev/stderr") == 0) {
799 if (cfg->
flags != O_WRONLY)
goto fail_dev;
801 fd = dup(STDERR_FILENO);
832 rcode = fcntl(fd, F_GETFD);
834 if (fcntl(fd, F_SETFD, rcode |
FD_CLOEXEC) < 0) {
901 if (rcode < 0)
goto fail;
905 if (rcode < 0)
goto fail;
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
int fr_bio_fd_socket_name(fr_bio_fd_t *my)
int fr_bio_fd_init_accept(fr_bio_fd_t *my)
int fr_bio_fd_init_connected(fr_bio_fd_t *my)
int fr_filename_to_sockaddr(struct sockaddr_un *sun, socklen_t *sunlen, char const *filename)
int fr_bio_fd_init_common(fr_bio_fd_t *my)
fr_socket_t socket
as connected socket
uint16_t src_port
our port
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
@ FR_BIO_FD_UNCONNECTED
unconnected UDP / datagram only
@ FR_BIO_FD_ACCEPT
returns new fd in buffer on fr_bio_read()
fr_bio_fd_type_t type
type of the socket
fr_bio_fd_state_t state
connecting, open, closed, etc.
uint32_t recv_buff
How big the kernel's receive buffer should be.
@ FR_BIO_FD_STATE_CONNECTING
@ FR_BIO_FD_STATE_OPEN
error states must be before this
fr_ipaddr_t dst_ipaddr
their IP address
fr_bio_fd_type_t type
accept, connected, unconnected, etc.
char const * path
for Unix domain sockets
uint32_t send_buff
How big the kernel's send buffer should be.
char const * filename
for files
uid_t uid
who owns the socket
fr_bio_fd_config_t const * cfg
so we know what was asked, vs what was granted.
gid_t gid
who owns the socket
char const * interface
for binding to an interface
mode_t perm
permissions for domain sockets
int socket_type
SOCK_STREAM or SOCK_DGRAM.
uint16_t dst_port
their port
bool tcp_delay
We do tcp_nodelay by default.
fr_ipaddr_t src_ipaddr
our IP address
Configuration for sockets.
Run-time status of the socket.
static int fr_bio_fd_socket_unix_mkdir(int *dirfd, char const **filename, fr_bio_fd_config_t const *cfg)
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.
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.
static int fr_bio_fd_server_tcp(int fd, UNUSED fr_socket_t const *sock)
Initialize a TCP server socket.
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.
static int fr_bio_fd_socket_bind(fr_bio_fd_t *my, fr_bio_fd_config_t const *cfg)
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.
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.
static int fr_bio_fd_unix_shutdown(fr_bio_t *bio)
static int fr_bio_fd_socket_bind_to_device(fr_bio_fd_t *my, fr_bio_fd_config_t const *cfg)
This system is missing SO_BINDTODEVICE, IP_BOUND_IF, IPV6_BOUND_IF.
int fr_bio_fd_open(fr_bio_t *bio, fr_bio_fd_config_t const *cfg)
Opens a socket and updates sock->fd.
static int fr_bio_fd_server_udp(int fd, fr_socket_t const *sock, fr_bio_fd_config_t const *cfg)
Initialize a UDP server socket.
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.
fr_bio_callback_t user_shutdown
user shutdown
int fr_dirfd(int *dirfd, char const **filename, char const *pathname)
From a pathname, return fd and filename needed for *at() functions.
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.
int fr_nonblock(UNUSED int fd)
int fr_socket_client_unix(UNUSED char const *path, UNUSED bool async)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
int af
AF_INET, AF_INET6, or AF_UNIX.
int fd
File descriptor if this is a live socket.
int type
SOCK_STREAM, SOCK_DGRAM, etc.
Holds information necessary for binding or connecting to a socket.
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
#define fr_strerror_const(_msg)