2013-05-08 15:57:22 +05:30
|
|
|
/* ifchd-parse.rl - interface change daemon parser
|
|
|
|
*
|
2018-02-18 11:13:19 +05:30
|
|
|
* Copyright (c) 2004-2018 Nicholas J. Kain <njkain at gmail dot com>
|
2013-05-08 15:57:22 +05:30
|
|
|
* 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>
|
2014-03-20 13:37:12 +05:30
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
2013-05-08 15:57:22 +05:30
|
|
|
#include <string.h>
|
2014-03-09 23:21:49 +05:30
|
|
|
#include <arpa/inet.h>
|
2014-03-31 02:32:48 +05:30
|
|
|
#include "nk/log.h"
|
2013-05-08 15:57:22 +05:30
|
|
|
|
2014-03-11 04:59:19 +05:30
|
|
|
#include "ifchd-parse.h"
|
2014-03-10 10:22:56 +05:30
|
|
|
#include "ifchd.h"
|
|
|
|
#include "ifset.h"
|
2014-03-20 13:37:12 +05:30
|
|
|
#include "ndhc.h"
|
2014-03-10 10:22:56 +05:30
|
|
|
|
2014-03-09 22:03:20 +05:30
|
|
|
%%{
|
|
|
|
machine ipv4set_parser;
|
|
|
|
|
|
|
|
action XSt { arg_start = p; }
|
|
|
|
action IpEn {
|
2018-02-09 13:09:46 +05:30
|
|
|
ptrdiff_t arg_len = p - arg_start;
|
|
|
|
if (arg_len > 0 && (size_t)arg_len < sizeof ip4_addr) {
|
2014-03-09 22:03:20 +05:30
|
|
|
have_ip = true;
|
2018-02-09 13:09:46 +05:30
|
|
|
memcpy(ip4_addr, arg_start, (size_t)arg_len);
|
2014-03-09 22:03:20 +05:30
|
|
|
}
|
|
|
|
ip4_addr[arg_len] = 0;
|
|
|
|
}
|
|
|
|
action SnEn {
|
2018-02-09 13:09:46 +05:30
|
|
|
ptrdiff_t arg_len = p - arg_start;
|
|
|
|
if (arg_len > 0 && (size_t)arg_len < sizeof ip4_subnet) {
|
2014-03-09 22:03:20 +05:30
|
|
|
have_subnet = true;
|
2018-02-09 13:09:46 +05:30
|
|
|
memcpy(ip4_subnet, arg_start, (size_t)arg_len);
|
2014-03-09 22:03:20 +05:30
|
|
|
}
|
|
|
|
ip4_subnet[arg_len] = 0;
|
|
|
|
}
|
|
|
|
action BcEn {
|
2018-02-09 13:09:46 +05:30
|
|
|
ptrdiff_t arg_len = p - arg_start;
|
|
|
|
if (arg_len > 0 && (size_t)arg_len < sizeof ip4_bcast) {
|
2014-03-09 22:03:20 +05:30
|
|
|
have_ip = true;
|
2018-02-09 13:09:46 +05:30
|
|
|
memcpy(ip4_bcast, arg_start, (size_t)arg_len);
|
2014-03-09 22:03:20 +05:30
|
|
|
}
|
|
|
|
ip4_bcast[arg_len] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
v4addr = digit{1,3} '.' digit{1,3} '.' digit{1,3} '.' digit{1,3};
|
|
|
|
ip4_nobc = (v4addr > XSt % IpEn) ',' (v4addr > XSt % SnEn);
|
|
|
|
ip4_bc = (v4addr > XSt % IpEn) ',' (v4addr > XSt % SnEn) ','
|
|
|
|
(v4addr > XSt % BcEn);
|
|
|
|
main := (ip4_bc|ip4_nobc);
|
|
|
|
}%%
|
|
|
|
|
|
|
|
%% write data;
|
|
|
|
|
2015-02-15 12:59:37 +05:30
|
|
|
static int perform_ip4set(const char buf[static 1], size_t len)
|
2014-03-09 22:03:20 +05:30
|
|
|
{
|
2014-03-09 23:21:49 +05:30
|
|
|
char ip4_addr[INET_ADDRSTRLEN];
|
|
|
|
char ip4_subnet[INET_ADDRSTRLEN];
|
|
|
|
char ip4_bcast[INET_ADDRSTRLEN];
|
2014-03-09 22:03:20 +05:30
|
|
|
const char *p = buf;
|
|
|
|
const char *pe = p + len;
|
|
|
|
const char *eof = pe;
|
|
|
|
const char *arg_start;
|
2014-03-11 04:30:08 +05:30
|
|
|
int cs = 0;
|
2014-03-09 22:03:20 +05:30
|
|
|
bool have_ip = false;
|
|
|
|
bool have_subnet = false;
|
|
|
|
bool have_bcast = false;
|
|
|
|
|
|
|
|
%% write init;
|
|
|
|
%% write exec;
|
|
|
|
|
|
|
|
if (cs < ipv4set_parser_first_final) {
|
|
|
|
log_line("%s: received invalid arguments", __func__);
|
2015-02-15 12:59:37 +05:30
|
|
|
return -1;
|
2014-03-09 22:03:20 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
// These should never trigger because of the above check, but be safe...
|
|
|
|
if (!have_ip) {
|
|
|
|
log_line("%s: No IPv4 address specified.", __func__);
|
2015-02-15 12:59:37 +05:30
|
|
|
return -1;
|
2014-03-09 22:03:20 +05:30
|
|
|
}
|
|
|
|
if (!have_subnet) {
|
|
|
|
log_line("%s: No IPv4 subnet specified.", __func__);
|
2015-02-15 12:59:37 +05:30
|
|
|
return -1;
|
2014-03-09 22:03:20 +05:30
|
|
|
}
|
|
|
|
|
2015-02-15 12:59:37 +05:30
|
|
|
return perform_ip_subnet_bcast(ip4_addr, ip4_subnet,
|
|
|
|
have_bcast ? ip4_bcast : NULL);
|
2014-03-09 22:03:20 +05:30
|
|
|
}
|
|
|
|
|
2013-05-08 15:57:22 +05:30
|
|
|
%%{
|
|
|
|
machine ifchd_parser;
|
|
|
|
|
2014-03-10 10:22:56 +05:30
|
|
|
action Reset { cl.state = STATE_NOTHING; }
|
2013-05-08 15:57:22 +05:30
|
|
|
action ArgSt { arg_start = p; }
|
|
|
|
action ArgEn {
|
2018-02-09 13:09:46 +05:30
|
|
|
ptrdiff_t al = p - arg_start;
|
|
|
|
if (al < 0 || (size_t)al > sizeof tb - 1) {
|
2013-05-08 15:57:22 +05:30
|
|
|
log_line("command argument would overflow");
|
2015-02-15 12:59:37 +05:30
|
|
|
return -99;
|
2013-05-08 15:57:22 +05:30
|
|
|
}
|
2018-02-09 13:09:46 +05:30
|
|
|
arg_len = (size_t)al;
|
2013-05-08 15:57:22 +05:30
|
|
|
memcpy(tb, arg_start, arg_len);
|
|
|
|
tb[arg_len] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
action Dispatch {
|
2015-07-03 10:19:13 +05:30
|
|
|
int pr = 0;
|
2014-03-10 10:22:56 +05:30
|
|
|
switch (cl.state) {
|
2015-07-03 10:19:13 +05:30
|
|
|
case STATE_IP4SET: pr = perform_ip4set(tb, arg_len); break;
|
|
|
|
case STATE_TIMEZONE: pr = perform_timezone( tb, arg_len); break;
|
|
|
|
case STATE_ROUTER: pr = perform_router(tb, arg_len); break;
|
|
|
|
case STATE_DNS: pr = perform_dns(tb, arg_len); break;
|
|
|
|
case STATE_LPRSVR: pr = perform_lprsvr(tb, arg_len); break;
|
|
|
|
case STATE_HOSTNAME: pr = perform_hostname(tb, arg_len); break;
|
|
|
|
case STATE_DOMAIN: pr = perform_domain(tb, arg_len); break;
|
|
|
|
case STATE_IPTTL: pr = perform_ipttl(tb, arg_len); break;
|
|
|
|
case STATE_MTU: pr = perform_mtu(tb, arg_len); break;
|
|
|
|
case STATE_NTPSVR: pr = perform_ntpsrv(tb, arg_len); break;
|
|
|
|
case STATE_WINS: pr = perform_wins(tb, arg_len); break;
|
|
|
|
case STATE_CARRIER: pr = perform_carrier(); break;
|
2013-05-08 15:57:22 +05:30
|
|
|
default:
|
2018-02-09 13:09:46 +05:30
|
|
|
arg_len = 0;
|
2013-05-08 15:57:22 +05:30
|
|
|
log_line("error: invalid state in dispatch_work");
|
2015-02-15 12:59:37 +05:30
|
|
|
return -99;
|
2013-05-08 15:57:22 +05:30
|
|
|
}
|
2018-02-09 13:09:46 +05:30
|
|
|
arg_len = 0;
|
2015-07-03 10:19:13 +05:30
|
|
|
if (pr == -99)
|
|
|
|
return -99;
|
|
|
|
cmdf |= pr;
|
2013-05-08 15:57:22 +05:30
|
|
|
}
|
|
|
|
|
2013-05-11 20:29:04 +05:30
|
|
|
terminator = ';' > Dispatch;
|
|
|
|
v4addr = digit{1,3} '.' digit{1,3} '.' digit{1,3} '.' digit{1,3};
|
|
|
|
ip_arg = (v4addr > ArgSt % ArgEn) terminator;
|
2014-03-09 22:03:20 +05:30
|
|
|
ip4set_arg = (((v4addr ','){1,2} v4addr) > ArgSt % ArgEn) terminator;
|
2013-05-11 20:29:04 +05:30
|
|
|
iplist_arg = (((v4addr ',')* v4addr) > ArgSt % ArgEn) terminator;
|
|
|
|
str_arg = ([^;\0]+ > ArgSt % ArgEn) terminator;
|
|
|
|
s32_arg = (extend{4} > ArgSt % ArgEn) terminator;
|
|
|
|
u16_arg = (extend{2} > ArgSt % ArgEn) terminator;
|
|
|
|
u8_arg = (extend{1} > ArgSt % ArgEn) terminator;
|
2013-05-08 15:57:22 +05:30
|
|
|
|
2014-03-10 10:43:38 +05:30
|
|
|
cmd_ip = ('routr:' % { cl.state = STATE_ROUTER; }) ip_arg;
|
2014-03-10 10:22:56 +05:30
|
|
|
cmd_ip4set = ('ip4:' % { cl.state = STATE_IP4SET; }) ip4set_arg;
|
|
|
|
cmd_iplist = ('dns:' % { cl.state = STATE_DNS; }
|
|
|
|
|'lpr:' % { cl.state = STATE_LPRSVR; }
|
|
|
|
|'ntp:' % { cl.state = STATE_NTPSVR; }
|
|
|
|
|'wins:' % { cl.state = STATE_WINS; }
|
2013-05-11 20:29:04 +05:30
|
|
|
) iplist_arg;
|
2014-03-10 10:22:56 +05:30
|
|
|
cmd_str = ('host:' % { cl.state = STATE_HOSTNAME; }
|
|
|
|
|'dom:' % { cl.state = STATE_DOMAIN; }
|
2013-05-11 20:29:04 +05:30
|
|
|
) str_arg;
|
2014-03-10 10:22:56 +05:30
|
|
|
cmd_s32 = ('tzone:' % { cl.state = STATE_TIMEZONE; }) s32_arg;
|
|
|
|
cmd_u16 = ('mtu:' % { cl.state = STATE_MTU; }) u16_arg;
|
|
|
|
cmd_u8 = ('ipttl:' % { cl.state = STATE_IPTTL; }) u8_arg;
|
2015-02-15 13:20:29 +05:30
|
|
|
cmd_none = ('carrier:' % { cl.state = STATE_CARRIER; }) terminator;
|
2013-05-08 15:57:22 +05:30
|
|
|
|
2015-02-15 13:20:29 +05:30
|
|
|
command = (cmd_ip|cmd_ip4set|cmd_iplist|cmd_str|cmd_s32|cmd_u16|cmd_u8|cmd_none);
|
2013-05-08 15:57:22 +05:30
|
|
|
main := (command > Reset)+;
|
|
|
|
}%%
|
|
|
|
|
|
|
|
%% write data;
|
|
|
|
|
|
|
|
/*
|
2015-02-15 12:59:37 +05:30
|
|
|
* Returns -99 on fatal error; that leads to peer connection being closed.
|
|
|
|
* Returns -1 if one of the commands failed.
|
|
|
|
* Returns 0 on success.
|
2013-05-08 15:57:22 +05:30
|
|
|
*/
|
2015-02-14 09:44:08 +05:30
|
|
|
int execute_buffer(const char newbuf[static 1])
|
2013-05-08 15:57:22 +05:30
|
|
|
{
|
|
|
|
char buf[MAX_BUF * 2];
|
|
|
|
char tb[MAX_BUF];
|
2015-02-15 12:59:37 +05:30
|
|
|
int cmdf = 0;
|
2013-05-08 15:57:22 +05:30
|
|
|
|
2014-03-20 13:37:12 +05:30
|
|
|
ssize_t buflen = snprintf(buf, sizeof buf, "%s%s", cl.ibuf, newbuf);
|
|
|
|
if (buflen < 0) {
|
|
|
|
log_error("%s: (%s) snprintf1 failed; your system is broken?",
|
|
|
|
client_config.interface, __func__);
|
2015-02-15 12:59:37 +05:30
|
|
|
return -99;
|
2014-03-20 13:37:12 +05:30
|
|
|
}
|
|
|
|
if ((size_t)buflen >= sizeof buf) {
|
|
|
|
log_error("%s: (%s) input is too long for buffer",
|
|
|
|
client_config.interface, __func__);
|
2015-02-15 12:59:37 +05:30
|
|
|
return -99;
|
2013-05-08 15:57:22 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
size_t init_siz = strlen(buf);
|
|
|
|
const char *p = buf;
|
|
|
|
const char *pe = p + init_siz;
|
|
|
|
const char *arg_start;
|
2018-02-09 13:09:46 +05:30
|
|
|
size_t arg_len = 0;
|
2014-03-11 04:30:08 +05:30
|
|
|
int cs = 0;
|
2013-05-08 15:57:22 +05:30
|
|
|
|
|
|
|
%% write init;
|
|
|
|
%% write exec;
|
|
|
|
|
2018-02-09 13:09:46 +05:30
|
|
|
ptrdiff_t blt = pe - p;
|
|
|
|
size_t bytes_left = blt >= 0 ? (size_t)blt : 0;
|
2013-05-08 15:57:22 +05:30
|
|
|
if (bytes_left > 0) {
|
|
|
|
size_t taken = init_siz - bytes_left;
|
2014-03-20 13:37:12 +05:30
|
|
|
ssize_t ilen = snprintf(cl.ibuf, sizeof cl.ibuf, "%s", buf + taken);
|
|
|
|
if (ilen < 0) {
|
|
|
|
log_error("%s: (%s) snprintf2 failed; your system is broken?",
|
|
|
|
client_config.interface, __func__);
|
2015-02-15 12:59:37 +05:30
|
|
|
return -99;
|
2014-03-20 13:37:12 +05:30
|
|
|
}
|
|
|
|
if ((size_t)ilen >= sizeof buf) {
|
|
|
|
log_error("%s: (%s) unconsumed input too long for buffer",
|
|
|
|
client_config.interface, __func__);
|
2015-02-15 12:59:37 +05:30
|
|
|
return -99;
|
2014-03-20 13:37:12 +05:30
|
|
|
}
|
2013-05-08 15:57:22 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
if (cs < ifchd_parser_first_final) {
|
2014-03-20 13:37:12 +05:30
|
|
|
log_error("%s: ifch received invalid commands",
|
|
|
|
client_config.interface);
|
2015-02-15 12:59:37 +05:30
|
|
|
return -99;
|
2013-05-08 15:57:22 +05:30
|
|
|
}
|
2015-02-15 12:59:37 +05:30
|
|
|
return !cmdf ? 0 : -1;
|
2013-05-08 15:57:22 +05:30
|
|
|
}
|
|
|
|
|