From 933417d4c4f45e0428c864f4e16baf3b7fa1b587 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Wed, 1 Sep 2021 09:52:15 +0200 Subject: [PATCH] Add recvmsg() API wrapper Signed-off-by: Joachim Wiberg --- README.md | 17 +++++++++++++++-- accept-guard.c | 42 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0e3b617..4430f20 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,16 @@ # accept-guard -Service access control by wrapping the Linux `accept()` and `recvfrom()` -system calls, for TCP and UDP respectively. +Service access control by wrapping the Linux `accept()`, `recvfrom()`, +and `recvmsg()` system calls, for TCP and UDP respectively. The accept guard wrapper allows access to services based on a list of interfaces and ports. It is loaded using the `LD_PRELOAD` environment variable, controlled by the environment variable `ACCEPT_GUARD_ACL` +**Example:** drop connections from WAN interface for your web server and + SNMP agent, without involving weird `iptables` or `nft` commands. + + ## Syntax ``` @@ -20,6 +24,7 @@ where rule obeys: - First matching rule allows access, i.e., it is expected that the first and only interface entry for the same port + ## TCP Example An example script to start mongoose webserver and limit access to port @@ -33,6 +38,7 @@ export ACCEPT_GUARD_ACL="eth2:80;eth3:443;eth4:80,443" exec /usr/sbin/mongoose /etc/mongoose/config ``` + ## UDP Example An example script to start Net-SNMP, limiting access to SNMP for @@ -45,3 +51,10 @@ export LD_PRELOAD=/lib/access-guard.so export ACCEPT_GUARD_ACL="eth2:161;eth4:161,162" exec /usr/sbin/snmpd -a -LS0-3d -c /etc/snmpd.conf -p /run/snmpd.pid ``` + + +## Origin + +This `LD_PRELOAD` wrapper was invented, developed, and is now maintained +by Westermo Network Technologies AB, Sweden. Please use GitHb for issues +and discussions. diff --git a/accept-guard.c b/accept-guard.c index 943cc05..78bb6ec 100644 --- a/accept-guard.c +++ b/accept-guard.c @@ -45,8 +45,11 @@ struct acl { static struct acl acl[MAX_IFACES]; -static int (*org_accept)(int socket, struct sockaddr *addr, socklen_t *length_ptr); -static ssize_t (*org_recvfrom)(int, void *, size_t, int, struct sockaddr *, socklen_t *); +static int (*org_accept) (int, struct sockaddr *, socklen_t *); +static ssize_t (*org_recvfrom) (int, void *, size_t, int, struct sockaddr *, socklen_t *); +static ssize_t (*org_recvmsg) (int, struct msghdr *, int); + + static size_t strlencpy(char *dst, const char *src, size_t len) { const char *p = src; @@ -212,13 +215,13 @@ static int iface_allowed(int sd, int ifindex) return 0; } -int accept(int socket, struct sockaddr *addr, socklen_t *length_ptr) +int accept(int socket, struct sockaddr *addr, socklen_t *addrlen) { int rc; org_accept = dlsym(RTLD_NEXT, "accept"); - rc = org_accept(socket, addr, length_ptr); + rc = org_accept(socket, addr, addrlen); if (rc != -1) { /* Parse configuration from environment variable. */ parse_acl(); @@ -253,7 +256,7 @@ static int peek_ifindex(int sd) msgh.msg_control = cmbuf; msgh.msg_controllen = sizeof(cmbuf); - if (recvmsg(sd, &msgh, MSG_PEEK) < 0) + if (org_recvmsg(sd, &msgh, MSG_PEEK) == -1) return 0; for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh, cmsg)) { @@ -273,6 +276,8 @@ ssize_t recvfrom(int sd, void *buf, size_t len, int flags, struct sockaddr *addr int ifindex, rc; org_recvfrom = dlsym(RTLD_NEXT, "recvfrom"); + org_recvmsg = dlsym(RTLD_NEXT, "recvmsg"); + /* Parse configuration from environment variable. */ parse_acl(); @@ -289,6 +294,33 @@ ssize_t recvfrom(int sd, void *buf, size_t len, int flags, struct sockaddr *addr return rc; } +ssize_t recvmsg(int sd, struct msghdr *msg, int flags) +{ + int ifindex, rc; + + org_recvmsg = dlsym(RTLD_NEXT, "recvmsg"); + + /* Try to peek ifindex from socket, on fail allow */ + ifindex = peek_ifindex(sd); + + rc = org_recvmsg(sd, msg, flags); + if (flags & MSG_PEEK) + goto done; + + if (rc == -1) + return -1; + + /* Parse configuration from environment variable. */ + parse_acl(); + + if (ifindex > 0 && !iface_allowed(sd, ifindex)) { + errno = EAGAIN; + return -1; + } +done: + return rc; +} + /** * Local Variables: * indent-tabs-mode: t