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 <troglobit@gmail.com>
This commit is contained in:
Joachim Nilsson
2015-02-16 10:26:54 +01:00
parent b4b63d3722
commit 58cc96115c
3 changed files with 86 additions and 8 deletions
+72 -7
View File
@@ -21,8 +21,8 @@
* THE SOFTWARE.
*/
//#include <unistd.h>
//#include <sys/types.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/socket.h>
@@ -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)
{
+3
View File
@@ -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);
+11 -1
View File
@@ -26,6 +26,7 @@
#include <sys/wait.h>
#include <utmp.h>
#include <netdb.h>
#include <net/if.h>
#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);