summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG18
-rwxr-xr-xcontrib/port-forward/dnsmasq-portforward10
-rw-r--r--man/dnsmasq.835
-rw-r--r--src/dnsmasq.c9
-rw-r--r--src/dnsmasq.h7
-rw-r--r--src/helper.c449
-rw-r--r--src/tftp.c21
7 files changed, 355 insertions, 194 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 2cc4b73..a08d25b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -24,6 +24,24 @@ version 2.61
Add --host-record. Thanks to Rob Zwissler for the
suggestion.
+ Invoke the DHCP script with action "tftp" when a TFTP file
+ transfer completes. The size of the file, address to which
+ it was sent and complete pathname are supplied. Note that
+ version 2.60 introduced some script incompatibilties
+ associated with DHCPv6, and this is a further change. To
+ be safe, scripts should ignore unknown actions, and if
+ not IPv6-aware, should exit if the environment
+ variable DNSMASQ_IAID is set. The use-case for this is
+ to track netboot/install. Suggestion from Shantanu
+ Gadgil.
+
+ Update contrib/port-forward/dnsmasq-portforward to reflect
+ the above.
+
+ Set the environment variable DNSMASQ_LOG_DHCP when running
+ the script id --log-dhcp is in effect, so that script can
+ taylor their logging verbosity. Suggestion from Malte Forkel.
+
version 2.60
Fix compilation problem in Mac OS X Lion. Thanks to Olaf
diff --git a/contrib/port-forward/dnsmasq-portforward b/contrib/port-forward/dnsmasq-portforward
index f9bb857..c2c634f 100755
--- a/contrib/port-forward/dnsmasq-portforward
+++ b/contrib/port-forward/dnsmasq-portforward
@@ -34,11 +34,21 @@ if [ ${DNSMASQ_OLD_HOSTNAME} ] && [ ${action} = old ] ; then
hostname=${DNSMASQ_OLD_HOSTNAME}
fi
+# IPv6 leases are not our concern. no NAT there!
+if [ ${DNSMASQ_IAID} ] ; then
+ exit 0
+fi
+
# action init is not relevant, and will only be seen when leasefile-ro is set.
if [ ${action} = init ] ; then
exit 0
fi
+# action tftp is not relevant.
+if [ ${action} = tftp ] ; then
+ exit 0
+fi
+
if [ ${hostname} ]; then
ports=$(sed -n -e "/^${hostname}\ .*/ s/^.* //p" ${PORTSFILE})
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 88609f1..9ebfe31 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -1069,7 +1069,8 @@ re-intialised. The enterprise-id is assigned by IANA, and the uid is a
string of hex octets unique to a particular device.
.TP
.B \-6 --dhcp-script=<path>
-Whenever a new DHCP lease is created, or an old one destroyed, the
+Whenever a new DHCP lease is created, or an old one destroyed, or a
+TFTP file transfer completes, the
executable specified by this option is run. <path>
must be an absolute pathname, no PATH search occurs.
The arguments to the process
@@ -1119,6 +1120,8 @@ is known.
DNSMASQ_TAGS contains all the tags set during the
DHCP transaction, separated by spaces.
+DNSMASQ_LOG_DHCP is set if --log-dhcp is in effect.
+
For IPv4 only:
DNSMASQ_CLIENT_ID if the host provided a client-id.
@@ -1145,6 +1148,8 @@ only supplied for
since these data are not held in dnsmasq's lease
database.
+
+
All file descriptors are
closed except stdin, stdout and stderr which are open to /dev/null
(except in debug mode).
@@ -1163,6 +1168,17 @@ all existing leases as they are read from the lease file. Expired
leases will be called with "del" and others with "old". When dnsmasq
receives a HUP signal, the script will be invoked for existing leases
with an "old " event.
+
+
+There are two further actions which may appear as the first argument
+to the script, "init" and "tftp". More may be added in the future, so
+scripts should be written to ignore unknown actions. "init" is
+decsribed below in
+.B --leasefile-ro
+The "tftp" action is invoked when a TFTP file transfer completes: the
+arguments are the file size in bytes, the address to which the file
+was sent, and the complete pathname of the file.
+
.TP
.B --dhcp-luascript=<path>
Specify a script written in Lua, to be run when leases are created,
@@ -1176,11 +1192,13 @@ function, and may provide
and
.B shutdown
functions, which are called, without arguments when dnsmasq starts up
-and terminates.
+and terminates. It may also provide a
+.B tftp
+function.
The
.B lease
-method receives the information detailed in
+function receives the information detailed in
.B --dhcp-script.
It gets two arguments, firstly the action, which is a string
containing, "add", "old" or "del", and secondly a table of tag value
@@ -1197,7 +1215,16 @@ for IPv4, and
.B client_duid, ip_address
and
.B hostname
-for IPv6.
+for IPv6.
+
+The
+.B tftp
+function is called in the same way as the lease function, and the
+table holds the tags
+.B destination_address,
+.B file_name
+and
+.B file_size.
.TP
.B --dhcp-scriptuser
Specify the user as which to run the lease-change script or Lua script. This defaults to root, but can be changed to another user using this flag.
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 531e0b0..efe63d1 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -721,6 +721,10 @@ int main (int argc, char **argv)
# ifdef HAVE_SCRIPT
while (helper_buf_empty() && do_script_run(now));
+# ifdef HAVE_TFTP
+ while (helper_buf_empty() && do_tftp_script_run());
+# endif
+
if (!helper_buf_empty())
{
FD_SET(daemon->helperfd, &wset);
@@ -729,6 +733,11 @@ int main (int argc, char **argv)
# else
/* need this for other side-effects */
while (do_script_run(now));
+
+# ifdef HAVE_TFTP
+ while (do_tftp_script_run());
+# endif
+
# endif
#endif
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 06f1549..f2a6f36 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -458,6 +458,7 @@ struct frec {
#define ACTION_OLD_HOSTNAME 2
#define ACTION_OLD 3
#define ACTION_ADD 4
+#define ACTION_TFTP 5
#define LEASE_NEW 1 /* newly created */
#define LEASE_CHANGED 2 /* modified */
@@ -803,7 +804,7 @@ extern struct daemon {
#endif
/* TFTP stuff */
- struct tftp_transfer *tftp_trans;
+ struct tftp_transfer *tftp_trans, *tftp_done_trans;
/* utility string buffer, hold max sized IP address as string */
char *addrbuff;
@@ -1040,6 +1041,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
void helper_write(void);
void queue_script(int action, struct dhcp_lease *lease,
char *hostname, time_t now);
+#ifdef HAVE_TFTP
+void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer);
+#endif
int helper_buf_empty(void);
#endif
@@ -1047,6 +1051,7 @@ int helper_buf_empty(void);
#ifdef HAVE_TFTP
void tftp_request(struct listener *listen, time_t now);
void check_tftp_listeners(fd_set *rset, time_t now);
+int do_tftp_script_run(void);
#endif
/* conntrack.c */
diff --git a/src/helper.c b/src/helper.c
index 135111d..5c07f05 100644
--- a/src/helper.c
+++ b/src/helper.c
@@ -192,18 +192,24 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
#endif
_exit(0);
}
-
+
+ is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
+
if (data.action == ACTION_DEL)
action_str = "del";
else if (data.action == ACTION_ADD)
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;
- is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
-
+
if (!is6)
{
/* stringify MAC into dhcp_buff */
@@ -271,13 +277,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
char *dot;
hostname = (char *)buf;
hostname[data.hostname_len - 1] = 0;
- if (!legal_hostname(hostname))
- hostname = NULL;
- else if ((dot = strchr(hostname, '.')))
+ if (data.action != ACTION_TFTP)
{
- domain = dot+1;
- *dot = 0;
- }
+ if (!legal_hostname(hostname))
+ hostname = NULL;
+ else if ((dot = strchr(hostname, '.')))
+ {
+ domain = dot+1;
+ *dot = 0;
+ }
+ }
}
extradata = buf + data.hostname_len;
@@ -289,116 +298,141 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
inet_ntop(AF_INET6, &data.hwaddr, daemon->addrbuff, ADDRSTRLEN);
#endif
+ /* file length */
+ if (data.action == ACTION_TFTP)
+ sprintf(daemon->dhcp_buff, "%u", data.hwaddr_len);
+
#ifdef HAVE_LUASCRIPT
if (daemon->luascript)
{
- lua_getglobal(lua, "lease"); /* function to call */
- lua_pushstring(lua, action_str); /* arg1 - action */
- lua_newtable(lua); /* arg2 - data table */
-
- if (is6)
+ if (data.action == ACTION_TFTP)
{
- lua_pushstring(lua, daemon->dhcp_buff);
- lua_setfield(lua, -2, "client_duid");
- lua_pushstring(lua, daemon->packet);
- 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");
+ 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, daemon->dhcp_buff);
+ lua_setfield(lua, -2, "file_size");
+ lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
+ }
}
-
- if (strlen(data.interface) != 0)
+ else
{
- lua_pushstring(lua, data.interface);
- lua_setfield(lua, -2, "interface");
- }
-
+ 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->dhcp_buff);
+ lua_setfield(lua, -2, "client_duid");
+ lua_pushstring(lua, daemon->packet);
+ 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");
+ lua_pushnumber(lua, data.length);
+ lua_setfield(lua, -2, "lease_length");
#else
- lua_pushnumber(lua, data.expires);
- lua_setfield(lua, -2, "lease_expires");
+ lua_pushnumber(lua, data.expires);
+ lua_setfield(lua, -2, "lease_expires");
#endif
-
- 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");
+
+ 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
- for (i = 0; i < data.hwaddr_len; i++)
- {
- sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
- buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
- }
+ else
+ for (i = 0; i < data.hwaddr_len; 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, "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)
- {
- lua_pushstring(lua, daemon->dhcp_buff);
- lua_setfield(lua, -2, "mac_address");
+
+ 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, "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)
+ {
+ 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 */
}
-
- lua_pushstring(lua, daemon->addrbuff);
- lua_setfield(lua, -2, "ip_address");
-
- lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
}
#endif
@@ -439,81 +473,87 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue;
}
- if (is6)
+ if (data.action != ACTION_TFTP)
{
- my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
- my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err);
- }
-
- if (!is6 && 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 (is6)
+ {
+ my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
+ my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err);
+ }
+
+ if (!is6 && data.clid_len != 0)
+ my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
+
+ if (strlen(data.interface) != 0)
+ my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
+
#ifdef HAVE_BROKEN_RTC
- my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
+ my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
#else
- my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
+ my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
#endif
-
- if (domain)
- my_setenv("DNSMASQ_DOMAIN", domain, &err);
-
- end = extradata + data.ed_len;
- buf = extradata;
-
- if (!is6)
- buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
+
+ if (domain)
+ 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
- {
- if (data.hwaddr_len != 0)
+ else
{
- buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
- for (i = 0; i < data.hwaddr_len - 1; i++)
+ if (data.hwaddr_len != 0)
{
- sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
- buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
+ buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
+ for (i = 0; i < data.hwaddr_len - 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_TAGS", &err);
-
- if (is6)
- buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
- else if (data.giaddr.s_addr != 0)
- my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &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.action != ACTION_DEL && data.remaining_time != 0)
- {
- 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;
+
+ 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_TAGS", &err);
+
+ if (is6)
+ buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
+ else if (data.giaddr.s_addr != 0)
+ my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &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.action != ACTION_DEL && data.remaining_time != 0)
+ {
+ 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;
+ }
}
+ if (option_bool(OPT_LOG_OPTS))
+ my_setenv("DNSMASQ_LOG_DHCP", "1", &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);
@@ -584,11 +624,29 @@ static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end,
}
#endif
+static void buff_alloc(size_t size)
+{
+ if (size > buf_size)
+ {
+ struct script_data *new;
+
+ /* start with reasonable size, will almost never need extending. */
+ if (size < sizeof(struct script_data) + 200)
+ size = sizeof(struct script_data) + 200;
+
+ if (!(new = whine_malloc(size)))
+ return;
+ if (buf)
+ free(buf);
+ 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;
- size_t size;
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
int fd = daemon->dhcpfd;
@@ -608,23 +666,7 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
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;
-
- /* start with reasonable size, will almost never need extending. */
- if (size < sizeof(struct script_data) + 200)
- size = sizeof(struct script_data) + 200;
-
- if (!(new = whine_malloc(size)))
- return;
- if (buf)
- free(buf);
- buf = new;
- buf_size = size;
- }
+ buff_alloc(sizeof(struct script_data) + clid_len + ed_len + hostname_len);
buf->action = action;
buf->flags = lease->flags;
@@ -669,6 +711,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->hwaddr_len = file_len;
+
+ if ((buf->flags = peer->sa.sa_family) == AF_INET)
+ buf->addr = peer->in.sin_addr;
+#ifdef HAVE_IPV6
+ else
+ memcpy(buf->hwaddr, &peer->in6.sin6_addr, IN6ADDRSZ);
+#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;
diff --git a/src/tftp.c b/src/tftp.c
index 569adf9..3ef6545 100644
--- a/src/tftp.c
+++ b/src/tftp.c
@@ -571,7 +571,9 @@ void check_tftp_listeners(fd_set *rset, time_t now)
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), transfer->file->filename, daemon->addrbuff);
/* unlink */
*up = tmp;
- free_transfer(transfer);
+ /* put on queue to be sent to script and deleted */
+ transfer->next = daemon->tftp_done_trans;
+ daemon->tftp_done_trans = transfer;
continue;
}
}
@@ -709,4 +711,21 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
}
}
+
+int do_tftp_script_run(void)
+{
+ struct tftp_transfer *transfer;
+
+ if ((transfer = daemon->tftp_done_trans))
+ {
+ daemon->tftp_done_trans = transfer->next;
+#ifdef HAVE_SCRIPT
+ queue_tftp(transfer->file->size, transfer->file->filename, &transfer->peer);
+#endif
+ free_transfer(transfer);
+ return 1;
+ }
+
+ return 0;
+}
#endif