From 18fdb0d6ecfd7ec8090ed7164fd6e4895a89e12b Mon Sep 17 00:00:00 2001 From: Dylan Taft Date: Sat, 14 Oct 2023 16:52:25 -0400 Subject: [PATCH] ipv6: Add support for RFC5014 for Linux Linux has a sockopt flag defined by RFC5014 that informs IPv6 systems with SLAAC config to prefer to bind the socket to a public address instead of any temporary private address. This patch adds a client info flag LCCSCF_IPV6_PREFER_PUBLIC_ADDR that lets the user indicate the client socket should be prepared with the public address binding preference. Currently it's only implemented on Linux. --- CMakeLists.txt | 1 + cmake/lws_config.h.in | 2 +- include/libwebsockets/lws-client.h | 5 +++++ lib/plat/unix/unix-sockets.c | 26 +++++++++++++++++++++++++- lib/plat/windows/windows-sockets.c | 10 ++++++++++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 321c5bd6e..802e2a2ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -658,6 +658,7 @@ CHECK_C_SOURCE_COMPILES("#include \nvoid main(void) { while(1) ; } voi CHECK_C_SOURCE_COMPILES("#include \nvoid main(void) { while(1) ; } void xxexit(void){}" LWS_HAVE_PTHREAD_H) CHECK_C_SOURCE_COMPILES("#include \nvoid main(void) { while(1) ; } void xxexit(void){}" LWS_HAVE_INTTYPES_H) CHECK_C_SOURCE_COMPILES("#include \nvoid main(void) { while(1) ; } void xxexit(void){}" LWS_HAVE_SYS_RESOURCE_H) +CHECK_C_SOURCE_COMPILES("#include \nvoid main(void) { while(1) ; } void xxexit(void){}" LWS_HAVE_LINUX_IPV6_H) if (LWS_EXT_PTHREAD_INCLUDE_DIR) set(LWS_HAVE_PTHREAD_H 1) diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in index 5a9e1a2ff..041cd8719 100644 --- a/cmake/lws_config.h.in +++ b/cmake/lws_config.h.in @@ -258,4 +258,4 @@ #cmakedefine LWS_WITH_PLUGINS_API #cmakedefine LWS_HAVE_RTA_PREF #cmakedefine PICO_SDK_PATH - +#cmakedefine LWS_HAVE_LINUX_IPV6_H diff --git a/include/libwebsockets/lws-client.h b/include/libwebsockets/lws-client.h index a0c390d2a..dd474a9cf 100644 --- a/include/libwebsockets/lws-client.h +++ b/include/libwebsockets/lws-client.h @@ -56,6 +56,11 @@ enum lws_client_connect_ssl_connection_flags { * then it is not possible to bind to this port for any local address */ + LCCSCF_IPV6_PREFER_PUBLIC_ADDR = (1 << 15), + /**< RFC5014 - For IPv6 systems with SLAAC config, allow for preference + * to bind a socket to public address vs temporary private address + */ + LCCSCF_PIPELINE = (1 << 16), /**< Serialize / pipeline multiple client connections * on a single connection where possible. diff --git a/lib/plat/unix/unix-sockets.c b/lib/plat/unix/unix-sockets.c index 2a3069b54..e06e83b3b 100644 --- a/lib/plat/unix/unix-sockets.c +++ b/lib/plat/unix/unix-sockets.c @@ -1,7 +1,7 @@ /* * libwebsockets - small server side websockets and web server implementation * - * Copyright (C) 2010 - 2019 Andy Green + * Copyright (C) 2010 - 2023 Andy Green * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -27,6 +27,10 @@ #endif #include "private-lib-core.h" +#if defined(LWS_HAVE_LINUX_IPV6_H) +#include +#endif + #include #if !defined(LWS_DETECTED_PLAT_IOS) @@ -273,6 +277,26 @@ lws_plat_set_socket_options_ip(lws_sockfd_type fd, uint8_t pri, int lws_flags) } + if (lws_flags & LCCSCF_IPV6_PREFER_PUBLIC_ADDR) { +#if defined(LWS_WITH_IPV6) && defined(IPV6_PREFER_SRC_PUBLIC) + optval = IPV6_PREFER_SRC_PUBLIC; + + if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES, + (const void *)&optval, optlen) < 0) { + #if (_LWS_ENABLED_LOGS & LLL_WARN) + en = errno; + lwsl_warn("%s: unable to set IPV6_PREFER_SRC_PUBLIC: errno %d\n", + __func__, en); + #endif + ret = 1; + } else + lwsl_notice("%s: set IPV6_PREFER_SRC_PUBLIC\n", __func__); +#else + lwsl_err("%s: IPV6_PREFER_SRC_PUBLIC UNIMPLEMENTED on this platform\n", __func__); +#endif + } + + #if !defined(__NuttX__) for (n = 0; n < 4; n++) { if (!(lws_flags & ip_opt_lws_flags[n])) diff --git a/lib/plat/windows/windows-sockets.c b/lib/plat/windows/windows-sockets.c index 9e8ce2656..0099d2f06 100644 --- a/lib/plat/windows/windows-sockets.c +++ b/lib/plat/windows/windows-sockets.c @@ -193,6 +193,16 @@ lws_plat_set_socket_options_ip(lws_sockfd_type fd, uint8_t pri, int lws_flags) } else lwsl_notice("%s: set use exclusive addresses\n", __func__); } + + +#if defined(LWS_WITH_IPV6) + /* I do not believe Microsoft supports RFC5014 + * Instead, you must set lws_client_connect_info::iface */ + if (lws_flags & LCCSCF_IPV6_PREFER_PUBLIC_ADDR) { + lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__); + } +#endif + return ret;