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

📄 dhcp6c.c

📁 DHCPv6协议在Linux操作系统下的一个客户端实现。
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* 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 + -