blob: b9da2259a840382bfec6fa291c17b82b501f72ca [file] [log] [blame]
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001/* dnsmasq is Copyright (c) 2000-2024 Simon Kelley
Simon Kelley16972692006-10-16 20:04:18 +01002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley16972692006-10-16 20:04:18 +01008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley16972692006-10-16 20:04:18 +010015*/
16
17#include "dnsmasq.h"
18
Simon Kelleyc72daea2012-01-05 21:33:27 +000019#ifdef HAVE_SCRIPT
20
Josh Soref730c6742017-02-06 16:14:04 +000021/* This file has code to fork a helper process which receives data via a pipe
Simon Kelley16972692006-10-16 20:04:18 +010022 shared with the main process and which is responsible for calling a script when
23 DHCP leases change.
24
25 The helper process is forked before the main process drops root, so it retains root
26 privs to pass on to the script. For this reason it tries to be paranoid about
27 data received from the main process, in case that has been compromised. We don't
28 want the helper to give an attacker root. In particular, the script to be run is
29 not settable via the pipe, once the fork has taken place it is not alterable by the
30 main process.
31*/
32
Simon Kelley824af852008-02-12 20:43:05 +000033static void my_setenv(const char *name, const char *value, int *error);
Simon Kelley316e2732010-01-22 20:16:09 +000034static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err);
Simon Kelley9009d742008-11-14 20:04:27 +000035
Simon Kelleyc72daea2012-01-05 21:33:27 +000036#ifdef HAVE_LUASCRIPT
Simon Kelley289a2532012-09-20 15:29:35 +010037#define LUA_COMPAT_ALL
Simon Kelleyc72daea2012-01-05 21:33:27 +000038#include <lua.h>
39#include <lualib.h>
40#include <lauxlib.h>
41
Simon Kelley289a2532012-09-20 15:29:35 +010042#ifndef lua_open
43#define lua_open() luaL_newstate()
44#endif
45
Simon Kelleyc72daea2012-01-05 21:33:27 +000046lua_State *lua;
47
48static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
49#endif
50
51
Simon Kelley16972692006-10-16 20:04:18 +010052struct script_data
53{
Simon Kelleyceae00d2012-02-09 21:28:14 +000054 int flags;
55 int action, hwaddr_len, hwaddr_type;
56 int clid_len, hostname_len, ed_len;
Simon Kelley1f15b812009-10-13 17:49:32 +010057 struct in_addr addr, giaddr;
Simon Kelley5aabfc72007-08-29 11:24:47 +010058 unsigned int remaining_time;
Simon Kelley16972692006-10-16 20:04:18 +010059#ifdef HAVE_BROKEN_RTC
60 unsigned int length;
61#else
62 time_t expires;
63#endif
Simon Kelley2f9fd1d2013-10-01 09:54:41 +010064#ifdef HAVE_TFTP
65 off_t file_len;
66#endif
Simon Kelley89500e32013-09-20 16:29:20 +010067 struct in6_addr addr6;
Simon Kelley903650a2013-10-03 11:43:09 +010068#ifdef HAVE_DHCP6
Dominik DL6ER456a3192019-10-20 18:51:52 +020069 int vendorclass_count;
70 unsigned int iaid;
Simon Kelley89500e32013-09-20 16:29:20 +010071#endif
Simon Kelley16972692006-10-16 20:04:18 +010072 unsigned char hwaddr[DHCP_CHADDR_MAX];
Simon Kelley824af852008-02-12 20:43:05 +000073 char interface[IF_NAMESIZE];
Simon Kelley16972692006-10-16 20:04:18 +010074};
75
Simon Kelley5aabfc72007-08-29 11:24:47 +010076static struct script_data *buf = NULL;
77static size_t bytes_in_buf = 0, buf_size = 0;
Simon Kelley16972692006-10-16 20:04:18 +010078
Simon Kelley1a6bca82008-07-11 11:11:42 +010079int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
Simon Kelley16972692006-10-16 20:04:18 +010080{
81 pid_t pid;
82 int i, pipefd[2];
83 struct sigaction sigact;
Simon Kelley69bc9472019-08-14 20:44:50 +010084 unsigned char *alloc_buff = NULL;
85
Simon Kelley5aabfc72007-08-29 11:24:47 +010086 /* create the pipe through which the main program sends us commands,
Simon Kelley1a6bca82008-07-11 11:11:42 +010087 then fork our process. */
Simon Kelley5aabfc72007-08-29 11:24:47 +010088 if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
89 {
Simon Kelleyc72daea2012-01-05 21:33:27 +000090 send_event(err_fd, EVENT_PIPE_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +010091 _exit(0);
Simon Kelley5aabfc72007-08-29 11:24:47 +010092 }
93
Simon Kelley16972692006-10-16 20:04:18 +010094 if (pid != 0)
95 {
96 close(pipefd[0]); /* close reader side */
97 return pipefd[1];
98 }
99
Simon Kelley3c973ad2018-01-14 21:05:37 +0000100 /* ignore SIGTERM and SIGINT, so that we can clean up when the main process gets hit
Simon Kelley5aabfc72007-08-29 11:24:47 +0100101 and SIGALRM so that we can use sleep() */
Simon Kelley16972692006-10-16 20:04:18 +0100102 sigact.sa_handler = SIG_IGN;
103 sigact.sa_flags = 0;
104 sigemptyset(&sigact.sa_mask);
105 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100106 sigaction(SIGALRM, &sigact, NULL);
Simon Kelley3c973ad2018-01-14 21:05:37 +0000107 sigaction(SIGINT, &sigact, NULL);
Simon Kelley16972692006-10-16 20:04:18 +0100108
Simon Kelley28866e92011-02-14 20:19:14 +0000109 if (!option_bool(OPT_DEBUG) && uid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100110 {
111 gid_t dummy;
112 if (setgroups(0, &dummy) == -1 ||
113 setgid(gid) == -1 ||
114 setuid(uid) == -1)
115 {
Simon Kelley28866e92011-02-14 20:19:14 +0000116 if (option_bool(OPT_NO_FORK))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100117 /* send error to daemon process if no-fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000118 send_event(event_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100119 else
120 {
121 /* kill daemon */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000122 send_event(event_fd, EVENT_DIE, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100123 /* return error */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000124 send_event(err_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100125 }
126 _exit(0);
127 }
128 }
129
Simon Kelleyc72daea2012-01-05 21:33:27 +0000130 /* close all the sockets etc, we don't need them here.
131 Don't close err_fd, in case the lua-init fails.
132 Note that we have to do this before lua init
133 so we don't close any lua fds. */
Simon Kelley0541a1a2020-03-02 17:10:25 +0000134 close_fds(max_fd, pipefd[0], event_fd, err_fd);
135
Simon Kelleyc72daea2012-01-05 21:33:27 +0000136#ifdef HAVE_LUASCRIPT
137 if (daemon->luascript)
138 {
139 const char *lua_err = NULL;
140 lua = lua_open();
141 luaL_openlibs(lua);
142
143 /* get Lua to load our script file */
144 if (luaL_dofile(lua, daemon->luascript) != 0)
145 lua_err = lua_tostring(lua, -1);
146 else
147 {
148 lua_getglobal(lua, "lease");
149 if (lua_type(lua, -1) != LUA_TFUNCTION)
150 lua_err = _("lease() function missing in Lua script");
151 }
152
153 if (lua_err)
154 {
155 if (option_bool(OPT_NO_FORK) || option_bool(OPT_DEBUG))
156 /* send error to daemon process if no-fork */
157 send_event(event_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
158 else
159 {
160 /* kill daemon */
161 send_event(event_fd, EVENT_DIE, 0, NULL);
162 /* return error */
163 send_event(err_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
164 }
165 _exit(0);
166 }
167
168 lua_pop(lua, 1); /* remove nil from stack */
169 lua_getglobal(lua, "init");
170 if (lua_type(lua, -1) == LUA_TFUNCTION)
171 lua_call(lua, 0, 0);
172 else
173 lua_pop(lua, 1); /* remove nil from stack */
174 }
175#endif
176
177 /* All init done, close our copy of the error pipe, so that main process can return */
178 if (err_fd != -1)
179 close(err_fd);
180
Simon Kelley16972692006-10-16 20:04:18 +0100181 /* loop here */
182 while(1)
183 {
184 struct script_data data;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000185 char *p, *action_str, *hostname = NULL, *domain = NULL;
Simon Kelley16972692006-10-16 20:04:18 +0100186 unsigned char *buf = (unsigned char *)daemon->namebuff;
Simon Kelley69bc9472019-08-14 20:44:50 +0100187 unsigned char *end, *extradata;
Simon Kelleyceae00d2012-02-09 21:28:14 +0000188 int is6, err = 0;
Petr Menšíkc77fb9d2017-04-16 20:20:08 +0100189 int pipeout[2];
Simon Kelley16972692006-10-16 20:04:18 +0100190
Simon Kelley69bc9472019-08-14 20:44:50 +0100191 /* Free rarely-allocated memory from previous iteration. */
192 if (alloc_buff)
193 {
194 free(alloc_buff);
195 alloc_buff = NULL;
196 }
Simon Kelleyc72daea2012-01-05 21:33:27 +0000197
Simon Kelley16972692006-10-16 20:04:18 +0100198 /* we read zero bytes when pipe closed: this is our signal to exit */
199 if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000200 {
201#ifdef HAVE_LUASCRIPT
202 if (daemon->luascript)
203 {
204 lua_getglobal(lua, "shutdown");
205 if (lua_type(lua, -1) == LUA_TFUNCTION)
206 lua_call(lua, 0, 0);
207 }
208#endif
209 _exit(0);
210 }
Simon Kelleya9530962012-03-20 22:07:35 +0000211
212 is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
213
Simon Kelley16972692006-10-16 20:04:18 +0100214 if (data.action == ACTION_DEL)
215 action_str = "del";
216 else if (data.action == ACTION_ADD)
217 action_str = "add";
218 else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
219 action_str = "old";
Simon Kelleya9530962012-03-20 22:07:35 +0000220 else if (data.action == ACTION_TFTP)
221 {
222 action_str = "tftp";
223 is6 = (data.flags != AF_INET);
224 }
Simon Kelley33702ab2015-12-28 23:17:15 +0000225 else if (data.action == ACTION_ARP)
226 {
Simon Kelleye6e751b2016-02-01 17:59:07 +0000227 action_str = "arp-add";
Simon Kelley33702ab2015-12-28 23:17:15 +0000228 is6 = (data.flags != AF_INET);
229 }
Simon Kelleye6e751b2016-02-01 17:59:07 +0000230 else if (data.action == ACTION_ARP_DEL)
Simon Kelley33702ab2015-12-28 23:17:15 +0000231 {
Simon Kelleye6e751b2016-02-01 17:59:07 +0000232 action_str = "arp-del";
Simon Kelley33702ab2015-12-28 23:17:15 +0000233 is6 = (data.flags != AF_INET);
234 data.action = ACTION_ARP;
235 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700236 else if (data.action == ACTION_RELAY_SNOOP)
237 {
238 is6 = 1;
239 action_str = "relay-snoop";
240 }
241 else
242 continue;
Simon Kelleya9530962012-03-20 22:07:35 +0000243
Simon Kelley89500e32013-09-20 16:29:20 +0100244 /* stringify MAC into dhcp_buff */
245 p = daemon->dhcp_buff;
246 if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
247 p += sprintf(p, "%.2x-", data.hwaddr_type);
248 for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
Simon Kelleyceae00d2012-02-09 21:28:14 +0000249 {
Simon Kelley89500e32013-09-20 16:29:20 +0100250 p += sprintf(p, "%.2x", data.hwaddr[i]);
251 if (i != data.hwaddr_len - 1)
252 p += sprintf(p, ":");
Simon Kelleyceae00d2012-02-09 21:28:14 +0000253 }
Simon Kelley89500e32013-09-20 16:29:20 +0100254
Simon Kelleyc72daea2012-01-05 21:33:27 +0000255 /* supplied data may just exceed normal buffer (unlikely) */
256 if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
257 !(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
Simon Kelley16972692006-10-16 20:04:18 +0100258 continue;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000259
260 if (!read_write(pipefd[0], buf,
261 data.hostname_len + data.ed_len + data.clid_len, 1))
262 continue;
263
264 /* CLID into packet */
Simon Kelley89500e32013-09-20 16:29:20 +0100265 for (p = daemon->packet, i = 0; i < data.clid_len; i++)
266 {
267 p += sprintf(p, "%.2x", buf[i]);
268 if (i != data.clid_len - 1)
Simon Kelleyceae00d2012-02-09 21:28:14 +0000269 p += sprintf(p, ":");
Simon Kelley89500e32013-09-20 16:29:20 +0100270 }
271
Simon Kelleyceae00d2012-02-09 21:28:14 +0000272#ifdef HAVE_DHCP6
Simon Kelley89500e32013-09-20 16:29:20 +0100273 if (is6)
Simon Kelley16972692006-10-16 20:04:18 +0100274 {
Simon Kelleyceae00d2012-02-09 21:28:14 +0000275 /* or IAID and server DUID for IPv6 */
Simon Kelley89500e32013-09-20 16:29:20 +0100276 sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.iaid);
277 for (p = daemon->dhcp_packet.iov_base, i = 0; i < daemon->duid_len; i++)
Simon Kelleyceae00d2012-02-09 21:28:14 +0000278 {
279 p += sprintf(p, "%.2x", daemon->duid[i]);
280 if (i != daemon->duid_len - 1)
281 p += sprintf(p, ":");
282 }
Simon Kelleycaa94382012-02-15 10:29:50 +0000283
Simon Kelley16972692006-10-16 20:04:18 +0100284 }
Simon Kelleyceae00d2012-02-09 21:28:14 +0000285#endif
Simon Kelleyc72daea2012-01-05 21:33:27 +0000286
287 buf += data.clid_len;
288
289 if (data.hostname_len != 0)
290 {
291 char *dot;
292 hostname = (char *)buf;
293 hostname[data.hostname_len - 1] = 0;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700294 if (data.action != ACTION_TFTP && data.action != ACTION_RELAY_SNOOP)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000295 {
Simon Kelleya9530962012-03-20 22:07:35 +0000296 if (!legal_hostname(hostname))
297 hostname = NULL;
298 else if ((dot = strchr(hostname, '.')))
299 {
300 domain = dot+1;
301 *dot = 0;
302 }
303 }
Simon Kelleyc72daea2012-01-05 21:33:27 +0000304 }
305
306 extradata = buf + data.hostname_len;
307
Simon Kelleyceae00d2012-02-09 21:28:14 +0000308 if (!is6)
309 inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelleyceae00d2012-02-09 21:28:14 +0000310 else
Simon Kelley89500e32013-09-20 16:29:20 +0100311 inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN);
Simon Kelleyceae00d2012-02-09 21:28:14 +0000312
Simon Kelley2f9fd1d2013-10-01 09:54:41 +0100313#ifdef HAVE_TFTP
Simon Kelleya9530962012-03-20 22:07:35 +0000314 /* file length */
315 if (data.action == ACTION_TFTP)
Simon Kelley2f9fd1d2013-10-01 09:54:41 +0100316 sprintf(is6 ? daemon->packet : daemon->dhcp_buff, "%lu", (unsigned long)data.file_len);
317#endif
318
Simon Kelleyc72daea2012-01-05 21:33:27 +0000319#ifdef HAVE_LUASCRIPT
320 if (daemon->luascript)
321 {
Simon Kelleya9530962012-03-20 22:07:35 +0000322 if (data.action == ACTION_TFTP)
Simon Kelleyceae00d2012-02-09 21:28:14 +0000323 {
Simon Kelleya9530962012-03-20 22:07:35 +0000324 lua_getglobal(lua, "tftp");
325 if (lua_type(lua, -1) != LUA_TFUNCTION)
326 lua_pop(lua, 1); /* tftp function optional */
327 else
328 {
329 lua_pushstring(lua, action_str); /* arg1 - action */
330 lua_newtable(lua); /* arg2 - data table */
331 lua_pushstring(lua, daemon->addrbuff);
332 lua_setfield(lua, -2, "destination_address");
333 lua_pushstring(lua, hostname);
334 lua_setfield(lua, -2, "file_name");
Simon Kelleyb5d9a362013-09-24 09:44:33 +0100335 lua_pushstring(lua, is6 ? daemon->packet : daemon->dhcp_buff);
Simon Kelleya9530962012-03-20 22:07:35 +0000336 lua_setfield(lua, -2, "file_size");
337 lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
338 }
Simon Kelleyceae00d2012-02-09 21:28:14 +0000339 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700340 else if (data.action == ACTION_RELAY_SNOOP)
341 {
342 lua_getglobal(lua, "snoop");
343 if (lua_type(lua, -1) != LUA_TFUNCTION)
344 lua_pop(lua, 1); /* tftp function optional */
345 else
346 {
347 lua_pushstring(lua, action_str); /* arg1 - action */
348 lua_newtable(lua); /* arg2 - data table */
349 lua_pushstring(lua, daemon->addrbuff);
350 lua_setfield(lua, -2, "client_address");
351 lua_pushstring(lua, hostname);
352 lua_setfield(lua, -2, "prefix");
353 lua_pushstring(lua, data.interface);
354 lua_setfield(lua, -2, "client_interface");
355 lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
356 }
357 }
Simon Kelley33702ab2015-12-28 23:17:15 +0000358 else if (data.action == ACTION_ARP)
359 {
360 lua_getglobal(lua, "arp");
361 if (lua_type(lua, -1) != LUA_TFUNCTION)
362 lua_pop(lua, 1); /* arp function optional */
363 else
364 {
365 lua_pushstring(lua, action_str); /* arg1 - action */
366 lua_newtable(lua); /* arg2 - data table */
367 lua_pushstring(lua, daemon->addrbuff);
368 lua_setfield(lua, -2, "client_address");
369 lua_pushstring(lua, daemon->dhcp_buff);
370 lua_setfield(lua, -2, "mac_address");
371 lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
372 }
373 }
Simon Kelleyceae00d2012-02-09 21:28:14 +0000374 else
Simon Kelleya9530962012-03-20 22:07:35 +0000375 {
376 lua_getglobal(lua, "lease"); /* function to call */
377 lua_pushstring(lua, action_str); /* arg1 - action */
378 lua_newtable(lua); /* arg2 - data table */
379
380 if (is6)
381 {
Simon Kelleya9530962012-03-20 22:07:35 +0000382 lua_pushstring(lua, daemon->packet);
Simon Kelley89500e32013-09-20 16:29:20 +0100383 lua_setfield(lua, -2, "client_duid");
384 lua_pushstring(lua, daemon->dhcp_packet.iov_base);
Simon Kelleya9530962012-03-20 22:07:35 +0000385 lua_setfield(lua, -2, "server_duid");
386 lua_pushstring(lua, daemon->dhcp_buff3);
387 lua_setfield(lua, -2, "iaid");
388 }
389
390 if (!is6 && data.clid_len != 0)
391 {
392 lua_pushstring(lua, daemon->packet);
393 lua_setfield(lua, -2, "client_id");
394 }
395
396 if (strlen(data.interface) != 0)
397 {
398 lua_pushstring(lua, data.interface);
399 lua_setfield(lua, -2, "interface");
400 }
401
402#ifdef HAVE_BROKEN_RTC
403 lua_pushnumber(lua, data.length);
404 lua_setfield(lua, -2, "lease_length");
405#else
406 lua_pushnumber(lua, data.expires);
407 lua_setfield(lua, -2, "lease_expires");
Simon Kelleyceae00d2012-02-09 21:28:14 +0000408#endif
Simon Kelleya9530962012-03-20 22:07:35 +0000409
410 if (hostname)
411 {
412 lua_pushstring(lua, hostname);
413 lua_setfield(lua, -2, "hostname");
414 }
415
416 if (domain)
417 {
418 lua_pushstring(lua, domain);
419 lua_setfield(lua, -2, "domain");
420 }
421
422 end = extradata + data.ed_len;
423 buf = extradata;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700424
425 lua_pushnumber(lua, data.ed_len == 0 ? 1 : 0);
426 lua_setfield(lua, -2, "data_missing");
Simon Kelleya9530962012-03-20 22:07:35 +0000427
428 if (!is6)
429 buf = grab_extradata_lua(buf, end, "vendor_class");
430#ifdef HAVE_DHCP6
Simon Kelley89500e32013-09-20 16:29:20 +0100431 else if (data.vendorclass_count != 0)
432 {
433 sprintf(daemon->dhcp_buff2, "vendor_class_id");
434 buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
435 for (i = 0; i < data.vendorclass_count - 1; i++)
436 {
437 sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
438 buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
439 }
440 }
Simon Kelleya9530962012-03-20 22:07:35 +0000441#endif
442
443 buf = grab_extradata_lua(buf, end, "supplied_hostname");
444
445 if (!is6)
446 {
447 buf = grab_extradata_lua(buf, end, "cpewan_oui");
448 buf = grab_extradata_lua(buf, end, "cpewan_serial");
449 buf = grab_extradata_lua(buf, end, "cpewan_class");
Simon Kelleydd1721c2013-02-18 21:04:04 +0000450 buf = grab_extradata_lua(buf, end, "circuit_id");
451 buf = grab_extradata_lua(buf, end, "subscriber_id");
452 buf = grab_extradata_lua(buf, end, "remote_id");
Simon Kelleya9530962012-03-20 22:07:35 +0000453 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700454
455 buf = grab_extradata_lua(buf, end, "requested_options");
456 buf = grab_extradata_lua(buf, end, "mud_url");
Simon Kelleya9530962012-03-20 22:07:35 +0000457 buf = grab_extradata_lua(buf, end, "tags");
458
459 if (is6)
460 buf = grab_extradata_lua(buf, end, "relay_address");
461 else if (data.giaddr.s_addr != 0)
462 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700463 inet_ntop(AF_INET, &data.giaddr, daemon->dhcp_buff2, ADDRSTRLEN);
464 lua_pushstring(lua, daemon->dhcp_buff2);
Simon Kelleya9530962012-03-20 22:07:35 +0000465 lua_setfield(lua, -2, "relay_address");
466 }
467
468 for (i = 0; buf; i++)
469 {
470 sprintf(daemon->dhcp_buff2, "user_class%i", i);
471 buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
472 }
473
474 if (data.action != ACTION_DEL && data.remaining_time != 0)
475 {
476 lua_pushnumber(lua, data.remaining_time);
477 lua_setfield(lua, -2, "time_remaining");
478 }
479
480 if (data.action == ACTION_OLD_HOSTNAME && hostname)
481 {
482 lua_pushstring(lua, hostname);
483 lua_setfield(lua, -2, "old_hostname");
484 }
485
Simon Kelley89500e32013-09-20 16:29:20 +0100486 if (!is6 || data.hwaddr_len != 0)
Simon Kelleya9530962012-03-20 22:07:35 +0000487 {
488 lua_pushstring(lua, daemon->dhcp_buff);
489 lua_setfield(lua, -2, "mac_address");
490 }
491
492 lua_pushstring(lua, daemon->addrbuff);
493 lua_setfield(lua, -2, "ip_address");
494
495 lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
Simon Kelleyceae00d2012-02-09 21:28:14 +0000496 }
Simon Kelleyc72daea2012-01-05 21:33:27 +0000497 }
498#endif
499
500 /* no script, just lua */
501 if (!daemon->lease_change_command)
Simon Kelley316e2732010-01-22 20:16:09 +0000502 continue;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000503
Petr Menšíkc77fb9d2017-04-16 20:20:08 +0100504 /* Pipe to capture stdout and stderr from script */
505 if (!option_bool(OPT_DEBUG) && pipe(pipeout) == -1)
506 continue;
507
Simon Kelley5aabfc72007-08-29 11:24:47 +0100508 /* possible fork errors are all temporary resource problems */
509 while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
510 sleep(2);
Simon Kelley316e2732010-01-22 20:16:09 +0000511
Simon Kelley5aabfc72007-08-29 11:24:47 +0100512 if (pid == -1)
Petr Menšíkc77fb9d2017-04-16 20:20:08 +0100513 {
514 if (!option_bool(OPT_DEBUG))
515 {
516 close(pipeout[0]);
517 close(pipeout[1]);
518 }
519 continue;
520 }
Simon Kelleyc72daea2012-01-05 21:33:27 +0000521
Simon Kelley16972692006-10-16 20:04:18 +0100522 /* wait for child to complete */
523 if (pid != 0)
524 {
Petr Menšíkc77fb9d2017-04-16 20:20:08 +0100525 if (!option_bool(OPT_DEBUG))
526 {
527 FILE *fp;
528
529 close(pipeout[1]);
530
531 /* Read lines sent to stdout/err by the script and pass them back to be logged */
532 if (!(fp = fdopen(pipeout[0], "r")))
533 close(pipeout[0]);
534 else
535 {
536 while (fgets(daemon->packet, daemon->packet_buff_sz, fp))
537 {
538 /* do not include new lines, log will append them */
539 size_t len = strlen(daemon->packet);
540 if (len > 0)
541 {
542 --len;
543 if (daemon->packet[len] == '\n')
544 daemon->packet[len] = 0;
545 }
546 send_event(event_fd, EVENT_SCRIPT_LOG, 0, daemon->packet);
547 }
548 fclose(fp);
549 }
550 }
551
Simon Kelley5aabfc72007-08-29 11:24:47 +0100552 /* reap our children's children, if necessary */
553 while (1)
554 {
555 int status;
556 pid_t rc = wait(&status);
557
558 if (rc == pid)
559 {
560 /* On error send event back to main process for logging */
561 if (WIFSIGNALED(status))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000562 send_event(event_fd, EVENT_KILLED, WTERMSIG(status), NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100563 else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000564 send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100565 break;
566 }
567
568 if (rc == -1 && errno != EINTR)
569 break;
570 }
571
Simon Kelley16972692006-10-16 20:04:18 +0100572 continue;
573 }
Petr Menšíkc77fb9d2017-04-16 20:20:08 +0100574
575 if (!option_bool(OPT_DEBUG))
576 {
577 /* map stdout/stderr of script to pipeout */
578 close(pipeout[0]);
579 dup2(pipeout[1], STDOUT_FILENO);
580 dup2(pipeout[1], STDERR_FILENO);
581 close(pipeout[1]);
582 }
Simon Kelley16972692006-10-16 20:04:18 +0100583
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700584 if (data.action != ACTION_TFTP && data.action != ACTION_ARP && data.action != ACTION_RELAY_SNOOP)
Simon Kelleyceae00d2012-02-09 21:28:14 +0000585 {
Simon Kelley89500e32013-09-20 16:29:20 +0100586#ifdef HAVE_DHCP6
Simon Kelleyd4da20f2013-10-04 10:12:49 +0100587 my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
588 my_setenv("DNSMASQ_SERVER_DUID", is6 ? daemon->dhcp_packet.iov_base : NULL, &err);
589 my_setenv("DNSMASQ_MAC", is6 && data.hwaddr_len != 0 ? daemon->dhcp_buff : NULL, &err);
Simon Kelley89500e32013-09-20 16:29:20 +0100590#endif
Simon Kelleya9530962012-03-20 22:07:35 +0000591
Simon Kelleyd4da20f2013-10-04 10:12:49 +0100592 my_setenv("DNSMASQ_CLIENT_ID", !is6 && data.clid_len != 0 ? daemon->packet : NULL, &err);
593 my_setenv("DNSMASQ_INTERFACE", strlen(data.interface) != 0 ? data.interface : NULL, &err);
Simon Kelleya9530962012-03-20 22:07:35 +0000594
595#ifdef HAVE_BROKEN_RTC
Simon Kelley208fb612013-02-21 22:26:18 +0000596 sprintf(daemon->dhcp_buff2, "%u", data.length);
Simon Kelleya9530962012-03-20 22:07:35 +0000597 my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
598#else
Simon Kelley208fb612013-02-21 22:26:18 +0000599 sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
Simon Kelleya9530962012-03-20 22:07:35 +0000600 my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
601#endif
602
Simon Kelleyd4da20f2013-10-04 10:12:49 +0100603 my_setenv("DNSMASQ_DOMAIN", domain, &err);
Simon Kelleya9530962012-03-20 22:07:35 +0000604
605 end = extradata + data.ed_len;
606 buf = extradata;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700607
608 if (data.ed_len == 0)
609 my_setenv("DNSMASQ_DATA_MISSING", "1", &err);
Simon Kelleya9530962012-03-20 22:07:35 +0000610
611 if (!is6)
612 buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
613#ifdef HAVE_DHCP6
614 else
615 {
Simon Kelley89500e32013-09-20 16:29:20 +0100616 if (data.vendorclass_count != 0)
Simon Kelleya5c72ab2012-02-10 13:42:47 +0000617 {
Simon Kelleya9530962012-03-20 22:07:35 +0000618 buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
Simon Kelley89500e32013-09-20 16:29:20 +0100619 for (i = 0; i < data.vendorclass_count - 1; i++)
Simon Kelleya9530962012-03-20 22:07:35 +0000620 {
621 sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
622 buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
623 }
Simon Kelleya5c72ab2012-02-10 13:42:47 +0000624 }
625 }
Simon Kelleyceae00d2012-02-09 21:28:14 +0000626#endif
Simon Kelleya9530962012-03-20 22:07:35 +0000627
628 buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
629
630 if (!is6)
631 {
632 buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
633 buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
634 buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
Simon Kelleydd1721c2013-02-18 21:04:04 +0000635 buf = grab_extradata(buf, end, "DNSMASQ_CIRCUIT_ID", &err);
636 buf = grab_extradata(buf, end, "DNSMASQ_SUBSCRIBER_ID", &err);
637 buf = grab_extradata(buf, end, "DNSMASQ_REMOTE_ID", &err);
Simon Kelleya9530962012-03-20 22:07:35 +0000638 }
639
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700640 buf = grab_extradata(buf, end, "DNSMASQ_REQUESTED_OPTIONS", &err);
641 buf = grab_extradata(buf, end, "DNSMASQ_MUD_URL", &err);
Simon Kelleya9530962012-03-20 22:07:35 +0000642 buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700643
Simon Kelleya9530962012-03-20 22:07:35 +0000644 if (is6)
645 buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700646 else
647 {
648 const char *giaddr = NULL;
649 if (data.giaddr.s_addr != 0)
650 giaddr = inet_ntop(AF_INET, &data.giaddr, daemon->dhcp_buff2, ADDRSTRLEN);
651 my_setenv("DNSMASQ_RELAY_ADDRESS", giaddr, &err);
652 }
Simon Kelleya9530962012-03-20 22:07:35 +0000653
654 for (i = 0; buf; i++)
655 {
656 sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
657 buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
658 }
659
Simon Kelleyd4da20f2013-10-04 10:12:49 +0100660 sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
661 my_setenv("DNSMASQ_TIME_REMAINING", data.action != ACTION_DEL && data.remaining_time != 0 ? daemon->dhcp_buff2 : NULL, &err);
Simon Kelleya9530962012-03-20 22:07:35 +0000662
Simon Kelleyd4da20f2013-10-04 10:12:49 +0100663 my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
664 if (data.action == ACTION_OLD_HOSTNAME)
665 hostname = NULL;
Simon Kelley33702ab2015-12-28 23:17:15 +0000666
667 my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
Petr Menšíkc77fb9d2017-04-16 20:20:08 +0100668 }
669
Simon Kelley5aabfc72007-08-29 11:24:47 +0100670 /* we need to have the event_fd around if exec fails */
671 if ((i = fcntl(event_fd, F_GETFD)) != -1)
672 fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
673 close(pipefd[0]);
674
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700675 if (data.action == ACTION_RELAY_SNOOP)
676 strcpy(daemon->packet, data.interface);
677
Simon Kelley16972692006-10-16 20:04:18 +0100678 p = strrchr(daemon->lease_change_command, '/');
Simon Kelley824af852008-02-12 20:43:05 +0000679 if (err == 0)
680 {
681 execl(daemon->lease_change_command,
Simon Kelley33702ab2015-12-28 23:17:15 +0000682 p ? p+1 : daemon->lease_change_command, action_str,
683 (is6 && data.action != ACTION_ARP) ? daemon->packet : daemon->dhcp_buff,
Simon Kelley89500e32013-09-20 16:29:20 +0100684 daemon->addrbuff, hostname, (char*)NULL);
Simon Kelley824af852008-02-12 20:43:05 +0000685 err = errno;
686 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100687 /* failed, send event so the main process logs the problem */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000688 send_event(event_fd, EVENT_EXEC_ERR, err, NULL);
Simon Kelley16972692006-10-16 20:04:18 +0100689 _exit(0);
690 }
691}
692
Simon Kelley824af852008-02-12 20:43:05 +0000693static void my_setenv(const char *name, const char *value, int *error)
694{
Simon Kelleyd4da20f2013-10-04 10:12:49 +0100695 if (*error == 0)
696 {
697 if (!value)
698 unsetenv(name);
699 else if (setenv(name, value, 1) != 0)
700 *error = errno;
701 }
Simon Kelley824af852008-02-12 20:43:05 +0000702}
703
Simon Kelley316e2732010-01-22 20:16:09 +0000704static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err)
705{
Simon Kelleyd4da20f2013-10-04 10:12:49 +0100706 unsigned char *next = NULL;
707 char *val = NULL;
Simon Kelley316e2732010-01-22 20:16:09 +0000708
Simon Kelleyd4da20f2013-10-04 10:12:49 +0100709 if (buf && (buf != end))
Simon Kelley316e2732010-01-22 20:16:09 +0000710 {
Simon Kelleyd4da20f2013-10-04 10:12:49 +0100711 for (next = buf; ; next++)
712 if (next == end)
713 {
714 next = NULL;
715 break;
716 }
717 else if (*next == 0)
718 break;
Simon Kelley316e2732010-01-22 20:16:09 +0000719
Simon Kelleyd4da20f2013-10-04 10:12:49 +0100720 if (next && (next != buf))
721 {
722 char *p;
723 /* No "=" in value */
724 if ((p = strchr((char *)buf, '=')))
725 *p = 0;
726 val = (char *)buf;
727 }
728 }
729
730 my_setenv(env, val, err);
731
732 return next ? next + 1 : NULL;
Simon Kelley316e2732010-01-22 20:16:09 +0000733}
734
Simon Kelleyc72daea2012-01-05 21:33:27 +0000735#ifdef HAVE_LUASCRIPT
736static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field)
737{
738 unsigned char *next;
739
740 if (!buf || (buf == end))
741 return NULL;
742
743 for (next = buf; *next != 0; next++)
744 if (next == end)
745 return NULL;
746
747 if (next != buf)
748 {
749 lua_pushstring(lua, (char *)buf);
750 lua_setfield(lua, -2, field);
751 }
752
753 return next + 1;
754}
755#endif
756
Simon Kelleya9530962012-03-20 22:07:35 +0000757static void buff_alloc(size_t size)
758{
759 if (size > buf_size)
760 {
761 struct script_data *new;
762
763 /* start with reasonable size, will almost never need extending. */
764 if (size < sizeof(struct script_data) + 200)
765 size = sizeof(struct script_data) + 200;
766
767 if (!(new = whine_malloc(size)))
768 return;
769 if (buf)
770 free(buf);
771 buf = new;
772 buf_size = size;
773 }
774}
775
Simon Kelley16972692006-10-16 20:04:18 +0100776/* pack up lease data into a buffer */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100777void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
Simon Kelley16972692006-10-16 20:04:18 +0100778{
779 unsigned char *p;
Simon Kelley316e2732010-01-22 20:16:09 +0000780 unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
Simon Kelleyceae00d2012-02-09 21:28:14 +0000781 int fd = daemon->dhcpfd;
Simon Kelley6f9aaa92013-04-10 10:25:26 +0100782#ifdef HAVE_DHCP6
Simon Kelleyceae00d2012-02-09 21:28:14 +0000783 if (!daemon->dhcp)
784 fd = daemon->dhcp6fd;
785#endif
786
Simon Kelley16972692006-10-16 20:04:18 +0100787 /* no script */
788 if (daemon->helperfd == -1)
789 return;
790
Simon Kelley316e2732010-01-22 20:16:09 +0000791 if (lease->extradata)
792 ed_len = lease->extradata_len;
Simon Kelley16972692006-10-16 20:04:18 +0100793 if (lease->clid)
794 clid_len = lease->clid_len;
795 if (hostname)
796 hostname_len = strlen(hostname) + 1;
797
Simon Kelleya9530962012-03-20 22:07:35 +0000798 buff_alloc(sizeof(struct script_data) + clid_len + ed_len + hostname_len);
Simon Kelley16972692006-10-16 20:04:18 +0100799
800 buf->action = action;
Simon Kelleyceae00d2012-02-09 21:28:14 +0000801 buf->flags = lease->flags;
Simon Kelley6f9aaa92013-04-10 10:25:26 +0100802#ifdef HAVE_DHCP6
Simon Kelley89500e32013-09-20 16:29:20 +0100803 buf->vendorclass_count = lease->vendorclass_count;
804 buf->addr6 = lease->addr6;
805 buf->iaid = lease->iaid;
Simon Kelley6f9aaa92013-04-10 10:25:26 +0100806#endif
Simon Kelley89500e32013-09-20 16:29:20 +0100807 buf->hwaddr_len = lease->hwaddr_len;
Simon Kelley16972692006-10-16 20:04:18 +0100808 buf->hwaddr_type = lease->hwaddr_type;
809 buf->clid_len = clid_len;
Simon Kelley316e2732010-01-22 20:16:09 +0000810 buf->ed_len = ed_len;
Simon Kelley16972692006-10-16 20:04:18 +0100811 buf->hostname_len = hostname_len;
812 buf->addr = lease->addr;
Simon Kelley1f15b812009-10-13 17:49:32 +0100813 buf->giaddr = lease->giaddr;
Simon Kelleyceae00d2012-02-09 21:28:14 +0000814 memcpy(buf->hwaddr, lease->hwaddr, DHCP_CHADDR_MAX);
815 if (!indextoname(fd, lease->last_interface, buf->interface))
Simon Kelley316e2732010-01-22 20:16:09 +0000816 buf->interface[0] = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000817
Simon Kelley16972692006-10-16 20:04:18 +0100818#ifdef HAVE_BROKEN_RTC
819 buf->length = lease->length;
820#else
821 buf->expires = lease->expires;
822#endif
Simon Kelleyc72daea2012-01-05 21:33:27 +0000823
824 if (lease->expires != 0)
825 buf->remaining_time = (unsigned int)difftime(lease->expires, now);
826 else
827 buf->remaining_time = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100828
Simon Kelley16972692006-10-16 20:04:18 +0100829 p = (unsigned char *)(buf+1);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100830 if (clid_len != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100831 {
832 memcpy(p, lease->clid, clid_len);
833 p += clid_len;
834 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100835 if (hostname_len != 0)
836 {
837 memcpy(p, hostname, hostname_len);
838 p += hostname_len;
839 }
Simon Kelley316e2732010-01-22 20:16:09 +0000840 if (ed_len != 0)
841 {
842 memcpy(p, lease->extradata, ed_len);
843 p += ed_len;
844 }
Simon Kelley16972692006-10-16 20:04:18 +0100845 bytes_in_buf = p - (unsigned char *)buf;
846}
847
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700848#ifdef HAVE_DHCP6
849void queue_relay_snoop(struct in6_addr *client, int if_index, struct in6_addr *prefix, int prefix_len)
850{
851 /* no script */
852 if (daemon->helperfd == -1)
853 return;
854
855 inet_ntop(AF_INET6, prefix, daemon->addrbuff, ADDRSTRLEN);
856
857 /* 5 for /nnn and zero on the end of the prefix. */
858 buff_alloc(sizeof(struct script_data) + ADDRSTRLEN + 5);
859 memset(buf, 0, sizeof(struct script_data));
860
861 buf->action = ACTION_RELAY_SNOOP;
862 buf->addr6 = *client;
863 buf->hostname_len = sprintf((char *)(buf+1), "%s/%u", daemon->addrbuff, prefix_len) + 1;
864
865 indextoname(daemon->dhcp6fd, if_index, buf->interface);
866
867 bytes_in_buf = sizeof(struct script_data) + buf->hostname_len;
868}
869#endif
870
Simon Kelleya9530962012-03-20 22:07:35 +0000871#ifdef HAVE_TFTP
872/* This nastily re-uses DHCP-fields for TFTP stuff */
873void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
874{
875 unsigned int filename_len;
876
877 /* no script */
878 if (daemon->helperfd == -1)
879 return;
880
881 filename_len = strlen(filename) + 1;
882 buff_alloc(sizeof(struct script_data) + filename_len);
883 memset(buf, 0, sizeof(struct script_data));
884
885 buf->action = ACTION_TFTP;
886 buf->hostname_len = filename_len;
Simon Kelley2f9fd1d2013-10-01 09:54:41 +0100887 buf->file_len = file_len;
Simon Kelleya9530962012-03-20 22:07:35 +0000888
889 if ((buf->flags = peer->sa.sa_family) == AF_INET)
890 buf->addr = peer->in.sin_addr;
Simon Kelleya9530962012-03-20 22:07:35 +0000891 else
Simon Kelleyb5d9a362013-09-24 09:44:33 +0100892 buf->addr6 = peer->in6.sin6_addr;
Simon Kelleya9530962012-03-20 22:07:35 +0000893
894 memcpy((unsigned char *)(buf+1), filename, filename_len);
895
896 bytes_in_buf = sizeof(struct script_data) + filename_len;
897}
898#endif
899
Simon Kelleycc921df2019-01-02 22:48:59 +0000900void queue_arp(int action, unsigned char *mac, int maclen, int family, union all_addr *addr)
Simon Kelley33702ab2015-12-28 23:17:15 +0000901{
902 /* no script */
903 if (daemon->helperfd == -1)
904 return;
905
906 buff_alloc(sizeof(struct script_data));
907 memset(buf, 0, sizeof(struct script_data));
908
909 buf->action = action;
910 buf->hwaddr_len = maclen;
911 buf->hwaddr_type = ARPHRD_ETHER;
912 if ((buf->flags = family) == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +0000913 buf->addr = addr->addr4;
Simon Kelley33702ab2015-12-28 23:17:15 +0000914 else
Simon Kelleycc921df2019-01-02 22:48:59 +0000915 buf->addr6 = addr->addr6;
Simon Kelley33702ab2015-12-28 23:17:15 +0000916
917 memcpy(buf->hwaddr, mac, maclen);
918
919 bytes_in_buf = sizeof(struct script_data);
920}
921
Simon Kelley16972692006-10-16 20:04:18 +0100922int helper_buf_empty(void)
923{
924 return bytes_in_buf == 0;
925}
926
Simon Kelley5aabfc72007-08-29 11:24:47 +0100927void helper_write(void)
Simon Kelley16972692006-10-16 20:04:18 +0100928{
929 ssize_t rc;
930
931 if (bytes_in_buf == 0)
932 return;
933
934 if ((rc = write(daemon->helperfd, buf, bytes_in_buf)) != -1)
935 {
936 if (bytes_in_buf != (size_t)rc)
937 memmove(buf, buf + rc, bytes_in_buf - rc);
938 bytes_in_buf -= rc;
939 }
940 else
941 {
942 if (errno == EAGAIN || errno == EINTR)
943 return;
944 bytes_in_buf = 0;
945 }
946}
947
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700948#endif /* HAVE_SCRIPT */