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 <ctype.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <limits.h> 21 #include <linux/if_addr.h> 22 #include <net/if.h> 23 #include <netinet/icmp6.h> 24 #include <poll.h> 25 #include <resolv.h> 26 #include <signal.h> 27 #include <stdbool.h> 28 #include <stddef.h> 29 #include <stdlib.h> 30 #include <stdarg.h> 31 #include <stdio.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <sys/syscall.h> 35 #include <time.h> 36 #include <unistd.h> 37 38 #include "config.h" 39 #include "odhcp6c.h" 40 #include "ra.h" 41 #include "ubus.h" 42 43 #define DHCPV6_FD_INDEX 0 44 #define UBUS_FD_INDEX 1 45 46 #ifndef IN6_IS_ADDR_UNIQUELOCAL 47 #define IN6_IS_ADDR_UNIQUELOCAL(a) \ 48 ((((__const uint32_t *) (a))[0] & htonl (0xfe000000)) \ 49 == htonl (0xfc000000)) 50 #endif 51 52 static void sighandler(int signal); 53 static int usage(void); 54 static void odhcp6c_cleanup(void); 55 56 static uint8_t *state_data[_STATE_MAX] = {NULL}; 57 static size_t state_len[_STATE_MAX] = {0}; 58 59 static volatile bool signal_io = false; 60 static volatile bool signal_usr1 = false; 61 static volatile bool signal_usr2 = false; 62 static volatile bool signal_term = false; 63 64 static bool client_id_param = false; 65 static int urandom_fd = -1; 66 static bool bound = false, ra = false; 67 static time_t last_update = 0; 68 static char *ifname = NULL; 69 struct config_dhcp *config_dhcp = NULL; 70 71 static void odhcp6c_cleanup(void) 72 { 73 for (int i = 0; i < _STATE_MAX; ++i) { 74 free(state_data[i]); 75 state_data[i] = NULL; 76 state_len[i] = 0; 77 } 78 79 if (config_dhcp && config_dhcp->auth_token) { 80 free(config_dhcp->auth_token); 81 config_dhcp->auth_token = NULL; 82 } 83 84 if (urandom_fd >= 0) { 85 close(urandom_fd); 86 urandom_fd = -1; 87 } 88 } 89 90 void __iflog(int lvl, const char *fmt, ...) 91 { 92 va_list ap; 93 94 if (lvl > config_dhcp->log_level) 95 return; 96 97 va_start(ap, fmt); 98 99 if (config_dhcp->log_syslog) { 100 vsyslog(lvl, fmt, ap); 101 } else { 102 vfprintf(stderr, fmt, ap); 103 fprintf(stderr, "\n"); 104 } 105 106 va_end(ap); 107 } 108 109 static unsigned int script_sync_delay = 10; 110 static unsigned int script_accu_delay = 1; 111 112 static struct odhcp6c_opt opts[] = { 113 { .code = DHCPV6_OPT_CLIENTID, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 114 { .code = DHCPV6_OPT_SERVERID, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 115 { .code = DHCPV6_OPT_IA_NA, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str= NULL }, 116 { .code = DHCPV6_OPT_IA_TA, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 117 { .code = DHCPV6_OPT_IA_ADDR, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 118 { .code = DHCPV6_OPT_ORO, .flags = OPT_INTERNAL, .str = NULL }, 119 { .code = DHCPV6_OPT_PREF, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 120 { .code = DHCPV6_OPT_ELAPSED, .flags = OPT_INTERNAL, .str = NULL }, 121 { .code = DHCPV6_OPT_RELAY_MSG, .flags = OPT_INTERNAL, .str = NULL }, 122 { .code = DHCPV6_OPT_AUTH, .flags = OPT_U8 | OPT_NO_PASSTHRU, .str = "authentication" }, 123 { .code = DHCPV6_OPT_UNICAST, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 124 { .code = DHCPV6_OPT_STATUS, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 125 { .code = DHCPV6_OPT_RAPID_COMMIT, .flags = OPT_INTERNAL, .str = NULL }, 126 { .code = DHCPV6_OPT_USER_CLASS, .flags = OPT_USER_CLASS | OPT_ARRAY, .str = "userclass" }, 127 { .code = DHCPV6_OPT_VENDOR_CLASS, .flags = OPT_U8, .str = "vendorclass" }, 128 { .code = DHCPV6_OPT_INTERFACE_ID, .flags = OPT_INTERNAL, .str = NULL }, 129 { .code = DHCPV6_OPT_RECONF_MESSAGE, .flags = OPT_INTERNAL, .str = NULL }, 130 { .code = DHCPV6_OPT_RECONF_ACCEPT, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 131 { .code = DHCPV6_OPT_SIP_SERVER_D, .flags = OPT_DNS_STR | OPT_ORO, .str = "sipserver_d" }, 132 { .code = DHCPV6_OPT_SIP_SERVER_A, .flags = OPT_IP6 | OPT_ARRAY | OPT_ORO, .str = "sipserver_a" }, 133 { .code = DHCPV6_OPT_DNS_SERVERS, .flags = OPT_IP6 | OPT_ARRAY | OPT_ORO, .str = "dns" }, 134 { .code = DHCPV6_OPT_DNS_DOMAIN, .flags = OPT_DNS_STR | OPT_ORO, .str = "search" }, 135 { .code = DHCPV6_OPT_IA_PD, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 136 { .code = DHCPV6_OPT_IA_PREFIX, .flags = OPT_INTERNAL, .str = NULL }, 137 { .code = DHCPV6_OPT_SNTP_SERVERS, .flags = OPT_IP6 | OPT_ARRAY | OPT_ORO, .str = "sntpservers" }, 138 { .code = DHCPV6_OPT_INFO_REFRESH, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU | OPT_ORO | OPT_ORO_STATELESS, .str = NULL }, 139 { .code = DHCPV6_OPT_REMOTE_ID, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 140 { .code = DHCPV6_OPT_SUBSCRIBER_ID, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 141 { .code = DHCPV6_OPT_FQDN, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU | OPT_ORO, .str = NULL }, 142 { .code = DHCPV6_OPT_ERO, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 143 { .code = DHCPV6_OPT_LQ_QUERY, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 144 { .code = DHCPV6_OPT_CLIENT_DATA, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 145 { .code = DHCPV6_OPT_CLT_TIME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 146 { .code = DHCPV6_OPT_LQ_RELAY_DATA, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 147 { .code = DHCPV6_OPT_LQ_CLIENT_LINK, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 148 { .code = DHCPV6_OPT_RELAY_ID, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 149 { .code = DHCPV6_OPT_NTP_SERVER, .flags = OPT_U8 | OPT_ORO, .str = "ntpserver" }, 150 { .code = DHCPV6_OPT_CLIENT_ARCH_TYPE, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 151 { .code = DHCPV6_OPT_AFTR_NAME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU | OPT_ORO, .str = NULL }, 152 { .code = DHCPV6_OPT_RSOO, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 153 { .code = DHCPV6_OPT_PD_EXCLUDE, .flags = OPT_INTERNAL | OPT_ORO | OPT_ORO_STATEFUL, .str = NULL }, 154 { .code = DHCPV6_OPT_VSS, .flags = OPT_U8, .str = "vss" }, 155 { .code = DHCPV6_OPT_LINK_LAYER_ADDRESS, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 156 { .code = DHCPV6_OPT_LINK_ADDRESS, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 157 { .code = DHCPV6_OPT_RADIUS, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 158 { .code = DHCPV6_OPT_SOL_MAX_RT, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU | OPT_ORO | OPT_ORO_SOLICIT, .str = NULL }, 159 { .code = DHCPV6_OPT_INF_MAX_RT, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU | OPT_ORO | OPT_ORO_STATELESS, .str = NULL }, 160 { .code = DHCPV6_OPT_DHCPV4_MSG, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 161 { .code = DHCPV6_OPT_S46_RULE, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 162 { .code = DHCPV6_OPT_S46_BR, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 163 { .code = DHCPV6_OPT_S46_DMR, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 164 { .code = DHCPV6_OPT_S46_V4V6BIND, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 165 { .code = DHCPV6_OPT_S46_PORTPARAMS, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 166 { .code = DHCPV6_OPT_S46_CONT_MAPE, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU | OPT_ORO, .str = NULL }, 167 { .code = DHCPV6_OPT_S46_CONT_MAPT, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU | OPT_ORO, .str = NULL }, 168 { .code = DHCPV6_OPT_S46_CONT_LW, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU | OPT_ORO, .str = NULL }, 169 { .code = DHCPV6_OPT_LQ_BASE_TIME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 170 { .code = DHCPV6_OPT_LQ_START_TIME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 171 { .code = DHCPV6_OPT_LQ_END_TIME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 172 { .code = DHCPV6_OPT_ANI_ATT, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 173 { .code = DHCPV6_OPT_ANI_NETWORK_NAME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 174 { .code = DHCPV6_OPT_ANI_AP_NAME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 175 { .code = DHCPV6_OPT_ANI_AP_BSSID, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 176 { .code = DHCPV6_OPT_ANI_OPERATOR_ID, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 177 { .code = DHCPV6_OPT_ANI_OPERATOR_REALM, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 178 { .code = DHCPV6_OPT_MUD_URL_V6, .flags = OPT_STR | OPT_NO_PASSTHRU, .str = "mud_url_v6" }, 179 { .code = DHCPV6_OPT_F_BINDING_STATUS, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 180 { .code = DHCPV6_OPT_F_CONNECT_FLAGS, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 181 { .code = DHCPV6_OPT_F_DNS_REMOVAL_INFO, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 182 { .code = DHCPV6_OPT_F_DNS_HOST_NAME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 183 { .code = DHCPV6_OPT_F_DNS_ZONE_NAME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 184 { .code = DHCPV6_OPT_F_DNS_FLAGS, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 185 { .code = DHCPV6_OPT_F_EXPIRATION_TIME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 186 { .code = DHCPV6_OPT_F_MAX_UNACKED_BNDUPD, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 187 { .code = DHCPV6_OPT_F_MCLT, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 188 { .code = DHCPV6_OPT_F_PARTNER_LIFETIME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 189 { .code = DHCPV6_OPT_F_PARTNER_LIFETIME_SENT, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 190 { .code = DHCPV6_OPT_F_PARTNER_DOWN_TIME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 191 { .code = DHCPV6_OPT_F_PARTNER_RAW_CLT_TIME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 192 { .code = DHCPV6_OPT_F_PROTOCOL_VERSION, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 193 { .code = DHCPV6_OPT_F_KEEPALIVE_TIME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 194 { .code = DHCPV6_OPT_F_RECONFIGURE_DATA, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 195 { .code = DHCPV6_OPT_F_RELATIONSHIP_NAME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 196 { .code = DHCPV6_OPT_F_SERVER_FLAGS, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 197 { .code = DHCPV6_OPT_F_SERVER_STATE, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 198 { .code = DHCPV6_OPT_F_START_TIME_OF_STATE, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 199 { .code = DHCPV6_OPT_F_STATE_EXPIRATION_TIME, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 200 { .code = DHCPV6_OPT_RELAY_PORT, .flags = OPT_INTERNAL | OPT_NO_PASSTHRU, .str = NULL }, 201 { .code = 0, .flags = 0, .str = NULL }, 202 }; 203 204 int main(_o_unused int argc, char* const argv[]) 205 { 206 static struct in6_addr ifid = IN6ADDR_ANY_INIT; 207 // Allocate resources 208 const char *pidfile = NULL; 209 const char *script = "/lib/netifd/dhcpv6.script"; 210 ssize_t l; 211 uint8_t buf[134], *o_data; 212 char *optpos; 213 uint16_t opttype; 214 struct odhcp6c_opt *opt; 215 int ia_pd_iaid_index = 0; 216 bool help = false, daemonize = false; 217 int logopt = LOG_PID; 218 int c; 219 int res = -1; 220 unsigned int ra_options = RA_RDNSS_DEFAULT_LIFETIME; 221 unsigned int ra_holdoff_interval = RA_MIN_ADV_INTERVAL; 222 ra_ifid_mode_t ra_ifid_mode = RA_IFID_LLA; 223 bool terminate = false; 224 bool deprecated_opt = false; 225 226 config_dhcp = config_dhcp_get(); 227 config_dhcp_reset(); 228 229 atexit(odhcp6c_cleanup); 230 231 while ((c = getopt(argc, argv, "SDN:V:P:FB:c:i:r:Ru:Ux:s:EkK:t:C:m:Lhedp:favl:")) != -1) { 232 switch (c) { 233 case 'S': 234 config_set_allow_slaac_only(false); 235 break; 236 237 case 'D': 238 config_set_stateful_only(true); 239 break; 240 241 case 'N': 242 if (!config_set_request_addresses(optarg)) 243 help = true; 244 break; 245 246 case 'V': 247 opt = odhcp6c_find_opt(DHCPV6_OPT_VENDOR_CLASS); 248 if (!opt) { 249 error("Failed to set vendor-class option"); 250 return 1; 251 } 252 253 o_data = NULL; 254 res = config_parse_opt_data(optarg, &o_data, opt->flags & OPT_MASK_SIZE, 255 (opt->flags & OPT_ARRAY) == OPT_ARRAY); 256 if (res > 0) { 257 res = config_add_opt(opt->code, o_data, res); 258 if (res) { 259 if (res > 0) 260 return 1; 261 262 help = true; 263 } 264 } else { 265 help = true; 266 } 267 268 free(o_data); 269 break; 270 271 case 'P': 272 if (config_dhcp->ia_pd_mode == IA_MODE_NONE) 273 config_dhcp->ia_pd_mode = IA_MODE_TRY; 274 275 struct odhcp6c_request_prefix prefix = { 0 }; 276 277 optpos = strchr(optarg, '/'); 278 if (optpos) { 279 strncpy((char *)buf, optarg, optpos - optarg); 280 buf[optpos - optarg] = '\0'; 281 if (inet_pton(AF_INET6, (char *)buf, &prefix.addr) <= 0) { 282 error("invalid argument: '%s'", optarg); 283 return 1; 284 } 285 optpos++; 286 } else { 287 optpos = optarg; 288 } 289 290 char *iaid_begin; 291 int iaid_len = 0; 292 prefix.length = strtoul(optpos, &iaid_begin, 10); 293 294 if (*iaid_begin != '\0' && *iaid_begin != ',' && *iaid_begin != ':') { 295 error("invalid argument: '%s'", optarg); 296 return 1; 297 } 298 299 if (*iaid_begin == ',' && (iaid_len = strlen(iaid_begin)) > 1) 300 memcpy(&prefix.iaid, iaid_begin + 1, iaid_len > 4 ? 4 : iaid_len); 301 else if (*iaid_begin == ':') 302 prefix.iaid = htonl((uint32_t)strtoul(&iaid_begin[1], NULL, 16)); 303 else 304 prefix.iaid = htonl(++ia_pd_iaid_index); 305 306 if (odhcp6c_add_state(STATE_IA_PD_INIT, &prefix, sizeof(prefix))) { 307 error("Failed to set request IPv6-Prefix"); 308 return 1; 309 } 310 break; 311 312 case 'F': 313 config_set_force_prefix(true); 314 break; 315 316 case 'c': 317 l = script_unhexlify(&buf[4], sizeof(buf) - DHCPV6_OPT_HDR_SIZE, optarg); 318 if (l > 0) { 319 buf[0] = 0; 320 buf[1] = DHCPV6_OPT_CLIENTID; 321 buf[2] = 0; 322 buf[3] = l; 323 if (odhcp6c_add_state(STATE_CLIENT_ID, buf, l + 4)) { 324 error("Failed to override client-ID"); 325 return 1; 326 } else { 327 client_id_param = true; 328 } 329 } else { 330 help = true; 331 } 332 break; 333 334 case 'i': 335 if (!strcmp(optarg, DHCPV6_IFACEID_EUI64)) { 336 ra_ifid_mode = RA_IFID_EUI64; 337 } else if (!strcmp(optarg, DHCPV6_IFACEID_RANDOM)) { 338 ra_ifid_mode = RA_IFID_RANDOM; 339 } else if (inet_pton(AF_INET6, optarg, &ifid) == 1) { 340 ra_ifid_mode = RA_IFID_FIXED; 341 ifid.s6_addr[0] = 0xfe; 342 ifid.s6_addr[1] = 0x80; 343 } else { 344 /* Do not error on bad values; fall back to default */ 345 error("Invalid interface-ID: %s", optarg); 346 } 347 break; 348 349 case 'r': 350 optpos = optarg; 351 while (optpos[0]) { 352 opttype = htons(strtoul(optarg, &optpos, 10)); 353 if (optpos == optarg) 354 break; 355 else if (optpos[0]) 356 optarg = &optpos[1]; 357 358 if (odhcp6c_add_state(STATE_ORO, &opttype, 2)) { 359 error("Failed to add requested option"); 360 return 1; 361 } 362 } 363 break; 364 365 case 'R': 366 config_set_client_options(DHCPV6_STRICT_OPTIONS, true); 367 break; 368 369 case 'u': 370 opt = odhcp6c_find_opt(DHCPV6_OPT_USER_CLASS); 371 if (!opt) { 372 error("Failed to set user-class option"); 373 return 1; 374 } 375 376 o_data = NULL; 377 res = config_parse_opt_data(optarg, &o_data, opt->flags & OPT_MASK_SIZE, 378 (opt->flags & OPT_ARRAY) == OPT_ARRAY); 379 if (res > 0) { 380 res = config_add_opt(opt->code, o_data, res); 381 if (res) { 382 if (res > 0) 383 return 1; 384 385 help = true; 386 } 387 } else { 388 help = true; 389 } 390 391 free(o_data); 392 break; 393 394 case 'U': 395 config_set_client_options(DHCPV6_IGNORE_OPT_UNICAST, true); 396 break; 397 398 case 's': 399 if (script) 400 script = optarg; 401 break; 402 403 case 'E': 404 #ifndef WITH_UBUS 405 error("Failed to use ubus event: ENABLE_UBUS compilation flag missing"); 406 return 1; 407 #endif /* WITH_UBUS */ 408 script = NULL; 409 break; 410 411 case 'k': 412 config_set_release(false); 413 break; 414 415 case 'K': 416 config_set_sk_priority(atoi(optarg)); 417 break; 418 419 case 't': 420 config_set_rtx_timeout_max(CONFIG_DHCP_SOLICIT, atoi(optarg)); 421 break; 422 423 case 'C': 424 config_set_dscp(atoi(optarg)); 425 break; 426 427 case 'm': 428 ra_holdoff_interval = atoi(optarg); 429 break; 430 431 case 'L': 432 ra_options &= ~RA_RDNSS_DEFAULT_LIFETIME; 433 break; 434 435 case 'e': 436 logopt |= LOG_PERROR; 437 break; 438 439 case 'd': 440 daemonize = true; 441 break; 442 443 case 'p': 444 pidfile = optarg; 445 break; 446 447 case 'f': 448 config_set_client_options(DHCPV6_CLIENT_FQDN, false); 449 break; 450 451 case 'a': 452 config_set_client_options(DHCPV6_ACCEPT_RECONFIGURE, false); 453 break; 454 455 case 'v': 456 /* deprecated - remove -v options from start scripts first */ 457 deprecated_opt = true; 458 break; 459 460 case 'l': 461 config_dhcp->log_level = (atoi(optarg) & LOG_PRIMASK); 462 break; 463 464 case 'x': 465 res = config_parse_opt(optarg); 466 if (res) { 467 if (res > 0) 468 return res; 469 470 help = true; 471 } 472 break; 473 474 default: 475 help = true; 476 break; 477 } 478 } 479 480 openlog("odhcp6c", logopt, LOG_DAEMON); 481 setlogmask(LOG_UPTO(config_dhcp->log_level)); 482 483 ifname = argv[optind]; 484 485 if (help || !ifname) 486 return usage(); 487 488 signal(SIGIO, sighandler); 489 signal(SIGHUP, sighandler); 490 signal(SIGINT, sighandler); 491 signal(SIGTERM, sighandler); 492 signal(SIGUSR1, sighandler); 493 signal(SIGUSR2, sighandler); 494 495 if (daemonize) { 496 openlog("odhcp6c", LOG_PID, LOG_DAEMON); // Disable LOG_PERROR 497 if (daemon(0, 0)) { 498 error("Failed to daemonize: %s", 499 strerror(errno)); 500 return 3; 501 } 502 503 if (!pidfile) { 504 snprintf((char*)buf, sizeof(buf), "/var/run/odhcp6c.%s.pid", ifname); 505 pidfile = (char*)buf; 506 } 507 508 FILE *fp = fopen(pidfile, "w"); 509 if (fp) { 510 fprintf(fp, "%i\n", getpid()); 511 fclose(fp); 512 } 513 } else { 514 config_dhcp->log_syslog = false; 515 } 516 517 if (deprecated_opt) 518 warn("The -v flag is deprecated and will be removed. Use -l[0-7]."); 519 520 if ((urandom_fd = open("/dev/urandom", O_CLOEXEC | O_RDONLY)) < 0 || 521 ra_init(ifname, &ifid, ra_ifid_mode, ra_options, ra_holdoff_interval) || 522 script_init(script, ifname)) { 523 error("failed to initialize: %s", strerror(errno)); 524 return 4; 525 } 526 527 struct pollfd fds[2] = {0}; 528 int nfds = 0; 529 530 int mode = DHCPV6_UNKNOWN; 531 enum dhcpv6_msg req_msg_type = DHCPV6_MSG_UNKNOWN; 532 533 fds[DHCPV6_FD_INDEX].fd = -1; 534 fds[DHCPV6_FD_INDEX].events = POLLIN; 535 nfds++; 536 537 #ifdef WITH_UBUS 538 char *err = ubus_init(ifname); 539 if (err) { 540 error("ubus error: %s", err); 541 return 1; 542 } 543 544 struct ubus_context *ubus = ubus_get_ctx(); 545 int ubus_socket = ubus->sock.fd; 546 if (ubus_socket < 0) { 547 error("Invalid ubus file descriptor"); 548 return 1; 549 } 550 fds[UBUS_FD_INDEX].fd = ubus_socket; 551 fds[UBUS_FD_INDEX].events = POLLIN; 552 nfds++; 553 #endif /* WITH_UBUS */ 554 555 notify_state_change("started", 0, false); 556 557 while (!terminate) { // Main logic 558 int poll_res; 559 bool signalled = odhcp6c_signal_process(); 560 561 switch (dhcpv6_get_state()) { 562 case DHCPV6_INIT: 563 odhcp6c_clear_state(STATE_SERVER_ID); 564 odhcp6c_clear_state(STATE_SERVER_ADDR); 565 odhcp6c_clear_state(STATE_IA_NA); 566 odhcp6c_clear_state(STATE_IA_PD); 567 odhcp6c_clear_state(STATE_SNTP_IP); 568 odhcp6c_clear_state(STATE_NTP_IP); 569 odhcp6c_clear_state(STATE_NTP_FQDN); 570 odhcp6c_clear_state(STATE_SIP_IP); 571 odhcp6c_clear_state(STATE_SIP_FQDN); 572 odhcp6c_clear_state(STATE_CAPT_PORT_DHCPV6); 573 bound = false; 574 res = -1; 575 576 size_t oro_len = 0; 577 odhcp6c_get_state(STATE_ORO, &oro_len); 578 config_dhcp->oro_user_cnt = oro_len / sizeof(uint16_t); 579 580 if (init_dhcpv6(ifname)) { 581 error("failed to initialize: %s", strerror(errno)); 582 return 1; 583 } 584 585 fds[DHCPV6_FD_INDEX].fd = dhcpv6_get_socket(); 586 587 notice("(re)starting transaction on %s", ifname); 588 589 signal_usr1 = signal_usr2 = false; 590 591 dhcpv6_set_state(DHCPV6_SOLICIT); 592 break; 593 594 case DHCPV6_SOLICIT: 595 mode = dhcpv6_get_ia_mode(); 596 if (mode == DHCPV6_STATELESS) { 597 dhcpv6_set_state(DHCPV6_REQUEST); 598 break; 599 } 600 601 req_msg_type = DHCPV6_MSG_SOLICIT; 602 dhcpv6_send_request(req_msg_type); 603 break; 604 605 case DHCPV6_ADVERT: 606 if (res > 0) { 607 mode = DHCPV6_STATEFUL; 608 dhcpv6_set_state(DHCPV6_REQUEST); 609 } else { 610 mode = DHCPV6_UNKNOWN; 611 dhcpv6_set_state(DHCPV6_RESET); 612 } 613 break; 614 615 case DHCPV6_REQUEST: 616 req_msg_type = (mode == DHCPV6_STATELESS) ? DHCPV6_MSG_INFO_REQ : DHCPV6_MSG_REQUEST; 617 dhcpv6_send_request(req_msg_type); 618 break; 619 620 case DHCPV6_REPLY: 621 if ((res > 0) && mode != DHCPV6_UNKNOWN) { 622 dhcpv6_set_state(DHCPV6_BOUND); 623 break; 624 } 625 626 if ((res < 0) && signalled) { 627 mode = DHCPV6_UNKNOWN; 628 dhcpv6_set_state(DHCPV6_RESET); 629 break; 630 } 631 632 mode = dhcpv6_promote_server_cand(); 633 dhcpv6_set_state(mode > DHCPV6_UNKNOWN ? DHCPV6_REQUEST : DHCPV6_RESET); 634 break; 635 636 case DHCPV6_BOUND: 637 if (!bound) { 638 bound = true; 639 if (mode == DHCPV6_STATELESS) { 640 notice("entering stateless-mode on %s", ifname); 641 signal_usr1 = false; 642 notify_state_change("informed", script_sync_delay, true); 643 } else { 644 notify_state_change("bound", script_sync_delay, true); 645 notice("entering stateful-mode on %s", ifname); 646 } 647 } 648 649 req_msg_type = DHCPV6_MSG_UNKNOWN; 650 dhcpv6_send_request(req_msg_type); 651 break; 652 653 case DHCPV6_BOUND_REPLY: 654 if (res == DHCPV6_MSG_RENEW || res == DHCPV6_MSG_REBIND || 655 res == DHCPV6_MSG_INFO_REQ) { 656 req_msg_type = res; 657 dhcpv6_set_state(DHCPV6_RECONF); 658 } else { 659 dhcpv6_set_state(DHCPV6_RECONF_REPLY); 660 } 661 break; 662 663 case DHCPV6_RECONF: 664 dhcpv6_send_request(req_msg_type); 665 break; 666 667 case DHCPV6_RECONF_REPLY: 668 if (res > 0) { 669 dhcpv6_set_state(DHCPV6_BOUND); 670 if (mode == DHCPV6_STATEFUL) 671 notify_state_change("updated", 0, false); 672 } else { 673 dhcpv6_set_state(mode == DHCPV6_STATELESS ? DHCPV6_INFO : DHCPV6_RENEW); 674 } 675 break; 676 677 case DHCPV6_RENEW: 678 req_msg_type = DHCPV6_MSG_RENEW; 679 dhcpv6_send_request(req_msg_type); 680 break; 681 682 case DHCPV6_RENEW_REPLY: 683 if (res > 0 ) { 684 notify_state_change("updated", 0, false); 685 dhcpv6_set_state(DHCPV6_BOUND); 686 } else { 687 dhcpv6_set_state(DHCPV6_REBIND); 688 } 689 break; 690 691 case DHCPV6_REBIND: 692 odhcp6c_clear_state(STATE_SERVER_ID); // Remove binding 693 odhcp6c_clear_state(STATE_SERVER_ADDR); 694 695 size_t ia_pd_len_r, ia_na_len_r; 696 odhcp6c_get_state(STATE_IA_PD, &ia_pd_len_r); 697 odhcp6c_get_state(STATE_IA_NA, &ia_na_len_r); 698 699 // If we have IAs, try rebind otherwise restart 700 if (ia_pd_len_r == 0 && ia_na_len_r == 0) { 701 dhcpv6_set_state(DHCPV6_RESET); 702 break; 703 } 704 705 req_msg_type = DHCPV6_MSG_REBIND; 706 dhcpv6_send_request(req_msg_type); 707 break; 708 709 case DHCPV6_REBIND_REPLY: 710 if (res < 0) { 711 dhcpv6_set_state(DHCPV6_RESET); 712 } else { 713 notify_state_change("rebound", 0, true); 714 dhcpv6_set_state(DHCPV6_BOUND); 715 } 716 break; 717 718 case DHCPV6_INFO: 719 req_msg_type = DHCPV6_MSG_INFO_REQ; 720 dhcpv6_send_request(req_msg_type); 721 break; 722 723 case DHCPV6_INFO_REPLY: 724 dhcpv6_set_state(res < 0 ? DHCPV6_RESET : DHCPV6_BOUND); 725 break; 726 727 case DHCPV6_SOLICIT_PROCESSING: 728 case DHCPV6_REQUEST_PROCESSING: 729 res = dhcpv6_state_processing(req_msg_type); 730 break; 731 732 case DHCPV6_BOUND_PROCESSING: 733 case DHCPV6_RECONF_PROCESSING: 734 case DHCPV6_REBIND_PROCESSING: 735 res = dhcpv6_state_processing(req_msg_type); 736 737 if (signal_usr1) 738 dhcpv6_set_state(mode == DHCPV6_STATELESS ? DHCPV6_INFO : DHCPV6_RENEW); 739 break; 740 741 case DHCPV6_RENEW_PROCESSING: 742 case DHCPV6_INFO_PROCESSING: 743 res = dhcpv6_state_processing(req_msg_type); 744 745 if (signal_usr1) 746 signal_usr1 = false; // Acknowledged 747 break; 748 749 case DHCPV6_EXIT: 750 odhcp6c_expire(false); 751 752 size_t ia_pd_len, ia_na_len, server_id_len; 753 odhcp6c_get_state(STATE_IA_PD, &ia_pd_len); 754 odhcp6c_get_state(STATE_IA_NA, &ia_na_len); 755 odhcp6c_get_state(STATE_SERVER_ID, &server_id_len); 756 757 // Add all prefixes to lost prefixes 758 if (bound) { 759 bound = false; 760 notify_state_change("unbound", 0, true); 761 } 762 763 if (server_id_len > 0 && (ia_pd_len > 0 || ia_na_len > 0) && (!signal_term || config_dhcp->release)) 764 dhcpv6_send_request(DHCPV6_MSG_RELEASE); 765 766 odhcp6c_clear_state(STATE_IA_NA); 767 odhcp6c_clear_state(STATE_IA_PD); 768 769 if (signal_term) { 770 terminate = true; 771 } else { 772 signal_usr2 = false; 773 dhcpv6_set_state(DHCPV6_RESET); 774 } 775 break; 776 777 case DHCPV6_RESET: 778 if (!client_id_param) 779 odhcp6c_clear_state(STATE_CLIENT_ID); 780 781 if (bound) { 782 bound = false; 783 notify_state_change("unbound", 0, true); 784 } 785 786 size_t oro_user_len, oro_total_len; 787 odhcp6c_get_state(STATE_ORO, &oro_total_len); 788 oro_user_len = config_dhcp->oro_user_cnt * sizeof(uint16_t); 789 odhcp6c_remove_state(STATE_ORO, oro_user_len, oro_total_len - oro_user_len); 790 791 close(dhcpv6_get_socket()); 792 fds[DHCPV6_FD_INDEX].fd = -1; 793 794 dhcpv6_set_state(DHCPV6_INIT); 795 break; 796 797 default: 798 break; 799 } 800 801 if (signal_usr2 || signal_term) 802 dhcpv6_set_state(DHCPV6_EXIT); 803 804 poll_res = poll(fds, nfds, dhcpv6_get_state_timeout()); 805 dhcpv6_reset_state_timeout(); 806 if (poll_res == -1 && (errno == EINTR || errno == EAGAIN)) { 807 continue; 808 } 809 810 if (fds[0].revents & POLLIN) 811 dhcpv6_receive_response(req_msg_type); 812 813 #ifdef WITH_UBUS 814 if (fds[1].revents & POLLIN) 815 ubus_handle_event(ubus); 816 #endif /* WITH_UBUS */ 817 } 818 819 notify_state_change("stopped", 0, true); 820 821 #ifdef WITH_UBUS 822 ubus_destroy(ubus); 823 #endif /* WITH_UBUS */ 824 825 return 0; 826 } 827 828 static int usage(void) 829 { 830 const char buf[] = 831 "Usage: odhcp6c [options] <interface>\n" 832 "\nFeature options:\n" 833 " -S Don't allow configuration via SLAAC (RAs) only\n" 834 " -D Discard advertisements without any address or prefix proposed\n" 835 " -N <mode> Mode for requesting addresses [try|force|none]\n" 836 " -P <[pfx/]len> Request IPv6-Prefix (0 = auto)\n" 837 " -F Force IPv6-Prefix\n" 838 " -V <class> Set vendor-class option (base-16 encoded)\n" 839 " -u <user-class> Set user-class option string\n" 840 " -x <opt>:<val> Add option opt (with value val) in sent packets (cumulative)\n" 841 " Examples of IPv6 address, string and base-16 encoded options:\n" 842 " -x dns:2001:2001::1,2001:2001::2 - option 23\n" 843 " -x 15:office - option 15 (userclass)\n" 844 " -x 0x1f4:ABBA - option 500\n" 845 " -x 202:'\"file\"' - option 202\n" 846 " -c <clientid> Override client-ID (base-16 encoded 16-bit type + value)\n" 847 " -i <iface-id> Use a custom interface identifier for RA handling\n" 848 " -r <options> Options to be requested (comma-separated)\n" 849 " -R Do not request any options except those specified with -r\n" 850 " -s <script> Status update script (/lib/netifd/dhcpv6.script)\n" 851 " -E Only use UBUS event and disable status update script\n" 852 " -a Don't send Accept Reconfigure option\n" 853 " -f Don't send Client FQDN option\n" 854 " -k Don't send a RELEASE when stopping\n" 855 " -K <sk-prio> Set packet kernel priority (0)\n" 856 " -C <dscp> Set packet DSCP value (0)\n" 857 " -t <seconds> Maximum timeout for DHCPv6-SOLICIT (120)\n" 858 " -m <seconds> Minimum time between accepting RA updates (3)\n" 859 " -L Ignore default lifetime for RDNSS records\n" 860 " -U Ignore Server Unicast option\n" 861 "\nInvocation options:\n" 862 " -p <pidfile> Set pidfile (/var/run/odhcp6c.pid)\n" 863 " -d Daemonize\n" 864 " -e Write logmessages to stderr\n" 865 " -l <level> Set logging level (0-7)\n" 866 " -h Show this help\n\n"; 867 fputs(buf, stderr); 868 869 return 1; 870 } 871 872 // Don't want to pull-in librt and libpthread just for a monotonic clock... 873 uint64_t odhcp6c_get_milli_time(void) 874 { 875 struct timespec t; 876 877 clock_gettime(CLOCK_MONOTONIC, &t); 878 879 return ((uint64_t)t.tv_sec) * 1000 + ((uint64_t)t.tv_nsec) / 1000000; 880 } 881 882 static uint8_t* odhcp6c_resize_state(enum odhcp6c_state state, ssize_t len) 883 { 884 if (len == 0) 885 return state_data[state] + state_len[state]; 886 else if (state_len[state] + len > 1024) 887 return NULL; 888 889 uint8_t *n = realloc(state_data[state], state_len[state] + len); 890 891 if (n || state_len[state] + len == 0) { 892 state_data[state] = n; 893 n += state_len[state]; 894 state_len[state] += len; 895 } 896 897 return n; 898 } 899 900 static bool odhcp6c_server_advertised() 901 { 902 size_t len; 903 uint8_t *start = odhcp6c_get_state(STATE_RA_ROUTE, &len); 904 905 for (struct odhcp6c_entry *c = (struct odhcp6c_entry*)start; 906 (uint8_t*)c < &start[len] && 907 (uint8_t*)odhcp6c_next_entry(c) <= &start[len]; 908 c = odhcp6c_next_entry(c)) { 909 // Only default route entries have flags 910 if (c->length != 0 || IN6_IS_ADDR_UNSPECIFIED(&c->router)) 911 continue; 912 913 if (c->ra_flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) 914 return true; 915 } 916 917 return false; 918 } 919 920 bool odhcp6c_signal_process(void) 921 { 922 while (signal_io) { 923 signal_io = false; 924 925 size_t old_ra_prefix_size = state_len[STATE_RA_PREFIX]; 926 bool ra_updated = ra_process(); 927 928 if (ra_link_up()) { 929 signal_usr2 = true; 930 ra = false; 931 } else if (old_ra_prefix_size != state_len[STATE_RA_PREFIX] && 932 odhcp6c_server_advertised()) { 933 // Restart DHCPv6 transaction when router advertisement flags 934 // show presence of a DHCPv6 server and new prefixes were 935 // added to STATE_RA_PREFIX state 936 signal_usr2 = true; 937 } 938 939 if (ra_updated && (bound || config_dhcp->allow_slaac_only)) { 940 notify_state_change("ra-updated", (!ra && !bound) ? 941 script_sync_delay : script_accu_delay, false); 942 ra = true; 943 } 944 } 945 946 return signal_usr1 || signal_usr2 || signal_term; 947 } 948 949 void odhcp6c_clear_state(enum odhcp6c_state state) 950 { 951 state_len[state] = 0; 952 } 953 954 int odhcp6c_add_state(enum odhcp6c_state state, const void *data, size_t len) 955 { 956 uint8_t *n = odhcp6c_resize_state(state, len); 957 958 if (!n) 959 return -1; 960 961 memcpy(n, data, len); 962 963 return 0; 964 } 965 966 int odhcp6c_insert_state(enum odhcp6c_state state, size_t offset, const void *data, size_t len) 967 { 968 ssize_t len_after = state_len[state] - offset; 969 if (len_after < 0) 970 return -1; 971 972 uint8_t *n = odhcp6c_resize_state(state, len); 973 974 if (n) { 975 uint8_t *sdata = state_data[state]; 976 977 memmove(sdata + offset + len, sdata + offset, len_after); 978 memcpy(sdata + offset, data, len); 979 } 980 981 return 0; 982 } 983 984 size_t odhcp6c_remove_state(enum odhcp6c_state state, size_t offset, size_t len) 985 { 986 uint8_t *data = state_data[state]; 987 ssize_t len_after = state_len[state] - (offset + len); 988 989 if (len_after < 0) 990 return state_len[state]; 991 992 memmove(data + offset, data + offset + len, len_after); 993 994 return state_len[state] -= len; 995 } 996 997 void* odhcp6c_move_state(enum odhcp6c_state state, size_t *len) 998 { 999 *len = state_len[state]; 1000 void *data = state_data[state]; 1001 1002 state_len[state] = 0; 1003 state_data[state] = NULL; 1004 1005 return data; 1006 } 1007 1008 void* odhcp6c_get_state(enum odhcp6c_state state, size_t *len) 1009 { 1010 *len = state_len[state]; 1011 1012 return state_data[state]; 1013 } 1014 1015 static struct odhcp6c_entry* odhcp6c_find_entry(enum odhcp6c_state state, const struct odhcp6c_entry *new) 1016 { 1017 size_t len, cmplen = offsetof(struct odhcp6c_entry, target) + ((new->length + 7) / 8); 1018 uint8_t *start = odhcp6c_get_state(state, &len); 1019 1020 for (struct odhcp6c_entry *c = (struct odhcp6c_entry*)start; 1021 (uint8_t*)c < &start[len] && 1022 (uint8_t*)odhcp6c_next_entry(c) <= &start[len]; 1023 c = odhcp6c_next_entry(c)) { 1024 if (!memcmp(c, new, cmplen) && !memcmp(c->auxtarget, new->auxtarget, new->auxlen)) 1025 return c; 1026 } 1027 1028 return NULL; 1029 } 1030 1031 bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new, 1032 unsigned int holdoff_interval) 1033 { 1034 struct odhcp6c_entry *x = odhcp6c_find_entry(state, new); 1035 1036 if (x) { 1037 if (holdoff_interval && new->valid >= x->valid && 1038 new->valid != UINT32_MAX && 1039 new->valid - x->valid < holdoff_interval && 1040 new->preferred >= x->preferred && 1041 new->preferred != UINT32_MAX && 1042 new->preferred - x->preferred < holdoff_interval) 1043 return false; 1044 1045 x->valid = new->valid; 1046 x->ra_flags = new->ra_flags; 1047 x->priority = new->priority; 1048 x->preferred = new->preferred; 1049 x->t1 = new->t1; 1050 x->t2 = new->t2; 1051 x->iaid = new->iaid; 1052 } else if (odhcp6c_add_state(state, new, odhcp6c_entry_size(new))) { 1053 return false; 1054 } 1055 1056 return true; 1057 } 1058 1059 static void odhcp6c_expire_list(enum odhcp6c_state state, uint32_t elapsed, bool remove_expired) 1060 { 1061 size_t len; 1062 uint8_t *start = odhcp6c_get_state(state, &len); 1063 1064 for (struct odhcp6c_entry *c = (struct odhcp6c_entry*)start; 1065 (uint8_t*)c < &start[len] && 1066 (uint8_t*)odhcp6c_next_entry(c) <= &start[len]; 1067 ) { 1068 if (c->t1 < elapsed) 1069 c->t1 = 0; 1070 else if (c->t1 != UINT32_MAX) 1071 c->t1 -= elapsed; 1072 1073 if (c->t2 < elapsed) 1074 c->t2 = 0; 1075 else if (c->t2 != UINT32_MAX) 1076 c->t2 -= elapsed; 1077 1078 if (c->preferred < elapsed) 1079 c->preferred = 0; 1080 else if (c->preferred != UINT32_MAX) 1081 c->preferred -= elapsed; 1082 1083 if (c->valid < elapsed) 1084 c->valid = 0; 1085 else if (c->valid != UINT32_MAX) 1086 c->valid -= elapsed; 1087 1088 if (!c->valid && remove_expired) { 1089 odhcp6c_remove_state(state, ((uint8_t*)c) - start, odhcp6c_entry_size(c)); 1090 start = odhcp6c_get_state(state, &len); 1091 } else { 1092 c = odhcp6c_next_entry(c); 1093 } 1094 } 1095 } 1096 1097 void odhcp6c_expire(bool expire_ia_pd) 1098 { 1099 time_t now = odhcp6c_get_milli_time() / 1000; 1100 uint32_t elapsed = (last_update > 0) ? now - last_update : 0; 1101 1102 last_update = now; 1103 1104 odhcp6c_expire_list(STATE_RA_PREFIX, elapsed, true); 1105 odhcp6c_expire_list(STATE_RA_ROUTE, elapsed, true); 1106 odhcp6c_expire_list(STATE_RA_DNS, elapsed, true); 1107 odhcp6c_expire_list(STATE_RA_SEARCH, elapsed, true); 1108 odhcp6c_expire_list(STATE_IA_NA, elapsed, true); 1109 odhcp6c_expire_list(STATE_IA_PD, elapsed, expire_ia_pd); 1110 } 1111 1112 uint32_t odhcp6c_elapsed(void) 1113 { 1114 return odhcp6c_get_milli_time() / 1000 - last_update; 1115 } 1116 1117 int odhcp6c_random(void *buf, size_t len) 1118 { 1119 return read(urandom_fd, buf, len); 1120 } 1121 1122 bool odhcp6c_is_bound(void) 1123 { 1124 return bound; 1125 } 1126 1127 bool odhcp6c_addr_in_scope(const struct in6_addr *addr) 1128 { 1129 FILE *fd = fopen("/proc/net/if_inet6", "r"); 1130 int len; 1131 bool ret = false; 1132 char buf[256]; 1133 1134 if (fd == NULL) 1135 return false; 1136 1137 while (fgets(buf, sizeof(buf), fd)) { 1138 struct in6_addr inet6_addr; 1139 uint32_t flags, dummy; 1140 unsigned int i; 1141 char name[IF_NAMESIZE], addr_buf[33]; 1142 1143 len = strlen(buf); 1144 1145 if ((len <= 0) || buf[len - 1] != '\n') 1146 break; 1147 1148 buf[--len] = '\0'; 1149 1150 if (sscanf(buf, "%s %x %x %x %x %s", 1151 addr_buf, &dummy, &dummy, &dummy, &flags, name) != 6) 1152 break; 1153 1154 if (strcmp(name, ifname) || 1155 (flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE | IFA_F_DEPRECATED))) 1156 continue; 1157 1158 for (i = 0; i < strlen(addr_buf); i++) { 1159 if (!isxdigit(addr_buf[i]) || isupper(addr_buf[i])) 1160 break; 1161 } 1162 1163 memset(&inet6_addr, 0, sizeof(inet6_addr)); 1164 for (i = 0; i < (strlen(addr_buf) / 2); i++) { 1165 unsigned char byte; 1166 static const char hex[] = "0123456789abcdef"; 1167 byte = ((index(hex, addr_buf[i * 2]) - hex) << 4) | 1168 (index(hex, addr_buf[i * 2 + 1]) - hex); 1169 inet6_addr.s6_addr[i] = byte; 1170 } 1171 1172 if ((IN6_IS_ADDR_LINKLOCAL(&inet6_addr) == IN6_IS_ADDR_LINKLOCAL(addr)) && 1173 (IN6_IS_ADDR_UNIQUELOCAL(&inet6_addr) == IN6_IS_ADDR_UNIQUELOCAL(addr))) { 1174 ret = true; 1175 break; 1176 } 1177 } 1178 1179 fclose(fd); 1180 return ret; 1181 } 1182 1183 static void sighandler(int signal) 1184 { 1185 if (signal == SIGUSR1) 1186 signal_usr1 = true; 1187 else if (signal == SIGUSR2) 1188 signal_usr2 = true; 1189 else if (signal == SIGIO) 1190 signal_io = true; 1191 else 1192 signal_term = true; 1193 } 1194 1195 void notify_state_change(const char *status, int delay, bool resume) 1196 { 1197 script_call(status, delay, resume); 1198 1199 #ifdef WITH_UBUS 1200 ubus_dhcp_event(status); 1201 #endif /* WITH_UBUS */ 1202 } 1203 1204 struct odhcp6c_opt *odhcp6c_find_opt(const uint16_t code) 1205 { 1206 struct odhcp6c_opt *opt = opts; 1207 1208 while (opt->code) { 1209 if (opt->code == code) 1210 return opt; 1211 1212 opt++; 1213 } 1214 1215 return NULL; 1216 } 1217 1218 struct odhcp6c_opt *odhcp6c_find_opt_by_name(const char *name) 1219 { 1220 struct odhcp6c_opt *opt = opts; 1221 1222 if (!name || !strlen(name)) 1223 return NULL; 1224 1225 while (opt->code && (!opt->str || strcmp(opt->str, name))) 1226 opt++; 1227 1228 return (opt->code > 0 ? opt : NULL); 1229 } 1230
This page was automatically generated by LXR 0.3.1. • OpenWrt