This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/9.0.x by this push: new 6d16a58 Add support for Unix Domain Sockets (APR Protocol) 6d16a58 is described below commit 6d16a5825ea7522ae448e29d6c2c74bc06a05197 Author: minfrin <minf...@users.noreply.github.com> AuthorDate: Mon Feb 1 14:36:49 2021 +0000 Add support for Unix Domain Sockets (APR Protocol) Add support and test case for Unix Domain Sockets in org.apache.coyote.http11.Http11AprProtocol, to support users using Java versions older than 16. Requires tomcat-native 1.2.26 and above. Backport of the following: https://github.com/apache/tomcat/commit/c400239cb17d82f8e10f12e40881293b7d2d70b9 https://github.com/apache/tomcat/commit/a616bf385a350175a33a0ebf09d8b6688344e9e3 --- .../apache/catalina/core/AprLifecycleListener.java | 3 +- .../apache/catalina/core/LocalStrings.properties | 2 +- .../catalina/core/LocalStrings_es.properties | 2 +- .../catalina/core/LocalStrings_fr.properties | 2 +- .../catalina/core/LocalStrings_ja.properties | 2 +- .../catalina/core/LocalStrings_ko.properties | 2 +- .../catalina/core/LocalStrings_zh_CN.properties | 2 +- java/org/apache/tomcat/jni/Address.java | 5 +- java/org/apache/tomcat/jni/Library.java | 8 ++ java/org/apache/tomcat/jni/Socket.java | 1 + java/org/apache/tomcat/util/net/AprEndpoint.java | 118 ++++++++++++++++----- .../apache/tomcat/util/net/LocalStrings.properties | 1 + webapps/docs/changelog.xml | 5 + webapps/docs/config/http.xml | 43 ++++++-- 14 files changed, 154 insertions(+), 42 deletions(-) diff --git a/java/org/apache/catalina/core/AprLifecycleListener.java b/java/org/apache/catalina/core/AprLifecycleListener.java index 9dd2e93..51c8308 100644 --- a/java/org/apache/catalina/core/AprLifecycleListener.java +++ b/java/org/apache/catalina/core/AprLifecycleListener.java @@ -247,7 +247,8 @@ public class AprLifecycleListener Boolean.valueOf(Library.APR_HAVE_IPV6), Boolean.valueOf(Library.APR_HAS_SENDFILE), Boolean.valueOf(Library.APR_HAS_SO_ACCEPTFILTER), - Boolean.valueOf(Library.APR_HAS_RANDOM))); + Boolean.valueOf(Library.APR_HAS_RANDOM), + Boolean.valueOf(Library.APR_HAVE_UNIX))); initInfoLogMessages.add(sm.getString("aprListener.config", Boolean.valueOf(AprStatus.getUseAprConnector()), diff --git a/java/org/apache/catalina/core/LocalStrings.properties b/java/org/apache/catalina/core/LocalStrings.properties index 3b45537..2011e68 100644 --- a/java/org/apache/catalina/core/LocalStrings.properties +++ b/java/org/apache/catalina/core/LocalStrings.properties @@ -75,7 +75,7 @@ aprListener.aprInitError=The Apache Tomcat Native library failed to load. The er aprListener.config=APR/OpenSSL configuration: useAprConnector [{0}], useOpenSSL [{1}] aprListener.currentFIPSMode=Current FIPS mode: [{0}] aprListener.enterAlreadyInFIPSMode=AprLifecycleListener is configured to force entering FIPS mode, but library is already in FIPS mode [{0}] -aprListener.flags=APR capabilities: IPv6 [{0}], sendfile [{1}], accept filters [{2}], random [{3}]. +aprListener.flags=APR capabilities: IPv6 [{0}], sendfile [{1}], accept filters [{2}], random [{3}], UDS [{4}]. aprListener.initializeFIPSFailed=Failed to enter FIPS mode aprListener.initializeFIPSSuccess=Successfully entered FIPS mode aprListener.initializedOpenSSL=OpenSSL successfully initialized [{0}] diff --git a/java/org/apache/catalina/core/LocalStrings_es.properties b/java/org/apache/catalina/core/LocalStrings_es.properties index c6604d7..89d247d 100644 --- a/java/org/apache/catalina/core/LocalStrings_es.properties +++ b/java/org/apache/catalina/core/LocalStrings_es.properties @@ -55,7 +55,7 @@ applicationServletRegistration.setServletSecurity.ise=No se pueden añadir restr aprListener.aprDestroy=No pude apagar la biblioteca nativa de Apache Tomcat aprListener.aprInit=La biblioteca nativa de Apache Tomcat basada en ARP que permite un rendimiento óptimo en entornos de desarrollo no ha sido hallada en java.library.path: [{0}] -aprListener.flags=Capacidades APR: IPv6 [{0}], enviar fichero [{1}], aceptar filtros [{2}], aleatorio [{3}]. +aprListener.flags=Capacidades APR: IPv6 [{0}], enviar fichero [{1}], aceptar filtros [{2}], aleatorio [{3}], UDS [{4}]. aprListener.initializedOpenSSL=OpenSSL inicializado correctamente [{0}] aprListener.initializingFIPS=Inicializando modo FIPS... aprListener.sslInit=No pude inicializar el SSLEngine (Motor SSL) diff --git a/java/org/apache/catalina/core/LocalStrings_fr.properties b/java/org/apache/catalina/core/LocalStrings_fr.properties index 8d341fe..daa194e 100644 --- a/java/org/apache/catalina/core/LocalStrings_fr.properties +++ b/java/org/apache/catalina/core/LocalStrings_fr.properties @@ -75,7 +75,7 @@ aprListener.aprInitError=La librairie Apache Tomcat Native basée sur APR n''a p aprListener.config=Configuration de APR/OpenSSL : useAprConnector [{0}], useOpenSSL [{1}] aprListener.currentFIPSMode=Mode FIPS actuel : [{0}] aprListener.enterAlreadyInFIPSMode=AprLifecycleListener est configuré pour forcer le mode FIPS mais la librairie est déjà en mode FIPS [{0}] -aprListener.flags=Fonctionnalités d''APR : IPv6 [{0}], sendfile [{1}], accept filters [{2}], random [{3}] +aprListener.flags=Fonctionnalités d''APR : IPv6 [{0}], sendfile [{1}], accept filters [{2}], random [{3}, UDS [{4}]] aprListener.initializeFIPSFailed=Echec d'entrée en mode FIPS aprListener.initializeFIPSSuccess=Entrée avec succès en mode FIPS aprListener.initializedOpenSSL=OpenSSL a été initialisé avec succès [{0}] diff --git a/java/org/apache/catalina/core/LocalStrings_ja.properties b/java/org/apache/catalina/core/LocalStrings_ja.properties index 047589d..7ed622b 100644 --- a/java/org/apache/catalina/core/LocalStrings_ja.properties +++ b/java/org/apache/catalina/core/LocalStrings_ja.properties @@ -75,7 +75,7 @@ aprListener.aprInitError=APRベースのApache Tomcatネイティブライブラ aprListener.config=APR/OpenSSL設定:useAprConnector [{0}]、useOpenSSL [{1}] aprListener.currentFIPSMode=現在のFIPSモード:[{0}] aprListener.enterAlreadyInFIPSMode=AprLifecycleListenerは強制的にFIPSモードに入るように設定されていますが、ライブラリはすでにFIPSモードになっています[{0}] -aprListener.flags=APR機能:IPv6 [{0}]、sendfile {1}]、受け入れフィルタ[{2}]、ランダム[{3}] +aprListener.flags=APR機能:IPv6 [{0}]、sendfile {1}]、受け入れフィルタ[{2}]、ランダム[{3}]、UDS [{4}] aprListener.initializeFIPSFailed=FIPS モードに変更できません。 aprListener.initializeFIPSSuccess=FIPS モードに入りました。 aprListener.initializedOpenSSL=OpenSSLは[{0}]を正常に初期化しました。 diff --git a/java/org/apache/catalina/core/LocalStrings_ko.properties b/java/org/apache/catalina/core/LocalStrings_ko.properties index 293da42..cc36efc 100644 --- a/java/org/apache/catalina/core/LocalStrings_ko.properties +++ b/java/org/apache/catalina/core/LocalStrings_ko.properties @@ -75,7 +75,7 @@ aprListener.aprInitError=APR 기반 Apache Tomcat Native 라이브러리를 로 aprListener.config=APR/OpenSSL 설정: useAprConnector [{0}], useOpenSSL [{1}] aprListener.currentFIPSMode=현재의 FIPS 모드: [{0}] aprListener.enterAlreadyInFIPSMode=AprLifecycleListener가 강제로 FIPS 모드로 들어가도록 설정되었으나, 라이브러리가 이미 FIPS 모드 [{0}]에 있습니다. -aprListener.flags=APR 용량정보들: IPv6 [{0}], sendfile [{1}], accept filters [{2}], random [{3}]. +aprListener.flags=APR 용량정보들: IPv6 [{0}], sendfile [{1}], accept filters [{2}], random [{3}], UDS [{4}]. aprListener.initializeFIPSFailed=FIPS 모드로 진입하지 못했습니다. aprListener.initializeFIPSSuccess=FIPS 모드로 성공적으로 진입했습니다. aprListener.initializedOpenSSL=OpenSSL이 성공적으로 초기화되었습니다: [{0}] diff --git a/java/org/apache/catalina/core/LocalStrings_zh_CN.properties b/java/org/apache/catalina/core/LocalStrings_zh_CN.properties index 5ecdd45..de75d8f 100644 --- a/java/org/apache/catalina/core/LocalStrings_zh_CN.properties +++ b/java/org/apache/catalina/core/LocalStrings_zh_CN.properties @@ -76,7 +76,7 @@ aprListener.aprInitError=基于APR的本地库加载失败.错误报告为[{0}] aprListener.config=APR/OpenSSL配置:useAprConnector[{0}],useOpenSSL[{1}] aprListener.currentFIPSMode=当前FIPS模式:[{0}]。 aprListener.enterAlreadyInFIPSMode=AprLifecycleListener 配置为强制进入FIPS模式,但库已处于FIPS模式[{0}] -aprListener.flags=APR功能:IPv6[{0}]、sendfile[{1}]、accept filters[{2}]、random[{3}]。 +aprListener.flags=APR功能:IPv6[{0}]、sendfile[{1}]、accept filters[{2}]、random[{3}]、UDS [{4}]。 aprListener.initializeFIPSFailed=进入FIPS模式失败 aprListener.initializeFIPSSuccess=成功的进入FIPS 模式 aprListener.initializedOpenSSL=OpenSSL成功初始化 [{0}] diff --git a/java/org/apache/tomcat/jni/Address.java b/java/org/apache/tomcat/jni/Address.java index 2310367..38a08f8 100644 --- a/java/org/apache/tomcat/jni/Address.java +++ b/java/org/apache/tomcat/jni/Address.java @@ -40,8 +40,9 @@ public class Address { /** * Create apr_sockaddr_t from hostname, address family, and port. - * @param hostname The hostname or numeric address string to resolve/parse, or - * NULL to build an address that corresponds to 0.0.0.0 or :: + * @param hostname The hostname or numeric address string to resolve/parse, the + * path of the Unix Domain Socket, or NULL to build an address + * that corresponds to 0.0.0.0 or :: * @param family The address family to use, or APR_UNSPEC if the system should * decide. * @param port The port number. diff --git a/java/org/apache/tomcat/jni/Library.java b/java/org/apache/tomcat/jni/Library.java index c6c1398..a9849d3 100644 --- a/java/org/apache/tomcat/jni/Library.java +++ b/java/org/apache/tomcat/jni/Library.java @@ -177,6 +177,12 @@ public final class Library { /* Is the O_NONBLOCK flag inherited from listening sockets? */ public static boolean APR_O_NONBLOCK_INHERITED = false; + /* Poll operations are interruptable by apr_pollset_wakeup(). + */ + public static boolean APR_POLLSET_WAKEABLE = false; + /* Support for Unix Domain Sockets. + */ + public static boolean APR_HAVE_UNIX = false; public static int APR_SIZEOF_VOIDP; @@ -244,6 +250,8 @@ public final class Library { APR_CHARSET_EBCDIC = has(18); APR_TCP_NODELAY_INHERITED = has(19); APR_O_NONBLOCK_INHERITED = has(20); + APR_POLLSET_WAKEABLE = has(21); + APR_HAVE_UNIX = has(22); if (APR_MAJOR_VERSION < 1) { throw new UnsatisfiedLinkError("Unsupported APR Version (" + aprVersionString() + ")"); diff --git a/java/org/apache/tomcat/jni/Socket.java b/java/org/apache/tomcat/jni/Socket.java index 976dd38..8882f3b 100644 --- a/java/org/apache/tomcat/jni/Socket.java +++ b/java/org/apache/tomcat/jni/Socket.java @@ -79,6 +79,7 @@ public class Socket { public static final int APR_UNSPEC = 0; public static final int APR_INET = 1; public static final int APR_INET6 = 2; + public static final int APR_UNIX = 3; public static final int APR_PROTO_TCP = 6; /** TCP */ public static final int APR_PROTO_UDP = 17; /** UDP */ diff --git a/java/org/apache/tomcat/util/net/AprEndpoint.java b/java/org/apache/tomcat/util/net/AprEndpoint.java index 887a1d5..99f8b7c 100644 --- a/java/org/apache/tomcat/util/net/AprEndpoint.java +++ b/java/org/apache/tomcat/util/net/AprEndpoint.java @@ -23,6 +23,11 @@ import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.channels.CompletionHandler; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -244,6 +249,26 @@ public class AprEndpoint extends AbstractEndpoint<Long,Long> implements SNICallB } + /** + * Path for the Unix Domain Socket, used to create the socket address. + */ + private String unixDomainSocketPath = null; + public String getUnixDomainSocketPath() { return this.unixDomainSocketPath; } + public void setUnixDomainSocketPath(String unixDomainSocketPath) { + this.unixDomainSocketPath = unixDomainSocketPath; + } + + + /** + * Permissions which will be set on the Unix Domain Socket if it is created. + */ + private String unixDomainSocketPathPermissions = null; + public String getUnixDomainSocketPathPermissions() { return this.unixDomainSocketPathPermissions; } + public void setUnixDomainSocketPathPermissions(String unixDomainSocketPathPermissions) { + this.unixDomainSocketPathPermissions = unixDomainSocketPathPermissions; + } + + // --------------------------------------------------------- Public Methods /** @@ -283,6 +308,9 @@ public class AprEndpoint extends AbstractEndpoint<Long,Long> implements SNICallB @Override public void bind() throws Exception { + int family; + String hostname = null; + // Create the root APR memory pool try { rootPool = Pool.create(0); @@ -292,52 +320,88 @@ public class AprEndpoint extends AbstractEndpoint<Long,Long> implements SNICallB // Create the pool for the server socket serverSockPool = Pool.create(rootPool); + // Create the APR address that will be bound - String addressStr = null; - if (getAddress() != null) { - addressStr = getAddress().getHostAddress(); - } - int family = Socket.APR_INET; - if (Library.APR_HAVE_IPV6) { - if (addressStr == null) { - if (!OS.IS_BSD) { + if (getUnixDomainSocketPath() != null) { + if (Library.APR_HAVE_UNIX) { + hostname = getUnixDomainSocketPath(); + family = Socket.APR_UNIX; + } + else { + throw new Exception(sm.getString("endpoint.init.unixnotavail")); + } + } + else { + + if (getAddress() != null) { + hostname = getAddress().getHostAddress(); + } + family = Socket.APR_INET; + if (Library.APR_HAVE_IPV6) { + if (hostname == null) { + if (!OS.IS_BSD) { + family = Socket.APR_UNSPEC; + } + } else if (hostname.indexOf(':') >= 0) { family = Socket.APR_UNSPEC; } - } else if (addressStr.indexOf(':') >= 0) { - family = Socket.APR_UNSPEC; } - } + } + + long sockAddress = Address.info(hostname, family, getPortWithOffset(), 0, rootPool); - long inetAddress = Address.info(addressStr, family, getPortWithOffset(), 0, rootPool); // Create the APR server socket - serverSock = Socket.create(Address.getInfo(inetAddress).family, + if (family == Socket.APR_UNIX) { + serverSock = Socket.create(family, Socket.SOCK_STREAM, 0, rootPool); + } + else { + serverSock = Socket.create(Address.getInfo(sockAddress).family, Socket.SOCK_STREAM, Socket.APR_PROTO_TCP, rootPool); - if (OS.IS_UNIX) { - Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1); - } - if (Library.APR_HAVE_IPV6) { - if (getIpv6v6only()) { - Socket.optSet(serverSock, Socket.APR_IPV6_V6ONLY, 1); - } else { - Socket.optSet(serverSock, Socket.APR_IPV6_V6ONLY, 0); + if (OS.IS_UNIX) { + Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1); } + if (Library.APR_HAVE_IPV6) { + if (getIpv6v6only()) { + Socket.optSet(serverSock, Socket.APR_IPV6_V6ONLY, 1); + } else { + Socket.optSet(serverSock, Socket.APR_IPV6_V6ONLY, 0); + } + } + // Deal with the firewalls that tend to drop the inactive sockets + Socket.optSet(serverSock, Socket.APR_SO_KEEPALIVE, 1); } - // Deal with the firewalls that tend to drop the inactive sockets - Socket.optSet(serverSock, Socket.APR_SO_KEEPALIVE, 1); + // Bind the server socket - int ret = Socket.bind(serverSock, inetAddress); + int ret = Socket.bind(serverSock, sockAddress); if (ret != 0) { throw new Exception(sm.getString("endpoint.init.bind", "" + ret, Error.strerror(ret))); } + // Start listening on the server socket ret = Socket.listen(serverSock, getAcceptCount()); if (ret != 0) { throw new Exception(sm.getString("endpoint.init.listen", "" + ret, Error.strerror(ret))); } - if (OS.IS_WIN32 || OS.IS_WIN64) { - // On Windows set the reuseaddr flag after the bind/listen - Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1); + + if (family == Socket.APR_UNIX) { + if (getUnixDomainSocketPathPermissions() != null) { + FileAttribute<Set<PosixFilePermission>> attrs = + PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString( + getUnixDomainSocketPathPermissions())); + Files.setAttribute(Paths.get(getUnixDomainSocketPath()), attrs.name(), attrs.value()); + } + else { + java.io.File file = Paths.get(getUnixDomainSocketPath()).toFile(); + file.setReadable(true, false); + file.setWritable(true, false); + file.setExecutable(false, false); + } + } else { + if (OS.IS_WIN32 || OS.IS_WIN64) { + // On Windows set the reuseaddr flag after the bind/listen + Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1); + } } // Enable Sendfile by default if it has not been configured but usage on diff --git a/java/org/apache/tomcat/util/net/LocalStrings.properties b/java/org/apache/tomcat/util/net/LocalStrings.properties index 76625b0..b1e5c2a 100644 --- a/java/org/apache/tomcat/util/net/LocalStrings.properties +++ b/java/org/apache/tomcat/util/net/LocalStrings.properties @@ -88,6 +88,7 @@ endpoint.init.bind=Socket bind failed: [{0}] [{1}] endpoint.init.bind.inherited=No inherited channel while the connector was configured to use one endpoint.init.listen=Socket listen failed: [{0}] [{1}] endpoint.init.notavail=APR not available +endpoint.init.unixnotavail=Unix Domain Socket support not available endpoint.invalidJmxNameSslHost=Unable to generate a valid JMX object name for the SSLHostConfig associated with host [{0}] endpoint.invalidJmxNameSslHostCert=Unable to generate a valid JMX object name for the SSLHostConfigCertificate associated with host [{0}] and certificate type [{1}] endpoint.jmxRegistrationFailed=Failed to register the JMX object with name [{0}] diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 8c58102..043903f 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -148,6 +148,11 @@ </subsection> <subsection name="Coyote"> <changelog> + <add> + <bug>64943</bug>: Add support for Unix Domain Sockets to + <code>org.apache.coyote.http11.Http11AprProtocol</code>. Depends on + <code>tomcat-native</code> 1.2.26 and up. (minfrin) + </add> <fix> <bug>65303</bug>: Fix a possible <code>NullPointerException</code> if an error occurs on an HTTP/1.1 connection being upgraded to HTTP/2 or on diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml index 3fe8515..d9ee92f 100644 --- a/webapps/docs/config/http.xml +++ b/webapps/docs/config/http.xml @@ -931,12 +931,8 @@ <attribute name="unixDomainSocketPath" required="false"> <p>Where supported, the path to a Unix Domain Socket that this <strong>Connector</strong> will create and await incoming connections. - Tomcat will NOT automatically remove the socket on server shutdown. - If the socket already exists, care must be taken by the administrator - to remove the socket after verifying that the socket isn't already - being used by an existing Tomcat process. Using this requires - Java 16 or later. When this is specified, the otherwise mandatory - <code>port</code> attribute may be omitted.</p> + When this is specified, the otherwise mandatory <code>port</code> + attribute may be omitted.</p> </attribute> <attribute name="unixDomainSocketPathPermissions" required="false"> @@ -1198,6 +1194,41 @@ </subsection> + <subsection name="Unix Domain Socket Support"> + + <p>When the <code>unixDomainSocketPath</code> attribute is used, connectors + that support Unix Domain Sockets will bind to the socket at the given path. + </p> + + <p>For users of Java 16 and higher, support is provided within the NIO + connectors. For users of Java earlier than 16, support is provided by + the <code>org.apache.coyote.http11.Http11AprProtocol</code> connector when + used with the Apache Tomcat Native library v1.2.26 and up, along with + Apache Portable Runtime v1.6 and higher. + </p> + + <p>The socket path is created with read and write permissions for all + users. To protect this socket, place it in a directory with suitable + permissions appropriately configured to restrict access as required. + Alternatively, on platforms that support posix permissions, the + permissions on the socket can be set directly with the + <code>unixDomainSocketPathPermissions</code> option. + </p> + + <p>Tomcat will automatically remove the socket on server shutdown. If the + socket already exists startup will fail. Care must be taken by the + administrator to remove the socket after verifying that the socket isn't + already being used by an existing Tomcat process.</p> + + <p>The Unix Domain Socket can be accessed using the + <code>--unix-socket</code> option of the <code>curl</code> command line + client, and the Unix Domain Socket support in Apache HTTP server's + <code>mod_proxy</code> module. + </p> + + </subsection> + + <subsection name="SSL Support"> <p>You can enable SSL support for a particular instance of this --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org