📄 dhcp6c.c
字号:
static voidprocess_signals(){ if ((sig_flags & SIGF_TERM)) { dprintf(LOG_INFO, FNAME "exiting"); free_resources(); unlink(DHCP6C_PIDFILE); exit(0); } if ((sig_flags & SIGF_HUP)) { dprintf(LOG_INFO, FNAME "restarting"); free_resources(); client6_ifinit(); } sig_flags = 0;}static voidclient6_mainloop(){ struct timeval *w; int ret; fd_set r; while(1) { if (sig_flags) process_signals(); w = dhcp6_check_timer(); FD_ZERO(&r); FD_SET(insock, &r); ret = select(insock + 1, &r, NULL, NULL, w); switch (ret) { case -1: if (errno != EINTR) { dprintf(LOG_ERR, "%s" "select: %s", FNAME, strerror(errno)); exit(1); } break; case 0: /* timeout */ break; /* dhcp6_check_timer() will treat the case */ default: /* received a packet */ client6_recv(); } }}struct dhcp6_timer *client6_timo(arg) void *arg;{ struct dhcp6_event *ev = (struct dhcp6_event *)arg; struct dhcp6_if *ifp; ifp = ev->ifp; ev->timeouts++; if (ev->max_retrans_cnt && ev->timeouts > ev->max_retrans_cnt) { dprintf(LOG_INFO, "%s" "no responses were received", FNAME); dhcp6_remove_event(ev); /* XXX: should free event data? */ return(NULL); } switch(ev->state) { case DHCP6S_INIT: ev->timeouts = 0; /* indicate to generate a new XID. */ if ((ifp->send_flags & DHCIFF_INFO_ONLY)) ev->state = DHCP6S_INFOREQ; else ev->state = DHCP6S_SOLICIT; dhcp6_set_timeoparam(ev); /* XXX */ /* fall through */ case DHCP6S_INFOREQ: client6_send(ev); break; case DHCP6S_RENEW: case DHCP6S_REBIND: if (!TAILQ_EMPTY(&ev->data_list)) { if (ev->state == DHCP6S_RENEW) client6_send_renew(ev); else client6_send_rebind(ev); } else { dprintf(LOG_INFO, "%s" "all information to be updated were canceled", FNAME); dhcp6_remove_event(ev); return(NULL); } break; case DHCP6S_SOLICIT: if (ifp->servers) { ifp->current_server = select_server(ifp); if (ifp->current_server == NULL) { /* this should not happen! */ dprintf(LOG_ERR, "%s" "can't find a server" FNAME); exit(1); /* XXX */ } ev->timeouts = 0; ev->state = DHCP6S_REQUEST; dhcp6_set_timeoparam(ev); } client6_send(ev); break; } dhcp6_reset_timer(ev); return(ev->timer);}static struct dhcp6_serverinfo *select_server(ifp) struct dhcp6_if *ifp;{ struct dhcp6_serverinfo *s; /* * pick the best server according to dhcpv6-26 Section 17.1.3 * XXX: we currently just choose the one that is active and has the * highest preference. */ for (s = ifp->servers; s; s = s->next) { if (s->active) { dprintf(LOG_DEBUG, "%s" "picked a server (ID: %s)", FNAME, duidstr(&s->optinfo.serverID)); return(s); } } return(NULL);}static voidclient6_signal(sig) int sig;{ dprintf(LOG_INFO, FNAME "received a signal (%d)", sig); switch (sig) { case SIGTERM: sig_flags |= SIGF_TERM; break; case SIGHUP: sig_flags |= SIGF_HUP; break; }}static intsa2plen(sa6) struct sockaddr_in6 *sa6;{ int masklen; u_char *p, *lim; p = (u_char *)(&sa6->sin6_addr); lim = (u_char *)sa6 + sa6->sin6_len; for (masklen = 0; p < lim; p++) { switch (*p) { case 0xff: masklen += 8; break; case 0xfe: masklen += 7; break; case 0xfc: masklen += 6; break; case 0xf8: masklen += 5; break; case 0xf0: masklen += 4; break; case 0xe0: masklen += 3; break; case 0xc0: masklen += 2; break; case 0x80: masklen += 1; break; case 0x00: break; default: return(-1); } } return(masklen);}static voidclient6_send(ev) struct dhcp6_event *ev;{ struct dhcp6_if *ifp; char buf[BUFSIZ]; struct sockaddr_in6 dst; int error; struct dhcp6 *dh6; struct dhcp6opt *opt; struct dhcp6_optinfo optinfo; ssize_t optlen, len; ifp = ev->ifp; dh6 = (struct dhcp6 *)buf; memset(dh6, 0, sizeof(*dh6)); switch(ev->state) { case DHCP6S_SOLICIT: dh6->dh6_msgtype = DH6_SOLICIT; break; case DHCP6S_REQUEST: if (ifp->current_server == NULL) { dprintf(LOG_ERR, "%s" "assumption failure", FNAME); exit(1); /* XXX */ } dh6->dh6_msgtype = DH6_REQUEST; break; case DHCP6S_INFOREQ: dh6->dh6_msgtype = DH6_INFORM_REQ; break; default: dprintf(LOG_ERR, "%s" "unexpected state"); exit(1); /* XXX */ } if (ev->timeouts == 0) { /* * A client SHOULD generate a random number that cannot easily * be guessed or predicted to use as the transaction ID for * each new message it sends. * * A client MUST leave the transaction-ID unchanged in * retransmissions of a message. [dhcpv6-26 15.1] */#ifdef HAVE_ARC4RANDOM ev->xid = arc4random() & DH6_XIDMASK;#else ev->xid = random() & DH6_XIDMASK;#endif dprintf(LOG_DEBUG, "%s" "a new XID (%x) is generated", FNAME, ev->xid); } dh6->dh6_xid &= ~ntohl(DH6_XIDMASK); dh6->dh6_xid |= htonl(ev->xid); len = sizeof(*dh6); /* * construct options */ dhcp6_init_options(&optinfo); /* server ID */ if (ev->state == DHCP6S_REQUEST) { if (duidcpy(&optinfo.serverID, &ifp->current_server->optinfo.serverID)) { dprintf(LOG_ERR, "%s" "failed to copy server ID", FNAME); goto end; } } /* client ID */ if (duidcpy(&optinfo.clientID, &client_duid)) { dprintf(LOG_ERR, "%s" "failed to copy client ID", FNAME); goto end; } /* rapid commit */ if (ev->state == DHCP6S_SOLICIT && (ifp->send_flags & DHCIFF_RAPID_COMMIT)) { optinfo.rapidcommit = 1; } /* option request options */ if (dhcp6_copy_list(&optinfo.reqopt_list, &ifp->reqopt_list)) { dprintf(LOG_ERR, "%s" "failed to copy requested options", FNAME); goto end; } /* configuration information provided by the server */ if (ev->state == DHCP6S_REQUEST) { /* do we have to check if we wanted prefixes? */ if (dhcp6_copy_list(&optinfo.prefix_list, &ifp->current_server->optinfo.prefix_list)) { dprintf(LOG_ERR, "%s" "failed to copy prefixes", FNAME); goto end; } } /* set options in the message */ if ((optlen = dhcp6_set_options((struct dhcp6opt *)(dh6 + 1), (struct dhcp6opt *)(buf + sizeof(buf)), &optinfo)) < 0) { dprintf(LOG_INFO, "%s" "failed to construct options", FNAME); goto end; } len += optlen; /* * Unless otherwise specified, a client sends DHCP messages to the * All_DHCP_Relay_Agents_and_Servers or the DHCP_Anycast address. * [dhcpv6-26 Section 13.] * Our current implementation always follows the case. */ dst = *sa6_allagent; dst.sin6_scope_id = ifp->linkid; if (sendto(ifp->outsock, buf, len, 0, (struct sockaddr *)&dst, ((struct sockaddr *)&dst)->sa_len) == -1) { dprintf(LOG_ERR, FNAME "transmit failed: %s", strerror(errno)); goto end; } dprintf(LOG_DEBUG, "%s" "send %s to %s", FNAME, dhcp6msgstr(dh6->dh6_msgtype), addr2str((struct sockaddr *)&dst)); end: dhcp6_clear_options(&optinfo); return;}voidclient6_send_renew(ev) struct dhcp6_event *ev;{ struct dhcp6_if *ifp; struct dhcp6_eventdata *evd; struct dhcp6_optinfo optinfo; struct dhcp6_listval *dlv; struct dhcp6 *dh6; char buf[BUFSIZ]; ssize_t optlen, len; struct sockaddr_in6 dst; ifp = ev->ifp; dh6 = (struct dhcp6 *)buf; memset(dh6, 0, sizeof(*dh6)); dh6->dh6_msgtype = DH6_RENEW; if (ev->timeouts == 0) {#ifdef HAVE_ARC4RANDOM ev->xid = arc4random() & DH6_XIDMASK;#else ev->xid = random() & DH6_XIDMASK;#endif dprintf(LOG_DEBUG, "%s" "a new XID (%x) is generated", FNAME, ev->xid); } dh6->dh6_xid &= ~ntohl(DH6_XIDMASK); dh6->dh6_xid |= htonl(ev->xid); len = sizeof(*dh6); /* * construct options */ dhcp6_init_options(&optinfo); /* server ID */ if (duidcpy(&optinfo.serverID, &ev->serverid)) { dprintf(LOG_ERR, "%s" "failed to copy server ID", FNAME); goto end; } /* client ID */ if (duidcpy(&optinfo.clientID, &client_duid)) { dprintf(LOG_ERR, "%s" "failed to copy client ID", FNAME); goto end; } /* configuration information to be renewed */ for (evd = TAILQ_FIRST(&ev->data_list); evd; evd = TAILQ_NEXT(evd, link)) { switch(evd->type) { case DHCP6_DATA_PREFIX: if (dhcp6_add_listval(&optinfo.prefix_list, &((struct dhcp6_siteprefix *)evd->data)->prefix, DHCP6_LISTVAL_PREFIX6) == NULL) { dprintf(LOG_ERR, "%s" "failed to add a " "prefix", FNAME); goto end; } break; default: dprintf(LOG_ERR, FNAME "unexpected event data (%d)", evd->type); exit(1); } } /* set options in the message */ if ((optlen = dhcp6_set_options((struct dhcp6opt *)(dh6 + 1), (struct dhcp6opt *)(buf + sizeof(buf)), &optinfo)) < 0) { dprintf(LOG_INFO, "%s" "failed to construct options", FNAME); goto end; } len += optlen; /* * Unless otherwise specified, a client sends DHCP messages to the * All_DHCP_Relay_Agents_and_Servers or the DHCP_Anycast address. * [dhcpv6-26 Section 13.] * Our current implementation always follows the case. */ dst = *sa6_allagent; dst.sin6_scope_id = ifp->linkid; if (sendto(ifp->outsock, buf, len, 0, (struct sockaddr *)&dst, ((struct sockaddr *)&dst)->sa_len) == -1) { dprintf(LOG_ERR, FNAME "transmit failed: %s", strerror(errno)); goto end; } dprintf(LOG_DEBUG, "%s" "send %s to %s", FNAME, dhcp6msgstr(dh6->dh6_msgtype), addr2str((struct sockaddr *)&dst));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -