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