Use a Ragel-generated DFA parser for ifchd command dispatch.

This commit is contained in:
Nicholas J. Kain
2013-05-08 06:27:22 -04:00
parent 930b92a268
commit b7e6f59fc7
6 changed files with 240 additions and 225 deletions

View File

@@ -1,6 +1,6 @@
/* ifchd.c - interface change daemon
*
* Copyright (c) 2004-2012 Nicholas J. Kain <njkain at gmail dot com>
* Copyright (c) 2004-2013 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -60,24 +60,6 @@
#include "linux.h"
#include "seccomp-bpf.h"
enum states {
STATE_NOTHING,
STATE_INTERFACE,
STATE_IP,
STATE_SUBNET,
STATE_TIMEZONE,
STATE_ROUTER,
STATE_DNS,
STATE_LPRSVR,
STATE_HOSTNAME,
STATE_DOMAIN,
STATE_IPTTL,
STATE_MTU,
STATE_BROADCAST,
STATE_NTPSVR,
STATE_WINS
};
struct ifchd_client clients[SOCK_QUEUE];
static int epollfd, signalFd;
@@ -96,6 +78,8 @@ static pid_t peer_pid;
static int gflags_verbose = 0;
extern int execute_buffer(struct ifchd_client *cl, char *newbuf);
static void writeordie(int fd, const char *buf, int len)
{
if (safe_write(fd, buf, len) == -1)
@@ -240,7 +224,7 @@ static void write_resolve_conf(struct ifchd_client *cl)
off = lseek(resolv_conf_fd, 0, SEEK_CUR);
if (off == -1) {
log_line("write_resolve_conf: lseek returned error: %s\n",
log_line("write_resolve_conf: lseek returned error: %s",
strerror(errno));
return;
}
@@ -249,64 +233,64 @@ static void write_resolve_conf(struct ifchd_client *cl)
if (r == -1) {
if (errno == EINTR)
goto retry;
log_line("write_resolve_conf: ftruncate returned error: %s\n",
log_line("write_resolve_conf: ftruncate returned error: %s",
strerror(errno));
return;
}
r = fsync(resolv_conf_fd);
if (r == -1) {
log_line("write_resolve_conf: fsync returned error: %s\n",
log_line("write_resolve_conf: fsync returned error: %s",
strerror(errno));
return;
}
}
/* XXX: addme */
static void perform_timezone(struct ifchd_client *cl, char *str)
void perform_timezone(struct ifchd_client *cl, const char *str, size_t len)
{}
/* Add a dns server to the /etc/resolv.conf -- we already have a fd. */
static void perform_dns(struct ifchd_client *cl, char *str)
void perform_dns(struct ifchd_client *cl, const char *str, size_t len)
{
if (!str || resolv_conf_fd == -1)
return;
strnkcpy(cl->namesvrs, str, MAX_BUF);
strnkcpy(cl->namesvrs, str, sizeof cl->namesvrs);
write_resolve_conf(cl);
}
/* Updates for print daemons are too non-standard to be useful. */
static void perform_lprsvr(struct ifchd_client *cl, char *str)
void perform_lprsvr(struct ifchd_client *cl, const char *str, size_t len)
{}
/* Sets machine hostname. */
static void perform_hostname(struct ifchd_client *cl, char *str)
void perform_hostname(struct ifchd_client *cl, const char *str, size_t len)
{
if (!allow_hostname || !str)
return;
if (sethostname(str, strlen(str) + 1) == -1)
log_line("sethostname returned %s\n", strerror(errno));
log_line("sethostname returned %s", strerror(errno));
}
/* update "domain" and "search" in /etc/resolv.conf */
static void perform_domain(struct ifchd_client *cl, char *str)
void perform_domain(struct ifchd_client *cl, const char *str, size_t len)
{
if (!str || resolv_conf_fd == -1)
return;
strnkcpy(cl->domains, str, MAX_BUF);
strnkcpy(cl->domains, str, sizeof cl->domains);
write_resolve_conf(cl);
}
/* I don't think this can be done without a netfilter extension
* that isn't in the mainline kernels. */
static void perform_ipttl(struct ifchd_client *cl, char *str)
void perform_ipttl(struct ifchd_client *cl, const char *str, size_t len)
{}
/* XXX: addme */
static void perform_ntpsrv(struct ifchd_client *cl, char *str)
void perform_ntpsrv(struct ifchd_client *cl, const char *str, size_t len)
{}
/* Maybe Samba cares about this feature? I don't know. */
static void perform_wins(struct ifchd_client *cl, char *str)
void perform_wins(struct ifchd_client *cl, const char *str, size_t len)
{}
static inline void clock_or_die(struct timespec *ts)
@@ -378,165 +362,6 @@ static void close_idle_sk(void)
}
}
/*
* Returns -1 on fatal error.
*/
static int execute_buffer(struct ifchd_client *cl, char *newbuf)
{
char buf[MAX_BUF * 2];
char *p = buf, *endp;
memset(buf, 0, sizeof buf);
if (strnkcat(buf, cl->ibuf, sizeof buf))
goto buftooshort;
if (strnkcat(buf, newbuf, sizeof buf)) {
buftooshort:
log_line("error: input is too long for buffer");
return -1;
}
for (endp = p;;p = endp) {
if (cl->state == STATE_NOTHING) {
char *colon = strchr(p, ':');
if (!colon)
break;
char *semi = strchr(p, ';');
if (semi && semi < colon) {
log_line("bad syntax: STATE_NOTHING and a ';' came before ':'");
return -1;
}
*colon = '\0';
endp = colon + 1;
} else {
char *semi = strchr(p, ';');
if (!semi)
break;
char *colon = strchr(p, ':');
if (colon && colon < semi) {
log_line("bad syntax: !STATE_NOTHING and a ':' came before ';'");
return -1;
}
*semi = '\0';
endp = semi + 1;
}
if (!strlen(p))
continue;
switch (cl->state) {
case STATE_NOTHING:
if (strncmp(p, CMD_INTERFACE, sizeof(CMD_INTERFACE)) == 0)
cl->state = STATE_INTERFACE;
if (strncmp(p, CMD_IP, sizeof(CMD_IP)) == 0)
cl->state = STATE_IP;
if (strncmp(p, CMD_SUBNET, sizeof(CMD_SUBNET)) == 0)
cl->state = STATE_SUBNET;
if (strncmp(p, CMD_TIMEZONE, sizeof(CMD_TIMEZONE)) == 0)
cl->state = STATE_TIMEZONE;
if (strncmp(p, CMD_ROUTER, sizeof(CMD_ROUTER)) == 0)
cl->state = STATE_ROUTER;
if (strncmp(p, CMD_DNS, sizeof(CMD_DNS)) == 0)
cl->state = STATE_DNS;
if (strncmp(p, CMD_LPRSVR, sizeof(CMD_LPRSVR)) == 0)
cl->state = STATE_LPRSVR;
if (strncmp(p, CMD_HOSTNAME, sizeof(CMD_HOSTNAME)) == 0)
cl->state = STATE_HOSTNAME;
if (strncmp(p, CMD_DOMAIN, sizeof(CMD_DOMAIN)) == 0)
cl->state = STATE_DOMAIN;
if (strncmp(p, CMD_IPTTL, sizeof(CMD_IPTTL)) == 0)
cl->state = STATE_IPTTL;
if (strncmp(p, CMD_MTU, sizeof(CMD_MTU)) == 0)
cl->state = STATE_MTU;
if (strncmp(p, CMD_BROADCAST, sizeof(CMD_BROADCAST)) == 0)
cl->state = STATE_BROADCAST;
if (strncmp(p, CMD_NTPSVR, sizeof(CMD_NTPSVR)) == 0)
cl->state = STATE_NTPSVR;
if (strncmp(p, CMD_WINS, sizeof(CMD_WINS)) == 0)
cl->state = STATE_WINS;
break;
case STATE_INTERFACE:
perform_interface(cl, p);
cl->state = STATE_NOTHING;
break;
case STATE_IP:
perform_ip(cl, p);
cl->state = STATE_NOTHING;
break;
case STATE_SUBNET:
perform_subnet(cl, p);
cl->state = STATE_NOTHING;
break;
case STATE_TIMEZONE:
perform_timezone(cl, p);
cl->state = STATE_NOTHING;
break;
case STATE_ROUTER:
perform_router(cl, p);
cl->state = STATE_NOTHING;
break;
case STATE_DNS:
perform_dns(cl, p);
cl->state = STATE_NOTHING;
break;
case STATE_LPRSVR:
perform_lprsvr(cl, p);
cl->state = STATE_NOTHING;
break;
case STATE_HOSTNAME:
perform_hostname(cl, p);
cl->state = STATE_NOTHING;
break;
case STATE_DOMAIN:
perform_domain(cl, p);
cl->state = STATE_NOTHING;
break;
case STATE_IPTTL:
perform_ipttl(cl, p);
cl->state = STATE_NOTHING;
break;
case STATE_MTU:
perform_mtu(cl, p);
cl->state = STATE_NOTHING;
break;
case STATE_BROADCAST:
perform_broadcast(cl, p);
cl->state = STATE_NOTHING;
break;
case STATE_NTPSVR:
perform_ntpsrv(cl, p);
cl->state = STATE_NOTHING;
break;
case STATE_WINS:
perform_wins(cl, p);
cl->state = STATE_NOTHING;
break;
default:
log_line("warning: invalid state in dispatch_work\n");
break;
}
}
size_t remsize = strlen(endp);
if (remsize > MAX_BUF - 1)
return -1;
strnkcpy(cl->ibuf, endp, MAX_BUF);
return 0;
}
/* Opens a non-blocking listening socket with the appropriate properties. */
static int get_listen(void)
{
@@ -600,7 +425,7 @@ static void accept_conns(int *lsock)
case EBADF:
case ENOTSOCK:
case EINVAL:
log_line("warning: accept returned %s!\n", strerror(errno));
log_line("warning: accept returned %s!", strerror(errno));
epoll_del(*lsock);
close(*lsock);
@@ -612,11 +437,11 @@ static void accept_conns(int *lsock)
case ECONNABORTED:
case EMFILE:
case ENFILE:
log_line("warning: accept returned %s!\n", strerror(errno));
log_line("warning: accept returned %s!", strerror(errno));
return;
default:
log_line("warning: accept returned a mysterious error: %s\n",
log_line("warning: accept returned a mysterious error: %s",
strerror(errno));
return;
}
@@ -811,7 +636,7 @@ int main(int argc, char** argv) {
case 'v':
printf("ifchd %s, if change daemon.\n", IFCHD_VERSION);
printf("Copyright (c) 2004-2012 Nicholas J. Kain\n"
printf("Copyright (c) 2004-2013 Nicholas J. Kain\n"
"All rights reserved.\n\n"
"Redistribution and use in source and binary forms, with or without\n"
"modification, are permitted provided that the following conditions are met:\n\n"