-*- coding: utf-8 -*-
Changes with Apache 2.4.64
+ *) mod_systemd: Systemd socket activation can now be enabled at
+ build time but disabled at run time, if mod_systemd is not
+ loaded. [Lubos Uhliarik <luhliari redhat.com>]
+
+ *) mod_systemd: Log the SELinux context at startup if available and
+ enabled. [Joe Orton]
+
+ *) mod_http2: update to version 2.0.32
+ The code setting the connection window size was set wrong,
+ preventing `H2WindowSize` to work.
+ Fixed <https://github.com/icing/mod_h2/issues/300>.
+ [Stefan Eissing, Michael Kaufmann]
+
+ *) mod_http2: update to version 2.0.30
+ - Fixed bug in handling over long response headers. When the 64 KB limit
+ of nghttp2 was exceeded, the request was not reset and the client was
+ left hanging, waiting for it. Now the stream is reset.
+ - Added new directive `H2MaxHeaderBlockLen` to set the limit on response
+ header sizes.
+ - Fixed handling of Timeout vs. KeepAliveTimeout when first request on a
+ connection was reset.
+
+ *) mod_lua: Fix memory handling in LuaOutputFilter. PR 69590.
+ [Guillermo Grandes <guillermo.grandes gmail.com>]
+
+ * mod_proxy_http2: revert r1912193 for detecting broken backend connections
+ as this interferes with backend selection who a node is unresponsive.
+ PR69624.
+
+ *) mod_proxy_balancer: Fix a regression that caused stickysession keys no
+ longer be recognized if they are provided as query parameter in the URL.
+ PR 69443 [Ruediger Pluem]
+
+ *) mod_md: update to version 2.5.2
+ - Fixed TLS-ALPN-01 challenges when multiple `MDPrivateKeys` are specified
+ with EC keys before RSA ones. Fixes #377. [Stefan Eissing]
+ - Fixed missing newlines in the status page output. [Andreas Groth]
+
+ *) mod_dav: Add API to expose DavBasePath setting. [Joe Orton]
+
+ *) mod_md: update to version 2.5.1
+ - Added support for ACME profiles with new directives MDProfile and
+ MDProfileMandatory.
+ - When installing a custom CA file via `MDCACertificateFile`, also set the
+ libcurl option CURLSSLOPT_NO_REVOKE that suppresses complains by Schannel
+ (when curl is linked with it) about missing CRL/OCSP in certificates.
+ - Fixed handling of corrupted httpd.json and added test 300_30 for it.
+ File is removed on error and written again. Fixes #369.
+ - Added explanation in log for how to proceed when md_store.json could not be
+ parsed and prevented the server start.
+ - restored fixed to #336 and #337 which got lost in a sync with Apache svn
+ - Add Issue Name/Uris to certificate information in md-status handler
+ - MDomains with static certificate files have MDRenewMode "manual", unless
+ "always" is configured.
+
+ *) core: Report invalid Options= argument when parsing AllowOverride
+ directives.
+ Github #310 [Zhou Qingyang <zhou1615 umn.edu>]
+
+ *) scoreboard/mod_http2: record durations of HTTP/2 requests.
+ PR 69579 [Pierre Brochard <pierre.brochard.1982@m4x.org>]
+
Changes with Apache 2.4.63
*) mod_dav: Update redirect-carefully example BrowserMatch config
#include <stdint.h>
#include <ap_config.h>
#include "ap_mpm.h"
+#include "ap_listen.h"
#include <http_core.h>
#include <httpd.h>
#include <http_log.h>
#include "scoreboard.h"
#include "mpm_common.h"
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
+
#include "systemd/sd-daemon.h"
#if APR_HAVE_UNISTD_H
return OK;
}
+#ifdef HAVE_SELINUX
+static void log_selinux_context(void)
+{
+ char *con;
+
+ if (is_selinux_enabled() && getcon(&con) == 0) {
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
+ APLOGNO(10497) "SELinux is enabled; "
+ "httpd running as context %s", con);
+ freecon(con);
+ }
+}
+#endif
+
/* Report the service is ready in post_config, which could be during
* startup or after a reload. The server could still hit a fatal
* startup error after this point during ap_run_mpm(), so this is
* the TCP ports so new connections will not be rejected. There will
* always be a possible async failure event simultaneous to the
* service reporting "ready", so this should be good enough. */
-static int systemd_post_config(apr_pool_t *p, apr_pool_t *plog,
+static int systemd_post_config(apr_pool_t *pconf, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *main_server)
{
+ if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG)
+ return OK;
+
+#ifdef HAVE_SELINUX
+ log_selinux_context();
+#endif
+
sd_notify(0, "READY=1\n"
"STATUS=Configuration loaded.\n");
return OK;
return DECLINED;
}
+static int ap_find_systemd_socket(process_rec * process, apr_port_t port) {
+ int fdcount, fd;
+ int sdc = sd_listen_fds(0);
+
+ if (sdc < 0) {
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02486)
+ "find_systemd_socket: Error parsing enviroment, sd_listen_fds returned %d",
+ sdc);
+ return -1;
+ }
+
+ if (sdc == 0) {
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02487)
+ "find_systemd_socket: At least one socket must be set.");
+ return -1;
+ }
+
+ fdcount = atoi(getenv("LISTEN_FDS"));
+ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fdcount; fd++) {
+ if (sd_is_socket_inet(fd, 0, 0, -1, port) > 0) {
+ return fd;
+ }
+ }
+
+ return -1;
+}
+
+static int ap_systemd_listen_fds(int unset_environment){
+ return sd_listen_fds(unset_environment);
+}
+
static void systemd_register_hooks(apr_pool_t *p)
{
+ APR_REGISTER_OPTIONAL_FN(ap_systemd_listen_fds);
+ APR_REGISTER_OPTIONAL_FN(ap_find_systemd_socket);
+
/* Enable ap_extended_status. */
ap_hook_pre_config(systemd_pre_config, NULL, NULL, APR_HOOK_LAST);
/* Signal service is ready. */
static int ap_listencbratio;
static int send_buffer_size;
static int receive_buffer_size;
+#ifdef HAVE_SYSTEMD
+static int use_systemd = -1;
+#endif
/* TODO: make_sock is just begging and screaming for APR abstraction */
-static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
+static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_listen)
{
apr_socket_t *s = server->sd;
int one = 1;
return stat;
}
-#if APR_HAVE_IPV6
- if (server->bind_addr->family == APR_INET6) {
- stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting);
- if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
- ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069)
- "make_sock: for address %pI, apr_socket_opt_set: "
- "(IPV6_V6ONLY)",
- server->bind_addr);
- apr_socket_close(s);
- return stat;
- }
- }
-#endif
-
/*
* To send data over high bandwidth-delay connections at full
* speed we must force the TCP window to open wide enough to keep the
}
#endif
- if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) {
- ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072)
- "make_sock: could not bind to address %pI",
- server->bind_addr);
- apr_socket_close(s);
- return stat;
- }
+ if (do_bind_listen) {
+#if APR_HAVE_IPV6
+ if (server->bind_addr->family == APR_INET6) {
+ stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting);
+ if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069)
+ "make_sock: for address %pI, apr_socket_opt_set: "
+ "(IPV6_V6ONLY)",
+ server->bind_addr);
+ apr_socket_close(s);
+ return stat;
+ }
+ }
+#endif
- if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
- ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073)
- "make_sock: unable to listen for connections "
- "on address %pI",
- server->bind_addr);
- apr_socket_close(s);
- return stat;
+ if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) {
+ ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072)
+ "make_sock: could not bind to address %pI",
+ server->bind_addr);
+ apr_socket_close(s);
+ return stat;
+ }
+
+ if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
+ ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073)
+ "make_sock: unable to listen for connections "
+ "on address %pI",
+ server->bind_addr);
+ apr_socket_close(s);
+ return stat;
+ }
}
#ifdef WIN32
return APR_SUCCESS;
}
+#ifdef HAVE_SYSTEMD
+
+static apr_status_t alloc_systemd_listener(process_rec * process,
+ int fd, const char *proto,
+ ap_listen_rec **out_rec)
+{
+ apr_status_t rv;
+ struct sockaddr sa;
+ socklen_t len = sizeof(struct sockaddr);
+ apr_os_sock_info_t si;
+ ap_listen_rec *rec;
+ *out_rec = NULL;
+
+ memset(&si, 0, sizeof(si));
+
+ rv = getsockname(fd, &sa, &len);
+
+ if (rv != 0) {
+ rv = apr_get_netos_error();
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02489)
+ "getsockname on %d failed.", fd);
+ return rv;
+ }
+
+ si.os_sock = &fd;
+ si.family = sa.sa_family;
+ si.local = &sa;
+ si.type = SOCK_STREAM;
+ si.protocol = APR_PROTO_TCP;
+
+ rec = apr_pcalloc(process->pool, sizeof(ap_listen_rec));
+
+
+ rv = apr_os_sock_make(&rec->sd, &si, process->pool);
+ if (rv != APR_SUCCESS) {
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02490)
+ "apr_os_sock_make on %d failed.", fd);
+ return rv;
+ }
+
+ rv = apr_socket_addr_get(&rec->bind_addr, APR_LOCAL, rec->sd);
+ if (rv != APR_SUCCESS) {
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02491)
+ "apr_socket_addr_get on %d failed.", fd);
+ return rv;
+ }
+
+ rec->protocol = apr_pstrdup(process->pool, proto);
+
+ *out_rec = rec;
+
+ return make_sock(process->pool, rec, 0);
+}
+
+static const char *set_systemd_listener(process_rec *process, apr_port_t port,
+ const char *proto)
+{
+ ap_listen_rec *last, *new;
+ apr_status_t rv;
+ APR_OPTIONAL_FN_TYPE(ap_find_systemd_socket) *find_systemd_socket;
+ int fd;
+
+ find_systemd_socket = APR_RETRIEVE_OPTIONAL_FN(ap_find_systemd_socket);
+
+ if (!find_systemd_socket)
+ return "Systemd socket activation is used, but mod_systemd is probably "
+ "not loaded";
+
+ fd = find_systemd_socket(process, port);
+ if (fd < 0) {
+ return "Systemd socket activation is used, but this port is not "
+ "configured in systemd";
+ }
+
+ last = ap_listeners;
+ while (last && last->next) {
+ last = last->next;
+ }
+
+ rv = alloc_systemd_listener(process, fd, proto, &new);
+ if (rv != APR_SUCCESS) {
+ return "Failed to setup socket passed by systemd using socket activation";
+ }
+
+ if (last == NULL) {
+ ap_listeners = new;
+ }
+ else {
+ last->next = new;
+ }
+
+ return NULL;
+}
+#endif /* HAVE_SYSTEMD */
+
/* Returns non-zero if socket address SA matches hostname, port and
* scope_id. p is used for temporary allocations. */
static int match_address(const apr_sockaddr_t *sa,
}
}
#endif
- if (make_sock(pool, lr) == APR_SUCCESS) {
+ if (make_sock(pool, lr, 1) == APR_SUCCESS) {
++num_open;
}
else {
int num_listeners = 0;
const char* proto;
int found;
+#ifdef HAVE_SYSTEMD
+ APR_OPTIONAL_FN_TYPE(ap_systemd_listen_fds) *systemd_listen_fds;
+#endif
for (ls = s; ls; ls = ls->next) {
proto = ap_get_server_protocol(ls);
}
}
- if (open_listeners(s->process->pool)) {
- return 0;
+
+#ifdef HAVE_SYSTEMD
+ if (use_systemd) {
+ const char *userdata_key = "ap_open_systemd_listeners";
+ void *data;
+ /* clear the enviroment on our second run
+ * so that none of our future children get confused.
+ */
+ apr_pool_userdata_get(&data, userdata_key, s->process->pool);
+ if (!data) {
+ apr_pool_userdata_set((const void *)1, userdata_key,
+ apr_pool_cleanup_null, s->process->pool);
+ }
+ else {
+ systemd_listen_fds = APR_RETRIEVE_OPTIONAL_FN(ap_systemd_listen_fds);
+ if (systemd_listen_fds != NULL) {
+ systemd_listen_fds(1);
+ }
+ }
+ }
+ else
+#endif
+ {
+ if (open_listeners(s->process->pool)) {
+ return 0;
+ }
}
for (lr = ap_listeners; lr; lr = lr->next) {
char *hostname;
apr_port_t port;
apr_sockaddr_t *sa;
- duplr = apr_palloc(p, sizeof(ap_listen_rec));
- duplr->slave = NULL;
- duplr->protocol = apr_pstrdup(p, lr->protocol);
- hostname = apr_pstrdup(p, lr->bind_addr->hostname);
- port = lr->bind_addr->port;
- apr_sockaddr_info_get(&sa, hostname, APR_UNSPEC, port, 0, p);
- duplr->bind_addr = sa;
- duplr->next = NULL;
- stat = apr_socket_create(&duplr->sd, duplr->bind_addr->family,
- SOCK_STREAM, 0, p);
- if (stat != APR_SUCCESS) {
- ap_log_perror(APLOG_MARK, APLOG_CRIT, 0, p, APLOGNO(02640)
- "ap_duplicate_listeners: for address %pI, "
- "cannot duplicate a new socket!",
- duplr->bind_addr);
- return stat;
+#ifdef HAVE_SYSTEMD
+ if (use_systemd) {
+ int thesock;
+ apr_os_sock_get(&thesock, lr->sd);
+ if ((stat = alloc_systemd_listener(s->process, thesock,
+ lr->protocol, &duplr)) != APR_SUCCESS) {
+ return stat;
+ }
+ }
+ else
+#endif
+ {
+ duplr = apr_palloc(p, sizeof(ap_listen_rec));
+ duplr->slave = NULL;
+ duplr->protocol = apr_pstrdup(p, lr->protocol);
+ hostname = apr_pstrdup(p, lr->bind_addr->hostname);
+ port = lr->bind_addr->port;
+ apr_sockaddr_info_get(&sa, hostname, APR_UNSPEC, port, 0, p);
+ duplr->bind_addr = sa;
+ duplr->next = NULL;
+ if ((stat = apr_socket_create(&duplr->sd, duplr->bind_addr->family,
+ SOCK_STREAM, 0, p)) != APR_SUCCESS) {
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, 0, p, APLOGNO(02640)
+ "ap_duplicate_socket: for address %pI, "
+ "cannot duplicate a new socket!",
+ duplr->bind_addr);
+ return stat;
+ }
+ make_sock(p, duplr, 1);
}
- make_sock(p, duplr);
#if AP_NONBLOCK_WHEN_MULTI_LISTEN
use_nonblock = (ap_listeners && ap_listeners->next);
stat = apr_socket_opt_set(duplr->sd, APR_SO_NONBLOCK, use_nonblock);
apr_port_t port;
apr_status_t rv;
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+#ifdef HAVE_SYSTEMD
+ APR_OPTIONAL_FN_TYPE(ap_systemd_listen_fds) *systemd_listen_fds;
+#endif
if (err != NULL) {
return err;
if (argc < 1 || argc > 2) {
return "Listen requires 1 or 2 arguments.";
}
+#ifdef HAVE_SYSTEMD
+ if (use_systemd == -1) {
+ systemd_listen_fds = APR_RETRIEVE_OPTIONAL_FN(ap_systemd_listen_fds);
+ if (systemd_listen_fds != NULL) {
+ use_systemd = systemd_listen_fds(0) > 0;
+ } else {
+ use_systemd = 0;
+ }
+ }
+#endif
rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool);
if (rv != APR_SUCCESS) {
ap_str_tolower(proto);
}
+#ifdef HAVE_SYSTEMD
+ if (use_systemd) {
+ return set_systemd_listener(cmd->server->process, port, proto);
+ }
+#endif
+
return alloc_listener(cmd->server->process, host, port, proto,
scope_id, NULL, cmd->temp_pool);
}