ndhc/ifchd/ifchd-parse.rl

152 lines
5.1 KiB
Ragel

/* 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;
}