• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/odhcp6c/src/script.c

  1 /**
  2  * Copyright (C) 2012-2014 Steven Barth <steven@midlink.org>
  3  * Copyright (C) 2017-2018 Hans Dedecker <dedeckeh@gmail.com>
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU General Public License v2 as published by
  7  * the Free Software Foundation.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12  * GNU General Public License for more details.
 13  *
 14  */
 15 
 16 #include <arpa/inet.h>
 17 #include <errno.h>
 18 #include <inttypes.h>
 19 #include <netdb.h>
 20 #include <netinet/in.h>
 21 #include <resolv.h>
 22 #include <signal.h>
 23 #include <stdio.h>
 24 #include <stdlib.h>
 25 #include <string.h>
 26 #include <sys/wait.h>
 27 #include <unistd.h>
 28 
 29 #include "odhcp6c.h"
 30 
 31 static const char hexdigits[] = "0123456789abcdef";
 32 static const int8_t hexvals[] = {
 33     -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1,
 34     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 35     -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 36      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
 37     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 38     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 39     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 40     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 41 };
 42 
 43 static char action[16] = "";
 44 static char *argv[4] = {NULL, NULL, action, NULL};
 45 static volatile pid_t running = 0;
 46 static time_t started;
 47 
 48 static void script_sighandle(int signal)
 49 {
 50         if (signal == SIGCHLD) {
 51                 pid_t child;
 52 
 53                 while ((child = waitpid(-1, NULL, WNOHANG)) > 0)
 54                         if (running == child)
 55                                 running = 0;
 56         }
 57 }
 58 
 59 int script_init(const char *path, const char *ifname)
 60 {
 61         argv[0] = (char*)path;
 62         argv[1] = (char*)ifname;
 63         signal(SIGCHLD, script_sighandle);
 64 
 65         return 0;
 66 }
 67 
 68 ssize_t script_unhexlify(uint8_t *dst, size_t len, const char *src)
 69 {
 70         size_t c;
 71 
 72         for (c = 0; c < len && src[0] && src[1]; ++c) {
 73                 int8_t x = (int8_t)*src++;
 74                 int8_t y = (int8_t)*src++;
 75                 if (x < 0 || (x = hexvals[x]) < 0
 76                                 || y < 0 || (y = hexvals[y]) < 0)
 77                         return -1;
 78                 dst[c] = x << 4 | y;
 79                 while (((int8_t)*src) < 0 ||
 80                                 (*src && hexvals[(uint8_t)*src] < 0))
 81                         src++;
 82         }
 83 
 84         return c;
 85 }
 86 
 87 void script_hexlify(char *dst, const uint8_t *src, size_t len)
 88 {
 89         for (size_t i = 0; i < len; ++i) {
 90                 *dst++ = hexdigits[src[i] >> 4];
 91                 *dst++ = hexdigits[src[i] & 0x0f];
 92         }
 93 
 94         *dst = 0;
 95 }
 96 
 97 static void ipv6_to_env(const char *name,
 98                 const struct in6_addr *addr, size_t cnt)
 99 {
100         size_t buf_len = strlen(name);
101         char *buf = malloc(cnt * INET6_ADDRSTRLEN + buf_len + 2);
102 
103         if (!buf)
104                 return;
105 
106         memcpy(buf, name, buf_len);
107         buf[buf_len++] = '=';
108 
109         for (size_t i = 0; i < cnt; ++i) {
110                 inet_ntop(AF_INET6, &addr[i], &buf[buf_len], INET6_ADDRSTRLEN);
111                 buf_len += strlen(&buf[buf_len]);
112                 buf[buf_len++] = ' ';
113         }
114 
115         if (buf[buf_len - 1] == ' ')
116                 buf_len--;
117 
118         buf[buf_len] = '\0';
119         putenv(buf);
120 }
121 
122 static void fqdn_to_env(const char *name, const uint8_t *fqdn, size_t len)
123 {
124         size_t buf_len = strlen(name);
125         size_t buf_size = len + buf_len + 2;
126         const uint8_t *fqdn_end = fqdn + len;
127         char *buf = malloc(buf_size);
128 
129         if (!buf)
130                 return;
131 
132         memcpy(buf, name, buf_len);
133         buf[buf_len++] = '=';
134 
135         while (fqdn < fqdn_end) {
136                 int l = dn_expand(fqdn, fqdn_end, fqdn, &buf[buf_len], buf_size - buf_len);
137                 if (l <= 0)
138                         break;
139                 fqdn += l;
140                 buf_len += strlen(&buf[buf_len]);
141                 buf[buf_len++] = ' ';
142         }
143 
144         if (buf[buf_len - 1] == ' ')
145                 buf_len--;
146 
147         buf[buf_len] = '\0';
148         putenv(buf);
149 }
150 
151 static void string_to_env(const char *name, const uint8_t *string, size_t len)
152 {
153         size_t name_len = strlen(name);
154         char *buf = malloc(name_len + 1 + len + 1);
155 
156         if (!buf)
157                 return;
158 
159         memcpy(buf, name, name_len);
160         buf[name_len] = '=';
161         memcpy(&buf[name_len + 1], string, len);
162         buf[name_len + 1 + len] = '\0';
163         putenv(buf);
164 }
165 
166 static void bin_to_env(uint8_t *opts, size_t len)
167 {
168         uint8_t *oend = opts + len, *odata;
169         uint16_t otype, olen;
170 
171         dhcpv6_for_each_option(opts, oend, otype, olen, odata) {
172                 char *buf = malloc(14 + (olen * 2));
173                 size_t buf_len = 0;
174 
175                 if (!buf)
176                         continue;
177 
178                 snprintf(buf, 14, "OPTION_%hu=", otype);
179                 buf_len += strlen(buf);
180 
181                 script_hexlify(&buf[buf_len], odata, olen);
182                 putenv(buf);
183         }
184 }
185 
186 enum entry_type {
187         ENTRY_ADDRESS,
188         ENTRY_HOST,
189         ENTRY_ROUTE,
190         ENTRY_PREFIX
191 };
192 
193 static void entry_to_env(const char *name, const void *data, size_t len, enum entry_type type)
194 {
195         size_t buf_len = strlen(name);
196         const uint8_t *start = data;
197         // Worst case: ENTRY_PREFIX with iaid != 1 and exclusion
198         const size_t max_entry_len = (INET6_ADDRSTRLEN-1 + 5 + 44 + 15 + 10 +
199                                       INET6_ADDRSTRLEN-1 + 11 + 1);
200         /* An upper bound on the entry count: every entry occupies at least
201          * sizeof(struct odhcp6c_entry) bytes (auxlen rounds up to 4-byte
202          * stride, never below 0). */
203         char *buf = malloc(buf_len + 2 + (len / sizeof(struct odhcp6c_entry)) * max_entry_len);
204 
205         if (!buf)
206                 return;
207 
208         memcpy(buf, name, buf_len);
209         buf[buf_len++] = '=';
210 
211         for (const struct odhcp6c_entry *e = (const struct odhcp6c_entry *)start;
212                         (const uint8_t *)e < start + len &&
213                         (const uint8_t *)odhcp6c_next_entry(e) <= start + len;
214                         e = odhcp6c_next_entry(e)) {
215                 /*
216                  * The only invalid entries allowed to be passed to the script are prefix and RA
217                  * entries. This will allow immediate removal of the old ipv6-prefix-assignment
218                  * that might otherwise be kept for up to 2 hours (see L-13 requirement of RFC 7084).
219                  * Similarly, a RA with router lifetime set to 0 indicates that the advertising
220                  * router "is not a default router and SHOULD NOT appear on the default router list"
221                  * (see RFC 4861, section 4.2).
222                  */
223                 if (!e->valid && type != ENTRY_PREFIX && type != ENTRY_ROUTE)
224                         continue;
225 
226                 inet_ntop(AF_INET6, &e->target, &buf[buf_len], INET6_ADDRSTRLEN);
227                 buf_len += strlen(&buf[buf_len]);
228 
229                 if (type != ENTRY_HOST) {
230                         snprintf(&buf[buf_len], 6, "/%"PRIu16, e->length);
231                         buf_len += strlen(&buf[buf_len]);
232 
233                         if (type == ENTRY_ROUTE) {
234                                 buf[buf_len++] = ',';
235 
236                                 if (!IN6_IS_ADDR_UNSPECIFIED(&e->router)) {
237                                         inet_ntop(AF_INET6, &e->router, &buf[buf_len], INET6_ADDRSTRLEN);
238                                         buf_len += strlen(&buf[buf_len]);
239                                 }
240 
241                                 snprintf(&buf[buf_len], 23, ",%u,%u", e->valid, e->priority);
242                                 buf_len += strlen(&buf[buf_len]);
243                         } else {
244                                 snprintf(&buf[buf_len], 45, ",%u,%u,%u,%u", e->preferred, e->valid, e->t1, e->t2);
245                                 buf_len += strlen(&buf[buf_len]);
246                         }
247 
248                         if (type == ENTRY_PREFIX && ntohl(e->iaid) != 1) {
249                                 snprintf(&buf[buf_len], 16, ",class=%08x", ntohl(e->iaid));
250                                 buf_len += strlen(&buf[buf_len]);
251                         }
252 
253                         if (type == ENTRY_PREFIX && e->exclusion_length) {
254                                 snprintf(&buf[buf_len], 11, ",excluded=");
255                                 buf_len += strlen(&buf[buf_len]);
256                                 // '.router' is dual-used: for prefixes it contains the prefix
257                                 inet_ntop(AF_INET6, &e->router, &buf[buf_len], INET6_ADDRSTRLEN);
258                                 buf_len += strlen(&buf[buf_len]);
259                                 snprintf(&buf[buf_len], 12, "/%u", e->exclusion_length);
260                                 buf_len += strlen(&buf[buf_len]);
261                         }
262                 }
263 
264                 buf[buf_len++] = ' ';
265         }
266 
267         if (buf[buf_len - 1] == ' ')
268                 buf_len--;
269 
270         buf[buf_len] = '\0';
271         putenv(buf);
272 }
273 
274 static void search_to_env(const char *name, const uint8_t *start, size_t len)
275 {
276         size_t buf_len = strlen(name);
277         char *buf = malloc(buf_len + 2 + len);
278         char *c;
279 
280         if (!buf)
281                 return;
282 
283         c = mempcpy(buf, name, buf_len);
284         *c++ = '=';
285 
286         for (struct odhcp6c_entry *e = (struct odhcp6c_entry*)start;
287                                 (uint8_t*)e < &start[len] &&
288                                 (uint8_t*)odhcp6c_next_entry(e) <= &start[len];
289                                 e = odhcp6c_next_entry(e)) {
290                 if (!e->valid)
291                         continue;
292                 c = mempcpy(c, e->auxtarget, e->auxlen);
293                 *c++ = ' ';
294         }
295 
296         if (c[-1] == ' ')
297                 c--;
298 
299         *c = '\0';
300         putenv(buf);
301 }
302 
303 static void int_to_env(const char *name, int value)
304 {
305         size_t len = 13 + strlen(name);
306         char *buf = malloc(len);
307 
308         if (!buf)
309                 return;
310 
311         snprintf(buf, len, "%s=%d", name, value);
312         putenv(buf);
313 }
314 
315 static void s46_to_env_portparams(const uint8_t *data, size_t len, FILE *fp)
316 {
317         uint8_t *odata;
318         uint16_t otype, olen;
319 
320         dhcpv6_for_each_option(data, &data[len], otype, olen, odata) {
321                 if (otype == DHCPV6_OPT_S46_PORTPARAMS &&
322                                 olen == sizeof(struct dhcpv6_s46_portparams)) {
323                         struct dhcpv6_s46_portparams *params = (void*)odata;
324                         fprintf(fp, "offset=%d,psidlen=%d,psid=%d,",
325                                         params->offset, params->psid_len, ntohs(params->psid));
326                 }
327         }
328 }
329 
330 static void s46_to_env(enum odhcp6c_state state, const uint8_t *data, size_t len)
331 {
332         const char *name = (state == STATE_S46_MAPE) ? "MAPE" :
333                         (state == STATE_S46_MAPT) ? "MAPT" : "LW4O6";
334 
335         if (len == 0)
336                 return;
337 
338         char *str;
339         size_t strsize;
340 
341         FILE *fp = open_memstream(&str, &strsize);
342         fputs(name, fp);
343         fputc('=', fp);
344 
345         const char *type = (state == STATE_S46_MAPE) ? "map-e" :
346                         (state == STATE_S46_MAPT) ? "map-t" : "lw4o6";
347 
348         uint8_t *odata;
349         uint16_t otype, olen;
350 
351         dhcpv6_for_each_option(data, &data[len], otype, olen, odata) {
352                 struct dhcpv6_s46_rule *rule = (struct dhcpv6_s46_rule*)odata;
353                 struct dhcpv6_s46_v4v6bind *bind = (struct dhcpv6_s46_v4v6bind*)odata;
354 
355                 if (state != STATE_S46_LW && otype == DHCPV6_OPT_S46_RULE &&
356                                 olen >= sizeof(struct dhcpv6_s46_rule)) {
357                         char buf4[INET_ADDRSTRLEN];
358                         char buf6[INET6_ADDRSTRLEN];
359                         struct in6_addr in6 = IN6ADDR_ANY_INIT;
360 
361                         size_t prefix6len = rule->prefix6_len;
362                         prefix6len = (prefix6len % 8 == 0) ? prefix6len / 8 : prefix6len / 8 + 1;
363 
364                         if (prefix6len > sizeof(in6) ||
365                             olen < sizeof(struct dhcpv6_s46_rule) + prefix6len)
366                                 continue;
367 
368                         memcpy(&in6, rule->ipv6_prefix, prefix6len);
369 
370                         inet_ntop(AF_INET, &rule->ipv4_prefix, buf4, sizeof(buf4));
371                         inet_ntop(AF_INET6, &in6, buf6, sizeof(buf6));
372 
373                         if (rule->flags & 1)
374                                 fputs("fmr,", fp);
375 
376                         fprintf(fp, "type=%s,ealen=%d,prefix4len=%d,prefix6len=%d,ipv4prefix=%s,ipv6prefix=%s,",
377                                         type, rule->ea_len, rule->prefix4_len, rule->prefix6_len, buf4, buf6);
378 
379                         s46_to_env_portparams(&rule->ipv6_prefix[prefix6len],
380                                         olen - sizeof(*rule) - prefix6len, fp);
381 
382                         dhcpv6_for_each_option(data, &data[len], otype, olen, odata) {
383                                 if (state != STATE_S46_MAPT && otype == DHCPV6_OPT_S46_BR &&
384                                                 olen == sizeof(struct in6_addr)) {
385                                         inet_ntop(AF_INET6, odata, buf6, sizeof(buf6));
386                                         fprintf(fp, "br=%s,", buf6);
387                                 } else if (state == STATE_S46_MAPT && otype == DHCPV6_OPT_S46_DMR &&
388                                                 olen >= sizeof(struct dhcpv6_s46_dmr)) {
389                                         struct dhcpv6_s46_dmr *dmr = (struct dhcpv6_s46_dmr*)odata;
390                                         memset(&in6, 0, sizeof(in6));
391                                         size_t prefix6len = dmr->dmr_prefix6_len;
392                                         prefix6len = (prefix6len % 8 == 0) ? prefix6len / 8 : prefix6len / 8 + 1;
393 
394                                         if (prefix6len > sizeof(in6) ||
395                                             olen < sizeof(struct dhcpv6_s46_dmr) + prefix6len)
396                                                 continue;
397 
398                                         memcpy(&in6, dmr->dmr_ipv6_prefix, prefix6len);
399                                         inet_ntop(AF_INET6, &in6, buf6, sizeof(buf6));
400                                         fprintf(fp, "dmr=%s/%d,", buf6, dmr->dmr_prefix6_len);
401                                 }
402                         }
403 
404                         fputc(' ', fp);
405                 } else if (state == STATE_S46_LW && otype == DHCPV6_OPT_S46_V4V6BIND &&
406                                 olen >= sizeof(struct dhcpv6_s46_v4v6bind)) {
407                         char buf4[INET_ADDRSTRLEN];
408                         char buf6[INET6_ADDRSTRLEN];
409                         struct in6_addr in6 = IN6ADDR_ANY_INIT;
410 
411                         size_t prefix6len = bind->bindprefix6_len;
412                         prefix6len = (prefix6len % 8 == 0) ? prefix6len / 8 : prefix6len / 8 + 1;
413 
414                         if (prefix6len > sizeof(in6) ||
415                             olen < sizeof(struct dhcpv6_s46_v4v6bind) + prefix6len)
416                                 continue;
417 
418                         memcpy(&in6, bind->bind_ipv6_prefix, prefix6len);
419 
420                         inet_ntop(AF_INET, &bind->ipv4_address, buf4, sizeof(buf4));
421                         inet_ntop(AF_INET6, &in6, buf6, sizeof(buf6));
422 
423                         fprintf(fp, "type=%s,prefix4len=32,prefix6len=%d,ipv4prefix=%s,ipv6prefix=%s,",
424                                         type, bind->bindprefix6_len, buf4, buf6);
425 
426                         s46_to_env_portparams(&bind->bind_ipv6_prefix[prefix6len],
427                                         olen - sizeof(*bind) - prefix6len, fp);
428 
429                         dhcpv6_for_each_option(data, &data[len], otype, olen, odata) {
430                                 if (otype == DHCPV6_OPT_S46_BR && olen == sizeof(struct in6_addr)) {
431                                         inet_ntop(AF_INET6, odata, buf6, sizeof(buf6));
432                                         fprintf(fp, "br=%s,", buf6);
433                                 }
434                         }
435 
436                         fputc(' ', fp);
437                 }
438         }
439 
440         fclose(fp);
441         putenv(str);
442 }
443 
444 void script_call(const char *status, int delay, bool resume)
445 {
446         time_t now = odhcp6c_get_milli_time() / 1000;
447         bool running_script = false;
448 
449         if (!argv[0])
450                 return;
451 
452         pid_t prev = running;
453         if (prev > 0) {
454                 time_t diff = now - started;
455 
456                 kill(prev, SIGTERM);
457 
458                 if (diff > delay)
459                         delay -= diff;
460                 else
461                         delay = 0;
462 
463                 running_script = true;
464         }
465 
466         if (resume || !running_script || !action[0])
467                 strncpy(action, status, sizeof(action) - 1);
468 
469         pid_t pid = fork();
470 
471         if (pid < 0) {
472                 error("Failed to fork script handler: %s", strerror(errno));
473                 running = 0;
474                 return;
475         }
476 
477         if (pid > 0) {
478                 running = pid;
479                 started = now;
480 
481                 if (!resume)
482                         action[0] = 0;
483 
484         } else if (pid == 0) {
485                 size_t dns_len, search_len, custom_len, sntp_ip_len, ntp_ip_len, ntp_dns_len;
486                 size_t sip_ip_len, sip_fqdn_len, aftr_name_len, addr_len;
487                 size_t s46_mapt_len, s46_mape_len, s46_lw_len, passthru_len;
488                 size_t capt_port_ra_len, capt_port_dhcpv6_len;
489 
490                 signal(SIGTERM, SIG_DFL);
491                 if (delay > 0) {
492                         sleep(delay);
493                         odhcp6c_expire(false);
494                 }
495 
496                 struct in6_addr *addr = odhcp6c_get_state(STATE_SERVER_ADDR, &addr_len);
497                 struct in6_addr *dns = odhcp6c_get_state(STATE_DNS, &dns_len);
498                 uint8_t *search = odhcp6c_get_state(STATE_SEARCH, &search_len);
499                 uint8_t *custom = odhcp6c_get_state(STATE_CUSTOM_OPTS, &custom_len);
500                 struct in6_addr *sntp = odhcp6c_get_state(STATE_SNTP_IP, &sntp_ip_len);
501                 struct in6_addr *ntp = odhcp6c_get_state(STATE_NTP_IP, &ntp_ip_len);
502                 uint8_t *ntp_dns = odhcp6c_get_state(STATE_NTP_FQDN, &ntp_dns_len);
503                 struct in6_addr *sip = odhcp6c_get_state(STATE_SIP_IP, &sip_ip_len);
504                 uint8_t *sip_fqdn = odhcp6c_get_state(STATE_SIP_FQDN, &sip_fqdn_len);
505                 uint8_t *aftr_name = odhcp6c_get_state(STATE_AFTR_NAME, &aftr_name_len);
506                 uint8_t *s46_mapt = odhcp6c_get_state(STATE_S46_MAPT, &s46_mapt_len);
507                 uint8_t *s46_mape = odhcp6c_get_state(STATE_S46_MAPE, &s46_mape_len);
508                 uint8_t *s46_lw = odhcp6c_get_state(STATE_S46_LW, &s46_lw_len);
509                 uint8_t *capt_port_ra = odhcp6c_get_state(STATE_CAPT_PORT_RA, &capt_port_ra_len);
510                 uint8_t *capt_port_dhcpv6 = odhcp6c_get_state(STATE_CAPT_PORT_DHCPV6, &capt_port_dhcpv6_len);
511                 uint8_t *passthru = odhcp6c_get_state(STATE_PASSTHRU, &passthru_len);
512 
513                 size_t prefix_len, address_len, ra_pref_len,
514                         ra_route_len, ra_dns_len, ra_search_len;
515                 uint8_t *prefix = odhcp6c_get_state(STATE_IA_PD, &prefix_len);
516                 uint8_t *address = odhcp6c_get_state(STATE_IA_NA, &address_len);
517                 uint8_t *ra_pref = odhcp6c_get_state(STATE_RA_PREFIX, &ra_pref_len);
518                 uint8_t *ra_route = odhcp6c_get_state(STATE_RA_ROUTE, &ra_route_len);
519                 uint8_t *ra_dns = odhcp6c_get_state(STATE_RA_DNS, &ra_dns_len);
520                 uint8_t *ra_search = odhcp6c_get_state(STATE_RA_SEARCH, &ra_search_len);
521 
522                 /* RFC8910 ยง3 */
523                 if (capt_port_ra_len > 0 && capt_port_dhcpv6_len > 0) {
524                         if (capt_port_ra_len != capt_port_dhcpv6_len ||
525                                 memcmp(capt_port_dhcpv6, capt_port_ra, capt_port_dhcpv6_len))
526                                 error(
527                                         "%s received via different vectors differ: preferring URI from DHCPv6",
528                                         CAPT_PORT_URI_STR);
529                 }
530 
531                 ipv6_to_env("SERVER", addr, addr_len / sizeof(*addr));
532                 ipv6_to_env("RDNSS", dns, dns_len / sizeof(*dns));
533                 ipv6_to_env("SNTP_IP", sntp, sntp_ip_len / sizeof(*sntp));
534                 ipv6_to_env("NTP_IP", ntp, ntp_ip_len / sizeof(*ntp));
535                 fqdn_to_env("NTP_FQDN", ntp_dns, ntp_dns_len);
536                 ipv6_to_env("SIP_IP", sip, sip_ip_len / sizeof(*sip));
537                 fqdn_to_env("DOMAINS", search, search_len);
538                 fqdn_to_env("SIP_DOMAIN", sip_fqdn, sip_fqdn_len);
539                 fqdn_to_env("AFTR", aftr_name, aftr_name_len);
540                 s46_to_env(STATE_S46_MAPE, s46_mape, s46_mape_len);
541                 s46_to_env(STATE_S46_MAPT, s46_mapt, s46_mapt_len);
542                 s46_to_env(STATE_S46_LW, s46_lw, s46_lw_len);
543                 if (capt_port_dhcpv6_len > 0)
544                         string_to_env(CAPT_PORT_URI_STR, capt_port_dhcpv6, capt_port_dhcpv6_len);
545                 else if (capt_port_ra_len > 0)
546                         string_to_env(CAPT_PORT_URI_STR, capt_port_ra, capt_port_ra_len);
547                 bin_to_env(custom, custom_len);
548 
549                 if (odhcp6c_is_bound()) {
550                         entry_to_env("PREFIXES", prefix, prefix_len, ENTRY_PREFIX);
551                         entry_to_env("ADDRESSES", address, address_len, ENTRY_ADDRESS);
552                 }
553 
554                 entry_to_env("RA_ADDRESSES", ra_pref, ra_pref_len, ENTRY_ADDRESS);
555                 entry_to_env("RA_ROUTES", ra_route, ra_route_len, ENTRY_ROUTE);
556                 entry_to_env("RA_DNS", ra_dns, ra_dns_len, ENTRY_HOST);
557                 search_to_env("RA_DOMAINS", ra_search, ra_search_len);
558 
559                 int_to_env("RA_HOPLIMIT", ra_get_hoplimit());
560                 int_to_env("RA_MTU", ra_get_mtu());
561                 int_to_env("RA_REACHABLE", ra_get_reachable());
562                 int_to_env("RA_RETRANSMIT", ra_get_retransmit());
563 
564                 char *buf = malloc(10 + passthru_len * 2);
565                 if (buf) {
566                         strncpy(buf, "PASSTHRU=", 10);
567                         script_hexlify(&buf[9], passthru, passthru_len);
568                         putenv(buf);
569                 }
570 
571                 execv(argv[0], argv);
572                 _exit(128);
573         }
574 }
575 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt