Quit using malloc entirely in ifchd and reduce buffer copies.
This change also modifies the ndhc/ifchd wire protocol slightly. The new protocol doesn't overload the ':' character as a key:value separator and a statement separator. Instead ';' is now used as a statement separator. The new format allows for more robust error-checking and reporting, and it greatly simplifies the parser. Old versions of ndhc/ifchd will not work properly with ones compiled after this commit. The 'domain' and 'search' keywords in resolv.conf updates are now used more precisely. The first domain in an update is the 'domain', and the subsequent 5 domains are 'search' domains. There are also supporting cleanups that pass struct ifchd_client pointers to functions instead of passing index values. This commit is large, but it cannot really be broken up into smaller chunks since the changes are dependent on each other.
This commit is contained in:
parent
a60a5fddb1
commit
f9c2059d37
@ -11,28 +11,19 @@
|
||||
#define MAX_IFACES 10
|
||||
|
||||
#include <net/if.h>
|
||||
#include "strlist.h"
|
||||
struct ifchd_client {
|
||||
/* Socket fd, current state, and idle time for connection. */
|
||||
int fd;
|
||||
int state;
|
||||
int idle_time;
|
||||
/*
|
||||
* Per-connection pointers into the command lists. Respectively, the
|
||||
* topmost item on the list, the current item, and the last item on the
|
||||
* list.
|
||||
*/
|
||||
strlist_t *head, *curl, *last;
|
||||
/* Lists of nameservers and search domains. Unfortunately they must be
|
||||
* per-connection, since otherwise seperate clients could race against
|
||||
* one another to write out unpredictable data.
|
||||
*/
|
||||
strlist_t *namesvrs, *domains;
|
||||
|
||||
/* Symbolic name of the interface associated with a connection. */
|
||||
char ifnam[IFNAMSIZ];
|
||||
/* Per-connection buffer. */
|
||||
char ibuf[MAX_BUF];
|
||||
/* ' '-delimited buffers of nameservers and domains */
|
||||
char namesvrs[MAX_BUF];
|
||||
char domains[MAX_BUF];
|
||||
};
|
||||
|
||||
#endif /* IFCHD_DEFINES_H_ */
|
||||
|
325
ifchd/ifchd.c
325
ifchd/ifchd.c
@ -49,12 +49,10 @@
|
||||
#include <getopt.h>
|
||||
|
||||
#include "ifchd-defines.h"
|
||||
#include "malloc.h"
|
||||
#include "log.h"
|
||||
#include "chroot.h"
|
||||
#include "pidfile.h"
|
||||
#include "signals.h"
|
||||
#include "strlist.h"
|
||||
#include "ifch_proto.h"
|
||||
#include "strl.h"
|
||||
#include "cap.h"
|
||||
@ -98,14 +96,6 @@ static pid_t peer_pid;
|
||||
|
||||
static int gflags_verbose = 0;
|
||||
|
||||
static void die_nulstr(strlist_t *p)
|
||||
{
|
||||
if (!p)
|
||||
suicide("FATAL - NULL passed to die_nulstr");
|
||||
if (!p->str)
|
||||
suicide("FATAL - NULL string in strlist");
|
||||
}
|
||||
|
||||
static void writeordie(int fd, const char *buf, int len)
|
||||
{
|
||||
if (safe_write(fd, buf, len) == -1)
|
||||
@ -177,43 +167,71 @@ static int enforce_seccomp(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Abstracts away the details of accept()ing a socket connection. */
|
||||
/* Writes out each element in a strlist as an argument to a keyword in
|
||||
* a file. */
|
||||
static void write_resolve_list(const char *keyword, strlist_t *list)
|
||||
{
|
||||
char *buf;
|
||||
strlist_t *p = list;
|
||||
unsigned int len;
|
||||
|
||||
if (!keyword || resolv_conf_fd == -1)
|
||||
return;
|
||||
|
||||
while (p) {
|
||||
buf = p->str;
|
||||
len = strlen(buf);
|
||||
if (len) {
|
||||
writeordie(resolv_conf_fd, keyword, strlen(keyword));
|
||||
writeordie(resolv_conf_fd, buf, strlen(buf));
|
||||
writeordie(resolv_conf_fd, "\n", 1);
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Writes a new resolv.conf based on the information we have received. */
|
||||
static void write_resolve_conf(int idx)
|
||||
static void write_resolve_conf(struct ifchd_client *cl)
|
||||
{
|
||||
const static char ns_str[] = "nameserver ";
|
||||
const static char dom_str[] = "domain ";
|
||||
const static char srch_str[] = "search ";
|
||||
int r;
|
||||
off_t off;
|
||||
char buf[MAX_BUF];
|
||||
|
||||
if (resolv_conf_fd == -1)
|
||||
return;
|
||||
if (strlen(cl->namesvrs) == 0)
|
||||
return;
|
||||
|
||||
if (lseek(resolv_conf_fd, 0, SEEK_SET) == -1)
|
||||
return;
|
||||
|
||||
write_resolve_list("nameserver ", clients[idx].namesvrs);
|
||||
write_resolve_list("search ", clients[idx].domains);
|
||||
char *p = cl->namesvrs;
|
||||
while (p && (*p != '\0')) {
|
||||
char *q = strchr(p, ' ');
|
||||
if (!q)
|
||||
q = strchr(p, '\0');
|
||||
else
|
||||
*q++ = '\0';
|
||||
strlcpy(buf, p, sizeof buf);
|
||||
|
||||
writeordie(resolv_conf_fd, ns_str, strlen(ns_str));
|
||||
writeordie(resolv_conf_fd, buf, strlen(buf));
|
||||
writeordie(resolv_conf_fd, "\n", 1);
|
||||
|
||||
p = q;
|
||||
}
|
||||
|
||||
p = cl->domains;
|
||||
int numdoms = 0;
|
||||
while (p && (*p != '\0')) {
|
||||
char *q = strchr(p, ' ');
|
||||
if (!q)
|
||||
q = strchr(p, '\0');
|
||||
else
|
||||
*q++ = '\0';
|
||||
strlcpy(buf, p, sizeof buf);
|
||||
|
||||
if (numdoms == 0) {
|
||||
writeordie(resolv_conf_fd, dom_str, strlen(dom_str));
|
||||
writeordie(resolv_conf_fd, buf, strlen(buf));
|
||||
} else {
|
||||
if (numdoms == 1) {
|
||||
writeordie(resolv_conf_fd, "\n", 1);
|
||||
writeordie(resolv_conf_fd, srch_str, strlen(srch_str));
|
||||
writeordie(resolv_conf_fd, buf, strlen(buf));
|
||||
} else {
|
||||
writeordie(resolv_conf_fd, " ", 1);
|
||||
writeordie(resolv_conf_fd, buf, strlen(buf));
|
||||
}
|
||||
}
|
||||
|
||||
++numdoms;
|
||||
p = q;
|
||||
if (numdoms > 6)
|
||||
break;
|
||||
}
|
||||
writeordie(resolv_conf_fd, "\n", 1);
|
||||
|
||||
off = lseek(resolv_conf_fd, 0, SEEK_CUR);
|
||||
if (off == -1) {
|
||||
log_line("write_resolve_conf: lseek returned error: %s\n",
|
||||
@ -237,55 +255,25 @@ static void write_resolve_conf(int idx)
|
||||
}
|
||||
}
|
||||
|
||||
/* Decomposes a ' '-delimited flat character array onto a strlist, then
|
||||
* calls the given function to perform work on the generated strlist. */
|
||||
static void parse_list(int idx, char *str, strlist_t **toplist,
|
||||
void (*fn)(int))
|
||||
{
|
||||
char *p, n[256];
|
||||
unsigned int i;
|
||||
strlist_t *newn = 0;
|
||||
|
||||
if (!str || !toplist || !fn)
|
||||
return;
|
||||
p = str;
|
||||
|
||||
while (p != '\0') {
|
||||
memset(n, '\0', sizeof n);
|
||||
for (i = 0; i < sizeof n - 1 && *p != '\0' && *p != ' '; ++p, ++i)
|
||||
n[i] = *p;
|
||||
if (*p == ' ')
|
||||
++p;
|
||||
add_to_strlist(&newn, n);
|
||||
}
|
||||
|
||||
if (newn) {
|
||||
free_strlist(*toplist);
|
||||
*toplist = newn;
|
||||
} else
|
||||
return;
|
||||
|
||||
(*fn)(idx);
|
||||
}
|
||||
|
||||
/* XXX: addme */
|
||||
static void perform_timezone(int idx, char *str)
|
||||
static void perform_timezone(struct ifchd_client *cl, char *str)
|
||||
{}
|
||||
|
||||
/* Add a dns server to the /etc/resolv.conf -- we already have a fd. */
|
||||
static void perform_dns(int idx, char *str)
|
||||
static void perform_dns(struct ifchd_client *cl, char *str)
|
||||
{
|
||||
if (!str || resolv_conf_fd == -1)
|
||||
return;
|
||||
parse_list(idx, str, &clients[idx].namesvrs, &write_resolve_conf);
|
||||
strlcpy(cl->namesvrs, str, MAX_BUF);
|
||||
write_resolve_conf(cl);
|
||||
}
|
||||
|
||||
/* Updates for print daemons are too non-standard to be useful. */
|
||||
static void perform_lprsvr(int idx, char *str)
|
||||
static void perform_lprsvr(struct ifchd_client *cl, char *str)
|
||||
{}
|
||||
|
||||
/* Sets machine hostname. */
|
||||
static void perform_hostname(int idx, char *str)
|
||||
static void perform_hostname(struct ifchd_client *cl, char *str)
|
||||
{
|
||||
if (!allow_hostname || !str)
|
||||
return;
|
||||
@ -293,25 +281,26 @@ static void perform_hostname(int idx, char *str)
|
||||
log_line("sethostname returned %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
/* update "search" in /etc/resolv.conf */
|
||||
static void perform_domain(int idx, char *str)
|
||||
/* update "domain" and "search" in /etc/resolv.conf */
|
||||
static void perform_domain(struct ifchd_client *cl, char *str)
|
||||
{
|
||||
if (!str || resolv_conf_fd == -1)
|
||||
return;
|
||||
parse_list(idx, str, &clients[idx].domains, &write_resolve_conf);
|
||||
strlcpy(cl->domains, str, MAX_BUF);
|
||||
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(int idx, char *str)
|
||||
static void perform_ipttl(struct ifchd_client *cl, char *str)
|
||||
{}
|
||||
|
||||
/* XXX: addme */
|
||||
static void perform_ntpsrv(int idx, char *str)
|
||||
static void perform_ntpsrv(struct ifchd_client *cl, char *str)
|
||||
{}
|
||||
|
||||
/* Maybe Samba cares about this feature? I don't know. */
|
||||
static void perform_wins(int idx, char *str)
|
||||
static void perform_wins(struct ifchd_client *cl, char *str)
|
||||
{}
|
||||
|
||||
static void ifchd_client_init(struct ifchd_client *p)
|
||||
@ -322,11 +311,8 @@ static void ifchd_client_init(struct ifchd_client *p)
|
||||
|
||||
memset(p->ibuf, 0, sizeof p->ibuf);
|
||||
memset(p->ifnam, 0, sizeof p->ifnam);
|
||||
p->head = NULL;
|
||||
p->curl = NULL;
|
||||
p->last = NULL;
|
||||
p->namesvrs = NULL;
|
||||
p->domains = NULL;
|
||||
memset(p->namesvrs, 0, sizeof p->namesvrs);
|
||||
memset(p->domains, 0, sizeof p->domains);
|
||||
}
|
||||
|
||||
static void ifchd_client_wipe(struct ifchd_client *p)
|
||||
@ -335,9 +321,6 @@ static void ifchd_client_wipe(struct ifchd_client *p)
|
||||
epoll_del(p->fd);
|
||||
close(p->fd);
|
||||
}
|
||||
free_strlist(p->head);
|
||||
free_strlist(p->namesvrs);
|
||||
free_strlist(p->domains);
|
||||
ifchd_client_init(p);
|
||||
}
|
||||
|
||||
@ -379,56 +362,43 @@ static void close_idle_sk(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Decomposes a ':'-delimited flat character array onto a strlist. */
|
||||
static int stream_onto_list(int i)
|
||||
/*
|
||||
* Returns -1 on fatal error.
|
||||
*/
|
||||
static int execute_buffer(struct ifchd_client *cl, char *newbuf)
|
||||
{
|
||||
int e, s;
|
||||
struct ifchd_client *cl = &clients[i];
|
||||
char buf[MAX_BUF * 2];
|
||||
char *p = buf, *endp;
|
||||
|
||||
for (e = 0, s = 0; cl->ibuf[e] != '\0'; e++) {
|
||||
if (cl->ibuf[e] == ':') {
|
||||
/* Zero-length command: skip. */
|
||||
if (s == e) {
|
||||
s = e + 1;
|
||||
continue;
|
||||
}
|
||||
cl->curl = xmalloc(sizeof(strlist_t));
|
||||
|
||||
if (cl->head == NULL) {
|
||||
cl->head = cl->curl;
|
||||
cl->last = NULL;
|
||||
}
|
||||
|
||||
cl->curl->next = NULL;
|
||||
if (cl->last != NULL)
|
||||
cl->last->next = cl->curl;
|
||||
|
||||
cl->curl->str = xmalloc(e - s + 1);
|
||||
|
||||
strlcpy(cl->curl->str, cl->ibuf + s, e - s + 1);
|
||||
cl->last = cl->curl;
|
||||
s = e + 1;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/* State machine that runs over the command and argument list,
|
||||
* executing commands. */
|
||||
static void execute_list(int i)
|
||||
{
|
||||
char *p;
|
||||
struct ifchd_client *cl = &clients[i];
|
||||
memset(buf, 0, sizeof buf);
|
||||
strlcat(buf, cl->ibuf, sizeof buf);
|
||||
strlcat(buf, newbuf, sizeof buf);
|
||||
|
||||
for (;;) {
|
||||
if (!cl->curl)
|
||||
break;
|
||||
die_nulstr(cl->curl);
|
||||
|
||||
p = cl->curl->str;
|
||||
|
||||
if (gflags_verbose)
|
||||
log_line("execute_list - p = '%s'", p);
|
||||
endp = p;
|
||||
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;
|
||||
}
|
||||
|
||||
switch (cl->state) {
|
||||
case STATE_NOTHING:
|
||||
@ -460,90 +430,75 @@ static void execute_list(int i)
|
||||
cl->state = STATE_NTPSVR;
|
||||
if (strncmp(p, CMD_WINS, sizeof(CMD_WINS)) == 0)
|
||||
cl->state = STATE_WINS;
|
||||
free_stritem(&cl->curl);
|
||||
break;
|
||||
|
||||
case STATE_INTERFACE:
|
||||
perform_interface(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_interface(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
case STATE_IP:
|
||||
perform_ip(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_ip(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
case STATE_SUBNET:
|
||||
perform_subnet(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_subnet(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
case STATE_TIMEZONE:
|
||||
perform_timezone(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_timezone(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
case STATE_ROUTER:
|
||||
perform_router(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_router(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
case STATE_DNS:
|
||||
perform_dns(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_dns(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
case STATE_LPRSVR:
|
||||
perform_lprsvr(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_lprsvr(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
case STATE_HOSTNAME:
|
||||
perform_hostname(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_hostname(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
case STATE_DOMAIN:
|
||||
perform_domain(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_domain(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
case STATE_IPTTL:
|
||||
perform_ipttl(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_ipttl(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
case STATE_MTU:
|
||||
perform_mtu(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_mtu(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
case STATE_BROADCAST:
|
||||
perform_broadcast(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_broadcast(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
case STATE_NTPSVR:
|
||||
perform_ntpsrv(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_ntpsrv(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
case STATE_WINS:
|
||||
perform_wins(i, p);
|
||||
free_stritem(&cl->curl);
|
||||
perform_wins(cl, p);
|
||||
cl->state = STATE_NOTHING;
|
||||
break;
|
||||
|
||||
@ -551,8 +506,13 @@ static void execute_list(int i)
|
||||
log_line("warning: invalid state in dispatch_work\n");
|
||||
break;
|
||||
}
|
||||
p = endp;
|
||||
}
|
||||
cl->head = cl->curl;
|
||||
size_t remsize = strlen(endp);
|
||||
if (remsize > MAX_BUF - 1)
|
||||
return -1;
|
||||
strlcpy(cl->ibuf, endp, MAX_BUF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Opens a non-blocking listening socket with the appropriate properties. */
|
||||
@ -687,53 +647,32 @@ static void signal_dispatch()
|
||||
|
||||
static void process_client_fd(int fd)
|
||||
{
|
||||
struct ifchd_client *cl = NULL;
|
||||
int r;
|
||||
char buf[MAX_BUF];
|
||||
int r, index, sqidx = -1;
|
||||
|
||||
for (int j = 0; j < SOCK_QUEUE; ++j) {
|
||||
if (clients[j].fd == fd) {
|
||||
sqidx = j;
|
||||
cl = &clients[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sqidx == -1)
|
||||
if (!cl)
|
||||
suicide("epoll returned pending read for untracked fd");
|
||||
struct ifchd_client *cl = &clients[sqidx];
|
||||
|
||||
cl->idle_time = time(NULL);
|
||||
memset(buf, '\0', sizeof buf);
|
||||
|
||||
r = safe_read(cl->fd, buf, sizeof buf / 2 - 1);
|
||||
r = safe_read(cl->fd, buf, sizeof buf - 1);
|
||||
if (r == 0)
|
||||
goto fail;
|
||||
return;
|
||||
else if (r < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return;
|
||||
log_line("error reading from client fd: %s", strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Discard everything and close connection if we risk overflow.
|
||||
* This approach is maximally conservative... worst case is that
|
||||
* some client requests will get dropped. */
|
||||
index = strlen(cl->ibuf);
|
||||
if (index + strlen(buf) > sizeof buf - 2)
|
||||
if (execute_buffer(cl, buf) == -1)
|
||||
goto fail;
|
||||
|
||||
/* Append new stream input avoiding overflow. */
|
||||
strlcpy(cl->ibuf + index, buf, sizeof cl->ibuf - index);
|
||||
|
||||
/* Decompose ibuf contents onto strlist. */
|
||||
index = stream_onto_list(sqidx);
|
||||
|
||||
/* Remove everything that we've parsed into the list. */
|
||||
strlcpy(buf, cl->ibuf + index, sizeof buf);
|
||||
strlcpy(cl->ibuf, buf, sizeof cl->ibuf);
|
||||
|
||||
/* Now we have a strlist of commands and arguments.
|
||||
* Decompose and execute it. */
|
||||
if (!cl->head)
|
||||
return;
|
||||
cl->curl = cl->head;
|
||||
execute_list(sqidx);
|
||||
return;
|
||||
fail:
|
||||
ifchd_client_wipe(cl);
|
||||
|
@ -103,42 +103,42 @@ int authorized_peer(int sk, pid_t pid, uid_t uid, gid_t gid)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void perform_interface(int idx, char *str)
|
||||
void perform_interface(struct ifchd_client *cl, char *str)
|
||||
{
|
||||
if (!str)
|
||||
return;
|
||||
|
||||
/* Update interface name. */
|
||||
memset(clients[idx].ifnam, '\0', IFNAMSIZ);
|
||||
strlcpy(clients[idx].ifnam, str, IFNAMSIZ);
|
||||
memset(cl->ifnam, '\0', IFNAMSIZ);
|
||||
strlcpy(cl->ifnam, str, IFNAMSIZ);
|
||||
}
|
||||
|
||||
static int set_if_flag(int idx, short flag)
|
||||
static int set_if_flag(struct ifchd_client *cl, short flag)
|
||||
{
|
||||
int fd, ret = -1;
|
||||
struct ifreq ifrt;
|
||||
|
||||
if (!is_permitted(clients[idx].ifnam))
|
||||
if (!is_permitted(cl->ifnam))
|
||||
goto out0;
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd == -1) {
|
||||
log_line("%s: (set_if_flag) failed to open interface socket: %s\n",
|
||||
clients[idx].ifnam, strerror(errno));
|
||||
cl->ifnam, strerror(errno));
|
||||
goto out0;
|
||||
}
|
||||
|
||||
strlcpy(ifrt.ifr_name, clients[idx].ifnam, IFNAMSIZ);
|
||||
strlcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ);
|
||||
if (ioctl(fd, SIOCGIFFLAGS, &ifrt) < 0) {
|
||||
log_line("%s: unknown interface: %s\n", clients[idx].ifnam, strerror(errno));
|
||||
log_line("%s: unknown interface: %s\n", cl->ifnam, strerror(errno));
|
||||
goto out1;
|
||||
}
|
||||
if (((ifrt.ifr_flags & flag ) ^ flag) & flag) {
|
||||
strlcpy(ifrt.ifr_name, clients[idx].ifnam, IFNAMSIZ);
|
||||
strlcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ);
|
||||
ifrt.ifr_flags |= flag;
|
||||
if (ioctl(fd, SIOCSIFFLAGS, &ifrt) < 0) {
|
||||
log_line("%s: failed to set interface flags: %s\n",
|
||||
clients[idx].ifnam, strerror(errno));
|
||||
cl->ifnam, strerror(errno));
|
||||
goto out1;
|
||||
}
|
||||
} else
|
||||
@ -151,7 +151,7 @@ static int set_if_flag(int idx, short flag)
|
||||
}
|
||||
|
||||
/* Sets IP address on an interface and brings it up. */
|
||||
void perform_ip(int idx, char *str)
|
||||
void perform_ip(struct ifchd_client *cl, char *str)
|
||||
{
|
||||
int fd;
|
||||
struct in_addr ipaddr;
|
||||
@ -160,14 +160,14 @@ void perform_ip(int idx, char *str)
|
||||
|
||||
if (!str)
|
||||
return;
|
||||
if (!is_permitted(clients[idx].ifnam))
|
||||
if (!is_permitted(cl->ifnam))
|
||||
return;
|
||||
if (!inet_pton(AF_INET, str, &ipaddr))
|
||||
return;
|
||||
if (set_if_flag(idx, (IFF_UP | IFF_RUNNING)))
|
||||
if (set_if_flag(cl, (IFF_UP | IFF_RUNNING)))
|
||||
return;
|
||||
|
||||
strlcpy(ifrt.ifr_name, clients[idx].ifnam, IFNAMSIZ);
|
||||
strlcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ);
|
||||
memset(&sin, 0, sizeof(struct sockaddr));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr = ipaddr;
|
||||
@ -176,17 +176,17 @@ void perform_ip(int idx, char *str)
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd == -1) {
|
||||
log_line("%s: (perform_ip) failed to open interface socket: %s\n",
|
||||
clients[idx].ifnam, strerror(errno));
|
||||
cl->ifnam, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (ioctl(fd, SIOCSIFADDR, &ifrt) < 0)
|
||||
log_line("%s: failed to configure IP: %s\n",
|
||||
clients[idx].ifnam, strerror(errno));
|
||||
cl->ifnam, strerror(errno));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* Sets the subnet mask on an interface. */
|
||||
void perform_subnet(int idx, char *str)
|
||||
void perform_subnet(struct ifchd_client *cl, char *str)
|
||||
{
|
||||
int fd;
|
||||
struct in_addr subnet;
|
||||
@ -195,12 +195,12 @@ void perform_subnet(int idx, char *str)
|
||||
|
||||
if (!str)
|
||||
return;
|
||||
if (!is_permitted(clients[idx].ifnam))
|
||||
if (!is_permitted(cl->ifnam))
|
||||
return;
|
||||
if (!inet_pton(AF_INET, str, &subnet))
|
||||
return;
|
||||
|
||||
strlcpy(ifrt.ifr_name, clients[idx].ifnam, IFNAMSIZ);
|
||||
strlcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ);
|
||||
memset(&sin, 0, sizeof(struct sockaddr));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr = subnet;
|
||||
@ -209,19 +209,19 @@ void perform_subnet(int idx, char *str)
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd == -1) {
|
||||
log_line("%s: (perform_ip) failed to open interface socket: %s\n",
|
||||
clients[idx].ifnam, strerror(errno));
|
||||
cl->ifnam, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (ioctl(fd, SIOCSIFNETMASK, &ifrt) < 0) {
|
||||
sin.sin_addr.s_addr = 0xffffffff;
|
||||
if (ioctl(fd, SIOCSIFNETMASK, &ifrt) < 0)
|
||||
log_line("%s: failed to configure subnet: %s\n",
|
||||
clients[idx].ifnam, strerror(errno));
|
||||
cl->ifnam, strerror(errno));
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void perform_router(int idx, char *str)
|
||||
void perform_router(struct ifchd_client *cl, char *str)
|
||||
{
|
||||
struct rtentry rt;
|
||||
struct sockaddr_in *dest;
|
||||
@ -232,7 +232,7 @@ void perform_router(int idx, char *str)
|
||||
|
||||
if (!str)
|
||||
return;
|
||||
if (!is_permitted(clients[idx].ifnam))
|
||||
if (!is_permitted(cl->ifnam))
|
||||
return;
|
||||
if (!inet_pton(AF_INET, str, &router))
|
||||
return;
|
||||
@ -250,24 +250,24 @@ void perform_router(int idx, char *str)
|
||||
|
||||
rt.rt_flags = RTF_UP | RTF_GATEWAY;
|
||||
if (mask->sin_addr.s_addr == 0xffffffff) rt.rt_flags |= RTF_HOST;
|
||||
rt.rt_dev = clients[idx].ifnam;
|
||||
rt.rt_dev = cl->ifnam;
|
||||
rt.rt_metric = 1;
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd == -1) {
|
||||
log_line("%s: (perform_router) failed to open interface socket: %s\n",
|
||||
clients[idx].ifnam, strerror(errno));
|
||||
cl->ifnam, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (ioctl(fd, SIOCADDRT, &rt)) {
|
||||
if (errno != EEXIST)
|
||||
log_line("%s: failed to set route: %s\n",
|
||||
clients[idx].ifnam, strerror(errno));
|
||||
cl->ifnam, strerror(errno));
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void perform_mtu(int idx, char *str)
|
||||
void perform_mtu(struct ifchd_client *cl, char *str)
|
||||
{
|
||||
int fd;
|
||||
unsigned int mtu;
|
||||
@ -275,26 +275,26 @@ void perform_mtu(int idx, char *str)
|
||||
|
||||
if (!str)
|
||||
return;
|
||||
if (!is_permitted(clients[idx].ifnam))
|
||||
if (!is_permitted(cl->ifnam))
|
||||
return;
|
||||
|
||||
mtu = strtol(str, NULL, 10);
|
||||
ifrt.ifr_mtu = mtu;
|
||||
strlcpy(ifrt.ifr_name, clients[idx].ifnam, IFNAMSIZ);
|
||||
strlcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ);
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd == -1) {
|
||||
log_line("%s: (perform_mtu) failed to open interface socket: %s\n",
|
||||
clients[idx].ifnam, strerror(errno));
|
||||
cl->ifnam, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (ioctl(fd, SIOCSIFMTU, &ifrt) < 0)
|
||||
log_line("%s: failed to set MTU (%d): %s\n", clients[idx].ifnam, mtu,
|
||||
log_line("%s: failed to set MTU (%d): %s\n", cl->ifnam, mtu,
|
||||
strerror(errno));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void perform_broadcast(int idx, char *str)
|
||||
void perform_broadcast(struct ifchd_client *cl, char *str)
|
||||
{
|
||||
int fd;
|
||||
struct in_addr broadcast;
|
||||
@ -303,12 +303,12 @@ void perform_broadcast(int idx, char *str)
|
||||
|
||||
if (!str)
|
||||
return;
|
||||
if (!is_permitted(clients[idx].ifnam))
|
||||
if (!is_permitted(cl->ifnam))
|
||||
return;
|
||||
if (!inet_pton(AF_INET, str, &broadcast))
|
||||
return;
|
||||
|
||||
strlcpy(ifrt.ifr_name, clients[idx].ifnam, IFNAMSIZ);
|
||||
strlcpy(ifrt.ifr_name, cl->ifnam, IFNAMSIZ);
|
||||
memset(&sin, 0, sizeof(struct sockaddr));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr = broadcast;
|
||||
@ -316,11 +316,11 @@ void perform_broadcast(int idx, char *str)
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd == -1) {
|
||||
log_line("%s: (perform_broadcast) failed to open interface socket: %s\n", clients[idx].ifnam, strerror(errno));
|
||||
log_line("%s: (perform_broadcast) failed to open interface socket: %s\n", cl->ifnam, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (ioctl(fd, SIOCSIFBRDADDR, &ifrt) < 0)
|
||||
log_line("%s: failed to set broadcast: %s\n",
|
||||
clients[idx].ifnam, strerror(errno));
|
||||
cl->ifnam, strerror(errno));
|
||||
close(fd);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* linux.h - ifchd Linux-specific functions include
|
||||
*
|
||||
* Copyright (c) 2004-2010 Nicholas J. Kain <njkain at gmail dot com>
|
||||
* Copyright (c) 2004-2012 Nicholas J. Kain <njkain at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -28,15 +28,15 @@
|
||||
|
||||
#ifndef NJK_IFCHD_LINUX_H_
|
||||
#define NJK_IFCHD_LINUX_H_
|
||||
void clear_if_data(int idx);
|
||||
void clear_if_data(struct ifchd_client *cl);
|
||||
void initialize_if_data(void);
|
||||
void add_permitted_if(char *s);
|
||||
int authorized_peer(int sk, pid_t pid, uid_t uid, gid_t gid);
|
||||
void perform_interface(int idx, char *str);
|
||||
void perform_ip(int idx, char *str);
|
||||
void perform_subnet(int idx, char *str);
|
||||
void perform_router(int idx, char *str);
|
||||
void perform_mtu(int idx, char *str);
|
||||
void perform_broadcast(int idx, char *str);
|
||||
void perform_interface(struct ifchd_client *cl, char *str);
|
||||
void perform_ip(struct ifchd_client *cl, char *str);
|
||||
void perform_subnet(struct ifchd_client *cl, char *str);
|
||||
void perform_router(struct ifchd_client *cl, char *str);
|
||||
void perform_mtu(struct ifchd_client *cl, char *str);
|
||||
void perform_broadcast(struct ifchd_client *cl, char *str);
|
||||
#endif
|
||||
|
||||
|
@ -57,7 +57,7 @@ static int ifchd_cmd_u8(char *buf, size_t buflen, char *optname,
|
||||
{
|
||||
if (!optdata || optlen < 1)
|
||||
return -1;
|
||||
return snprintf(buf, buflen, "%s:%c:", optname, *optdata);
|
||||
return snprintf(buf, buflen, "%s:%c;", optname, *optdata);
|
||||
}
|
||||
|
||||
static int ifchd_cmd_u16(char *buf, size_t buflen, char *optname,
|
||||
@ -68,7 +68,7 @@ static int ifchd_cmd_u16(char *buf, size_t buflen, char *optname,
|
||||
uint16_t v;
|
||||
memcpy(&v, optdata, 2);
|
||||
v = ntohs(v);
|
||||
return snprintf(buf, buflen, "%s:%hu:", optname, v);
|
||||
return snprintf(buf, buflen, "%s:%hu;", optname, v);
|
||||
}
|
||||
|
||||
static int ifchd_cmd_s32(char *buf, size_t buflen, char *optname,
|
||||
@ -79,7 +79,7 @@ static int ifchd_cmd_s32(char *buf, size_t buflen, char *optname,
|
||||
int32_t v;
|
||||
memcpy(&v, optdata, 4);
|
||||
v = ntohl(v);
|
||||
return snprintf(buf, buflen, "%s:%d:", optname, v);
|
||||
return snprintf(buf, buflen, "%s:%d;", optname, v);
|
||||
}
|
||||
|
||||
static int ifchd_cmd_ip(char *buf, size_t buflen, char *optname,
|
||||
@ -89,7 +89,7 @@ static int ifchd_cmd_ip(char *buf, size_t buflen, char *optname,
|
||||
if (!optdata || optlen < 4)
|
||||
return -1;
|
||||
inet_ntop(AF_INET, optdata, ipbuf, sizeof ipbuf);
|
||||
return snprintf(buf, buflen, "%s:%s:", optname, ipbuf);
|
||||
return snprintf(buf, buflen, "%s:%s;", optname, ipbuf);
|
||||
}
|
||||
|
||||
static int ifchd_cmd_iplist(char *buf, size_t buflen, char *optname,
|
||||
@ -109,7 +109,10 @@ static int ifchd_cmd_iplist(char *buf, size_t buflen, char *optname,
|
||||
inet_ntop(AF_INET, optdata, ipbuf, sizeof ipbuf);
|
||||
if (buflen < strlen(ipbuf) + (buf - obuf) + 2)
|
||||
break;
|
||||
buf += snprintf(buf, buflen - (buf - obuf), "%s:", ipbuf);
|
||||
if (optlen >= 8)
|
||||
buf += snprintf(buf, buflen - (buf - obuf), "%s:", ipbuf);
|
||||
else
|
||||
buf += snprintf(buf, buflen - (buf - obuf), "%s;", ipbuf);
|
||||
optlen -= 4;
|
||||
optdata += 4;
|
||||
}
|
||||
@ -124,7 +127,7 @@ static int ifchd_cmd_str(char *buf, size_t buflen, char *optname,
|
||||
return -1;
|
||||
buf += snprintf(buf, buflen, "%s:", optname);
|
||||
memcpy(buf, optdata, optlen);
|
||||
buf[optlen] = ':';
|
||||
buf[optlen] = ';';
|
||||
buf[optlen+1] = '\0';
|
||||
return (buf - obuf) + optlen + 1;
|
||||
}
|
||||
@ -193,7 +196,7 @@ void ifchange_deconfig(void)
|
||||
|
||||
sockfd = open_ifch();
|
||||
|
||||
snprintf(buf, sizeof buf, CMD_INTERFACE ":%s:" CMD_IP ":0.0.0.0:",
|
||||
snprintf(buf, sizeof buf, CMD_INTERFACE ":%s;" CMD_IP ":0.0.0.0;",
|
||||
client_config.interface);
|
||||
log_line("Resetting %s IP configuration.", client_config.interface);
|
||||
sockwrite(sockfd, buf, strlen(buf));
|
||||
@ -210,9 +213,9 @@ static size_t send_client_ip(char *out, size_t olen, struct dhcpmsg *packet)
|
||||
if (!memcmp(&packet->yiaddr, &cfg_packet.yiaddr, sizeof packet->yiaddr))
|
||||
return 0;
|
||||
inet_ntop(AF_INET, &packet->yiaddr, ip, sizeof ip);
|
||||
snprintf(ipb, sizeof ipb, "ip:%s:", ip);
|
||||
snprintf(ipb, sizeof ipb, "ip:%s;", ip);
|
||||
strlcat(out, ipb, olen);
|
||||
log_line("Sent to ifchd: %s", ipb);
|
||||
log_line("Sent to ifchd: %s", out);
|
||||
return strlen(ipb);
|
||||
}
|
||||
|
||||
@ -249,7 +252,7 @@ void ifchange_bind(struct dhcpmsg *packet)
|
||||
if (!packet)
|
||||
return;
|
||||
|
||||
snprintf(buf, sizeof buf, CMD_INTERFACE ":%s:", client_config.interface);
|
||||
snprintf(buf, sizeof buf, CMD_INTERFACE ":%s;", client_config.interface);
|
||||
tbs |= send_client_ip(buf, sizeof buf, packet);
|
||||
tbs |= send_cmd(buf, sizeof buf, packet, DCODE_SUBNET);
|
||||
tbs |= send_cmd(buf, sizeof buf, packet, DCODE_ROUTER);
|
||||
|
Loading…
Reference in New Issue
Block a user