From 58cc96115c4b39737349ffa47860050fdaf81049 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 16 Feb 2015 10:26:54 +0100 Subject: [PATCH] Initial support for figuring out inbound interface for inetd connections This patch adds initial support (only SOCK_STREAM verified!) for figuring out the inbound interface for inetd service connections. The intention is to use this later on for a very simple tcpwrappers replacement, e.g: `deny telnet eth0 eth3` Signed-off-by: Joachim Nilsson --- inetd.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- inetd.h | 3 +++ svc.c | 12 ++++++++- 3 files changed, 86 insertions(+), 8 deletions(-) diff --git a/inetd.c b/inetd.c index 170a3bc7..aecc775c 100644 --- a/inetd.c +++ b/inetd.c @@ -21,8 +21,8 @@ * THE SOFTWARE. */ -//#include -//#include +#include +#include #include #include @@ -76,11 +76,18 @@ static void spawn_socket(uev_ctx_t *ctx, svc_t *svc) return; } - if (svc->port && svc->sock_type != SOCK_DGRAM) { - if (-1 == listen(sd, 20)) { - FLOG_PERROR("Failed listening to inetd service %s", svc->service); - close(sd); - return; + if (svc->port) { + if (svc->sock_type == SOCK_STREAM) { + if (-1 == listen(sd, 20)) { + FLOG_PERROR("Failed listening to inetd service %s", svc->service); + close(sd); + return; + } + } else { /* SOCK_DGRAM */ + int opt = 1; + + /* Set extra sockopt to get ifindex from inbound packets */ + setsockopt(sd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)); } } @@ -89,6 +96,64 @@ static void spawn_socket(uev_ctx_t *ctx, svc_t *svc) uev_io_init(ctx, &svc->watcher, socket_cb, svc, sd, UEV_READ); } +/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */ +int inetd_dgram_peek(int sd, char *ifname) +{ + struct msghdr msgh; + struct cmsghdr *cmsg; + + if (recvmsg(sd, &msgh, MSG_PEEK) < 0) + return -1; + + for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh,cmsg)) { + struct in_pktinfo *ipi = (struct in_pktinfo *)CMSG_DATA(cmsg); + + if (cmsg->cmsg_level != SOL_IP || cmsg->cmsg_type != IP_PKTINFO) + continue; + + if_indextoname(ipi->ipi_ifindex, ifname); + + return 0; + } + + return -1; +} + +/* Peek into SOCK_STREAM on accepted client socket to figure out inbound interface */ +int inetd_stream_peek(int sd, char *ifname) +{ + struct ifaddrs *ifaddr, *ifa; + struct sockaddr_in sin; + socklen_t len = sizeof(sin); + + if (-1 == getsockname(sd, (struct sockaddr *)&sin, &len)) + return -1; + + if (-1 == getifaddrs(&ifaddr)) + return -1; + + for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { + size_t len = sizeof(struct in_addr); + struct sockaddr_in *iin; + + if (!ifa->ifa_addr) + continue; + + if (ifa->ifa_addr->sa_family != AF_INET) + continue; + + iin = (struct sockaddr_in *)ifa->ifa_addr; + if (!memcmp(&sin.sin_addr, &iin->sin_addr, len)) { + strncpy(ifname, ifa->ifa_name, IF_NAMESIZE); + break; + } + } + + freeifaddrs(ifaddr); + + return 0; +} + /* Inetd monitor, called by svc_monitor() */ int inetd_respawn(pid_t pid) { diff --git a/inetd.h b/inetd.h index 9670f07d..8559b1dd 100644 --- a/inetd.h +++ b/inetd.h @@ -26,6 +26,9 @@ #include "libuev/uev.h" +int inetd_dgram_peek (int sd, char *ifname); +int inetd_stream_peek (int sd, char *ifname); + int inetd_respawn (pid_t pid); void inetd_runlevel(uev_ctx_t *ctx, int runlevel); diff --git a/svc.c b/svc.c index 477c3be6..fd55341f 100644 --- a/svc.c +++ b/svc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "finit.h" #include "helpers.h" @@ -517,6 +518,7 @@ void svc_monitor(pid_t lost) int svc_start(svc_t *svc) { int respawn, sd = 0; + char ifname[IF_NAMESIZE] = "UNKNOWN"; pid_t pid; sigset_t nmask, omask; @@ -551,9 +553,17 @@ int svc_start(svc_t *svc) } _d("New client socket %d accepted for inetd service %d/tcp", sd, svc->port); + + /* Find ifname by means of getsockname() and getifaddrs() */ + inetd_stream_peek(sd, ifname); + } else { /* SOCK_DGRAM */ + /* Find ifname by means of IP_PKTINFO sockopt --> ifindex + if_indextoname() */ + inetd_dgram_peek(sd, ifname); } - FLOG_INFO("Starting inetd service %s ...", svc->service); + /* XXX: Add poor man's tcpwrappers here, we now know inbound ifname ... */ + + FLOG_INFO("Starting inetd service %s for requst from iface %s ...", svc->service, ifname); } else if (SVC_CMD_SERVICE != svc->type) print_desc("", svc->desc);