25 #include <freeradius-devel/bio/fd_priv.h>
26 #include <freeradius-devel/bio/null.h>
33 # define SOL_IP IPPROTO_IP
47 # ifdef IPV6_RECVPKTINFO
48 # include <linux/version.h>
49 # if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
50 # ifdef IPV6_2292PKTINFO
51 # undef IPV6_RECVPKTINFO
53 # define IPV6_RECVPKTINFO IPV6_2292PKTINFO
54 # define IPV6_PKTINFO IPV6_2292PKTINFO
58 # elif defined(IPV6_2292PKTINFO)
59 # define IPV6_RECVPKTINFO IPV6_2292PKTINFO
72 # if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
73 # define IPV6_RECVPKTINFO IPV6_PKTINFO
79 # elif !defined(IPV6_PKTINFO)
80 # undef IPV6_RECVPKTINFO
84 #define ADDR_INIT do { \
85 addr->when = fr_time(); \
86 addr->socket.type = my->info.socket.type; \
87 addr->socket.fd = -1; \
88 addr->socket.inet.ifindex = my->info.socket.inet.ifindex; \
119 if (rcode > 0)
return rcode;
135 #define flag_blocked info.read_blocked
158 if (rcode >= 0)
return rcode;
161 #define flag_blocked info.read_blocked
175 struct sockaddr_storage sockaddr;
180 salen =
sizeof(sockaddr);
182 rcode = recvfrom(my->
info.
socket.
fd,
buffer, size, 0, (
struct sockaddr *) &sockaddr, &salen);
196 if (rcode == 0 )
return rcode;
199 #define flag_blocked info.read_blocked
239 if (rcode >= 0)
return rcode;
242 #define flag_blocked info.write_blocked
258 struct sockaddr_storage sockaddr;
271 rcode = sendto(my->
info.
socket.
fd,
buffer, size, 0, (
struct sockaddr *) &sockaddr, salen);
272 if (rcode >= 0)
return rcode;
275 #define flag_blocked info.write_blocked
282 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) || defined(IPV6_PKTINFO)
287 struct sockaddr_storage from;
290 #ifdef STATIC_ANALYZER
291 from.ss_family = AF_UNSPEC;
296 memset(&my->cbuf, 0,
sizeof(my->cbuf));
297 memset(&my->msgh, 0,
sizeof(
struct msghdr));
299 my->iov = (
struct iovec) {
304 my->msgh = (
struct msghdr) {
305 .msg_control = my->cbuf,
306 .msg_controllen =
sizeof(my->cbuf),
308 .msg_namelen =
sizeof(from),
320 &from, my->msgh.msg_namelen);
325 if (rcode == 0)
return rcode;
328 #define flag_blocked info.read_blocked
335 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
342 struct cmsghdr *cmsg;
347 rcode = fd_fd_recvfromto_common(my, packet_ctx,
buffer, size);
348 if (rcode <= 0)
return rcode;
352 for (cmsg = CMSG_FIRSTHDR(&my->msgh);
354 cmsg = CMSG_NXTHDR(&my->msgh, cmsg)) {
358 if ((cmsg->cmsg_level ==
SOL_IP) &&
359 (cmsg->cmsg_type == IP_PKTINFO)) {
360 struct in_pktinfo *i = (
struct in_pktinfo *) CMSG_DATA(cmsg);
361 struct sockaddr_in to;
363 to.sin_addr = i->ipi_addr;
366 (
struct sockaddr_storage *) &to,
sizeof(
struct sockaddr_in));
367 addr->
socket.inet.ifindex = i->ipi_ifindex;
372 #ifdef IP_RECVDSTADDR
373 if ((cmsg->cmsg_level == IPPROTO_IP) &&
374 (cmsg->cmsg_type == IP_RECVDSTADDR)) {
375 struct in_addr *i = (
struct in_addr *) CMSG_DATA(cmsg);
376 struct sockaddr_in to;
380 (
struct sockaddr_storage *) &to,
sizeof(
struct sockaddr_in));
385 #ifdef SO_TIMESTAMPNS
386 if ((cmsg->cmsg_level ==
SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
390 #elif defined(SO_TIMESTAMP)
391 if ((cmsg->cmsg_level ==
SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
410 struct cmsghdr *cmsg;
411 struct sockaddr_storage to;
418 memset(&my->cbuf, 0,
sizeof(my->cbuf));
419 memset(&my->msgh, 0,
sizeof(
struct msghdr));
423 my->iov = (
struct iovec) {
428 my->msgh = (
struct msghdr) {
429 .msg_control = my->cbuf,
432 .msg_namelen = to_len,
438 cmsg = CMSG_FIRSTHDR(&my->msgh);
442 struct in_pktinfo *pkt;
444 my->msgh.msg_controllen = CMSG_SPACE(
sizeof(*pkt));
446 cmsg->cmsg_level =
SOL_IP;
447 cmsg->cmsg_type = IP_PKTINFO;
448 cmsg->cmsg_len = CMSG_LEN(
sizeof(*pkt));
450 pkt = (
struct in_pktinfo *) CMSG_DATA(cmsg);
451 memset(pkt, 0,
sizeof(*pkt));
452 pkt->ipi_spec_dst = addr->
socket.inet.src_ipaddr.addr.v4;
453 pkt->ipi_ifindex = addr->
socket.inet.ifindex;
455 #elif defined(IP_SENDSRCADDR)
458 my->msgh.msg_controllen = CMSG_SPACE(
sizeof(*
in));
460 cmsg->cmsg_level = IPPROTO_IP;
461 cmsg->cmsg_type = IP_SENDSRCADDR;
462 cmsg->cmsg_len = CMSG_LEN(
sizeof(*
in));
464 in = (
struct in_addr *) CMSG_DATA(cmsg);
465 *
in = addr->
socket.inet.src_ipaddr.addr.v4;
471 if (rcode >= 0)
return rcode;
474 #define flag_blocked info.write_blocked
480 static inline int fr_bio_fd_udpfromto_init4(
int fd)
482 int proto = 0, flag = 0, opt = 1;
484 #ifdef HAVE_IP_PKTINFO
491 #elif defined(IP_RECVDSTADDR)
497 flag = IP_RECVDSTADDR;
500 return setsockopt(fd,
proto, flag, &opt,
sizeof(opt));
504 #if defined(IPV6_PKTINFO)
510 struct cmsghdr *cmsg;
515 rcode = fd_fd_recvfromto_common(my, packet_ctx,
buffer, size);
516 if (rcode <= 0)
return rcode;
520 for (cmsg = CMSG_FIRSTHDR(&my->msgh);
522 cmsg = CMSG_NXTHDR(&my->msgh, cmsg)) {
525 if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
526 (cmsg->cmsg_type == IPV6_PKTINFO)) {
527 struct in6_pktinfo *i = (
struct in6_pktinfo *) CMSG_DATA(cmsg);
528 struct sockaddr_in6 to;
530 to.sin6_addr = i->ipi6_addr;
533 (
struct sockaddr_storage *) &to,
sizeof(
struct sockaddr_in6));
534 addr->
socket.inet.ifindex = i->ipi6_ifindex;
538 #ifdef SO_TIMESTAMPNS
539 if ((cmsg->cmsg_level ==
SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
543 #elif defined(SO_TIMESTAMP)
544 if ((cmsg->cmsg_level ==
SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
563 struct cmsghdr *cmsg;
564 struct sockaddr_storage to;
571 memset(&my->cbuf, 0,
sizeof(my->cbuf));
572 memset(&my->msgh, 0,
sizeof(
struct msghdr));
576 my->iov = (
struct iovec) {
581 my->msgh = (
struct msghdr) {
582 .msg_control = my->cbuf,
585 .msg_namelen = to_len,
591 cmsg = CMSG_FIRSTHDR(&my->msgh);
594 struct in6_pktinfo *pkt;
596 my->msgh.msg_controllen = CMSG_SPACE(
sizeof(*pkt));
598 cmsg->cmsg_level = IPPROTO_IPV6;
599 cmsg->cmsg_type = IPV6_PKTINFO;
600 cmsg->cmsg_len = CMSG_LEN(
sizeof(*pkt));
602 pkt = (
struct in6_pktinfo *) CMSG_DATA(cmsg);
603 memset(pkt, 0,
sizeof(*pkt));
604 pkt->ipi6_addr = addr->
socket.inet.src_ipaddr.addr.v6;
605 pkt->ipi6_ifindex = addr->
socket.inet.ifindex;
610 if (rcode >= 0)
return rcode;
613 #define flag_blocked info.write_blocked
620 static inline int fr_bio_fd_udpfromto_init6(
int fd)
624 return setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt,
sizeof(opt));
632 len = strlen(filename);
633 if (len >=
sizeof(sun->sun_path)) {
634 fr_strerror_const(
"Failed parsing unix domain socket filename: Name is too long");
638 sun->sun_family = AF_LOCAL;
639 memcpy(sun->sun_path, filename, len + 1);
641 *sunlen = SUN_LEN(sun);
649 struct sockaddr_storage salocal;
661 salen =
sizeof(salocal);
662 memset(&salocal, 0, salen);
663 if (getsockname(my->
info.
socket.
fd, (
struct sockaddr *) &salocal, &salen) < 0) {
687 struct sockaddr_storage sockaddr;
703 if (connect(my->
info.
socket.
fd, (
struct sockaddr *) &sockaddr, salen) == 0) {
719 if (tries <= my->max_tries)
goto retry;
758 switch (my->
info.
cfg->
flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
825 setsockopt(my->
info.
socket.
fd, SOL_SOCKET, SO_NOSIGPIPE, &on,
sizeof(on));
835 if (rcode == 0)
return 0;
837 if (rcode !=
fr_bio_error(IO_WOULD_BLOCK))
return rcode;
859 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
860 }
else if (my->
info.
socket.inet.src_ipaddr.
af == AF_INET) {
861 if (fr_bio_fd_udpfromto_init4(my->
info.
socket.
fd) < 0)
return -1;
863 my->bio.read = fr_bio_fd_recvfromto4;
864 my->bio.write = fr_bio_fd_sendfromto4;
867 #if defined(IPV6_PKTINFO)
868 }
else if (my->
info.
socket.inet.src_ipaddr.
af == AF_INET6) {
870 if (fr_bio_fd_udpfromto_init6(my->
info.
socket.
fd) < 0)
return -1;
872 my->bio.read = fr_bio_fd_recvfromto6;
873 my->bio.write = fr_bio_fd_sendfromto6;
898 struct sockaddr_storage sockaddr;
900 if (size <
sizeof(
int))
return fr_bio_error(BUFFER_TOO_SMALL);
902 salen =
sizeof(sockaddr);
909 fd = accept4(my->
info.
socket.
fd, (
struct sockaddr *) &sockaddr, &salen, SOCK_NONBLOCK | SOCK_CLOEXEC);
911 fd = accept(my->
info.
socket.
fd, (
struct sockaddr *) &sockaddr, &salen);
935 if (tries <= my->max_tries)
goto retry;
942 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1023 if (!my)
return NULL;
1025 if (cb) my->cb = *cb;
1038 .read_blocked =
true,
1039 .write_blocked =
true,
1074 if (rcode < 0)
return rcode;
1101 if (tries < my->max_tries)
goto retry;
1128 socklen_t socklen =
sizeof(error);
1148 if (getsockopt(my->
info.
socket.
fd, SOL_SOCKET, SO_ERROR, (
void *)&error, &socklen) < 0) {
1187 if (rcode >= 0)
return 0;
1190 #define flag_blocked info.read_blocked
static int const char char buffer[256]
fr_bio_write_t _CONST write
write to the underlying bio
fr_bio_read_t _CONST read
read from the underlying bio
static fr_bio_t * fr_bio_prev(fr_bio_t *bio)
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
static ssize_t fr_bio_fd_read_discard(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Discard all reads from a UDP socket.
fr_bio_fd_info_t const * fr_bio_fd_info(fr_bio_t *bio)
Returns a pointer to the bio-specific information.
static ssize_t fr_bio_fd_write(fr_bio_t *bio, UNUSED void *packet_ctx, const void *buffer, size_t size)
Write to fd.
int fr_bio_fd_socket_name(fr_bio_fd_t *my)
fr_bio_t * fr_bio_fd_alloc(TALLOC_CTX *ctx, fr_bio_cb_funcs_t *cb, fr_bio_fd_config_t const *cfg, size_t offset)
Allocate a FD bio.
int fr_bio_fd_init_accept(fr_bio_fd_t *my)
int fr_bio_fd_connect(fr_bio_t *bio)
Finalize a connect()
int fr_bio_fd_init_connected(fr_bio_fd_t *my)
static ssize_t fr_bio_fd_read_connected_datagram(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Connected datagram read.
static ssize_t fr_bio_fd_try_connect(fr_bio_fd_t *my)
Try to connect().
static ssize_t fr_bio_fd_recvfrom(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Read from a UDP socket where we know our IP.
static ssize_t fr_bio_fd_sendto(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
Write to a UDP socket where we know our IP.
int fr_filename_to_sockaddr(struct sockaddr_un *sun, socklen_t *sunlen, char const *filename)
static ssize_t fr_bio_fd_read_accept(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Return an fd on read()
static int fr_bio_fd_init_file(fr_bio_fd_t *my)
Files are a special case of connected sockets.
static int fr_bio_fd_destructor(fr_bio_fd_t *my)
int fr_bio_fd_init_common(fr_bio_fd_t *my)
int fr_bio_fd_write_only(fr_bio_t *bio)
Mark up a bio as write-only.
int fr_bio_fd_close(fr_bio_t *bio)
Close the FD, but leave the bio allocated and alive.
static ssize_t fr_bio_fd_read_stream(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Stream read.
fr_socket_t socket
as connected socket
@ 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.
@ FR_BIO_FD_STATE_CONNECTING
@ FR_BIO_FD_STATE_OPEN
error states must be before this
fr_bio_fd_config_t const * cfg
so we know what was asked, vs what was granted.
bool read_blocked
did we block on read?
int fr_bio_fd_open(fr_bio_t *bio, fr_bio_fd_config_t const *cfg)
Opens a socket and updates sock->fd.
fr_socket_t socket
socket information, including FD.
bool write_blocked
did we block on write?
Configuration for sockets.
Run-time status of the socket.
size_t offset
where fr_bio_fd_packet_ctx_t is stored
int max_tries
how many times we retry on EINTR
#define fr_bio_fd_packet_ctx(_my, _packet_ctx)
void fr_ipaddr_get_scope_id(fr_ipaddr_t *ipaddr)
int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port, struct sockaddr_storage const *sa, socklen_t salen)
Convert sockaddr to our internal ip address representation.
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
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.
ssize_t fr_bio_eof_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
Always returns EOF on fr_bio_read()
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
ssize_t fr_bio_null_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
Always return 0 on write.
ssize_t fr_bio_null_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
Always return 0 on read.
static char const * proto(int id, int porttype)
#define fr_time()
Allow us to arbitrarily manipulate time.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
static fr_time_t fr_time_from_timeval(struct timeval const *when_tv)
Convert a timeval (wallclock time) to a fr_time_t (internal time)
#define fr_time_wrap(_time)
#define fr_time_eq(_a, _b)
static fr_time_t fr_time_from_timespec(struct timespec const *when_ts)
Convert a timespec (wallclock time) to a fr_time_t (internal time)
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.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)