Use a Ragel-generated DFA parser for ifchd command dispatch.
This commit is contained in:
parent
930b92a268
commit
b7e6f59fc7
@ -2,7 +2,19 @@ project (ifchd)
|
|||||||
|
|
||||||
cmake_minimum_required (VERSION 2.6)
|
cmake_minimum_required (VERSION 2.6)
|
||||||
|
|
||||||
|
set(RAGEL_IFCHD_PARSE ${CMAKE_CURRENT_BINARY_DIR}/ifchd-parse.c)
|
||||||
|
|
||||||
|
find_program(RAGEL ragel)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${RAGEL_IFCHD_PARSE}
|
||||||
|
COMMAND ${RAGEL} -G2 -o ${RAGEL_IFCHD_PARSE} ifchd-parse.rl
|
||||||
|
DEPENDS ifchd-parse.rl
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
COMMENT "Compiling Ragel state machine: ifchd-parse.rl"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
file(GLOB IFCHD_SRCS "*.c")
|
file(GLOB IFCHD_SRCS "*.c")
|
||||||
|
|
||||||
add_executable(ifchd ${IFCHD_SRCS})
|
add_executable(ifchd ${RAGEL_IFCHD_PARSE} ${IFCHD_SRCS})
|
||||||
target_link_libraries(ifchd ncmlib)
|
target_link_libraries(ifchd ncmlib)
|
||||||
|
@ -10,6 +10,24 @@
|
|||||||
#define CONN_TIMEOUT 60
|
#define CONN_TIMEOUT 60
|
||||||
#define MAX_IFACES 10
|
#define MAX_IFACES 10
|
||||||
|
|
||||||
|
enum ifchd_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
|
||||||
|
};
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
struct ifchd_client {
|
struct ifchd_client {
|
||||||
/* Socket fd, current state, and idle time for connection. */
|
/* Socket fd, current state, and idle time for connection. */
|
||||||
@ -26,5 +44,14 @@ struct ifchd_client {
|
|||||||
char domains[MAX_BUF];
|
char domains[MAX_BUF];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern void perform_timezone(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
|
extern void perform_dns(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
|
extern void perform_lprsvr(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
|
extern void perform_hostname(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
|
extern void perform_domain(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
|
extern void perform_ipttl(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
|
extern void perform_ntpsrv(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
|
extern void perform_wins(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
|
|
||||||
#endif /* IFCHD_DEFINES_H_ */
|
#endif /* IFCHD_DEFINES_H_ */
|
||||||
|
|
||||||
|
151
ifchd/ifchd-parse.rl
Normal file
151
ifchd/ifchd-parse.rl
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/* ifchd-parse.rl - interface change daemon parser
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ifchd-defines.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "ifch_proto.h"
|
||||||
|
#include "strl.h"
|
||||||
|
#include "linux.h"
|
||||||
|
|
||||||
|
%%{
|
||||||
|
machine ifchd_parser;
|
||||||
|
|
||||||
|
action Reset { cl->state = STATE_NOTHING; }
|
||||||
|
action ArgSt { arg_start = p; }
|
||||||
|
action ArgEn {
|
||||||
|
arg_len = p - arg_start;
|
||||||
|
if (arg_len > sizeof tb - 1) {
|
||||||
|
log_line("command argument would overflow");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(tb, arg_start, arg_len);
|
||||||
|
tb[arg_len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
action Dispatch {
|
||||||
|
switch (cl->state) {
|
||||||
|
case STATE_INTERFACE: perform_interface(cl, tb, arg_len); break;
|
||||||
|
case STATE_IP: perform_ip(cl, tb, arg_len); break;
|
||||||
|
case STATE_SUBNET: perform_subnet(cl, tb, arg_len); break;
|
||||||
|
case STATE_TIMEZONE: perform_timezone(cl, tb, arg_len); break;
|
||||||
|
case STATE_ROUTER: perform_router(cl, tb, arg_len); break;
|
||||||
|
case STATE_DNS: perform_dns(cl, tb, arg_len); break;
|
||||||
|
case STATE_LPRSVR: perform_lprsvr(cl, tb, arg_len); break;
|
||||||
|
case STATE_HOSTNAME: perform_hostname(cl, tb, arg_len); break;
|
||||||
|
case STATE_DOMAIN: perform_domain(cl, tb, arg_len); break;
|
||||||
|
case STATE_IPTTL: perform_ipttl(cl, tb, arg_len); break;
|
||||||
|
case STATE_MTU: perform_mtu(cl, tb, arg_len); break;
|
||||||
|
case STATE_BROADCAST: perform_broadcast(cl, tb, arg_len); break;
|
||||||
|
case STATE_NTPSVR: perform_ntpsrv(cl, tb, arg_len); break;
|
||||||
|
case STATE_WINS: perform_wins(cl, tb, arg_len); break;
|
||||||
|
default:
|
||||||
|
log_line("error: invalid state in dispatch_work");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface = 'iface';
|
||||||
|
ip = 'ip';
|
||||||
|
subnet = 'snet';
|
||||||
|
dns = 'dns';
|
||||||
|
lprsvr = 'lpr';
|
||||||
|
ntpsvr = 'ntp';
|
||||||
|
wins = 'wins';
|
||||||
|
router = 'routr';
|
||||||
|
broadcast = 'bcast';
|
||||||
|
timezone = 'tzone';
|
||||||
|
hostname = 'host';
|
||||||
|
domain = 'dom';
|
||||||
|
ipttl = 'ipttl';
|
||||||
|
mtu = 'mtu';
|
||||||
|
|
||||||
|
cmdname = (interface % { cl->state = STATE_INTERFACE; }
|
||||||
|
|ip % { cl->state = STATE_IP; }
|
||||||
|
|subnet % { cl->state = STATE_SUBNET; }
|
||||||
|
|dns % { cl->state = STATE_DNS; }
|
||||||
|
|lprsvr % { cl->state = STATE_LPRSVR; }
|
||||||
|
|ntpsvr % { cl->state = STATE_NTPSVR; }
|
||||||
|
|wins % { cl->state = STATE_WINS; }
|
||||||
|
|router % { cl->state = STATE_ROUTER; }
|
||||||
|
|broadcast % { cl->state = STATE_BROADCAST; }
|
||||||
|
|timezone % { cl->state = STATE_TIMEZONE; }
|
||||||
|
|hostname % { cl->state = STATE_HOSTNAME; }
|
||||||
|
|domain % { cl->state = STATE_DOMAIN; }
|
||||||
|
|ipttl % { cl->state = STATE_IPTTL; }
|
||||||
|
|mtu % { cl->state = STATE_MTU; }
|
||||||
|
);
|
||||||
|
|
||||||
|
command = cmdname ':' ([^;\0]+ > ArgSt % ArgEn) (';' > Dispatch);
|
||||||
|
main := (command > Reset)+;
|
||||||
|
}%%
|
||||||
|
|
||||||
|
%% write data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns -1 on fatal error; that leads to peer connection being closed.
|
||||||
|
*/
|
||||||
|
int execute_buffer(struct ifchd_client *cl, char *newbuf)
|
||||||
|
{
|
||||||
|
char buf[MAX_BUF * 2];
|
||||||
|
char tb[MAX_BUF];
|
||||||
|
|
||||||
|
if (strnkcpy(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t init_siz = strlen(buf);
|
||||||
|
const char *p = buf;
|
||||||
|
const char *pe = p + init_siz;
|
||||||
|
const char *arg_start;
|
||||||
|
size_t arg_len;
|
||||||
|
unsigned int cs = 0;
|
||||||
|
|
||||||
|
%% write init;
|
||||||
|
%% write exec;
|
||||||
|
|
||||||
|
size_t bytes_left = pe - p;
|
||||||
|
if (bytes_left > 0) {
|
||||||
|
size_t taken = init_siz - bytes_left;
|
||||||
|
strnkcpy(cl->ibuf, buf + taken, MAX_BUF);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cs < ifchd_parser_first_final) {
|
||||||
|
log_line("error: received invalid commands");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
log_line("Commands received and successfully executed.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
217
ifchd/ifchd.c
217
ifchd/ifchd.c
@ -1,6 +1,6 @@
|
|||||||
/* ifchd.c - interface change daemon
|
/* 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.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -60,24 +60,6 @@
|
|||||||
#include "linux.h"
|
#include "linux.h"
|
||||||
#include "seccomp-bpf.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];
|
struct ifchd_client clients[SOCK_QUEUE];
|
||||||
|
|
||||||
static int epollfd, signalFd;
|
static int epollfd, signalFd;
|
||||||
@ -96,6 +78,8 @@ static pid_t peer_pid;
|
|||||||
|
|
||||||
static int gflags_verbose = 0;
|
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)
|
static void writeordie(int fd, const char *buf, int len)
|
||||||
{
|
{
|
||||||
if (safe_write(fd, buf, len) == -1)
|
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);
|
off = lseek(resolv_conf_fd, 0, SEEK_CUR);
|
||||||
if (off == -1) {
|
if (off == -1) {
|
||||||
log_line("write_resolve_conf: lseek returned error: %s\n",
|
log_line("write_resolve_conf: lseek returned error: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -249,64 +233,64 @@ static void write_resolve_conf(struct ifchd_client *cl)
|
|||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
goto retry;
|
goto retry;
|
||||||
log_line("write_resolve_conf: ftruncate returned error: %s\n",
|
log_line("write_resolve_conf: ftruncate returned error: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
r = fsync(resolv_conf_fd);
|
r = fsync(resolv_conf_fd);
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
log_line("write_resolve_conf: fsync returned error: %s\n",
|
log_line("write_resolve_conf: fsync returned error: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: addme */
|
/* 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. */
|
/* 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)
|
if (!str || resolv_conf_fd == -1)
|
||||||
return;
|
return;
|
||||||
strnkcpy(cl->namesvrs, str, MAX_BUF);
|
strnkcpy(cl->namesvrs, str, sizeof cl->namesvrs);
|
||||||
write_resolve_conf(cl);
|
write_resolve_conf(cl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Updates for print daemons are too non-standard to be useful. */
|
/* 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. */
|
/* 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)
|
if (!allow_hostname || !str)
|
||||||
return;
|
return;
|
||||||
if (sethostname(str, strlen(str) + 1) == -1)
|
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 */
|
/* 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)
|
if (!str || resolv_conf_fd == -1)
|
||||||
return;
|
return;
|
||||||
strnkcpy(cl->domains, str, MAX_BUF);
|
strnkcpy(cl->domains, str, sizeof cl->domains);
|
||||||
write_resolve_conf(cl);
|
write_resolve_conf(cl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* I don't think this can be done without a netfilter extension
|
/* I don't think this can be done without a netfilter extension
|
||||||
* that isn't in the mainline kernels. */
|
* 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 */
|
/* 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. */
|
/* 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)
|
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. */
|
/* Opens a non-blocking listening socket with the appropriate properties. */
|
||||||
static int get_listen(void)
|
static int get_listen(void)
|
||||||
{
|
{
|
||||||
@ -600,7 +425,7 @@ static void accept_conns(int *lsock)
|
|||||||
case EBADF:
|
case EBADF:
|
||||||
case ENOTSOCK:
|
case ENOTSOCK:
|
||||||
case EINVAL:
|
case EINVAL:
|
||||||
log_line("warning: accept returned %s!\n", strerror(errno));
|
log_line("warning: accept returned %s!", strerror(errno));
|
||||||
|
|
||||||
epoll_del(*lsock);
|
epoll_del(*lsock);
|
||||||
close(*lsock);
|
close(*lsock);
|
||||||
@ -612,11 +437,11 @@ static void accept_conns(int *lsock)
|
|||||||
case ECONNABORTED:
|
case ECONNABORTED:
|
||||||
case EMFILE:
|
case EMFILE:
|
||||||
case ENFILE:
|
case ENFILE:
|
||||||
log_line("warning: accept returned %s!\n", strerror(errno));
|
log_line("warning: accept returned %s!", strerror(errno));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log_line("warning: accept returned a mysterious error: %s\n",
|
log_line("warning: accept returned a mysterious error: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -811,7 +636,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
printf("ifchd %s, if change daemon.\n", IFCHD_VERSION);
|
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"
|
"All rights reserved.\n\n"
|
||||||
"Redistribution and use in source and binary forms, with or without\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"
|
"modification, are permitted provided that the following conditions are met:\n\n"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* linux.c - ifchd Linux-specific functions
|
/* linux.c - ifchd Linux-specific functions
|
||||||
*
|
*
|
||||||
* 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.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -76,7 +76,7 @@ static int is_permitted(char *name)
|
|||||||
if (strcmp(name, okif[i]) == 0)
|
if (strcmp(name, okif[i]) == 0)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
log_line("attempt to modify interface %s denied\n", name);
|
log_line("attempt to modify interface %s denied", name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,11 +99,11 @@ int authorized_peer(int sk, pid_t pid, uid_t uid, gid_t gid)
|
|||||||
(gid == 0 || cr.gid == gid))
|
(gid == 0 || cr.gid == gid))
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else
|
} else
|
||||||
log_line("getsockopt returned an error: %s\n", strerror(errno));
|
log_line("getsockopt returned an error: %s", strerror(errno));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void perform_interface(struct ifchd_client *cl, char *str)
|
void perform_interface(struct ifchd_client *cl, const char *str, size_t len)
|
||||||
{
|
{
|
||||||
if (!str)
|
if (!str)
|
||||||
return;
|
return;
|
||||||
@ -123,21 +123,21 @@ static int set_if_flag(struct ifchd_client *cl, short flag)
|
|||||||
|
|
||||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
log_line("%s: (set_if_flag) failed to open interface socket: %s\n",
|
log_line("%s: (set_if_flag) failed to open interface socket: %s",
|
||||||
cl->ifnam, strerror(errno));
|
cl->ifnam, strerror(errno));
|
||||||
goto out0;
|
goto out0;
|
||||||
}
|
}
|
||||||
|
|
||||||
strnkcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ);
|
strnkcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ);
|
||||||
if (ioctl(fd, SIOCGIFFLAGS, &ifrt) < 0) {
|
if (ioctl(fd, SIOCGIFFLAGS, &ifrt) < 0) {
|
||||||
log_line("%s: unknown interface: %s\n", cl->ifnam, strerror(errno));
|
log_line("%s: unknown interface: %s", cl->ifnam, strerror(errno));
|
||||||
goto out1;
|
goto out1;
|
||||||
}
|
}
|
||||||
if (((ifrt.ifr_flags & flag ) ^ flag) & flag) {
|
if (((ifrt.ifr_flags & flag ) ^ flag) & flag) {
|
||||||
strnkcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ);
|
strnkcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ);
|
||||||
ifrt.ifr_flags |= flag;
|
ifrt.ifr_flags |= flag;
|
||||||
if (ioctl(fd, SIOCSIFFLAGS, &ifrt) < 0) {
|
if (ioctl(fd, SIOCSIFFLAGS, &ifrt) < 0) {
|
||||||
log_line("%s: failed to set interface flags: %s\n",
|
log_line("%s: failed to set interface flags: %s",
|
||||||
cl->ifnam, strerror(errno));
|
cl->ifnam, strerror(errno));
|
||||||
goto out1;
|
goto out1;
|
||||||
}
|
}
|
||||||
@ -151,7 +151,7 @@ static int set_if_flag(struct ifchd_client *cl, short flag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Sets IP address on an interface and brings it up. */
|
/* Sets IP address on an interface and brings it up. */
|
||||||
void perform_ip(struct ifchd_client *cl, char *str)
|
void perform_ip(struct ifchd_client *cl, const char *str, size_t len)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct in_addr ipaddr;
|
struct in_addr ipaddr;
|
||||||
@ -175,18 +175,18 @@ void perform_ip(struct ifchd_client *cl, char *str)
|
|||||||
|
|
||||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
log_line("%s: (perform_ip) failed to open interface socket: %s\n",
|
log_line("%s: (perform_ip) failed to open interface socket: %s",
|
||||||
cl->ifnam, strerror(errno));
|
cl->ifnam, strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ioctl(fd, SIOCSIFADDR, &ifrt) < 0)
|
if (ioctl(fd, SIOCSIFADDR, &ifrt) < 0)
|
||||||
log_line("%s: failed to configure IP: %s\n",
|
log_line("%s: failed to configure IP: %s",
|
||||||
cl->ifnam, strerror(errno));
|
cl->ifnam, strerror(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sets the subnet mask on an interface. */
|
/* Sets the subnet mask on an interface. */
|
||||||
void perform_subnet(struct ifchd_client *cl, char *str)
|
void perform_subnet(struct ifchd_client *cl, const char *str, size_t len)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct in_addr subnet;
|
struct in_addr subnet;
|
||||||
@ -208,20 +208,20 @@ void perform_subnet(struct ifchd_client *cl, char *str)
|
|||||||
|
|
||||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
log_line("%s: (perform_ip) failed to open interface socket: %s\n",
|
log_line("%s: (perform_ip) failed to open interface socket: %s",
|
||||||
cl->ifnam, strerror(errno));
|
cl->ifnam, strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ioctl(fd, SIOCSIFNETMASK, &ifrt) < 0) {
|
if (ioctl(fd, SIOCSIFNETMASK, &ifrt) < 0) {
|
||||||
sin.sin_addr.s_addr = 0xffffffff;
|
sin.sin_addr.s_addr = 0xffffffff;
|
||||||
if (ioctl(fd, SIOCSIFNETMASK, &ifrt) < 0)
|
if (ioctl(fd, SIOCSIFNETMASK, &ifrt) < 0)
|
||||||
log_line("%s: failed to configure subnet: %s\n",
|
log_line("%s: failed to configure subnet: %s",
|
||||||
cl->ifnam, strerror(errno));
|
cl->ifnam, strerror(errno));
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void perform_router(struct ifchd_client *cl, char *str)
|
void perform_router(struct ifchd_client *cl, const char *str, size_t len)
|
||||||
{
|
{
|
||||||
struct rtentry rt;
|
struct rtentry rt;
|
||||||
struct sockaddr_in *dest;
|
struct sockaddr_in *dest;
|
||||||
@ -255,19 +255,19 @@ void perform_router(struct ifchd_client *cl, char *str)
|
|||||||
|
|
||||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
log_line("%s: (perform_router) failed to open interface socket: %s\n",
|
log_line("%s: (perform_router) failed to open interface socket: %s",
|
||||||
cl->ifnam, strerror(errno));
|
cl->ifnam, strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ioctl(fd, SIOCADDRT, &rt)) {
|
if (ioctl(fd, SIOCADDRT, &rt)) {
|
||||||
if (errno != EEXIST)
|
if (errno != EEXIST)
|
||||||
log_line("%s: failed to set route: %s\n",
|
log_line("%s: failed to set route: %s",
|
||||||
cl->ifnam, strerror(errno));
|
cl->ifnam, strerror(errno));
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void perform_mtu(struct ifchd_client *cl, char *str)
|
void perform_mtu(struct ifchd_client *cl, const char *str, size_t len)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
unsigned int mtu;
|
unsigned int mtu;
|
||||||
@ -287,17 +287,17 @@ void perform_mtu(struct ifchd_client *cl, char *str)
|
|||||||
|
|
||||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
log_line("%s: (perform_mtu) failed to open interface socket: %s\n",
|
log_line("%s: (perform_mtu) failed to open interface socket: %s",
|
||||||
cl->ifnam, strerror(errno));
|
cl->ifnam, strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ioctl(fd, SIOCSIFMTU, &ifrt) < 0)
|
if (ioctl(fd, SIOCSIFMTU, &ifrt) < 0)
|
||||||
log_line("%s: failed to set MTU (%d): %s\n", cl->ifnam, mtu,
|
log_line("%s: failed to set MTU (%d): %s", cl->ifnam, mtu,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void perform_broadcast(struct ifchd_client *cl, char *str)
|
void perform_broadcast(struct ifchd_client *cl, const char *str, size_t len)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct in_addr broadcast;
|
struct in_addr broadcast;
|
||||||
@ -319,11 +319,11 @@ void perform_broadcast(struct ifchd_client *cl, char *str)
|
|||||||
|
|
||||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
log_line("%s: (perform_broadcast) failed to open interface socket: %s\n", cl->ifnam, strerror(errno));
|
log_line("%s: (perform_broadcast) failed to open interface socket: %s", cl->ifnam, strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ioctl(fd, SIOCSIFBRDADDR, &ifrt) < 0)
|
if (ioctl(fd, SIOCSIFBRDADDR, &ifrt) < 0)
|
||||||
log_line("%s: failed to set broadcast: %s\n",
|
log_line("%s: failed to set broadcast: %s",
|
||||||
cl->ifnam, strerror(errno));
|
cl->ifnam, strerror(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
@ -32,11 +32,11 @@ void clear_if_data(struct ifchd_client *cl);
|
|||||||
void initialize_if_data(void);
|
void initialize_if_data(void);
|
||||||
void add_permitted_if(char *s);
|
void add_permitted_if(char *s);
|
||||||
int authorized_peer(int sk, pid_t pid, uid_t uid, gid_t gid);
|
int authorized_peer(int sk, pid_t pid, uid_t uid, gid_t gid);
|
||||||
void perform_interface(struct ifchd_client *cl, char *str);
|
void perform_interface(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
void perform_ip(struct ifchd_client *cl, char *str);
|
void perform_ip(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
void perform_subnet(struct ifchd_client *cl, char *str);
|
void perform_subnet(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
void perform_router(struct ifchd_client *cl, char *str);
|
void perform_router(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
void perform_mtu(struct ifchd_client *cl, char *str);
|
void perform_mtu(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
void perform_broadcast(struct ifchd_client *cl, char *str);
|
void perform_broadcast(struct ifchd_client *cl, const char *str, size_t len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user