⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dhcp6c.c

📁 IPv6环境下的DHCP实现
💻 C
📖 第 1 页 / 共 3 页
字号:
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 + -