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
+}


Reply via email to