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

📄 dhcp6c.c

📁 DHCPv6协议在Linux操作系统下的一个客户端实现。
💻 C
📖 第 1 页 / 共 4 页
字号:
			FNAME, strerror(errno));		exit(1);	}}static voidclient6_ifinit(char *device){	struct dhcp6_if *ifp = dhcp6_if;	struct dhcp6_event *ev;	char iaidstr[20];	dhcp6_init_iaidaddr();	/* get iaid for each interface */	if (num_device == 0) {		if ((num_device = create_iaid(&iaidtab[0], num_device)) < 0)			exit(1);		ifp->iaidinfo.iaid = get_iaid(ifp->ifname, &iaidtab[0], num_device);		if (ifp->iaidinfo.iaid == 0) {			dprintf(LOG_DEBUG, "%s" 				"interface %s iaid failed to be created", 				FNAME, ifp->ifname);			exit(1);		}		dprintf(LOG_DEBUG, "%s" "interface %s iaid is %u", 			FNAME, ifp->ifname, ifp->iaidinfo.iaid);	}	client6_iaidaddr.ifp = ifp;	memcpy(&client6_iaidaddr.client6_info.iaidinfo, &ifp->iaidinfo, 			sizeof(client6_iaidaddr.client6_info.iaidinfo));	duidcpy(&client6_iaidaddr.client6_info.clientid, &client_duid);	/* parse the lease file */	strcpy(leasename, PATH_CLIENT6_LEASE);	sprintf(iaidstr, "%u", ifp->iaidinfo.iaid);	strcat(leasename, iaidstr);	if ((client6_lease_file = 		init_leases(leasename)) == NULL) {			dprintf(LOG_ERR, "%s" "failed to parse lease file", FNAME);		exit(1);	}	strcpy(client6_lease_temp, leasename);	strcat(client6_lease_temp, "XXXXXX");	client6_lease_file = 		sync_leases(client6_lease_file, leasename, client6_lease_temp);	if (client6_lease_file == NULL)		exit(1);	if (!TAILQ_EMPTY(&client6_iaidaddr.lease_list)) {		struct dhcp6_lease *cl;		struct dhcp6_listval *lv;		if (!(client6_request_flag & CLIENT6_REQUEST_ADDR) && 				!(client6_request_flag & CLIENT6_RELEASE_ADDR))			client6_request_flag |= CLIENT6_CONFIRM_ADDR;		if (TAILQ_EMPTY(&request_list)) {			if (create_request_list(1) < 0) 				exit(1);		} else if (client6_request_flag & CLIENT6_RELEASE_ADDR) {			for (lv = TAILQ_FIRST(&request_list); lv; 					lv = TAILQ_NEXT(lv, link)) {				if (dhcp6_find_lease(&client6_iaidaddr, 						&lv->val_dhcp6addr) == NULL) {					dprintf(LOG_INFO, "this address %s is not"						" leased by this client", 					    in6addr2str(&lv->val_dhcp6addr.addr,0));					exit(0);				}			}		}		} else if (client6_request_flag & CLIENT6_RELEASE_ADDR) {		dprintf(LOG_INFO, "no ipv6 addresses are leased by client");		exit(0);	}	setup_interface(ifp->ifname);	ifp->link_flag |= IFF_RUNNING;	/* get addrconf prefix from kernel */	(void)get_if_rainfo(ifp);	/* set up check link timer and sync file timer */		if ((ifp->link_timer =	    dhcp6_add_timer(check_link_timo, ifp)) < 0) {		dprintf(LOG_ERR, "%s" "failed to create a timer", FNAME);		exit(1);	}	if ((ifp->sync_timer = dhcp6_add_timer(check_lease_file_timo, ifp)) < 0) {		dprintf(LOG_ERR, "%s" "failed to create a timer", FNAME);		exit(1);	}	/* DAD timer set up after getting the address */	ifp->dad_timer = NULL;	/* create an event for the initial delay */	if ((ev = dhcp6_create_event(ifp, DHCP6S_INIT)) == NULL) {		dprintf(LOG_ERR, "%s" "failed to create an event",			FNAME);		exit(1);	}	ifp->servers = NULL;	ev->ifp->current_server = NULL;	TAILQ_INSERT_TAIL(&ifp->event_list, ev, link);	if ((ev->timer = dhcp6_add_timer(client6_timo, ev)) == NULL) {		dprintf(LOG_ERR, "%s" "failed to add a timer for %s",			FNAME, ifp->ifname);		exit(1);	}	dhcp6_reset_timer(ev);}static voidfree_resources(struct dhcp6_if *ifp){	struct dhcp6_event *ev, *ev_next;	struct dhcp6_lease *sp, *sp_next;	struct stat buf;	if (client6_iaidaddr.client6_info.type == IAPD && 	    !TAILQ_EMPTY(&client6_iaidaddr.lease_list))		radvd_parse(&client6_iaidaddr, ADDR_REMOVE);	else {		for (sp = TAILQ_FIRST(&client6_iaidaddr.lease_list); sp; sp = sp_next) { 			sp_next = TAILQ_NEXT(sp, link);			if (client6_ifaddrconf(IFADDRCONF_REMOVE, &sp->lease_addr) != 0) 				dprintf(LOG_INFO, "%s" "deconfiging address %s failed",					FNAME, in6addr2str(&sp->lease_addr.addr, 0));		}	}	dprintf(LOG_DEBUG, "%s" " remove all events on interface", FNAME);	/* cancel all outstanding events for each interface */	for (ev = TAILQ_FIRST(&ifp->event_list); ev; ev = ev_next) {		ev_next = TAILQ_NEXT(ev, link);		dhcp6_remove_event(ev);	}	/* XXX: check the last dhcpv6 client daemon to restore the original file */	{		/* restore /etc/radv.conf.bak back to /etc/radvd.conf */		if (!lstat(RADVD_CONF_BAK_FILE, &buf))			rename(RADVD_CONF_BAK_FILE, RADVD_CONF_FILE);		/* restore /etc/resolv.conf.dhcpv6.bak back to /etc/resolv.conf */		if (!lstat(RESOLV_CONF_BAK_FILE, &buf)) {			if (rename(RESOLV_CONF_BAK_FILE, RESOLV_CONF_FILE)) 				dprintf(LOG_ERR, "%s" " failed to backup resolv.conf", FNAME);		}	}	free_servers(ifp);}static voidprocess_signals(){	struct stat buf;	if ((sig_flags & SIGF_TERM)) {		dprintf(LOG_INFO, FNAME "exiting");		free_resources(dhcp6_if);		unlink(DHCP6C_PIDFILE);		exit(0);	}	if ((sig_flags & SIGF_HUP)) {		dprintf(LOG_INFO, FNAME "restarting");		free_resources(dhcp6_if);		client6_ifinit(device);	}	if ((sig_flags & SIGF_CLEAN)) {		free_resources(dhcp6_if);		exit(0);	}	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;	struct timeval now;	struct ra_info *rainfo;		ifp = ev->ifp;	ev->timeouts++;	gettimeofday(&now, NULL);	if ((ev->max_retrans_cnt && ev->timeouts >= ev->max_retrans_cnt) ||	    (ev->max_retrans_dur && (now.tv_sec - ev->start_time.tv_sec) 	     >= ev->max_retrans_dur)) {		/* XXX: check up the duration time for renew & rebind */		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:		/* From INIT state client could		 * go to CONFIRM state if the client reboots;		 * go to RELEASE state if the client issues a release;		 * go to INFOREQ state if the client requests info-only;		 * go to SOLICIT state if the client requests addresses;		 */		ev->timeouts = 0; /* indicate to generate a new XID. */		/* 		 * three cases client send information request:		 * 1. configuration file includes information-only		 * 2. command line includes -I		 * 3. check interface flags if managed bit isn't set and		 *    if otherconf bit set by RA		 *    and information-only, conmand line -I are not set.		 */		if ((ifp->send_flags & DHCIFF_INFO_ONLY) || 		    (client6_request_flag & CLIENT6_INFO_REQ) ||		    (!(ifp->ra_flag & IF_RA_MANAGED) && 		     (ifp->ra_flag & IF_RA_OTHERCONF)))			ev->state = DHCP6S_INFOREQ;		else if (client6_request_flag & CLIENT6_RELEASE_ADDR) 			/* do release */			ev->state = DHCP6S_RELEASE;		else if (client6_request_flag & CLIENT6_CONFIRM_ADDR) {			struct dhcp6_listval *lv;			/* do confirm for reboot for IANA, IATA*/			if (client6_iaidaddr.client6_info.type == IAPD)				ev->state = DHCP6S_REBIND;			else				ev->state = DHCP6S_CONFIRM;			for (lv = TAILQ_FIRST(&request_list); lv; 					lv = TAILQ_NEXT(lv, link)) {				lv->val_dhcp6addr.preferlifetime = 0;				lv->val_dhcp6addr.validlifetime = 0;			}		} else			ev->state = DHCP6S_SOLICIT;		dhcp6_set_timeoparam(ev);	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 */			}			/* if get the address assginment break */			if (!TAILQ_EMPTY(&client6_iaidaddr.lease_list)) {				dhcp6_remove_event(ev);				return (NULL);			}			ev->timeouts = 0;			ev->state = DHCP6S_REQUEST;			dhcp6_set_timeoparam(ev);		}	case DHCP6S_INFOREQ:	case DHCP6S_REQUEST:		client6_send(ev);		break;	case DHCP6S_RELEASE:	case DHCP6S_DECLINE:	case DHCP6S_CONFIRM:	case DHCP6S_RENEW:	case DHCP6S_REBIND:		if (!TAILQ_EMPTY(&request_list))			client6_send(ev);		else {			dprintf(LOG_INFO, "%s"		    		"all information to be updated were canceled",		    		FNAME);			dhcp6_remove_event(ev);			return (NULL);		}		break;	default:		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;	case SIGINT:	case SIGKILL:		sig_flags |= SIGF_CLEAN;		break;	default:		break;	}}voidclient6_send(ev)	struct dhcp6_event *ev;{	struct dhcp6_if *ifp;	char buf[BUFSIZ];	struct sockaddr_in6 dst;	struct dhcp6 *dh6;	struct dhcp6_optinfo optinfo;	ssize_t optlen, len;	struct timeval duration, now;	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_RENEW:		if (ifp->current_server == NULL) {			dprintf(LOG_ERR, "%s" "assumption failure", FNAME);			exit(1); /* XXX */		}		dh6->dh6_msgtype = DH6_RENEW;		break;	case DHCP6S_DECLINE:		if (ifp->current_server == NULL) {			dprintf(LOG_ERR, "%s" "assumption failure", FNAME);			exit(1); /* XXX */		}		dh6->dh6_msgtype = DH6_DECLINE;		break;	case DHCP6S_INFOREQ:			dh6->dh6_msgtype = DH6_INFORM_REQ;		break;	case DHCP6S_REBIND:		dh6->dh6_msgtype = DH6_REBIND;		break;	case DHCP6S_CONFIRM:		dh6->dh6_msgtype = DH6_CONFIRM;		break;	case DHCP6S_RELEASE:		dh6->dh6_msgtype = DH6_RELEASE;		break;	default:		dprintf(LOG_ERR, "%s" "unexpected state %d", FNAME, ev->state);		exit(1);	/* XXX */	}	/*	 * construct options	 */	dhcp6_init_options(&optinfo);	if (ev->timeouts == 0) {		gettimeofday(&ev->start_time, NULL);		optinfo.elapsed_time = 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]		 */		ev->xid = random() & DH6_XIDMASK;		dprintf(LOG_DEBUG, "%s" "ifp %p event %p a new XID (%x) is generated",			FNAME, ifp, ev, ev->xid);	} else {		unsigned int etime;		gettimeofday(&now, NULL);		timeval_sub(&now, &(ev->start_time), &duration);		optinfo.elapsed_time = 		etime = (duration.tv_sec) * 100 + (duration.tv_usec) / 10000;		if (etime > DHCP6_ELAPSEDTIME_MAX)			optinfo.elapsed_time = DHCP6_ELAPSEDTIME_MAX;		else			optinfo.elapsed_time = etime;	}	dh6->dh6_xid &= ~ntohl(DH6_XIDMASK);	dh6->dh6_xid |= htonl(ev->xid);	len = sizeof(*dh6);	/* server ID */	switch(ev->state) {	case DHCP6S_REQUEST:	case DHCP6S_RENEW:	case DHCP6S_DECLINE:		if (&ifp->current_server->optinfo == NULL)			exit(1);		dprintf(LOG_DEBUG, "current server ID %s",			duidstr(&ifp->current_server->optinfo.serverID));		if (duidcpy(&optinfo.serverID,		    &ifp->current_server->optinfo.serverID)) {			dprintf(LOG_ERR, "%s" "failed to copy server ID",			    FNAME);			goto end;		}		break;	case DHCP6S_RELEASE:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -