static reply_handler dhcpv6_handle_reconfigure;
static int dhcpv6_commit_advert(void);
-
-
// RFC 3315 - 5.5 Timeout and Delay values
static struct dhcpv6_retx dhcpv6_retx[_DHCPV6_MSG_MAX] = {
[DHCPV6_MSG_UNKNOWN] = {false, 1, 120, 0, "<POLL>",
dhcpv6_handle_reply, NULL},
};
-
// Sockets
static int sock = -1;
static int ifindex = -1;
// client options
static unsigned int client_options = 0;
-
static uint32_t ntohl_unaligned(const uint8_t *data)
{
uint32_t buf;
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0)
return -1;
+
ifindex = ifr.ifr_ifindex;
// Create client DUID
struct sockaddr_in6 client_addr = { .sin6_family = AF_INET6,
.sin6_port = htons(DHCPV6_CLIENT_PORT), .sin6_flowinfo = 0 };
+
if (bind(sock, (struct sockaddr*)&client_addr, sizeof(client_addr)) < 0)
return -1;
fqdn.len = htons(fqdn_len - 4);
fqdn.flags = 0;
-
// Build Client ID
size_t cl_id_len;
void *cl_id = odhcp6c_get_state(STATE_CLIENT_ID, &cl_id_len);
cnt = 9;
iov[IOV_ORO_REFRESH].iov_len = sizeof(oro_refresh);
hdr.oro_len = htons(oro_len + sizeof(oro_refresh));
- } else if (!request_prefix) {
+ } else if (!request_prefix)
cnt = 13;
- }
// Disable IAs if not used
if (type != DHCPV6_MSG_SOLICIT && ia_na_len == 0)
}
}
-
static int64_t dhcpv6_rand_delay(int64_t time)
{
int random;
odhcp6c_random(&random, sizeof(random));
+
return (time * ((int64_t)random % 1000LL)) / 10000LL;
}
-
int dhcpv6_request(enum dhcpv6_msg type)
{
uint8_t rc = 0;
if (retx->delay) {
struct timespec ts = {0, 0};
ts.tv_nsec = (dhcpv6_rand_delay((10000 * DHCPV6_REQ_DELAY) / 2) + (1000 * DHCPV6_REQ_DELAY) / 2) * 1000000;
+
while (nanosleep(&ts, &ts) < 0 && errno == EINTR);
}
uint8_t trid[3] = {0, 0, 0};
if (type != DHCPV6_MSG_UNKNOWN)
odhcp6c_random(trid, sizeof(trid));
+
ssize_t len = -1;
int64_t rto = 0;
delay = dhcpv6_rand_delay(retx->init_timeo * 1000);
rto = (retx->init_timeo * 1000 + delay);
- }
- else
+ } else
rto = (2 * rto + dhcpv6_rand_delay(rto));
if (retx->max_timeo && (rto >= retx->max_timeo * 1000))
.msg_controllen = sizeof(cmsg_buf)};
struct in6_pktinfo *pktinfo = NULL;
-
// Check for pending signal
if (odhcp6c_signal_process())
return -1;
if (rep->msg_type != DHCPV6_MSG_ADVERT &&
rep->msg_type != DHCPV6_MSG_REPLY)
return false;
+
} else if (type == DHCPV6_MSG_UNKNOWN) {
if (!accept_reconfig || rep->msg_type != DHCPV6_MSG_RECONF)
return false;
- } else if (rep->msg_type != DHCPV6_MSG_REPLY) {
+
+ } else if (rep->msg_type != DHCPV6_MSG_REPLY)
return false;
- }
uint8_t *end = ((uint8_t*)buf) + len, *odata = NULL,
rcmsg = DHCPV6_MSG_UNKNOWN;
ia_present = true;
if (olen < -4 + sizeof(struct dhcpv6_ia_hdr))
options_valid = false;
- }
- else if ((otype == DHCPV6_OPT_IA_ADDR) || (otype == DHCPV6_OPT_IA_PREFIX) ||
- (otype == DHCPV6_OPT_PD_EXCLUDE)) {
+ } else if ((otype == DHCPV6_OPT_IA_ADDR) || (otype == DHCPV6_OPT_IA_PREFIX) ||
+ (otype == DHCPV6_OPT_PD_EXCLUDE))
// Options are not allowed on global level
options_valid = false;
- }
}
if (!options_valid || ((odata + olen) > end))
return clientid_ok && serverid_ok;
}
-
int dhcpv6_poll_reconfigure(void)
{
int ret = dhcpv6_request(DHCPV6_MSG_UNKNOWN);
+
if (ret != -1)
ret = dhcpv6_request(ret);
return ret;
}
-
static int dhcpv6_handle_reconfigure(_unused enum dhcpv6_msg orig, const int rc,
const void *opt, const void *end, _unused const struct sockaddr_in6 *from)
{
uint16_t otype, olen;
uint8_t *odata, msg = DHCPV6_MSG_RENEW;
- dhcpv6_for_each_option(opt, end, otype, olen, odata)
+
+ dhcpv6_for_each_option(opt, end, otype, olen, odata) {
if (otype == DHCPV6_OPT_RECONF_MESSAGE && olen == 1 && (
odata[0] == DHCPV6_MSG_RENEW ||
odata[0] == DHCPV6_MSG_INFO_REQ))
msg = odata[0];
+ }
dhcpv6_handle_reply(DHCPV6_MSG_UNKNOWN, rc, NULL, NULL, NULL);
+
return msg;
}
-
// Collect all advertised servers
static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc,
const void *opt, const void *end, _unused const struct sockaddr_in6 *from)
if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN &&
sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX)
cand.sol_max_rt = sol_max_rt;
+
} else if (otype == DHCPV6_OPT_INF_MAX_RT && olen == 4) {
uint32_t inf_max_rt = ntohl_unaligned(odata);
if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN &&
inf_max_rt <= DHCPV6_INF_MAX_RT_MAX)
cand.inf_max_rt = inf_max_rt;
+
} else if (otype == DHCPV6_OPT_IA_PD && request_prefix &&
olen >= -4 + sizeof(struct dhcpv6_ia_hdr)) {
struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr*)&odata[-4];
olen >= -4 + sizeof(struct dhcpv6_ia_hdr)) {
struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr*)&odata[-4];
uint8_t *oend = odata + olen, *d;
- dhcpv6_for_each_option(&h[1], oend, otype, olen, d)
+
+ dhcpv6_for_each_option(&h[1], oend, otype, olen, d) {
if (otype == DHCPV6_OPT_IA_ADDR &&
olen >= -4 + sizeof(struct dhcpv6_ia_addr))
have_na = true;
+ }
}
}
return (rc > 1 || (pref == 255 && cand.preference > 0)) ? 1 : -1;
}
-
static int dhcpv6_commit_advert(void)
{
return dhcpv6_promote_server_cand();
}
-
static int dhcpv6_handle_rebind_reply(enum dhcpv6_msg orig, const int rc,
const void *opt, const void *end, const struct sockaddr_in6 *from)
{
return dhcpv6_handle_reply(orig, rc, opt, end, from);
}
-
static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc,
const void *opt, const void *end, const struct sockaddr_in6 *from)
{
dhcpv6_handle_ia_status_code(orig, ia_hdr,
code, mdata, mlen, handled_status_codes, &ret);
-
if (ret > 0)
return ret;
+
break;
}
}
} else if (otype == DHCPV6_OPT_DNS_SERVERS) {
if (olen % 16 == 0)
odhcp6c_add_state(STATE_DNS, odata, olen);
- } else if (otype == DHCPV6_OPT_DNS_DOMAIN) {
+ } else if (otype == DHCPV6_OPT_DNS_DOMAIN)
odhcp6c_add_state(STATE_SEARCH, odata, olen);
- } else if (otype == DHCPV6_OPT_SNTP_SERVERS) {
+ else if (otype == DHCPV6_OPT_SNTP_SERVERS) {
if (olen % 16 == 0)
odhcp6c_add_state(STATE_SNTP_IP, odata, olen);
} else if (otype == DHCPV6_OPT_NTP_SERVER) {
} else if (otype == DHCPV6_OPT_SIP_SERVER_A) {
if (olen == 16)
odhcp6c_add_state(STATE_SIP_IP, odata, olen);
- } else if (otype == DHCPV6_OPT_SIP_SERVER_D) {
+ } else if (otype == DHCPV6_OPT_SIP_SERVER_D)
odhcp6c_add_state(STATE_SIP_FQDN, odata, olen);
- } else if (otype == DHCPV6_OPT_INFO_REFRESH && olen >= 4) {
+ else if (otype == DHCPV6_OPT_INFO_REFRESH && olen >= 4) {
refresh = ntohl_unaligned(odata);
passthru = false;
} else if (otype == DHCPV6_OPT_AUTH) {
otype == DHCPV6_OPT_PREF ||
otype == DHCPV6_OPT_UNICAST ||
otype == DHCPV6_OPT_FQDN ||
- otype == DHCPV6_OPT_RECONF_ACCEPT) {
+ otype == DHCPV6_OPT_RECONF_ACCEPT)
passthru = false;
- } else {
+ else
odhcp6c_add_state(STATE_CUSTOM_OPTS, &odata[-4], olen + 4);
- }
if (passthru)
odhcp6c_add_state(STATE_PASSTHRU, &odata[-4], olen + 4);
odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, 16);
}
}
- }
- else if (ret > 0) {
+ } else if (ret > 0) {
// All server candidates can be cleared if not yet bound
if (!odhcp6c_is_bound())
dhcpv6_clear_all_server_cand();
return ret;
}
-
static int dhcpv6_parse_ia(void *opt, void *end)
{
struct dhcpv6_ia_hdr *ia_hdr = (struct dhcpv6_ia_hdr *)opt;
continue;
}
-
uint8_t bytes = ((elen - entry.length - 1) / 8) + 1;
if (slen <= bytes) {
ok = false;
return parsed_ia;
}
-
static int dhcpv6_calc_refresh_timers(void)
{
struct odhcp6c_entry *e;
e = odhcp6c_get_state(STATE_IA_NA, &ia_na_entries);
ia_na_entries /= sizeof(*e);
+
for (i = 0; i < ia_na_entries; i++) {
if (e[i].t1 < l_t1)
l_t1 = e[i].t1;
e = odhcp6c_get_state(STATE_IA_PD, &ia_pd_entries);
ia_pd_entries /= sizeof(*e);
+
for (i = 0; i < ia_pd_entries; i++) {
if (e[i].t1 < l_t1)
l_t1 = e[i].t1;
return (int)(ia_pd_entries + ia_na_entries);
}
-
static void dhcpv6_log_status_code(const uint16_t code, const char *scope,
const void *status_msg, int len)
{
}
*dst++ = ')';
}
+
*dst = 0;
syslog(LOG_WARNING, "Server returned %s status %i %s",
scope, code, buf);
}
-
static void dhcpv6_handle_status_code(const enum dhcpv6_msg orig,
const uint16_t code, const void *status_msg, const int len,
int *ret)
}
}
-
static void dhcpv6_handle_ia_status_code(const enum dhcpv6_msg orig,
const struct dhcpv6_ia_hdr *ia_hdr, const uint16_t code,
const void *status_msg, const int len,
odhcp6c_add_state(STATE_SERVER_ID, hdr, sizeof(hdr));
odhcp6c_add_state(STATE_SERVER_ID, cand->duid, cand->duid_len);
accept_reconfig = cand->wants_reconfigure;
+
if (cand->ia_na_len) {
odhcp6c_add_state(STATE_IA_NA, cand->ia_na, cand->ia_na_len);
free(cand->ia_na);
if (na_mode != IA_MODE_NONE)
ret = DHCPV6_STATEFUL;
}
+
if (cand->ia_pd_len) {
odhcp6c_add_state(STATE_IA_PD, cand->ia_pd, cand->ia_pd_len);
free(cand->ia_pd);
#include "odhcp6c.h"
#include "ra.h"
-
#ifndef IN6_IS_ADDR_UNIQUELOCAL
#define IN6_IS_ADDR_UNIQUELOCAL(a) \
((((__const uint32_t *) (a))[0] & htonl (0xfe000000)) \
int main(_unused int argc, char* const argv[])
{
- // Allocate ressources
+ static struct in6_addr ifid = IN6ADDR_ANY_INIT;
+ // Allocate resources
const char *pidfile = NULL;
const char *script = "/usr/sbin/odhcp6c-update";
ssize_t l;
enum odhcp6c_ia_mode ia_na_mode = IA_MODE_TRY;
enum odhcp6c_ia_mode ia_pd_mode = IA_MODE_NONE;
int ia_pd_iaid_index = 0;
- static struct in6_addr ifid = IN6ADDR_ANY_INIT;
int sol_timeout = DHCPV6_SOL_MAX_RT;
int verbosity = 0;
-
-
bool help = false, daemonize = false;
int logopt = LOG_PID;
int c;
if (!strcmp(optarg, "force")) {
ia_na_mode = IA_MODE_FORCE;
allow_slaac_only = -1;
- } else if (!strcmp(optarg, "none")) {
+ } else if (!strcmp(optarg, "none"))
ia_na_mode = IA_MODE_NONE;
- } else if (!strcmp(optarg, "try")) {
+ else if (!strcmp(optarg, "try"))
ia_na_mode = IA_MODE_TRY;
- } else{
+ else
help = true;
- }
break;
case 'V':
l = script_unhexlify(buf, sizeof(buf), optarg);
if (!l)
- help=true;
+ help = true;
odhcp6c_add_state(STATE_VENDORCLASS, buf, l);
-
break;
+
case 'P':
if (ia_pd_mode == IA_MODE_NONE)
ia_pd_mode = IA_MODE_TRY;
char *iaid_begin;
int iaid_len = 0;
-
int prefix_length = strtoul(optarg, &iaid_begin, 10);
if (*iaid_begin != '\0' && *iaid_begin != ',' && *iaid_begin != ':') {
prefix.iaid = htonl(++ia_pd_iaid_index);
odhcp6c_add_state(STATE_IA_PD_INIT, &prefix, sizeof(prefix));
-
break;
case 'F':
buf[2] = 0;
buf[3] = l;
odhcp6c_add_state(STATE_CLIENT_ID, buf, l + 4);
- } else {
+ } else
help = true;
- }
break;
case 'i':
break;
else if (optpos[0])
optarg = &optpos[1];
+
odhcp6c_add_state(STATE_ORO, &opttype, 2);
}
break;
int mode = dhcpv6_set_ia_mode(ia_na_mode, ia_pd_mode);
if (mode != DHCPV6_STATELESS)
mode = dhcpv6_request(DHCPV6_MSG_SOLICIT);
+
odhcp6c_signal_process();
if (mode < 0)
signal_usr1 = false; // Acknowledged
continue;
}
+
if (signal_usr2 || signal_term)
break;
res = dhcpv6_request(DHCPV6_MSG_INFO_REQ);
odhcp6c_signal_process();
+
if (signal_usr1)
continue;
else if (res < 0)
// Handle signal, if necessary
if (signal_usr1)
signal_usr1 = false; // Acknowledged
+
if (signal_usr2 || signal_term)
break; // Other signal type
// Send renew as T1 expired
res = dhcpv6_request(DHCPV6_MSG_RENEW);
odhcp6c_signal_process();
+
if (res > 0) { // Renew was succesfull
// Publish updates
script_call("updated", 0, false);
if (res > 0)
script_call("rebound", 0, true);
- else {
+ else
break;
- }
}
break;
}
script_call("stopped", 0, true);
+
return 0;
}
-
static int usage(void)
{
const char buf[] =
" -v Increase logging verbosity\n"
" -h Show this help\n\n";
fputs(buf, stderr);
+
return 1;
}
-
// Don't want to pull-in librt and libpthread just for a monotonic clock...
uint64_t odhcp6c_get_milli_time(void)
{
struct timespec t = {0, 0};
syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &t);
+
return ((uint64_t)t.tv_sec) * 1000 + ((uint64_t)t.tv_nsec) / 1000000;
}
-
static uint8_t* odhcp6c_resize_state(enum odhcp6c_state state, ssize_t len)
{
if (len == 0)
return NULL;
uint8_t *n = realloc(state_data[state], state_len[state] + len);
+
if (n || state_len[state] + len == 0) {
state_data[state] = n;
n += state_len[state];
state_len[state] += len;
}
+
return n;
}
-
bool odhcp6c_signal_process(void)
{
while (signal_io) {
return signal_usr1 || signal_usr2 || signal_term;
}
-
void odhcp6c_clear_state(enum odhcp6c_state state)
{
state_len[state] = 0;
}
-
void odhcp6c_add_state(enum odhcp6c_state state, const void *data, size_t len)
{
uint8_t *n = odhcp6c_resize_state(state, len);
+
if (n)
memcpy(n, data, len);
}
return -1;
uint8_t *n = odhcp6c_resize_state(state, len);
+
if (n) {
uint8_t *sdata = state_data[state];
{
uint8_t *data = state_data[state];
ssize_t len_after = state_len[state] - (offset + len);
+
if (len_after < 0)
return state_len[state];
memmove(data + offset, data + offset + len, len_after);
+
return state_len[state] -= len;
}
-
void* odhcp6c_move_state(enum odhcp6c_state state, size_t *len)
{
*len = state_len[state];
return data;
}
-
void* odhcp6c_get_state(enum odhcp6c_state state, size_t *len)
{
*len = state_len[state];
+
return state_data[state];
}
-
static struct odhcp6c_entry* odhcp6c_find_entry(enum odhcp6c_state state, const struct odhcp6c_entry *new)
{
size_t len, cmplen = offsetof(struct odhcp6c_entry, target) + ((new->length + 7) / 8);
for (struct odhcp6c_entry *c = (struct odhcp6c_entry*)start;
(uint8_t*)c < &start[len] &&
(uint8_t*)odhcp6c_next_entry(c) <= &start[len];
- c = odhcp6c_next_entry(c))
+ c = odhcp6c_next_entry(c)) {
if (!memcmp(c, new, cmplen) && !memcmp(c->auxtarget, new->auxtarget, new->auxlen))
return c;
+ }
return NULL;
}
-
bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new,
uint32_t safe, bool filterexcess)
{
new->preferred != UINT32_MAX &&
new->preferred - x->preferred < min_update_interval)
return false;
+
x->valid = new->valid;
x->preferred = new->preferred;
x->t1 = new->t1;
x->t2 = new->t2;
x->iaid = new->iaid;
- } else {
+ } else
odhcp6c_add_state(state, new, odhcp6c_entry_size(new));
- }
- } else if (x) {
+ } else if (x)
odhcp6c_remove_state(state, ((uint8_t*)x) - start, odhcp6c_entry_size(x));
- }
+
return true;
}
-
static void odhcp6c_expire_list(enum odhcp6c_state state, uint32_t elapsed)
{
size_t len;
uint8_t *start = odhcp6c_get_state(state, &len);
+
for (struct odhcp6c_entry *c = (struct odhcp6c_entry*)start;
(uint8_t*)c < &start[len] &&
(uint8_t*)odhcp6c_next_entry(c) <= &start[len];
if (!c->valid) {
odhcp6c_remove_state(state, ((uint8_t*)c) - start, odhcp6c_entry_size(c));
start = odhcp6c_get_state(state, &len);
- } else {
+ } else
c = odhcp6c_next_entry(c);
- }
}
}
-
void odhcp6c_expire(void)
{
time_t now = odhcp6c_get_milli_time() / 1000;
uint32_t elapsed = (last_update > 0) ? now - last_update : 0;
+
last_update = now;
odhcp6c_expire_list(STATE_RA_PREFIX, elapsed);
odhcp6c_expire_list(STATE_IA_PD, elapsed);
}
-
uint32_t odhcp6c_elapsed(void)
{
return odhcp6c_get_milli_time() / 1000 - last_update;
}
-
int odhcp6c_random(void *buf, size_t len)
{
return read(urandom_fd, buf, len);
(IN6_IS_ADDR_UNIQUELOCAL(&inet6_addr) == IN6_IS_ADDR_UNIQUELOCAL(addr)))
return true;
}
+
return false;
}
/**
* Copyright (C) 2012-2014 Steven Barth <steven@midlink.org>
+ * Copyright (C) 2017 Hans Dedecker <dedeckeh@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License v2 as published by
#include "odhcp6c.h"
#include "ra.h"
-
static bool nocarrier = false;
static int sock = -1, rtnl = -1;
.lladdr = {ND_OPT_SOURCE_LINKADDR, 1, {0}},
};
-
static void ra_send_rs(int signal __attribute__((unused)));
int ra_init(const char *ifname, const struct in6_addr *ifid, unsigned int options)
return 0;
}
-
static void ra_send_rs(int signal __attribute__((unused)))
{
const struct sockaddr_in6 dest = {AF_INET6, 0, 0, ALL_IPV6_ROUTERS, if_index};
alarm(4);
}
-
static int16_t pref_to_priority(uint8_t flags)
{
flags = (flags >> 3) & 0x03;
+
return (flags == 0x0) ? 512 : (flags == 0x1) ? 384 :
(flags == 0x3) ? 640 : -1;
}
-
bool ra_link_up(void)
{
static bool firstcall = true;
struct ifinfomsg msg;
uint8_t pad[4000];
} resp;
-
bool ret = false;
ssize_t read;
do {
read = recv(rtnl, &resp, sizeof(resp), MSG_DONTWAIT);
+
if (read < 0 || !NLMSG_OK(&resp.hdr, (size_t)read) ||
resp.hdr.nlmsg_type != RTM_NEWLINK ||
resp.msg.ifi_index != if_index)
int ra_conf_hoplimit(int newvalue)
{
static int value = 0;
+
if (newvalue > 0)
value = newvalue;
+
return value;
}
int ra_conf_mtu(int newvalue)
{
static int value = 0;
+
if (newvalue >= 1280 && newvalue <= 65535)
value = newvalue;
+
return value;
}
int ra_conf_reachable(int newvalue)
{
static int value = 0;
+
if (newvalue > 0 && newvalue <= 3600000)
value = newvalue;
+
return value;
}
int ra_conf_retransmit(int newvalue)
{
static int value = 0;
+
if (newvalue > 0 && newvalue <= 60000)
value = newvalue;
+
return value;
}
entry->priority = pref_to_priority(adv->nd_ra_flags_reserved);
if (entry->priority < 0)
entry->priority = pref_to_priority(0);
+
entry->valid = router_valid;
entry->preferred = entry->valid;
changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry, 0, true);
if (ra_options & RA_RDNSS_DEFAULT_LIFETIME) {
int states[2] = {STATE_RA_DNS, STATE_RA_SEARCH};
+
for (size_t i = 0; i < 2; ++i) {
size_t ra_dns_len;
uint8_t *start = odhcp6c_get_state(states[i], &ra_dns_len);
+
for (struct odhcp6c_entry *c = (struct odhcp6c_entry*)start;
(uint8_t*)c < &start[ra_dns_len] &&
(uint8_t*)odhcp6c_next_entry(c) <= &start[ra_dns_len];
- c = odhcp6c_next_entry(c))
+ c = odhcp6c_next_entry(c)) {
if (IN6_ARE_ADDR_EQUAL(&c->router, &from.sin6_addr) &&
c->valid > router_valid)
c->valid = router_valid;
+ }
}
}
}
/**
* Copyright (C) 2012-2014 Steven Barth <steven@midlink.org>
+ * Copyright (C) 2017 Hans Dedecker <dedeckeh@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License v2 as published by
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
-
static char action[16] = "";
static char *argv[4] = {NULL, NULL, action, NULL};
static volatile pid_t running = 0;
static time_t started;
-
static void script_sighandle(int signal)
{
if (signal == SIGCHLD) {
pid_t child;
+
while ((child = waitpid(-1, NULL, WNOHANG)) > 0)
if (running == child)
running = 0;
argv[0] = (char*)path;
argv[1] = (char*)ifname;
signal(SIGCHLD, script_sighandle);
+
return 0;
}
-
ssize_t script_unhexlify(uint8_t *dst, size_t len, const char *src)
{
size_t c;
+
for (c = 0; c < len && src[0] && src[1]; ++c) {
int8_t x = (int8_t)*src++;
int8_t y = (int8_t)*src++;
return c;
}
-
-static void script_hexlify(char *dst, const uint8_t *src, size_t len) {
+static void script_hexlify(char *dst, const uint8_t *src, size_t len)
+{
for (size_t i = 0; i < len; ++i) {
*dst++ = hexdigits[src[i] >> 4];
*dst++ = hexdigits[src[i] & 0x0f];
}
+
*dst = 0;
}
-
static void ipv6_to_env(const char *name,
const struct in6_addr *addr, size_t cnt)
{
size_t buf_len = strlen(name);
char *buf = realloc(NULL, cnt * INET6_ADDRSTRLEN + buf_len + 2);
+
memcpy(buf, name, buf_len);
buf[buf_len++] = '=';
+
for (size_t i = 0; i < cnt; ++i) {
inet_ntop(AF_INET6, &addr[i], &buf[buf_len], INET6_ADDRSTRLEN);
buf_len += strlen(&buf[buf_len]);
buf[buf_len++] = ' ';
}
+
if (buf[buf_len - 1] == ' ')
buf_len--;
+
buf[buf_len] = '\0';
putenv(buf);
}
-
static void fqdn_to_env(const char *name, const uint8_t *fqdn, size_t len)
{
size_t buf_len = strlen(name);
size_t buf_size = len + buf_len + 2;
const uint8_t *fqdn_end = fqdn + len;
char *buf = realloc(NULL, len + buf_len + 2);
+
memcpy(buf, name, buf_len);
buf[buf_len++] = '=';
+
while (fqdn < fqdn_end) {
int l = dn_expand(fqdn, fqdn_end, fqdn, &buf[buf_len], buf_size - buf_len);
if (l <= 0)
buf_len += strlen(&buf[buf_len]);
buf[buf_len++] = ' ';
}
+
if (buf[buf_len - 1] == ' ')
buf_len--;
+
buf[buf_len] = '\0';
putenv(buf);
}
{
uint8_t *oend = opts + len, *odata;
uint16_t otype, olen;
+
dhcpv6_for_each_option(opts, oend, otype, olen, odata) {
char *buf = realloc(NULL, 14 + (olen * 2));
size_t buf_len = 0;
const size_t max_entry_len = (INET6_ADDRSTRLEN-1 + 5 + 22 + 15 + 10 +
INET6_ADDRSTRLEN-1 + 11 + 1);
char *buf = realloc(NULL, buf_len + 2 + (len / sizeof(*e)) * max_entry_len);
+
memcpy(buf, name, buf_len);
buf[buf_len++] = '=';
for (size_t i = 0; i < len / sizeof(*e); ++i) {
inet_ntop(AF_INET6, &e[i].target, &buf[buf_len], INET6_ADDRSTRLEN);
buf_len += strlen(&buf[buf_len]);
+
if (type != ENTRY_HOST) {
snprintf(&buf[buf_len], 6, "/%"PRIu16, e[i].length);
buf_len += strlen(&buf[buf_len]);
+
if (type == ENTRY_ROUTE) {
buf[buf_len++] = ',';
+
if (!IN6_IS_ADDR_UNSPECIFIED(&e[i].router)) {
inet_ntop(AF_INET6, &e[i].router, &buf[buf_len], INET6_ADDRSTRLEN);
buf_len += strlen(&buf[buf_len]);
}
+
snprintf(&buf[buf_len], 23, ",%u,%u", e[i].valid, e[i].priority);
buf_len += strlen(&buf[buf_len]);
} else {
buf_len += strlen(&buf[buf_len]);
}
}
+
buf[buf_len++] = ' ';
}
if (buf[buf_len - 1] == ' ')
buf_len--;
+
buf[buf_len] = '\0';
putenv(buf);
}
-
static void search_to_env(const char *name, const uint8_t *start, size_t len)
{
size_t buf_len = strlen(name);
if (c[-1] == ' ')
c--;
+
*c = '\0';
putenv(buf);
}
-
static void int_to_env(const char *name, int value)
{
size_t len = 13 + strlen(name);
char *buf = realloc(NULL, len);
+
snprintf(buf, len, "%s=%d", name, value);
putenv(buf);
}
-
static void s46_to_env_portparams(const uint8_t *data, size_t len, FILE *fp)
{
uint8_t *odata;
uint16_t otype, olen;
+
dhcpv6_for_each_option(data, &data[len], otype, olen, odata) {
if (otype == DHCPV6_OPT_S46_PORTPARAMS &&
olen == sizeof(struct dhcpv6_s46_portparams)) {
}
}
-
static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len)
{
const char *name = (state == STATE_S46_MAPE) ? "MAPE" :
uint8_t *odata;
uint16_t otype, olen;
+
dhcpv6_for_each_option(data, &data[len], otype, olen, odata) {
struct dhcpv6_s46_rule *rule = (struct dhcpv6_s46_rule*)odata;
struct dhcpv6_s46_v4v6bind *bind = (struct dhcpv6_s46_v4v6bind*)odata;
putenv(str);
}
-
void script_call(const char *status, int delay, bool resume)
{
time_t now = odhcp6c_get_milli_time() / 1000;
strncpy(action, status, sizeof(action) - 1);
pid_t pid = fork();
+
if (pid > 0) {
running = pid;
started = now;
if (!resume)
action[0] = 0;
+
} else if (pid == 0) {
size_t dns_len, search_len, custom_len, sntp_ip_len, ntp_ip_len, ntp_dns_len;
size_t sip_ip_len, sip_fqdn_len, aftr_name_len, cer_len, addr_len;