nDPIsrvd: Change user/group, allow listening on UNIX socket for incoming distributor connections

Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
This commit is contained in:
Toni Uhlig
2020-09-05 17:52:34 +02:00
parent ec101fbc0f
commit ab374d193f
4 changed files with 151 additions and 21 deletions

View File

@@ -3,6 +3,7 @@
/* macros shared across multiple executables */
#define COLLECTOR_UNIX_SOCKET "/tmp/ndpid-collector.sock"
#define DISTRIBUTOR_UNIX_SOCKET "/tmp/npid-distributor.sock"
#define DISTRIBUTOR_HOST "127.0.0.1"
#define DISTRIBUTOR_PORT 7000

View File

@@ -62,15 +62,19 @@ static int main_thread_shutdown = 0;
static int log_to_stderr = 0;
static char pidfile[UNIX_PATH_MAX] = nDPIsrvd_PIDFILE;
static char json_sockpath[UNIX_PATH_MAX] = COLLECTOR_UNIX_SOCKET;
static enum { SERV_LISTEN_NONE, SERV_LISTEN_TCP, SERV_LISTEN_UNIX } serv_type = SERV_LISTEN_NONE;
static char serv_listen_addr[INET_ADDRSTRLEN] = DISTRIBUTOR_HOST;
static char serv_listen_path[UNIX_PATH_MAX] = DISTRIBUTOR_UNIX_SOCKET;
static uint16_t serv_listen_port = DISTRIBUTOR_PORT;
static int json_sockfd;
static int serv_sockfd;
static char * user = NULL;
static char * group = NULL;
static int create_listen_sockets(void)
{
json_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
serv_sockfd = socket(AF_INET, SOCK_STREAM, 0);
serv_sockfd = socket((serv_type == SERV_LISTEN_UNIX ? AF_UNIX : AF_INET), SOCK_STREAM, 0);
if (json_sockfd < 0 || serv_sockfd < 0)
{
syslog(LOG_DAEMON | LOG_ERR, "Error opening socket: %s", strerror(errno));
@@ -93,27 +97,66 @@ static int create_listen_sockets(void)
return 1;
}
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
if (inet_pton(AF_INET, &serv_listen_addr[0], &serv_addr.sin_addr) != 1)
struct sockaddr * addr;
socklen_t addrlen;
struct sockaddr_in serv_addr_in;
struct sockaddr_un serv_addr_un;
switch (serv_type)
{
syslog(LOG_DAEMON | LOG_ERR, "Error converting an internet address: %s", strerror(errno));
return 1;
case SERV_LISTEN_NONE:
case SERV_LISTEN_TCP:
memset(&serv_addr_in, 0, sizeof(serv_addr_in));
serv_addr_in.sin_family = AF_INET;
if (inet_pton(AF_INET, &serv_listen_addr[0], &serv_addr_in.sin_addr) != 1)
{
syslog(LOG_DAEMON | LOG_ERR, "Error converting an internet address: %s", strerror(errno));
return 1;
}
serv_addr_in.sin_port = htons(serv_listen_port);
addr = (struct sockaddr *)&serv_addr_in;
addrlen = sizeof(serv_addr_in);
break;
case SERV_LISTEN_UNIX:
memset(&serv_addr_un, 0, sizeof(serv_addr_un));
serv_addr_un.sun_family = AF_UNIX;
if (snprintf(serv_addr_un.sun_path, sizeof(serv_addr_un.sun_path), "%s", serv_listen_path) <= 0)
{
syslog(LOG_DAEMON | LOG_ERR, "snprintf failed: %s", strerror(errno));
return 1;
}
addr = (struct sockaddr *)&serv_addr_un;
addrlen = sizeof(serv_addr_un);
break;
}
serv_addr.sin_port = htons(serv_listen_port);
if (bind(json_sockfd, (struct sockaddr *)&json_addr, sizeof(json_addr)) < 0)
{
unlink(json_sockpath);
syslog(LOG_DAEMON | LOG_ERR, "Error on binding the UNIX socket: %s", strerror(errno));
syslog(LOG_DAEMON | LOG_ERR, "Error on binding the UNIX socket to %s: %s", json_sockpath, strerror(errno));
return 1;
}
if (bind(serv_sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
if (bind(serv_sockfd, addr, addrlen) < 0)
{
unlink(json_sockpath);
syslog(LOG_DAEMON | LOG_ERR, "Error on binding the INET socket: %s", strerror(errno));
switch (serv_type)
{
case SERV_LISTEN_NONE:
case SERV_LISTEN_TCP:
syslog(LOG_DAEMON | LOG_ERR,
"Error on binding the INET socket to %s:%u: %s",
serv_listen_addr,
serv_listen_port,
strerror(errno));
break;
case SERV_LISTEN_UNIX:
syslog(LOG_DAEMON | LOG_ERR,
"Error on binding the UNIX socket to %s: %s",
serv_listen_path,
strerror(errno));
break;
}
return 1;
}
@@ -200,7 +243,7 @@ static int parse_options(int argc, char ** argv)
{
int opt;
while ((opt = getopt(argc, argv, "hlc:dp:s:")) != -1)
while ((opt = getopt(argc, argv, "hlc:dp:s:S:u:g:")) != -1)
{
switch (opt)
{
@@ -208,18 +251,22 @@ static int parse_options(int argc, char ** argv)
log_to_stderr = 1;
break;
case 'c':
strncpy(json_sockpath, optarg, sizeof(json_sockpath) - 1);
json_sockpath[sizeof(json_sockpath) - 1] = '\0';
snprintf(json_sockpath, sizeof(json_sockpath), "%s", optarg);
break;
case 'd':
daemonize_enable();
break;
case 'p':
strncpy(pidfile, optarg, sizeof(pidfile) - 1);
pidfile[sizeof(pidfile) - 1] = '\0';
snprintf(pidfile, sizeof(pidfile), "%s", optarg);
break;
case 's':
{
if (serv_type != SERV_LISTEN_NONE)
{
fprintf(stderr, "%s: -s / -S already set\n", argv[0]);
return 1;
}
char * delim = strchr(optarg, ':');
if (delim != NULL)
{
@@ -232,13 +279,36 @@ static int parse_options(int argc, char ** argv)
return 1;
}
}
size_t len = (delim != NULL ? (size_t)(delim - optarg) : strlen(optarg));
strncpy(serv_listen_addr, optarg, (len < sizeof(serv_listen_addr) ? len : sizeof(serv_listen_addr)));
size_t len = (delim != NULL ? (size_t)(delim - optarg) : strlen(optarg)) + 1;
snprintf(serv_listen_addr, (len < sizeof(serv_listen_addr) ? len : sizeof(serv_listen_addr)),
"%s", optarg);
serv_type = SERV_LISTEN_TCP;
break;
}
case 'S':
{
if (serv_type != SERV_LISTEN_NONE)
{
fprintf(stderr, "%s: -s / -S already set\n", argv[0]);
return 1;
}
size_t len = strlen(optarg) + 1;
snprintf(serv_listen_path, (len < sizeof(serv_listen_path) ? len : sizeof(serv_listen_path)),
"%s", optarg);
serv_type = SERV_LISTEN_UNIX;
break;
}
case 'u':
user = strdup(optarg);
break;
case 'g':
group = strdup(optarg);
break;
default:
fprintf(stderr,
"Usage: %s [-l] [-c path-to-unix-sock] [-d] [-p pidfile] -s [distributor-host:port]\n",
"Usage: %s [-l] [-c path-to-unix-sock] [-d] [-p pidfile] [-s distributor-host:port] "
"[-S path-to-unix-socket] [-u user] [-g group]\n",
argv[0]);
return 1;
}
@@ -296,8 +366,30 @@ int main(int argc, char ** argv)
return 1;
}
syslog(LOG_DAEMON, "collector listen on %s", json_sockpath);
syslog(
LOG_DAEMON, "distributor listen on %.*s:%u", (int)sizeof(serv_listen_addr), serv_listen_addr, serv_listen_port);
switch (serv_type) {
case SERV_LISTEN_NONE:
case SERV_LISTEN_TCP:
syslog(LOG_DAEMON, "distributor listen on %.*s:%u", (int)sizeof(serv_listen_addr),
serv_listen_addr, serv_listen_port);
break;
case SERV_LISTEN_UNIX:
syslog(LOG_DAEMON, "distributor listen on %s", serv_listen_path);
break;
}
errno = 0;
if (change_user_group(user, group) != 0)
{
if (errno != 0)
{
syslog(LOG_DAEMON | LOG_ERR, "Change user/group failed: %s", strerror(errno));
}
else
{
syslog(LOG_DAEMON | LOG_ERR, "Change user/group failed.");
}
return 1;
}
signal(SIGINT, sighandler);
signal(SIGTERM, sighandler);

35
utils.c
View File

@@ -1,8 +1,11 @@
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <sys/types.h>
#include <unistd.h>
#include "utils.h"
@@ -110,3 +113,35 @@ int daemonize_shutdown(char const * const pidfile)
return 0;
}
int change_user_group(char const * const user, char const * const group)
{
struct passwd * pwd;
struct group * grp;
gid_t gid;
if (getuid() != 0) {
return 0;
}
if (user == NULL) {
return 1;
}
pwd = getpwnam(user);
if (pwd == NULL) {
return 1;
}
if (group != NULL) {
grp = getgrnam(group);
if (grp == NULL) {
return 1;
}
gid = grp->gr_gid;
} else {
gid = pwd->pw_gid;
}
return setregid(gid, gid) != 0 || setreuid(pwd->pw_uid, pwd->pw_uid);
}

View File

@@ -7,4 +7,6 @@ int daemonize_with_pidfile(char const * const pidfile);
int daemonize_shutdown(char const * const pidfile);
int change_user_group(char const * const user, char const * const group);
#endif