Initial commit

This commit is contained in:
jeltz 2021-06-12 00:43:17 +02:00
commit c17b7a2201

170
mod_unix_socket.c Normal file
View file

@ -0,0 +1,170 @@
#include <unistd.h>
#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"
#include "ap_listen.h"
#include "apr_strings.h"
#include "http_log.h"
static ap_listen_rec *
alloc_unix_listener (process_rec * process, const char *path,
const char *proto)
{
struct sockaddr_un sun = {
.sun_family = AF_UNIX,
};
apr_os_sock_info_t si;
ap_listen_rec *rec;
apr_status_t rv;
int one = 1;
int fd;
apr_cpystrn (sun.sun_path, path, sizeof (sun.sun_path));
rec = apr_palloc (process->pool, sizeof (*rec));
rec->protocol = apr_pstrdup (process->pool, proto);
rec->accept_func = NULL;
rec->next = NULL;
rec->active = 1;
if (unlink (sun.sun_path))
{
ap_log_perror (APLOG_MARK, APLOG_CRIT, APR_EGENERAL, process->pool,
APLOGNO (10100) "unlink failed: %s", strerror (errno));
return NULL;
}
fd = socket (AF_UNIX, SOCK_STREAM, 0);
if (fd == -1)
{
ap_log_perror (APLOG_MARK, APLOG_CRIT, APR_EGENERAL, process->pool,
APLOGNO (10101) "socket failed: %s", strerror (errno));
return NULL;
}
if (setsockopt (fd, SOL_SOCKET, SO_REUSEPORT,
(void *) &one, sizeof (one)) < 0)
{
ap_log_perror (APLOG_MARK, APLOG_CRIT, APR_EGENERAL, process->pool,
APLOGNO (10102) "setsockopt failed: %s",
strerror (errno));
close (fd);
return NULL;
}
/* apr_socket_bind() is not used because apr_sockaddr_t is not compatible
* with sockaddr_un
*/
if (bind (fd, (struct sockaddr *) &sun, sizeof (sun)))
{
ap_log_perror (APLOG_MARK, APLOG_CRIT, APR_EGENERAL, process->pool,
APLOGNO (10103) "bind failed: %s", strerror (errno));
close (fd);
return NULL;
}
/* FIXME (ugly hack): configure fake socket information to allow
* ap_setup_listeners() to set the protocol of servers.
* I don't know if it interacts well with other parts of the codebase
* (I haven't even checked properly the whole server/listen.c file!)
*/
si.os_sock = &fd;
si.remote = NULL;
si.local = NULL;
si.family = APR_INET;
si.type = SOCK_STREAM;
si.protocol = APR_PROTO_TCP;
rv = apr_os_sock_make (&rec->sd, &si, process->pool);
if (rv != APR_SUCCESS)
{
ap_log_perror (APLOG_MARK, APLOG_CRIT, APR_EGENERAL, process->pool,
APLOGNO (10104) "apr_os_sock_make failed (%d)", fd);
close (fd);
return NULL;
}
rv = apr_socket_listen (rec->sd, 10);
if (rv != APR_SUCCESS)
{
ap_log_perror (APLOG_MARK, APLOG_CRIT, rv, process->pool,
APLOGNO (10105) "apr_socket_listen failed (%d)", fd);
return NULL;
}
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 (10106) "apr_socket_addr_get failed (%d)", fd);
return NULL;
}
/* TODO: implement useful parts of make_sock (server/listen.c) */
return rec;
}
static const char *
set_listen_path (cmd_parms * cmd, void *cfg, const char *path,
const char *proto)
{
ap_listen_rec *last;
ap_listen_rec *new;
apr_status_t rv;
const char *err;
err = ap_check_cmd_context (cmd, GLOBAL_ONLY);
if (err)
{
return err;
}
if (strcmp (proto, "http") && strcmp (proto, "https"))
{
return "Proto must be either 'http' or 'https'";
}
new = alloc_unix_listener (cmd->server->process, path, proto);
if (!new)
{
return "Failed to listen on Unix socket";
}
last = ap_listeners;
while (last && last->next)
{
last = last->next;
}
if (!last)
{
ap_listeners = new;
}
else
{
last->next = new;
}
return NULL;
}
static const command_rec directives[] = {
AP_INIT_TAKE2 ("ListenUnixPath", set_listen_path, NULL, RSRC_CONF,
"Listen to Unix socket"),
{NULL},
};
module AP_MODULE_DECLARE_DATA unix_socket_module = {
STANDARD20_MODULE_STUFF,
NULL,
NULL,
NULL,
NULL,
directives,
NULL,
};