summaryrefslogtreecommitdiff
path: root/src/helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/helper.c')
-rw-r--r--src/helper.c630
1 files changed, 506 insertions, 124 deletions
diff --git a/src/helper.c b/src/helper.c
index 93f99f0..1fee72d 100644
--- a/src/helper.c
+++ b/src/helper.c
@@ -1,4 +1,4 @@
-/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
+/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,6 +16,8 @@
#include "dnsmasq.h"
+#ifdef HAVE_SCRIPT
+
/* This file has code to fork a helper process which recieves data via a pipe
shared with the main process and which is responsible for calling a script when
DHCP leases change.
@@ -28,15 +30,30 @@
main process.
*/
-#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
-
static void my_setenv(const char *name, const char *value, int *error);
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err);
+#ifdef HAVE_LUASCRIPT
+#define LUA_COMPAT_ALL
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+#ifndef lua_open
+#define lua_open() luaL_newstate()
+#endif
+
+lua_State *lua;
+
+static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
+#endif
+
+
struct script_data
{
- unsigned char action, hwaddr_len, hwaddr_type;
- unsigned char clid_len, hostname_len, ed_len;
+ int flags;
+ int action, hwaddr_len, hwaddr_type;
+ int clid_len, hostname_len, ed_len;
struct in_addr addr, giaddr;
unsigned int remaining_time;
#ifdef HAVE_BROKEN_RTC
@@ -44,6 +61,15 @@ struct script_data
#else
time_t expires;
#endif
+#ifdef HAVE_TFTP
+ off_t file_len;
+#endif
+#ifdef HAVE_IPV6
+ struct in6_addr addr6;
+#endif
+#ifdef HAVE_DHCP6
+ int iaid, vendorclass_count;
+#endif
unsigned char hwaddr[DHCP_CHADDR_MAX];
char interface[IF_NAMESIZE];
};
@@ -61,7 +87,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
then fork our process. */
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
{
- send_event(err_fd, EVENT_PIPE_ERR, errno);
+ send_event(err_fd, EVENT_PIPE_ERR, errno, NULL);
_exit(0);
}
@@ -88,37 +114,99 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
{
if (option_bool(OPT_NO_FORK))
/* send error to daemon process if no-fork */
- send_event(event_fd, EVENT_HUSER_ERR, errno);
+ send_event(event_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
else
{
/* kill daemon */
- send_event(event_fd, EVENT_DIE, 0);
+ send_event(event_fd, EVENT_DIE, 0, NULL);
/* return error */
- send_event(err_fd, EVENT_HUSER_ERR, errno);
+ send_event(err_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
}
_exit(0);
}
}
- /* close all the sockets etc, we don't need them here. This closes err_fd, so that
- main process can return. */
+ /* close all the sockets etc, we don't need them here.
+ Don't close err_fd, in case the lua-init fails.
+ Note that we have to do this before lua init
+ so we don't close any lua fds. */
for (max_fd--; max_fd >= 0; max_fd--)
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
- max_fd != STDIN_FILENO && max_fd != pipefd[0] && max_fd != event_fd)
+ max_fd != STDIN_FILENO && max_fd != pipefd[0] &&
+ max_fd != event_fd && max_fd != err_fd)
close(max_fd);
+#ifdef HAVE_LUASCRIPT
+ if (daemon->luascript)
+ {
+ const char *lua_err = NULL;
+ lua = lua_open();
+ luaL_openlibs(lua);
+
+ /* get Lua to load our script file */
+ if (luaL_dofile(lua, daemon->luascript) != 0)
+ lua_err = lua_tostring(lua, -1);
+ else
+ {
+ lua_getglobal(lua, "lease");
+ if (lua_type(lua, -1) != LUA_TFUNCTION)
+ lua_err = _("lease() function missing in Lua script");
+ }
+
+ if (lua_err)
+ {
+ if (option_bool(OPT_NO_FORK) || option_bool(OPT_DEBUG))
+ /* send error to daemon process if no-fork */
+ send_event(event_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
+ else
+ {
+ /* kill daemon */
+ send_event(event_fd, EVENT_DIE, 0, NULL);
+ /* return error */
+ send_event(err_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
+ }
+ _exit(0);
+ }
+
+ lua_pop(lua, 1); /* remove nil from stack */
+ lua_getglobal(lua, "init");
+ if (lua_type(lua, -1) == LUA_TFUNCTION)
+ lua_call(lua, 0, 0);
+ else
+ lua_pop(lua, 1); /* remove nil from stack */
+ }
+#endif
+
+ /* All init done, close our copy of the error pipe, so that main process can return */
+ if (err_fd != -1)
+ close(err_fd);
+
/* loop here */
while(1)
{
struct script_data data;
- char *p, *action_str, *hostname = NULL;
+ char *p, *action_str, *hostname = NULL, *domain = NULL;
unsigned char *buf = (unsigned char *)daemon->namebuff;
- unsigned char *end, *alloc_buff = NULL;
- int err = 0;
+ unsigned char *end, *extradata, *alloc_buff = NULL;
+ int is6, err = 0;
+ free(alloc_buff);
+
/* we read zero bytes when pipe closed: this is our signal to exit */
if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
- _exit(0);
+ {
+#ifdef HAVE_LUASCRIPT
+ if (daemon->luascript)
+ {
+ lua_getglobal(lua, "shutdown");
+ if (lua_type(lua, -1) == LUA_TFUNCTION)
+ lua_call(lua, 0, 0);
+ }
+#endif
+ _exit(0);
+ }
+
+ is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
if (data.action == ACTION_DEL)
action_str = "del";
@@ -126,55 +214,244 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
action_str = "add";
else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
action_str = "old";
+ else if (data.action == ACTION_TFTP)
+ {
+ action_str = "tftp";
+ is6 = (data.flags != AF_INET);
+ }
else
continue;
-
+
+
/* stringify MAC into dhcp_buff */
p = daemon->dhcp_buff;
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
- p += sprintf(p, "%.2x-", data.hwaddr_type);
+ p += sprintf(p, "%.2x-", data.hwaddr_type);
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
- {
- p += sprintf(p, "%.2x", data.hwaddr[i]);
- if (i != data.hwaddr_len - 1)
- p += sprintf(p, ":");
- }
+ {
+ p += sprintf(p, "%.2x", data.hwaddr[i]);
+ if (i != data.hwaddr_len - 1)
+ p += sprintf(p, ":");
+ }
- /* and CLID into packet, avoid overwrite from bad data */
- if ((data.clid_len > daemon->packet_buff_sz) || !read_write(pipefd[0], buf, data.clid_len, 1))
+ /* supplied data may just exceed normal buffer (unlikely) */
+ if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
+ !(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
continue;
+
+ if (!read_write(pipefd[0], buf,
+ data.hostname_len + data.ed_len + data.clid_len, 1))
+ continue;
+
+ /* CLID into packet */
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
{
p += sprintf(p, "%.2x", buf[i]);
if (i != data.clid_len - 1)
- p += sprintf(p, ":");
+ p += sprintf(p, ":");
}
-
- /* and expiry or length into dhcp_buff2 */
-#ifdef HAVE_BROKEN_RTC
- sprintf(daemon->dhcp_buff2, "%u", data.length);
+
+#ifdef HAVE_DHCP6
+ if (is6)
+ {
+ /* or IAID and server DUID for IPv6 */
+ sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.iaid);
+ for (p = daemon->dhcp_packet.iov_base, i = 0; i < daemon->duid_len; i++)
+ {
+ p += sprintf(p, "%.2x", daemon->duid[i]);
+ if (i != daemon->duid_len - 1)
+ p += sprintf(p, ":");
+ }
+
+ }
+#endif
+
+ buf += data.clid_len;
+
+ if (data.hostname_len != 0)
+ {
+ char *dot;
+ hostname = (char *)buf;
+ hostname[data.hostname_len - 1] = 0;
+ if (data.action != ACTION_TFTP)
+ {
+ if (!legal_hostname(hostname))
+ hostname = NULL;
+ else if ((dot = strchr(hostname, '.')))
+ {
+ domain = dot+1;
+ *dot = 0;
+ }
+ }
+ }
+
+ extradata = buf + data.hostname_len;
+
+ if (!is6)
+ inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
+#ifdef HAVE_DHCP6
+ else
+ inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN);
+#endif
+
+#ifdef HAVE_TFTP
+ /* file length */
+ if (data.action == ACTION_TFTP)
+ sprintf(is6 ? daemon->packet : daemon->dhcp_buff, "%lu", (unsigned long)data.file_len);
+#endif
+
+#ifdef HAVE_LUASCRIPT
+ if (daemon->luascript)
+ {
+ if (data.action == ACTION_TFTP)
+ {
+ lua_getglobal(lua, "tftp");
+ if (lua_type(lua, -1) != LUA_TFUNCTION)
+ lua_pop(lua, 1); /* tftp function optional */
+ else
+ {
+ lua_pushstring(lua, action_str); /* arg1 - action */
+ lua_newtable(lua); /* arg2 - data table */
+ lua_pushstring(lua, daemon->addrbuff);
+ lua_setfield(lua, -2, "destination_address");
+ lua_pushstring(lua, hostname);
+ lua_setfield(lua, -2, "file_name");
+ lua_pushstring(lua, is6 ? daemon->packet : daemon->dhcp_buff);
+ lua_setfield(lua, -2, "file_size");
+ lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
+ }
+ }
+ else
+ {
+ lua_getglobal(lua, "lease"); /* function to call */
+ lua_pushstring(lua, action_str); /* arg1 - action */
+ lua_newtable(lua); /* arg2 - data table */
+
+ if (is6)
+ {
+ lua_pushstring(lua, daemon->packet);
+ lua_setfield(lua, -2, "client_duid");
+ lua_pushstring(lua, daemon->dhcp_packet.iov_base);
+ lua_setfield(lua, -2, "server_duid");
+ lua_pushstring(lua, daemon->dhcp_buff3);
+ lua_setfield(lua, -2, "iaid");
+ }
+
+ if (!is6 && data.clid_len != 0)
+ {
+ lua_pushstring(lua, daemon->packet);
+ lua_setfield(lua, -2, "client_id");
+ }
+
+ if (strlen(data.interface) != 0)
+ {
+ lua_pushstring(lua, data.interface);
+ lua_setfield(lua, -2, "interface");
+ }
+
+#ifdef HAVE_BROKEN_RTC
+ lua_pushnumber(lua, data.length);
+ lua_setfield(lua, -2, "lease_length");
#else
- sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
+ lua_pushnumber(lua, data.expires);
+ lua_setfield(lua, -2, "lease_expires");
#endif
-
- /* supplied data may just exceed normal buffer (unlikely) */
- if ((data.hostname_len + data.ed_len) > daemon->packet_buff_sz &&
- !(alloc_buff = buf = malloc(data.hostname_len + data.ed_len)))
- continue;
-
- if (!read_write(pipefd[0], buf,
- data.hostname_len + data.ed_len, 1))
+
+ if (hostname)
+ {
+ lua_pushstring(lua, hostname);
+ lua_setfield(lua, -2, "hostname");
+ }
+
+ if (domain)
+ {
+ lua_pushstring(lua, domain);
+ lua_setfield(lua, -2, "domain");
+ }
+
+ end = extradata + data.ed_len;
+ buf = extradata;
+
+ if (!is6)
+ buf = grab_extradata_lua(buf, end, "vendor_class");
+#ifdef HAVE_DHCP6
+ else if (data.vendorclass_count != 0)
+ {
+ sprintf(daemon->dhcp_buff2, "vendor_class_id");
+ buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
+ for (i = 0; i < data.vendorclass_count - 1; i++)
+ {
+ sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
+ buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
+ }
+ }
+#endif
+
+ buf = grab_extradata_lua(buf, end, "supplied_hostname");
+
+ if (!is6)
+ {
+ buf = grab_extradata_lua(buf, end, "cpewan_oui");
+ buf = grab_extradata_lua(buf, end, "cpewan_serial");
+ buf = grab_extradata_lua(buf, end, "cpewan_class");
+ buf = grab_extradata_lua(buf, end, "circuit_id");
+ buf = grab_extradata_lua(buf, end, "subscriber_id");
+ buf = grab_extradata_lua(buf, end, "remote_id");
+ }
+
+ buf = grab_extradata_lua(buf, end, "tags");
+
+ if (is6)
+ buf = grab_extradata_lua(buf, end, "relay_address");
+ else if (data.giaddr.s_addr != 0)
+ {
+ lua_pushstring(lua, inet_ntoa(data.giaddr));
+ lua_setfield(lua, -2, "relay_address");
+ }
+
+ for (i = 0; buf; i++)
+ {
+ sprintf(daemon->dhcp_buff2, "user_class%i", i);
+ buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
+ }
+
+ if (data.action != ACTION_DEL && data.remaining_time != 0)
+ {
+ lua_pushnumber(lua, data.remaining_time);
+ lua_setfield(lua, -2, "time_remaining");
+ }
+
+ if (data.action == ACTION_OLD_HOSTNAME && hostname)
+ {
+ lua_pushstring(lua, hostname);
+ lua_setfield(lua, -2, "old_hostname");
+ }
+
+ if (!is6 || data.hwaddr_len != 0)
+ {
+ lua_pushstring(lua, daemon->dhcp_buff);
+ lua_setfield(lua, -2, "mac_address");
+ }
+
+ lua_pushstring(lua, daemon->addrbuff);
+ lua_setfield(lua, -2, "ip_address");
+
+ lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
+ }
+ }
+#endif
+
+ /* no script, just lua */
+ if (!daemon->lease_change_command)
continue;
-
+
/* possible fork errors are all temporary resource problems */
while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
sleep(2);
- free(alloc_buff);
-
if (pid == -1)
continue;
-
+
/* wait for child to complete */
if (pid != 0)
{
@@ -188,9 +465,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
{
/* On error send event back to main process for logging */
if (WIFSIGNALED(status))
- send_event(event_fd, EVENT_KILLED, WTERMSIG(status));
+ send_event(event_fd, EVENT_KILLED, WTERMSIG(status), NULL);
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
- send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status));
+ send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), NULL);
break;
}
@@ -201,62 +478,82 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue;
}
- if (data.clid_len != 0)
- my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
-
- if (strlen(data.interface) != 0)
- my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
-
+ if (data.action != ACTION_TFTP)
+ {
+#ifdef HAVE_DHCP6
+ my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
+ my_setenv("DNSMASQ_SERVER_DUID", is6 ? daemon->dhcp_packet.iov_base : NULL, &err);
+ my_setenv("DNSMASQ_MAC", is6 && data.hwaddr_len != 0 ? daemon->dhcp_buff : NULL, &err);
+#endif
+
+ my_setenv("DNSMASQ_CLIENT_ID", !is6 && data.clid_len != 0 ? daemon->packet : NULL, &err);
+ my_setenv("DNSMASQ_INTERFACE", strlen(data.interface) != 0 ? data.interface : NULL, &err);
+
#ifdef HAVE_BROKEN_RTC
- my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
+ sprintf(daemon->dhcp_buff2, "%u", data.length);
+ my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
#else
- my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
+ sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
+ my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
#endif
-
- if (data.hostname_len != 0)
- {
- char *dot;
- hostname = (char *)buf;
- hostname[data.hostname_len - 1] = 0;
- if (!legal_hostname(hostname))
- hostname = NULL;
- else if ((dot = strchr(hostname, '.')))
+
+ my_setenv("DNSMASQ_DOMAIN", domain, &err);
+
+ end = extradata + data.ed_len;
+ buf = extradata;
+
+ if (!is6)
+ buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
+#ifdef HAVE_DHCP6
+ else
{
- my_setenv("DNSMASQ_DOMAIN", dot+1, &err);
- *dot = 0;
- }
- buf += data.hostname_len;
- }
-
- end = buf + data.ed_len;
- buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
- buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
- buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
- buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
- buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
- buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
-
- for (i = 0; buf; i++)
- {
- sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
- buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
- }
-
- if (data.giaddr.s_addr != 0)
- my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
+ if (data.vendorclass_count != 0)
+ {
+ buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
+ for (i = 0; i < data.vendorclass_count - 1; i++)
+ {
+ sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
+ buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
+ }
+ }
+ }
+#endif
+
+ buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
+
+ if (!is6)
+ {
+ buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
+ buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
+ buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
+ buf = grab_extradata(buf, end, "DNSMASQ_CIRCUIT_ID", &err);
+ buf = grab_extradata(buf, end, "DNSMASQ_SUBSCRIBER_ID", &err);
+ buf = grab_extradata(buf, end, "DNSMASQ_REMOTE_ID", &err);
+ }
+
+ buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
- if (data.action != ACTION_DEL)
- {
+ if (is6)
+ buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
+ else
+ my_setenv("DNSMASQ_RELAY_ADDRESS", data.giaddr.s_addr != 0 ? inet_ntoa(data.giaddr) : NULL, &err);
+
+ for (i = 0; buf; i++)
+ {
+ sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
+ buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
+ }
+
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
- my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
- }
-
- if (data.action == ACTION_OLD_HOSTNAME && hostname)
- {
- my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err);
- hostname = NULL;
+ my_setenv("DNSMASQ_TIME_REMAINING", data.action != ACTION_DEL && data.remaining_time != 0 ? daemon->dhcp_buff2 : NULL, &err);
+
+ my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
+ if (data.action == ACTION_OLD_HOSTNAME)
+ hostname = NULL;
}
+ my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
+
/* we need to have the event_fd around if exec fails */
if ((i = fcntl(event_fd, F_GETFD)) != -1)
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
@@ -267,23 +564,61 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
{
execl(daemon->lease_change_command,
p ? p+1 : daemon->lease_change_command,
- action_str, daemon->dhcp_buff, inet_ntoa(data.addr), hostname, (char*)NULL);
+ action_str, is6 ? daemon->packet : daemon->dhcp_buff,
+ daemon->addrbuff, hostname, (char*)NULL);
err = errno;
}
/* failed, send event so the main process logs the problem */
- send_event(event_fd, EVENT_EXEC_ERR, err);
+ send_event(event_fd, EVENT_EXEC_ERR, err, NULL);
_exit(0);
}
}
static void my_setenv(const char *name, const char *value, int *error)
{
- if (*error == 0 && setenv(name, value, 1) != 0)
- *error = errno;
+ if (*error == 0)
+ {
+ if (!value)
+ unsetenv(name);
+ else if (setenv(name, value, 1) != 0)
+ *error = errno;
+ }
}
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err)
{
+ unsigned char *next = NULL;
+ char *val = NULL;
+
+ if (buf && (buf != end))
+ {
+ for (next = buf; ; next++)
+ if (next == end)
+ {
+ next = NULL;
+ break;
+ }
+ else if (*next == 0)
+ break;
+
+ if (next && (next != buf))
+ {
+ char *p;
+ /* No "=" in value */
+ if ((p = strchr((char *)buf, '=')))
+ *p = 0;
+ val = (char *)buf;
+ }
+ }
+
+ my_setenv(env, val, err);
+
+ return next ? next + 1 : NULL;
+}
+
+#ifdef HAVE_LUASCRIPT
+static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field)
+{
unsigned char *next;
if (!buf || (buf == end))
@@ -295,36 +630,16 @@ static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, ch
if (next != buf)
{
- char *p;
- /* No "=" in value */
- if ((p = strchr((char *)buf, '=')))
- *p = 0;
- my_setenv(env, (char *)buf, err);
+ lua_pushstring(lua, (char *)buf);
+ lua_setfield(lua, -2, field);
}
return next + 1;
}
+#endif
-/* pack up lease data into a buffer */
-void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
+static void buff_alloc(size_t size)
{
- unsigned char *p;
- size_t size;
- unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
-
- /* no script */
- if (daemon->helperfd == -1)
- return;
-
- if (lease->extradata)
- ed_len = lease->extradata_len;
- if (lease->clid)
- clid_len = lease->clid_len;
- if (hostname)
- hostname_len = strlen(hostname) + 1;
-
- size = sizeof(struct script_data) + clid_len + ed_len + hostname_len;
-
if (size > buf_size)
{
struct script_data *new;
@@ -340,8 +655,39 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
buf = new;
buf_size = size;
}
+}
+
+/* pack up lease data into a buffer */
+void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
+{
+ unsigned char *p;
+ unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
+ int fd = daemon->dhcpfd;
+#ifdef HAVE_DHCP6
+ if (!daemon->dhcp)
+ fd = daemon->dhcp6fd;
+#endif
+
+ /* no script */
+ if (daemon->helperfd == -1)
+ return;
+
+ if (lease->extradata)
+ ed_len = lease->extradata_len;
+ if (lease->clid)
+ clid_len = lease->clid_len;
+ if (hostname)
+ hostname_len = strlen(hostname) + 1;
+
+ buff_alloc(sizeof(struct script_data) + clid_len + ed_len + hostname_len);
buf->action = action;
+ buf->flags = lease->flags;
+#ifdef HAVE_DHCP6
+ buf->vendorclass_count = lease->vendorclass_count;
+ buf->addr6 = lease->addr6;
+ buf->iaid = lease->iaid;
+#endif
buf->hwaddr_len = lease->hwaddr_len;
buf->hwaddr_type = lease->hwaddr_type;
buf->clid_len = clid_len;
@@ -349,8 +695,8 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
buf->hostname_len = hostname_len;
buf->addr = lease->addr;
buf->giaddr = lease->giaddr;
- memcpy(buf->hwaddr, lease->hwaddr, lease->hwaddr_len);
- if (!indextoname(daemon->dhcpfd, lease->last_interface, buf->interface))
+ memcpy(buf->hwaddr, lease->hwaddr, DHCP_CHADDR_MAX);
+ if (!indextoname(fd, lease->last_interface, buf->interface))
buf->interface[0] = 0;
#ifdef HAVE_BROKEN_RTC
@@ -358,7 +704,11 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
#else
buf->expires = lease->expires;
#endif
- buf->remaining_time = (unsigned int)difftime(lease->expires, now);
+
+ if (lease->expires != 0)
+ buf->remaining_time = (unsigned int)difftime(lease->expires, now);
+ else
+ buf->remaining_time = 0;
p = (unsigned char *)(buf+1);
if (clid_len != 0)
@@ -379,6 +729,37 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
bytes_in_buf = p - (unsigned char *)buf;
}
+#ifdef HAVE_TFTP
+/* This nastily re-uses DHCP-fields for TFTP stuff */
+void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
+{
+ unsigned int filename_len;
+
+ /* no script */
+ if (daemon->helperfd == -1)
+ return;
+
+ filename_len = strlen(filename) + 1;
+ buff_alloc(sizeof(struct script_data) + filename_len);
+ memset(buf, 0, sizeof(struct script_data));
+
+ buf->action = ACTION_TFTP;
+ buf->hostname_len = filename_len;
+ buf->file_len = file_len;
+
+ if ((buf->flags = peer->sa.sa_family) == AF_INET)
+ buf->addr = peer->in.sin_addr;
+#ifdef HAVE_IPV6
+ else
+ buf->addr6 = peer->in6.sin6_addr;
+#endif
+
+ memcpy((unsigned char *)(buf+1), filename, filename_len);
+
+ bytes_in_buf = sizeof(struct script_data) + filename_len;
+}
+#endif
+
int helper_buf_empty(void)
{
return bytes_in_buf == 0;
@@ -408,3 +789,4 @@ void helper_write(void)
#endif
+