📄 dhcp6c.c
字号:
/* get current server */ switch (ev->state) { case DHCP6S_SOLICIT: case DHCP6S_CONFIRM: case DHCP6S_REBIND: newserver = allocate_newserver(ifp, optinfo); if (newserver == NULL) return (-1); ifp->current_server = newserver; duidcpy(&client6_iaidaddr.client6_info.serverid, &ifp->current_server->optinfo.serverID); break; default: break; } /* * DUID in the Client ID option (which must be contained for our * client implementation) must match ours. */ if (optinfo->clientID.duid_len == 0) { dprintf(LOG_INFO, "%s" "no client ID option", FNAME); return -1; } if (duidcmp(&optinfo->clientID, &client_duid)) { dprintf(LOG_INFO, "%s" "client DUID mismatch", FNAME); return -1; } if (!TAILQ_EMPTY(&optinfo->dns_list.addrlist) || optinfo->dns_list.domainlist != NULL) { resolv_parse(&optinfo->dns_list); } /* * The client MAY choose to report any status code or message from the * status code option in the Reply message. * [dhcpv6-26 Section 18.1.8] */ addr_status_code = 0; for (lv = TAILQ_FIRST(&optinfo->stcode_list); lv; lv = TAILQ_NEXT(lv, link)) { dprintf(LOG_INFO, "%s" "status code: %s", FNAME, dhcp6_stcodestr(lv->val_num)); switch (lv->val_num) { case DH6OPT_STCODE_SUCCESS: case DH6OPT_STCODE_UNSPECFAIL: case DH6OPT_STCODE_NOADDRAVAIL: case DH6OPT_STCODE_NOPREFIXAVAIL: case DH6OPT_STCODE_NOBINDING: case DH6OPT_STCODE_NOTONLINK: case DH6OPT_STCODE_USEMULTICAST: addr_status_code = lv->val_num; default: break; } } switch (addr_status_code) { case DH6OPT_STCODE_UNSPECFAIL: case DH6OPT_STCODE_USEMULTICAST: dprintf(LOG_INFO, "%s" "status code: %s", FNAME, dhcp6_stcodestr(addr_status_code)); /* retransmit the message with multicast address */ /* how many time allow the retransmission with error status code? */ return -1; } /* * Update configuration information to be renewed or rebound * declined, confirmed, released. * Note that the returned list may be empty, in which case * the waiting information should be removed. */ switch (ev->state) { case DHCP6S_SOLICIT: if (optinfo->iaidinfo.iaid == 0) break; else if (!optinfo->flags & DHCIFF_RAPID_COMMIT) { newstate = DHCP6S_REQUEST; break; } case DHCP6S_REQUEST: /* NotOnLink: 1. SOLICIT * NoAddrAvail: Information Request */ switch(addr_status_code) { case DH6OPT_STCODE_NOTONLINK: dprintf(LOG_DEBUG, "%s" "got a NotOnLink reply for request/rapid commit," " sending solicit.", FNAME); newstate = DHCP6S_SOLICIT; break; case DH6OPT_STCODE_NOADDRAVAIL: case DH6OPT_STCODE_NOPREFIXAVAIL: dprintf(LOG_DEBUG, "%s" "got a NoAddrAvail reply for request/rapid commit," " sending inforeq.", FNAME); optinfo->iaidinfo.iaid = 0; newstate = DHCP6S_INFOREQ; break; case DH6OPT_STCODE_SUCCESS: case DH6OPT_STCODE_UNDEFINE: default: if (!TAILQ_EMPTY(&optinfo->addr_list)) { (void)get_if_rainfo(ifp); dhcp6_add_iaidaddr(optinfo); if (optinfo->type == IAPD) radvd_parse(&client6_iaidaddr, ADDR_UPDATE); else if (ifp->dad_timer == NULL && (ifp->dad_timer = dhcp6_add_timer(check_dad_timo, ifp)) < 0) { dprintf(LOG_INFO, "%s" "failed to create a timer for " " DAD", FNAME); } setup_check_timer(ifp); } break; } break; case DHCP6S_RENEW: case DHCP6S_REBIND: if (client6_request_flag & CLIENT6_CONFIRM_ADDR) goto rebind_confirm; /* NoBinding for RENEW, REBIND, send REQUEST */ switch(addr_status_code) { case DH6OPT_STCODE_NOBINDING: newstate = DHCP6S_REQUEST; dprintf(LOG_DEBUG, "%s" "got a NoBinding reply, sending request.", FNAME); dhcp6_remove_iaidaddr(&client6_iaidaddr); break; case DH6OPT_STCODE_NOADDRAVAIL: case DH6OPT_STCODE_NOPREFIXAVAIL: case DH6OPT_STCODE_UNSPECFAIL: break; case DH6OPT_STCODE_SUCCESS: case DH6OPT_STCODE_UNDEFINE: default: dhcp6_update_iaidaddr(optinfo, ADDR_UPDATE); if (optinfo->type == IAPD) radvd_parse(&client6_iaidaddr, ADDR_UPDATE); break; } break; case DHCP6S_CONFIRM: /* NOtOnLink for a Confirm, send SOLICIT message */rebind_confirm: client6_request_flag &= ~CLIENT6_CONFIRM_ADDR; switch(addr_status_code) { struct timeb now; struct timeval timo; time_t offset; case DH6OPT_STCODE_NOTONLINK: case DH6OPT_STCODE_NOBINDING: case DH6OPT_STCODE_NOADDRAVAIL: dprintf(LOG_DEBUG, "%s" "got a NotOnLink reply for confirm, sending solicit.", FNAME); /* remove event data list */ free_servers(ifp); newstate = DHCP6S_SOLICIT; break; case DH6OPT_STCODE_SUCCESS: case DH6OPT_STCODE_UNDEFINE: /* XXX: set up renew/rebind timer */ dprintf(LOG_DEBUG, "%s" "got an expected reply for confirm", FNAME); ftime(&now); client6_iaidaddr.state = ACTIVE; if ((client6_iaidaddr.timer = dhcp6_add_timer(dhcp6_iaidaddr_timo, &client6_iaidaddr)) == NULL) { dprintf(LOG_ERR, "%s" "failed to add a timer for iaid %u", FNAME, client6_iaidaddr.client6_info.iaidinfo.iaid); return (-1); } if (client6_iaidaddr.client6_info.iaidinfo.renewtime == 0) { client6_iaidaddr.client6_info.iaidinfo.renewtime = get_min_preferlifetime(&client6_iaidaddr)/2; } if (client6_iaidaddr.client6_info.iaidinfo.rebindtime == 0) { client6_iaidaddr.client6_info.iaidinfo.rebindtime = (get_min_preferlifetime(&client6_iaidaddr)*4)/5; } offset = now.time - client6_iaidaddr.start_date; if ( offset > client6_iaidaddr.client6_info.iaidinfo.renewtime) timo.tv_sec = 0; else timo.tv_sec = client6_iaidaddr.client6_info.iaidinfo.renewtime - offset; timo.tv_usec = 0; dhcp6_set_timer(&timo, client6_iaidaddr.timer); /* check DAD */ if (optinfo->type != IAPD && ifp->dad_timer == NULL && (ifp->dad_timer = dhcp6_add_timer(check_dad_timo, ifp)) < 0) { dprintf(LOG_INFO, "%s" "failed to create a timer for " " DAD", FNAME); } setup_check_timer(ifp); break; default: break; } break; case DHCP6S_DECLINE: /* send REQUEST message to server with none decline address */ dprintf(LOG_DEBUG, "%s" "got an expected reply for decline, sending request.", FNAME); create_request_list(0); /* remove event data list */ newstate = DHCP6S_REQUEST; break; case DHCP6S_RELEASE: dprintf(LOG_INFO, "%s" "got an expected release, exit.", FNAME); dhcp6_remove_event(ev); exit(0); default: break; } dhcp6_remove_event(ev); if (newstate) { client6_send_newstate(ifp, newstate); } else dprintf(LOG_DEBUG, "%s" "got an expected reply, sleeping.", FNAME); TAILQ_INIT(&request_list); return 0;}int client6_send_newstate(ifp, state) struct dhcp6_if *ifp; int state;{ struct dhcp6_event *ev; if ((ev = dhcp6_create_event(ifp, state)) == NULL) { dprintf(LOG_ERR, "%s" "failed to create an event", FNAME); return (-1); } if ((ev->timer = dhcp6_add_timer(client6_timo, ev)) == NULL) { dprintf(LOG_ERR, "%s" "failed to add a timer for %s", FNAME, ifp->ifname); free(ev); return(-1); } TAILQ_INSERT_TAIL(&ifp->event_list, ev, link); ev->timeouts = 0; dhcp6_set_timeoparam(ev); dhcp6_reset_timer(ev); client6_send(ev); return 0;}static struct dhcp6_event *find_event_withid(ifp, xid) struct dhcp6_if *ifp; u_int32_t xid;{ struct dhcp6_event *ev; for (ev = TAILQ_FIRST(&ifp->event_list); ev; ev = TAILQ_NEXT(ev, link)) { dprintf(LOG_DEBUG, "%s" "ifp %p event %p id is %x", FNAME, ifp, ev, ev->xid); if (ev->xid == xid) return (ev); } return (NULL);}static int create_request_list(int reboot){ struct dhcp6_lease *cl; struct dhcp6_listval *lv; /* create an address list for release all/confirm */ for (cl = TAILQ_FIRST(&client6_iaidaddr.lease_list); cl; cl = TAILQ_NEXT(cl, link)) { /* IANA, IAPD */ if ((lv = malloc(sizeof(*lv))) == NULL) { dprintf(LOG_ERR, "%s" "failed to allocate memory for an ipv6 addr", FNAME); exit(1); } memcpy(&lv->val_dhcp6addr, &cl->lease_addr, sizeof(lv->val_dhcp6addr)); lv->val_dhcp6addr.status_code = DH6OPT_STCODE_UNDEFINE; TAILQ_INSERT_TAIL(&request_list, lv, link); /* config the interface for reboot */ if (reboot && client6_iaidaddr.client6_info.type != IAPD && (client6_request_flag & CLIENT6_CONFIRM_ADDR)) { if (client6_ifaddrconf(IFADDRCONF_ADD, &cl->lease_addr) != 0) { dprintf(LOG_INFO, "config address failed: %s", in6addr2str(&cl->lease_addr.addr, 0)); return (-1); } } } /* update radvd.conf for prefix delegation */ if (reboot && client6_iaidaddr.client6_info.type == IAPD && (client6_request_flag & CLIENT6_CONFIRM_ADDR)) radvd_parse(&client6_iaidaddr, ADDR_UPDATE); return (0);}static void setup_check_timer(struct dhcp6_if *ifp){ double d; struct timeval timo; d = DHCP6_CHECKLINK_TIME; timo.tv_sec = (long)d; timo.tv_usec = 0; dprintf(LOG_DEBUG, "set timer for checking link ..."); dhcp6_set_timer(&timo, ifp->link_timer); if (ifp->dad_timer != NULL) { d = DHCP6_CHECKDAD_TIME; timo.tv_sec = (long)d; timo.tv_usec = 0; dprintf(LOG_DEBUG, "set timer for checking DAD ..."); dhcp6_set_timer(&timo, ifp->dad_timer); } d = DHCP6_SYNCFILE_TIME; timo.tv_sec = (long)d; timo.tv_usec = 0; dprintf(LOG_DEBUG, "set timer for syncing file ..."); dhcp6_set_timer(&timo, ifp->sync_timer); return;}static struct dhcp6_timer*check_lease_file_timo(void *arg){ struct dhcp6_if *ifp = (struct dhcp6_if *)arg; double d; struct timeval timo; struct stat buf; FILE *file; stat(leasename, &buf); strcpy(client6_lease_temp, leasename); strcat(client6_lease_temp, "XXXXXX"); if (buf.st_size > MAX_FILE_SIZE) { file = sync_leases(client6_lease_file, leasename, client6_lease_temp); if ( file != NULL) client6_lease_file = file; } d = DHCP6_SYNCFILE_TIME; timo.tv_sec = (long)d; timo.tv_usec = 0; dhcp6_set_timer(&timo, ifp->sync_timer); return ifp->sync_timer;}static struct dhcp6_timer*check_dad_timo(void *arg){ struct dhcp6_if *ifp = (struct dhcp6_if *)arg; struct dhcp6_listval *lv; struct dhcp6_lease *cl, *cl_next; struct timeval timo; double d; int newstate; if (client6_iaidaddr.client6_info.type == IAPD) goto end; dprintf(LOG_DEBUG, "enter checking dad ..."); if (dad_parse(ifproc_file) < 0) { dprintf(LOG_ERR, "parse /proc/net/if_inet6 failed"); goto end; } if (TAILQ_EMPTY(&request_list)) goto end; /* remove RENEW timer for client6_iaidaddr */ if (client6_iaidaddr.timer != NULL) dhcp6_remove_timer(client6_iaidaddr.timer); newstate = DHCP6S_DECLINE; client6_send_newstate(ifp, newstate);end: /* one time check for DAD */ dhcp6_remove_timer(ifp->dad_timer); ifp->dad_timer = NULL; return NULL;} static struct dhcp6_timer *check_link_timo(void *arg){ struct dhcp6_if *ifp = (struct dhcp6_if *)arg; struct ifreq ifr; struct timeval timo; double d; int newstate; dprintf(LOG_DEBUG, "enter checking link ..."); strncpy(ifr.ifr_name, dhcp6_if->ifname, IFNAMSIZ); if (ioctl(nlsock, SIOCGIFFLAGS, &ifr) < 0) { dprintf(LOG_DEBUG, "ioctl SIOCGIFFLAGS failed"); goto settimer; } if (ifr.ifr_flags & IFF_RUNNING) { /* check previous flag * set current flag UP */ if (ifp->link_flag & IFF_RUNNING) { goto settimer; } /* check current state ACTIVE */ if (client6_iaidaddr.state == ACTIVE) { /* remove timer for renew/rebind * send confirm for ipv6address or * rebind for prefix delegation */ dhcp6_remove_timer(client6_iaidaddr.timer); client6_request_flag &= CLIENT6_CONFIRM_ADDR; create_request_list(0); if (client6_iaidaddr.client6_info.type == IAPD) newstate = DHCP6S_REBIND; else newstate = DHCP6S_CONFIRM; client6_send_newstate(ifp, newstate); } dprintf(LOG_INFO, "interface is from down to up"); ifp->link_flag |= IFF_RUNNING; } else { dprintf(LOG_INFO, "interface is down"); /* set flag_prev flag DOWN */ ifp->link_flag &= ~IFF_RUNNING; }settimer: d = DHCP6_CHECKLINK_TIME; timo.tv_sec = (long)d; timo.tv_usec = 0; dhcp6_set_timer(&timo, ifp->link_timer); return ifp->link_timer;}static voidsetup_interface(char *ifname){ struct ifreq ifr; /* check the interface */ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);again: if (ioctl(nlsock, SIOCGIFFLAGS, &ifr) < 0) { dprintf(LOG_ERR, "ioctl SIOCGIFFLAGS failed"); exit(1); } if (!ifr.ifr_flags & IFF_UP) { ifr.ifr_flags |= IFF_UP; if (ioctl(nlsock, SIOCSIFFLAGS, &ifr) < 0) { dprintf(LOG_ERR, "ioctl SIOCSIFFLAGS failed"); exit(1); } if (ioctl(nlsock, SIOCGIFFLAGS, &ifr) < 0) { dprintf(LOG_ERR, "ioctl SIOCGIFFLAGS failed"); exit(1); } } if (!ifr.ifr_flags & IFF_RUNNING) { dprintf(LOG_INFO, "NIC is not connected to the network, " "please connect it. dhcp6c is sleeping ..."); sleep(10); goto again; } return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -