Skip to content

Commit

Permalink
Add recvmsg() API wrapper
Browse files Browse the repository at this point in the history
Signed-off-by: Joachim Wiberg <[email protected]>
  • Loading branch information
troglobit committed Sep 1, 2021
1 parent d55de1a commit 933417d
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 7 deletions.
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -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

```
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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.
42 changes: 37 additions & 5 deletions accept-guard.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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)) {
Expand All @@ -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();

Expand All @@ -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
Expand Down

0 comments on commit 933417d

Please sign in to comment.