This is an automated email from the ASF dual-hosted git repository.
cmcfarlen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 2ac2ff24e1 Add support for Unix Domain Socket server (#12031)
2ac2ff24e1 is described below
commit 2ac2ff24e1aa750a94222086f5ca67f9c8b4ac83
Author: Chris McFarlen <[email protected]>
AuthorDate: Thu Feb 20 14:21:03 2025 -0600
Add support for Unix Domain Socket server (#12031)
* Add support for Unix Domain Socket server
(cherry picked from commit ebeb3e7ce4c9aef37f55554a2c3350a575980833)
(cherry picked from commit aeb355c6e500e032830577e500650411742f118a)
* support unix domain socket per listen thread
(cherry picked from commit d7bd4eb2ac69760d538dc07dfef22934ee28eed0)
(cherry picked from commit 71017c0c888ceb8569212f65c039197b24346a57)
* add check for sun_len
(cherry picked from commit c22ad1e29de3ea8d9d182383a04e3351a92c6a6b)
(cherry picked from commit f52eadc6c9dd3e05cbf58c7a46a1745ee2cdfb20)
* allow all acl for unix socket
(cherry picked from commit 682a664eaae6fae10473f5f39924014f9e8e6ce3)
(cherry picked from commit c99f4f85a0dc7f498ea2925bf534b3a1ce55c96a)
* chmod unix socket after bind
* Dont specify destination for unix socket iov
(cherry picked from commit 239c8f333bed8c926c77048adfa0d64c017561e0)
(cherry picked from commit 6fe907766139fa7f0d405c22a64a9d4012289e2b)
* Use IP address form Proxy protocol for ACLs
(cherry picked from commit 02b09634ff7d7a1acacb2d1709d17147faaa2d48)
(cherry picked from commit 4d46aa22985f7038856aef67a70bc5eb5837f034)
* Use IP address form Proxy protocol for Remap ACLs as well
(cherry picked from commit ca746dc1f6cec60e04404ed20195e40a65ca38c5)
(cherry picked from commit 6d82ac5029581cb951207a0c2409d4e3d977d00f)
* Reenable method ACL in remap rules (a fix for regression)
(cherry picked from commit 553f96820fbb0a8804e6ae6c2ebca29e03f4c46d)
(cherry picked from commit 8635fe35e02415b9846248231ee9f413d53b69dc)
* Don't use TCP socket options for UDS
(cherry picked from commit 3848f7165ef7edffd516d71706db8f69dab1344d)
(cherry picked from commit 6627e48b19371cbfad1772e474778e603ac30614)
* Add docs for configuring domain socket ports
(cherry picked from commit 67d5d79d4a56451627149fb32193f2fba5f452f0)
* fix linux build issue
* Check socket type before pcap
* Fixes for c++20
* address clang-analyzer warning
* Dont use proxyprotocol data for acls yet.
* use correct src_addr
* Clear SOCK_OPT_TCP_NOTSENT_LOWAT for domain sockets
* Address PR requests
---------
Co-authored-by: Chris McFarlen <[email protected]>
Co-authored-by: Masakazu Kitajo <[email protected]>
---
CMakeLists.txt | 1 +
doc/admin-guide/files/records.yaml.en.rst | 67 ++++++-----
include/iocore/net/AcceptOptions.h | 1 +
include/proxy/logging/LogField.h | 6 +
include/records/RecHttp.h | 2 +
include/tscore/ink_config.h.cmake.in | 1 +
include/tscore/ink_inet.h | 179 ++++++++++++++++++++++++++++--
src/iocore/net/Server.cc | 24 ++--
src/iocore/net/UnixNetAccept.cc | 5 +
src/iocore/net/UnixNetProcessor.cc | 8 +-
src/iocore/net/UnixNetVConnection.cc | 12 +-
src/proxy/http/HttpProxyServerMain.cc | 4 +
src/proxy/http/HttpSessionAccept.cc | 17 ++-
src/proxy/http/remap/UrlRewrite.cc | 63 ++++++-----
src/proxy/logging/LogAccess.cc | 7 ++
src/records/RecHttp.cc | 23 +++-
src/tscore/ink_inet.cc | 7 ++
src/tscore/unit_tests/test_ink_inet.cc | 21 ++++
18 files changed, 356 insertions(+), 92 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a993424882..e691ab2c94 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -545,6 +545,7 @@ check_struct_has_member("struct tcp_info" __tcpi_retrans
"netinet/tcp.h" HAVE_ST
check_struct_has_member("struct sockaddr" sa_len "netinet/in.h"
HAVE_STRUCT_SOCKADDR_SA_LEN)
check_struct_has_member("struct sockaddr_in" sin_len "netinet/in.h"
HAVE_STRUCT_SOCKADDR_IN_SIN_LEN)
check_struct_has_member("struct sockaddr_in6" sin6_len "netinet/in.h"
HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN)
+check_struct_has_member("struct sockaddr_un" sun_len "sys/un.h"
HAVE_STRUCT_SOCKADDR_UN_SUN_LEN)
check_struct_has_member("struct stat" st_mtimespec "sys/stat.h"
HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
check_struct_has_member("struct stat" st_mtim "sys/stat.h"
HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
check_struct_has_member("struct mptcp_info" mptcpi_subflows "linux/mptcp.h"
HAVE_STRUCT_MPTCP_INFO_SUBFLOWS)
diff --git a/doc/admin-guide/files/records.yaml.en.rst
b/doc/admin-guide/files/records.yaml.en.rst
index 356764ce93..07d8b920b2 100644
--- a/doc/admin-guide/files/records.yaml.en.rst
+++ b/doc/admin-guide/files/records.yaml.en.rst
@@ -378,7 +378,10 @@ Thread Variables
.. ts:cv:: CONFIG proxy.config.exec_thread.listen INT 0
If enabled (``1``) all the exec_threads listen for incoming connections.
`proxy.config.accept_threads`
- should be disabled to enable this variable.
+ should be disabled to enable this variable. If a unix domain path is
+ configured as a server port and this setting is enabled, each exec thread
+ will create its own domain socket with a ``-<thread id>`` suffix added to
the
+ end of the path.
.. ts:cv:: CONFIG proxy.config.accept_threads INT 1
@@ -711,31 +714,36 @@ HTTP Engine
Quick reference chart:
- =========== =============== ========================================
- Name Note Definition
- =========== =============== ========================================
- *number* Required The local port.
- blind Blind (``CONNECT``) port.
- compress Not Implemented Compressed.
- ipv4 Default Bind to IPv4 address family.
- ipv6 Bind to IPv6 address family.
- ip-in Value Local inbound IP address.
- ip-out Value Local outbound IP address.
- ip-resolve Value IP address resolution style.
- proto Value List of supported session protocols.
- pp Enable Proxy Protocol.
- ssl SSL terminated.
- quic QUIC terminated.
- tr-full Fully transparent (inbound and outbound)
- tr-in Inbound transparent.
- tr-out Outbound transparent.
- tr-pass Pass through enabled.
- mptcp Multipath TCP.
- allow-plain Allow failback to non-TLS for TLS ports
- =========== =============== ========================================
-
-*number*
- Local IP port to bind. This is the port to which ATS clients will connect.
+ ============ =============== ========================================
+ Name Note Definition
+ ============ =============== ========================================
+ *port/path* Required The local IP port or Unix domain path.
+ blind Blind (``CONNECT``) port.
+ compress Not Implemented Compressed.
+ ipv4 Default Bind to IPv4 address family.
+ ipv6 Bind to IPv6 address family.
+ ip-in Value Local inbound IP address.
+ ip-out Value Local outbound IP address.
+ ip-resolve Value IP address resolution style.
+ proto Value List of supported session protocols.
+ pp Enable Proxy Protocol.
+ ssl SSL terminated.
+ quic QUIC terminated.
+ tr-full Fully transparent (inbound and outbound)
+ tr-in Inbound transparent.
+ tr-out Outbound transparent.
+ tr-pass Pass through enabled.
+ mptcp Multipath TCP.
+ allow-plain Allow failback to non-TLS for TLS ports
+ ============ =============== ========================================
+
+*port*
+ Local IP port number to bind. This is the port to which ATS clients will
connect.
+
+*path*
+ Unix Domain Socket path to bind to. This socket will be available for local
+ clients to connect to. Some port descriptors below are not applicable to
+ domain sockets.
blind
Accept only the ``CONNECT`` method on this port.
@@ -826,6 +834,13 @@ allow-plain
80 80:ipv6
+.. topic:: Example
+
+ Listen on unix domain socket at /var/run/trafficserver/proxy.sock and enable
+ Proxy Protocol
+
+ /var/run/trafficserver/proxy.sock:pp
+
.. topic:: Example
Listen transparently on any IPv4 address on port 8080, and
diff --git a/include/iocore/net/AcceptOptions.h
b/include/iocore/net/AcceptOptions.h
index 88b34fd0af..ed3c1d727d 100644
--- a/include/iocore/net/AcceptOptions.h
+++ b/include/iocore/net/AcceptOptions.h
@@ -35,6 +35,7 @@ struct AcceptOptions {
/// Local address to bind for accept.
/// If not set -> any address.
IpAddr local_ip;
+ UnAddr local_path;
/// IP address family.
/// @note Ignored if an explicit incoming address is set in the
/// the configuration (@c local_ip). If neither is set IPv4 is used.
diff --git a/include/proxy/logging/LogField.h b/include/proxy/logging/LogField.h
index 111aaa6937..dcc5b23bb0 100644
--- a/include/proxy/logging/LogField.h
+++ b/include/proxy/logging/LogField.h
@@ -27,6 +27,7 @@
#include <string>
#include <variant>
+#include "tscore/ink_inet.h"
#include "tscore/ink_platform.h"
#include "tscore/List.h"
#include "proxy/logging/LogFieldAliasMap.h"
@@ -294,9 +295,14 @@ struct LogFieldIp4 : public LogFieldIp {
struct LogFieldIp6 : public LogFieldIp {
in6_addr _addr; ///< IPv6 address.
};
+/// Unix address as log field.
+struct LogFieldUn : public LogFieldIp {
+ char _path[TS_UNIX_SIZE]; ///< Unix domain path
+};
/// Something big enough to hold any of the IP field types.
union LogFieldIpStorage {
LogFieldIp _ip;
LogFieldIp4 _ip4;
LogFieldIp6 _ip6;
+ LogFieldUn _un;
};
diff --git a/include/records/RecHttp.h b/include/records/RecHttp.h
index 4bb3df37b8..3efa034bac 100644
--- a/include/records/RecHttp.h
+++ b/include/records/RecHttp.h
@@ -277,6 +277,8 @@ public:
bool m_mptcp = false;
/// Local address for inbound connections (listen address).
IpAddr m_inbound_ip;
+ /// Path for listening on unix domain socket
+ UnAddr m_unix_path;
/// Local address for outbound connections (to origin server).
ts::IPAddrPair m_outbound;
/// Ordered preference for DNS resolution family ( @c FamilyPrefence )
diff --git a/include/tscore/ink_config.h.cmake.in
b/include/tscore/ink_config.h.cmake.in
index 99036c6ec6..d243952d07 100644
--- a/include/tscore/ink_config.h.cmake.in
+++ b/include/tscore/ink_config.h.cmake.in
@@ -99,6 +99,7 @@
#cmakedefine HAVE_STRUCT_SOCKADDR_SA_LEN 1
#cmakedefine HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 1
#cmakedefine HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN 1
+#cmakedefine HAVE_STRUCT_SOCKADDR_UN_SUN_LEN 1
#cmakedefine HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
#cmakedefine HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1
#cmakedefine HAVE_SYSCTLBYNAME 1
diff --git a/include/tscore/ink_inet.h b/include/tscore/ink_inet.h
index 98f3b236d9..22cd738bbf 100644
--- a/include/tscore/ink_inet.h
+++ b/include/tscore/ink_inet.h
@@ -28,6 +28,7 @@
#include <netdb.h>
#include <sys/socket.h>
#include <string_view>
+#include <sys/un.h>
#include "swoc/swoc_ip.h"
@@ -78,6 +79,7 @@ extern const std::string_view IP_PROTO_TAG_HTTP_QUIC_D29;
extern const std::string_view IP_PROTO_TAG_HTTP_3_D29;
struct IpAddr; // forward declare.
+struct UnAddr; // forward declare.
/** A union to hold the standard IP address structures.
By standard we mean @c sockaddr compliant.
@@ -100,6 +102,7 @@ union IpEndpoint {
struct sockaddr sa; ///< Generic address.
struct sockaddr_in sin; ///< IPv4
struct sockaddr_in6 sin6; ///< IPv6
+ struct sockaddr_un sun; ///< domain
/** Assign from a socket address.
The entire address (all parts) are copied if the @a ip is valid.
@@ -110,6 +113,7 @@ union IpEndpoint {
self &assign(IpAddr const &addr, ///< Address and address family.
in_port_t port = 0 ///< Port (network byte order).
);
+ self &assign(UnAddr const &addr);
/// Test for valid IP address.
bool isValid() const;
@@ -186,6 +190,7 @@ const char *ats_ip_ntop(const struct sockaddr *addr, char
*dst, size_t size);
/// Size in bytes of an port and IPv4/IPv6 address.
static constexpr size_t TS_IP4_SIZE = sizeof(in_addr_t); ///< 4
static constexpr size_t TS_IP6_SIZE = sizeof(in6_addr); ///< 16
+static constexpr size_t TS_UNIX_SIZE = sizeof(sockaddr_un::sun_path);
static constexpr size_t TS_PORT_SIZE = sizeof(in_port_t); ///< 2
/// Reset an address to invalid.
@@ -224,6 +229,7 @@ ats_is_ip(IpEndpoint const *addr)
{
return addr && (AF_INET == addr->sa.sa_family || AF_INET6 ==
addr->sa.sa_family);
}
+
/// Test for IP protocol.
/// @return @c true if the value is an IP address family, @c false otherwise.
inline bool
@@ -262,6 +268,17 @@ ats_is_ip6(IpEndpoint const *addr)
return addr && AF_INET6 == addr->sa.sa_family;
}
+inline bool
+ats_is_unix(sockaddr const *addr)
+{
+ return addr && AF_UNIX == addr->sa_family;
+}
+inline bool
+ats_is_unix(IpEndpoint const *addr)
+{
+ return addr && AF_UNIX == addr->sa.sa_family;
+}
+
/// @return @c true if the address families are compatible.
inline bool
ats_ip_are_compatible(sockaddr const *lhs, ///< Address to test.
@@ -295,6 +312,26 @@ ats_ip_are_compatible(sockaddr const *lhs, ///< Address to
test.
return lhs->sa_family == rhs;
}
+/// @return the path length not including the \0
+inline int
+ats_unix_path_len(sockaddr_un *s)
+{
+ return strnlen(s->sun_path, TS_UNIX_SIZE);
+}
+
+inline void
+ats_unix_append_id(sockaddr_un *s, int id)
+{
+ char tmp[16];
+ int cnt = snprintf(tmp, sizeof(tmp), "-%d", id);
+ if (static_cast<size_t>(ats_unix_path_len(s) + cnt) < TS_UNIX_SIZE) {
+ strncat(s->sun_path, tmp, cnt);
+#if HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
+ s->sun_len = SUN_LEN(s);
+#endif
+ }
+}
+
// IP address casting.
// sa_cast to cast to sockaddr*.
// ss_cast to cast to sockaddr_storage*.
@@ -334,6 +371,17 @@ ats_ip_sa_cast(sockaddr_in6 const *a)
return static_cast<sockaddr const *>(static_cast<void const *>(a));
}
+inline sockaddr *
+ats_ip_sa_cast(sockaddr_un *a)
+{
+ return static_cast<sockaddr *>(static_cast<void *>(a));
+}
+inline constexpr sockaddr const *
+ats_ip_sa_cast(sockaddr_un const *a)
+{
+ return static_cast<sockaddr const *>(static_cast<void const *>(a));
+}
+
inline sockaddr_storage *
ats_ip_ss_cast(sockaddr *a)
{
@@ -410,31 +458,64 @@ ats_ip6_cast(sockaddr const &a)
return *static_cast<sockaddr_in6 const *>(static_cast<void const *>(&a));
}
+inline sockaddr_un *
+ats_unix_cast(sockaddr *a)
+{
+ return static_cast<sockaddr_un *>(static_cast<void *>(a));
+}
+inline sockaddr_un const *
+ats_unix_cast(sockaddr const *a)
+{
+ return static_cast<sockaddr_un const *>(static_cast<void const *>(a));
+}
+inline sockaddr_un &
+ats_unix_cast(sockaddr &a)
+{
+ return *static_cast<sockaddr_un *>(static_cast<void *>(&a));
+}
+inline sockaddr_un const &
+ats_unix_cast(sockaddr const &a)
+{
+ return *static_cast<sockaddr_un const *>(static_cast<void const *>(&a));
+}
+
/// @return The @c sockaddr size for the family of @a addr.
inline size_t
ats_ip_size(sockaddr const *addr ///< Address object.
)
{
- return AF_INET == addr->sa_family ? sizeof(sockaddr_in) : AF_INET6 ==
addr->sa_family ? sizeof(sockaddr_in6) : 0;
+ return AF_INET == addr->sa_family ? sizeof(sockaddr_in) :
+ AF_INET6 == addr->sa_family ? sizeof(sockaddr_in6) :
+ AF_UNIX == addr->sa_family ? sizeof(sockaddr_un) :
+ 0;
}
inline size_t
ats_ip_size(IpEndpoint const *addr ///< Address object.
)
{
- return AF_INET == addr->sa.sa_family ? sizeof(sockaddr_in) : AF_INET6 ==
addr->sa.sa_family ? sizeof(sockaddr_in6) : 0;
+ return AF_INET == addr->sa.sa_family ? sizeof(sockaddr_in) :
+ AF_INET6 == addr->sa.sa_family ? sizeof(sockaddr_in6) :
+ AF_UNIX == addr->sa.sa_family ? sizeof(sockaddr_un) :
+ 0;
}
/// @return The size of the IP address only.
inline size_t
ats_ip_addr_size(sockaddr const *addr ///< Address object.
)
{
- return AF_INET == addr->sa_family ? sizeof(in_addr_t) : AF_INET6 ==
addr->sa_family ? sizeof(in6_addr) : 0;
+ return AF_INET == addr->sa_family ? sizeof(in_addr_t) :
+ AF_INET6 == addr->sa_family ? sizeof(in6_addr) :
+ AF_UNIX == addr->sa_family ? sizeof(sockaddr_un::sun_path) :
+ 0;
}
inline size_t
ats_ip_addr_size(IpEndpoint const *addr ///< Address object.
)
{
- return AF_INET == addr->sa.sa_family ? sizeof(in_addr_t) : AF_INET6 ==
addr->sa.sa_family ? sizeof(in6_addr) : 0;
+ return AF_INET == addr->sa.sa_family ? sizeof(in_addr_t) :
+ AF_INET6 == addr->sa.sa_family ? sizeof(in6_addr) :
+ AF_UNIX == addr->sa.sa_family ? sizeof(sockaddr_un::sun_path) :
+ 0;
}
/** Get a reference to the port in an address.
@@ -738,6 +819,9 @@ ats_ip_copy(sockaddr *dst, ///< Destination object.
case AF_INET6:
n = sizeof(sockaddr_in6);
break;
+ case AF_UNIX:
+ n = sizeof(sockaddr_un);
+ break;
}
}
if (n) {
@@ -825,8 +909,14 @@ ats_ip_addr_cmp(sockaddr const *lhs, ///< Left hand
operand.
} else {
zret = 1; // IPv6 greater than any other type.
}
- } else if (AF_INET == rtype || AF_INET6 == rtype) {
- // ltype is non-IP so it's less than either IP type.
+ } else if (AF_UNIX == ltype) {
+ if (AF_UNIX == rtype) {
+ zret = strncmp(ats_unix_cast(lhs)->sun_path,
ats_unix_cast(rhs)->sun_path, TS_UNIX_SIZE);
+ } else {
+ zret = -1; // UNIX < all
+ }
+ } else if (AF_INET == rtype || AF_INET6 == rtype || AF_UNIX == rtype) {
+ // ltype is non-IP/unix so it's less than either IP/unix type.
zret = -1;
} else {
// Both types are non-IP so they're equal.
@@ -877,11 +967,15 @@ inline bool
ats_ip_addr_port_eq(sockaddr const *lhs, sockaddr const *rhs)
{
bool zret = false;
- if (lhs->sa_family == rhs->sa_family && ats_ip_port_cast(lhs) ==
ats_ip_port_cast(rhs)) {
- if (AF_INET == lhs->sa_family) {
- zret = ats_ip4_cast(lhs)->sin_addr.s_addr ==
ats_ip4_cast(rhs)->sin_addr.s_addr;
- } else if (AF_INET6 == lhs->sa_family) {
- zret = 0 == memcmp(&ats_ip6_cast(lhs)->sin6_addr,
&ats_ip6_cast(rhs)->sin6_addr, sizeof(in6_addr));
+ if (lhs->sa_family == rhs->sa_family) {
+ if (lhs->sa_family == AF_UNIX) {
+ zret = 0 == strncmp(ats_unix_cast(lhs)->sun_path,
ats_unix_cast(rhs)->sun_path, TS_UNIX_SIZE);
+ } else if (ats_ip_port_cast(lhs) == ats_ip_port_cast(rhs)) {
+ if (AF_INET == lhs->sa_family) {
+ zret = ats_ip4_cast(lhs)->sin_addr.s_addr ==
ats_ip4_cast(rhs)->sin_addr.s_addr;
+ } else if (AF_INET6 == lhs->sa_family) {
+ zret = 0 == memcmp(&ats_ip6_cast(lhs)->sin6_addr,
&ats_ip6_cast(rhs)->sin6_addr, sizeof(in6_addr));
+ }
}
}
return zret;
@@ -1490,6 +1584,58 @@ IpAddr::hash() const
return zret;
}
+/// A separate Addr struct for unix paths
+struct UnAddr {
+ using self = UnAddr;
+
+ UnAddr() { _path[0] = 0; }
+
+ UnAddr(self const &addr) { strncpy(_path, addr._path, TS_UNIX_SIZE); }
+ explicit constexpr UnAddr(const char *path) { strncpy(_path, path,
TS_UNIX_SIZE - 1); }
+ explicit constexpr UnAddr(const std::string &path) { strncpy(_path,
path.c_str(), TS_UNIX_SIZE); }
+
+ explicit constexpr UnAddr(sockaddr const *addr) { this->assign(addr); }
+ explicit constexpr UnAddr(sockaddr_un const *addr) {
this->assign(ats_ip_sa_cast(addr)); }
+ /// Construct from @c IpEndpoint.
+ explicit constexpr UnAddr(IpEndpoint const &addr) { this->assign(&addr.sa); }
+ /// Construct from @c IpEndpoint.
+ explicit constexpr UnAddr(IpEndpoint const *addr) { this->assign(&addr->sa);
}
+ /// Assign sockaddr storage.
+ constexpr self &assign(sockaddr const *addr);
+
+ constexpr uint16_t
+ family() const
+ {
+ return AF_UNIX;
+ }
+
+ self &
+ operator=(IpEndpoint const &ip)
+ {
+ return this->assign(&ip.sa);
+ }
+
+ self &
+ operator=(self const &addr)
+ {
+ if (this != &addr) {
+ strncpy(_path, addr._path, TS_UNIX_SIZE);
+ }
+ return *this;
+ }
+
+ char _path[TS_UNIX_SIZE];
+};
+
+inline constexpr UnAddr &
+UnAddr::assign(sockaddr const *addr)
+{
+ if (addr) {
+ strncpy(_path, ats_unix_cast(addr)->sun_path, TS_UNIX_SIZE);
+ }
+ return *this;
+}
+
/// Write IP @a addr to storage @a dst.
/// @return @s dst.
sockaddr *ats_ip_set(sockaddr *dst, ///< Destination storage.
@@ -1525,6 +1671,17 @@ IpEndpoint::assign(sockaddr const *ip)
return *this;
}
+inline IpEndpoint &
+IpEndpoint::assign(UnAddr const &addr)
+{
+ sa.sa_family = AF_UNIX;
+ strncpy(ats_unix_cast(&sa)->sun_path, addr._path, TS_UNIX_SIZE);
+#if HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
+ sa.sa_len = SUN_LEN(&sun);
+#endif
+ return *this;
+}
+
inline in_port_t &
IpEndpoint::network_order_port()
{
diff --git a/src/iocore/net/Server.cc b/src/iocore/net/Server.cc
index 258daf3bfb..ddc922f80e 100644
--- a/src/iocore/net/Server.cc
+++ b/src/iocore/net/Server.cc
@@ -95,7 +95,11 @@ Server::listen(bool non_blocking, const
NetProcessor::AcceptOptions &opt)
socklen_t namelen;
int prot = IPPROTO_TCP;
- if (!ats_is_ip(&accept_addr)) {
+ if (ats_is_unix(&accept_addr)) {
+ prot = 0;
+ ats_ip_copy(&addr, &accept_addr);
+ unlink(accept_addr.sun.sun_path);
+ } else if (!ats_is_ip(&accept_addr)) {
ats_ip4_set(&addr, INADDR_ANY, 0);
} else {
ats_ip_copy(&addr, &accept_addr);
@@ -120,6 +124,10 @@ Server::listen(bool non_blocking, const
NetProcessor::AcceptOptions &opt)
goto Lerror;
}
+ if (ats_is_unix(&accept_addr)) {
+ chmod(accept_addr.sun.sun_path, 0777);
+ }
+
if ((res = safe_listen(sock.get_fd(), get_listen_backlog())) < 0) {
goto Lerror;
}
@@ -256,7 +264,7 @@ Server::setup_fd_for_listen(bool non_blocking, const
NetProcessor::AcceptOptions
}
#ifdef TCP_FASTOPEN
- if (opt.sockopt_flags & NetVCOptions::SOCK_OPT_TCP_FAST_OPEN) {
+ if (opt.sockopt_flags & NetVCOptions::SOCK_OPT_TCP_FAST_OPEN &&
opt.ip_family != AF_UNIX) {
if (safe_setsockopt(sock.get_fd(), IPPROTO_TCP, TCP_FASTOPEN,
&opt.tfo_queue_length, sizeof(int))) {
// EOPNOTSUPP also checked for general safeguarding of unsupported
operations of socket functions
if (opt.f_mptcp && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) {
@@ -284,7 +292,7 @@ Server::setup_fd_for_listen(bool non_blocking, const
NetProcessor::AcceptOptions
}
#if defined(TCP_MAXSEG)
- if (NetProcessor::accept_mss > 0) {
+ if (NetProcessor::accept_mss > 0 && opt.ip_family != AF_UNIX) {
if (opt.f_mptcp) {
Warning("[Server::listen] TCP_MAXSEG socket option not valid on MPTCP
socket level");
} else if (safe_setsockopt(sock.get_fd(), IPPROTO_TCP, TCP_MAXSEG,
reinterpret_cast<char *>(&NetProcessor::accept_mss),
@@ -297,10 +305,12 @@ Server::setup_fd_for_listen(bool non_blocking, const
NetProcessor::AcceptOptions
#ifdef TCP_DEFER_ACCEPT
// set tcp defer accept timeout if it is configured, this will not trigger
an accept until there is
// data on the socket ready to be read
- if (opt.defer_accept > 0 && setsockopt(sock.get_fd(), IPPROTO_TCP,
TCP_DEFER_ACCEPT, &opt.defer_accept, sizeof(int)) < 0) {
- // FIXME: should we go to the error
- // goto error;
- Error("[Server::listen] Defer accept is configured but set failed: %d",
errno);
+ if (opt.defer_accept > 0 && opt.ip_family != AF_UNIX) {
+ if (setsockopt(sock.get_fd(), IPPROTO_TCP, TCP_DEFER_ACCEPT,
&opt.defer_accept, sizeof(int)) < 0) {
+ // FIXME: should we go to the error
+ // goto error;
+ Error("[Server::listen] Defer accept is configured but set failed: %d",
errno);
+ }
}
#endif
diff --git a/src/iocore/net/UnixNetAccept.cc b/src/iocore/net/UnixNetAccept.cc
index 1807482178..ee4d5bf94f 100644
--- a/src/iocore/net/UnixNetAccept.cc
+++ b/src/iocore/net/UnixNetAccept.cc
@@ -261,6 +261,11 @@ NetAccept::accept_per_thread(int /* event ATS_UNUSED */,
void * /* ep ATS_UNUSED
REC_ReadConfigInteger(listen_per_thread, "proxy.config.exec_thread.listen");
if (listen_per_thread == 1) {
+ if (ats_is_unix(server.accept_addr)) {
+ auto id = this_ethread()->id;
+ ats_unix_append_id(&server.accept_addr.sun, id);
+ }
+
if (do_listen()) {
Fatal("[NetAccept::accept_per_thread]:error listenting on ports");
return -1;
diff --git a/src/iocore/net/UnixNetProcessor.cc
b/src/iocore/net/UnixNetProcessor.cc
index 1478ca9c2e..504c56ea5f 100644
--- a/src/iocore/net/UnixNetProcessor.cc
+++ b/src/iocore/net/UnixNetProcessor.cc
@@ -106,14 +106,16 @@ UnixNetProcessor::accept_internal(Continuation *cont, int
fd, AcceptOptions cons
// We've handled the config stuff at start up, but there are a few cases
// we must handle at this point.
- if (opt.localhost_only) {
+ if (opt.ip_family == AF_UNIX) {
+ accept_ip.assign(opt.local_path);
+ } else if (opt.localhost_only) {
accept_ip.setToLoopback(opt.ip_family);
} else if (opt.local_ip.isValid()) {
accept_ip.assign(opt.local_ip);
} else {
accept_ip.setToAnyAddr(opt.ip_family);
}
- ink_assert(0 < opt.local_port && opt.local_port < 65536);
+ ink_assert(opt.ip_family == AF_UNIX || (0 < opt.local_port && opt.local_port
< 65536));
accept_ip.network_order_port() = htons(opt.local_port);
na->accept_fn = net_accept; // All callers used this.
@@ -143,7 +145,7 @@ UnixNetProcessor::accept_internal(Continuation *cont, int
fd, AcceptOptions cons
na->init_accept_per_thread();
}
#if !TS_USE_POSIX_CAP
- if (fd == ts::NO_FD && opt.local_port < 1024 && 0 != geteuid()) {
+ if (fd == ts::NO_FD && opt.local_port < 1024 && 0 != geteuid() &&
opt.ip_family != AF_UNIX) {
// TS-2054 - we can fail to bind a privileged port if we waited for
cache and we tried
// to open the socket in do_listen and we're not using libcap
(POSIX_CAP) and so have reduced
// privilege. Mention this to the admin.
diff --git a/src/iocore/net/UnixNetVConnection.cc
b/src/iocore/net/UnixNetVConnection.cc
index ea4b22483b..7e29f1e6fb 100644
--- a/src/iocore/net/UnixNetVConnection.cc
+++ b/src/iocore/net/UnixNetVConnection.cc
@@ -896,11 +896,13 @@ UnixNetVConnection::load_buffer_and_write(int64_t
towrite, MIOBufferAccessor &bu
struct msghdr msg;
ink_zero(msg);
- msg.msg_name = const_cast<sockaddr *>(this->get_remote_addr());
- msg.msg_namelen = ats_ip_size(this->get_remote_addr());
- msg.msg_iov = &tiovec[0];
- msg.msg_iovlen = niov;
- int flags = 0;
+ if (!ats_is_unix(this->get_local_addr())) {
+ msg.msg_name = const_cast<sockaddr *>(this->get_remote_addr());
+ msg.msg_namelen = ats_ip_size(this->get_remote_addr());
+ }
+ msg.msg_iov = &tiovec[0];
+ msg.msg_iovlen = niov;
+ int flags = 0;
if (!this->con.is_connected && this->options.f_tcp_fastopen) {
Metrics::Counter::increment(net_rsb.fastopen_attempts);
diff --git a/src/proxy/http/HttpProxyServerMain.cc
b/src/proxy/http/HttpProxyServerMain.cc
index 1b9f58d9ad..601f47b310 100644
--- a/src/proxy/http/HttpProxyServerMain.cc
+++ b/src/proxy/http/HttpProxyServerMain.cc
@@ -155,6 +155,10 @@ make_net_accept_options(const HttpProxyPort *port,
unsigned nthreads)
net.local_ip = HttpConfig::m_master.inbound.ip6().network_order();
} else if (AF_INET == port->m_family &&
HttpConfig::m_master.inbound.has_ip4()) {
net.local_ip = HttpConfig::m_master.inbound.ip4().network_order();
+ } else if (AF_UNIX == port->m_family) {
+ net.local_path = port->m_unix_path;
+ net.sockopt_flags &=
+ ~(NetVCOptions::SOCK_OPT_NO_DELAY |
NetVCOptions::SOCK_OPT_TCP_FAST_OPEN |
NetVCOptions::SOCK_OPT_TCP_NOTSENT_LOWAT);
}
}
return net;
diff --git a/src/proxy/http/HttpSessionAccept.cc
b/src/proxy/http/HttpSessionAccept.cc
index c686a95596..62657a4652 100644
--- a/src/proxy/http/HttpSessionAccept.cc
+++ b/src/proxy/http/HttpSessionAccept.cc
@@ -35,14 +35,21 @@ DbgCtl dbg_ctl_http_seq{"http_seq"};
bool
HttpSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf,
IOBufferReader *reader)
{
- sockaddr const *client_ip = netvc->get_remote_addr();
+ sockaddr const *client_ip;
IpAllow::ACL acl;
ip_port_text_buffer ipb;
- acl = IpAllow::match(client_ip, IpAllow::SRC_ADDR);
- if (!acl.isValid()) { // if there's no ACL, it's a hard deny.
- Warning("client '%s' prohibited by ip-allow policy",
ats_ip_ntop(client_ip, ipb, sizeof(ipb)));
- return false;
+ client_ip = netvc->get_remote_addr();
+
+ if (ats_is_ip(client_ip)) {
+ acl = IpAllow::match(client_ip, IpAllow::SRC_ADDR);
+ if (!acl.isValid()) { // if there's no ACL, it's a hard deny.
+ Warning("client '%s' prohibited by ip-allow policy",
ats_ip_ntop(client_ip, ipb, sizeof(ipb)));
+ return false;
+ }
+ } else {
+ // If IP address is not available (e.g. UDS), IP-based ACLs are not
relevant
+ acl = IpAllow::makeAllowAllACL();
}
// Set the transport type if not already set
diff --git a/src/proxy/http/remap/UrlRewrite.cc
b/src/proxy/http/remap/UrlRewrite.cc
index 22e2fd3e16..7db0bac4db 100644
--- a/src/proxy/http/remap/UrlRewrite.cc
+++ b/src/proxy/http/remap/UrlRewrite.cc
@@ -458,7 +458,8 @@ UrlRewrite::PerformACLFiltering(HttpTransact::State *s,
const url_mapping *const
int method = s->hdr_info.client_request.method_get_wksidx();
int method_wksidx = (method != -1) ? (method - HTTP_WKSIDX_CONNECT) : -1;
- ink_release_assert(ats_is_ip(&s->client_info.src_addr));
+ const IpEndpoint *src_addr;
+ src_addr = &s->client_info.src_addr;
s->client_connection_allowed = true; // Default is that we allow things
unless some filter matches
@@ -482,42 +483,44 @@ UrlRewrite::PerformACLFiltering(HttpTransact::State *s,
const url_mapping *const
}
bool ip_matches = true;
- // Is there a @src_ip specified? If so, check it.
- if (rp->src_ip_valid) {
- bool src_ip_matches = false;
- for (int j = 0; j < rp->src_ip_cnt && !src_ip_matches; j++) {
- bool in_range =
rp->src_ip_array[j].contains(s->client_info.src_addr);
- if (rp->src_ip_array[j].invert) {
- if (!in_range) {
- src_ip_matches = true;
- }
- } else {
- if (in_range) {
- src_ip_matches = true;
+ if (ats_is_ip(src_addr)) {
+ // Is there a @src_ip specified? If so, check it.
+ if (rp->src_ip_valid) {
+ bool src_ip_matches = false;
+ for (int j = 0; j < rp->src_ip_cnt && !src_ip_matches; j++) {
+ bool in_range = rp->src_ip_array[j].contains(*src_addr);
+ if (rp->src_ip_array[j].invert) {
+ if (!in_range) {
+ src_ip_matches = true;
+ }
+ } else {
+ if (in_range) {
+ src_ip_matches = true;
+ }
}
}
+ Dbg(dbg_ctl_url_rewrite, "Checked the specified src_ip, result: %s",
src_ip_matches ? "true" : "false");
+ ip_matches &= src_ip_matches;
}
- Dbg(dbg_ctl_url_rewrite, "Checked the specified src_ip, result: %s",
src_ip_matches ? "true" : "false");
- ip_matches &= src_ip_matches;
- }
- // Is there a @src_ip_category specified? If so, check it.
- if (ip_matches && rp->src_ip_category_valid) {
- bool category_ip_matches = false;
- for (int j = 0; j < rp->src_ip_category_cnt && !category_ip_matches;
j++) {
- bool in_category =
rp->src_ip_category_array[j].contains(s->client_info.src_addr);
- if (rp->src_ip_category_array[j].invert) {
- if (!in_category) {
- category_ip_matches = true;
- }
- } else {
- if (in_category) {
- category_ip_matches = true;
+ // Is there a @src_ip_category specified? If so, check it.
+ if (ip_matches && rp->src_ip_category_valid) {
+ bool category_ip_matches = false;
+ for (int j = 0; j < rp->src_ip_category_cnt && !category_ip_matches;
j++) {
+ bool in_category =
rp->src_ip_category_array[j].contains(*src_addr);
+ if (rp->src_ip_category_array[j].invert) {
+ if (!in_category) {
+ category_ip_matches = true;
+ }
+ } else {
+ if (in_category) {
+ category_ip_matches = true;
+ }
}
}
+ Dbg(dbg_ctl_url_rewrite, "Checked the specified src_ip_category,
result: %s", category_ip_matches ? "true" : "false");
+ ip_matches &= category_ip_matches;
}
- Dbg(dbg_ctl_url_rewrite, "Checked the specified src_ip_category,
result: %s", category_ip_matches ? "true" : "false");
- ip_matches &= category_ip_matches;
}
// Is there an @in_ip specified? If so, check it.
diff --git a/src/proxy/logging/LogAccess.cc b/src/proxy/logging/LogAccess.cc
index e9dad4c1bf..f4fffcb2c0 100644
--- a/src/proxy/logging/LogAccess.cc
+++ b/src/proxy/logging/LogAccess.cc
@@ -32,6 +32,7 @@
#include "proxy/logging/LogBuffer.h"
#include "tscore/Encoding.h"
#include "../private/SSLProxySession.h"
+#include "tscore/ink_inet.h"
char INVALID_STR[] = "!INVALID_STR!";
@@ -427,6 +428,12 @@ LogAccess::marshal_ip(char *dest, sockaddr const *ip)
data._ip6._addr = ats_ip6_addr_cast(ip);
}
len = sizeof(data._ip6);
+ } else if (ats_is_unix(ip)) {
+ if (dest) {
+ data._un._family = AF_UNIX;
+ strncpy(data._un._path, ats_unix_cast(ip)->sun_path, TS_UNIX_SIZE);
+ }
+ len = sizeof(data._un);
} else {
data._ip._family = AF_UNSPEC;
}
diff --git a/src/records/RecHttp.cc b/src/records/RecHttp.cc
index c51c93e914..8c89c366fd 100644
--- a/src/records/RecHttp.cc
+++ b/src/records/RecHttp.cc
@@ -369,7 +369,12 @@ HttpProxyPort::processOptions(const char *opts)
}
for (auto item : values) {
- if (isdigit(item[0])) { // leading digit -> port value
+ if (item[0] == '/') {
+ m_family = AF_UNIX;
+ m_unix_path = UnAddr(item);
+ af_set_p = true;
+ zret = true;
+ } else if (isdigit(item[0])) { // leading digit -> port value
char *ptr;
int port = strtoul(item, &ptr, 10);
if (ptr == item) {
@@ -407,11 +412,19 @@ HttpProxyPort::processOptions(const char *opts)
} else if (0 == strcasecmp(OPT_BLIND_TUNNEL, item)) {
m_type = TRANSPORT_BLIND_TUNNEL;
} else if (0 == strcasecmp(OPT_IPV6, item)) {
- m_family = AF_INET6;
- af_set_p = true;
+ if (m_family != AF_UNIX) {
+ m_family = AF_INET6;
+ af_set_p = true;
+ } else {
+ Warning("Invalid ipv6 specification after unix domain path specified");
+ }
} else if (0 == strcasecmp(OPT_IPV4, item)) {
- m_family = AF_INET;
- af_set_p = true;
+ if (m_family != AF_UNIX) {
+ m_family = AF_INET;
+ af_set_p = true;
+ } else {
+ Warning("Invalid ipv4 specification after unix domain path specified");
+ }
} else if (0 == strcasecmp(OPT_SSL, item)) {
m_type = TRANSPORT_SSL;
#if TS_USE_QUIC == 1
diff --git a/src/tscore/ink_inet.cc b/src/tscore/ink_inet.cc
index a605343f8c..0194dc9d94 100644
--- a/src/tscore/ink_inet.cc
+++ b/src/tscore/ink_inet.cc
@@ -71,6 +71,9 @@ ats_ip_ntop(const struct sockaddr *addr, char *dst, size_t
size)
case AF_INET6:
zret = inet_ntop(AF_INET6, &ats_ip6_addr_cast(addr), dst, size);
break;
+ case AF_UNIX:
+ zret = strncpy(dst, ats_unix_cast(addr)->sun_path, size);
+ break;
default:
zret = dst;
snprintf(dst, size, "*Not IP address [%u]*", addr->sa_family);
@@ -792,6 +795,10 @@ bwformat(BufferWriter &w, bwf::Spec const &spec, sockaddr
const *addr)
}
bwformat(w, spec, ats_ip6_addr_cast(addr));
break;
+ case AF_UNIX:
+ bwformat(w, spec, ats_unix_cast(addr)->sun_path);
+ port_p = false;
+ break;
default:
w.print("*Not IP address [{}]*", addr->sa_family);
break;
diff --git a/src/tscore/unit_tests/test_ink_inet.cc
b/src/tscore/unit_tests/test_ink_inet.cc
index 93858aadae..73686e571d 100644
--- a/src/tscore/unit_tests/test_ink_inet.cc
+++ b/src/tscore/unit_tests/test_ink_inet.cc
@@ -260,3 +260,24 @@ TEST_CASE("inet formatting", "[libts][ink_inet][bwformat]")
w.clear().print("{}", swoc::bwf::As_Hex(ats_ip6_addr_cast(ep)));
REQUIRE(w.view() == "ffee00000000000024c333493cee0143");
}
+
+TEST_CASE("ink_inet_unix", "[libts][inet][unix]")
+{
+ auto addr = UnAddr("/tmp/sock.test");
+ swoc::LocalBufferWriter<1024> w;
+
+ IpEndpoint ep;
+ ep.assign(addr);
+ w.print("{}", ep);
+ REQUIRE(w.view() == "/tmp/sock.test");
+#if HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
+ REQUIRE(ep.sun.sun_len == SUN_LEN(&ep.sun));
+#endif
+
+ ats_unix_append_id(&ep.sun, 0);
+ w.clear().print("{}", ep);
+ REQUIRE(w.view() == "/tmp/sock.test-0");
+#if HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
+ REQUIRE(ep.sun.sun_len == SUN_LEN(&ep.sun));
+#endif
+}