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

📄 dhcp6c.c

📁 DHCPv6协议在Linux操作系统下的一个客户端实现。
💻 C
📖 第 1 页 / 共 4 页
字号:
		if (duidcpy(&optinfo.serverID, &client6_iaidaddr.client6_info.serverid)) {			dprintf(LOG_ERR, "%s" "failed to copy server ID", FNAME);			goto end;		}		break;	}	/* client ID */	if (duidcpy(&optinfo.clientID, &client_duid)) {		dprintf(LOG_ERR, "%s" "failed to copy client ID", FNAME);		goto end;	}	/* 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;	}		switch(ev->state) {	case DHCP6S_SOLICIT:		/* rapid commit */		if (ifp->send_flags & DHCIFF_RAPID_COMMIT) 			optinfo.flags |= DHCIFF_RAPID_COMMIT;		if (!(ifp->send_flags & DHCIFF_INFO_ONLY) ||		    (client6_request_flag & CLIENT6_REQUEST_ADDR)) {			memcpy(&optinfo.iaidinfo, &client6_iaidaddr.client6_info.iaidinfo,					sizeof(optinfo.iaidinfo));			if (ifp->send_flags & DHCIFF_PREFIX_DELEGATION)				optinfo.type = IAPD;			else if (ifp->send_flags & DHCIFF_TEMP_ADDRS)				optinfo.type = IATA;			else				optinfo.type = IANA;		}		/* support for client preferred ipv6 address */		if (client6_request_flag & CLIENT6_REQUEST_ADDR) {			if (dhcp6_copy_list(&optinfo.addr_list, &request_list))				goto end;		}		break;	case DHCP6S_REQUEST:		if (!(ifp->send_flags & DHCIFF_INFO_ONLY)) {			memcpy(&optinfo.iaidinfo, &client6_iaidaddr.client6_info.iaidinfo,					sizeof(optinfo.iaidinfo));			dprintf(LOG_DEBUG, "%s IAID is %u", FNAME, optinfo.iaidinfo.iaid);			if (ifp->send_flags & DHCIFF_TEMP_ADDRS) 				optinfo.type = IATA;			else if (ifp->send_flags & DHCIFF_PREFIX_DELEGATION)				optinfo.type = IAPD;			else				optinfo.type = IANA;		}		break;	case DHCP6S_RENEW:	case DHCP6S_REBIND:	case DHCP6S_RELEASE:	case DHCP6S_CONFIRM:	case DHCP6S_DECLINE:		memcpy(&optinfo.iaidinfo, &client6_iaidaddr.client6_info.iaidinfo,			sizeof(optinfo.iaidinfo));		optinfo.type = client6_iaidaddr.client6_info.type;		if (ev->state == DHCP6S_CONFIRM) {			optinfo.iaidinfo.renewtime = 0;			optinfo.iaidinfo.rebindtime = 0;		}		if (!TAILQ_EMPTY(&request_list)) {			/* XXX: ToDo: seperate to prefix list and address list */			if (dhcp6_copy_list(&optinfo.addr_list, &request_list))				goto end;		} else {			if (ev->state == DHCP6S_RELEASE) {				dprintf(LOG_INFO, "release empty address list");				exit(1);			}			/* XXX: allow the other emtpy list ?? */		}		if (client6_request_flag & CLIENT6_RELEASE_ADDR) {			if (dhcp6_update_iaidaddr(&optinfo, ADDR_REMOVE)) {				dprintf(LOG_INFO, "client release failed");				exit(1);			}			if (client6_iaidaddr.client6_info.type == IAPD)				radvd_parse(&client6_iaidaddr, ADDR_REMOVE);		}		break;	default:		break;	}	/* 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.	 */	switch(ev->state) {	case DHCP6S_REQUEST:	case DHCP6S_RENEW:	case DHCP6S_DECLINE:	case DHCP6S_RELEASE:		if (ifp->current_server && 		    !IN6_IS_ADDR_UNSPECIFIED(&ifp->current_server->server_addr)) {			struct addrinfo hints, *res;			int error;			memset(&hints, 0, sizeof(hints));			hints.ai_family = PF_INET6;			hints.ai_socktype = SOCK_DGRAM;			hints.ai_protocol = IPPROTO_UDP;			error = getaddrinfo(in6addr2str(&ifp->current_server->server_addr,0),				DH6PORT_UPSTREAM, &hints, &res);			if (error) {				dprintf(LOG_ERR, "%s" "getaddrinfo: %s",					FNAME, gai_strerror(error));				exit(1);			}			memcpy(&dst, res->ai_addr, res->ai_addrlen);			break;		}	default:		dst = *sa6_allagent;		break;	}	dst.sin6_scope_id = ifp->linkid;	dprintf(LOG_DEBUG, "send dst if %s addr is %s scope id is %d", 		ifp->ifname, addr2str((struct sockaddr *)&dst), ifp->linkid);	if (sendto(ifp->outsock, buf, len, MSG_DONTROUTE, (struct sockaddr *)&dst,	    sizeof(dst)) == -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;}	static voidclient6_recv(){	char rbuf[BUFSIZ], cmsgbuf[BUFSIZ];	struct msghdr mhdr;	struct iovec iov;	struct sockaddr_storage from;	struct dhcp6_if *ifp;	struct dhcp6opt *p, *ep;	struct dhcp6_optinfo optinfo;	ssize_t len;	struct dhcp6 *dh6;	struct cmsghdr *cm;	struct in6_pktinfo *pi = NULL;	memset(&iov, 0, sizeof(iov));	memset(&mhdr, 0, sizeof(mhdr));	iov.iov_base = (caddr_t)rbuf;	iov.iov_len = sizeof(rbuf);	mhdr.msg_name = (caddr_t)&from;	mhdr.msg_namelen = sizeof(from);	mhdr.msg_iov = &iov;	mhdr.msg_iovlen = 1;	mhdr.msg_control = (caddr_t)cmsgbuf;	mhdr.msg_controllen = sizeof(cmsgbuf);	if ((len = recvmsg(insock, &mhdr, 0)) < 0) {		dprintf(LOG_ERR, "%s" "recvmsg: %s", FNAME, strerror(errno));		return;	}	/* detect receiving interface */	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr); cm;	     cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm)) {		if (cm->cmsg_level == IPPROTO_IPV6 &&		    cm->cmsg_type == IPV6_PKTINFO &&		    cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));		}	}	if (pi == NULL) {		dprintf(LOG_NOTICE, "%s" "failed to get packet info", FNAME);		return;	}	if ((ifp = find_ifconfbyid(pi->ipi6_ifindex)) == NULL) {		dprintf(LOG_INFO, "%s" "unexpected interface (%d)", FNAME,			(unsigned int)pi->ipi6_ifindex);		return;	}	dprintf(LOG_DEBUG, "receive packet info ifname %s, addr is %s scope id is %d", 		ifp->ifname, in6addr2str(&pi->ipi6_addr, 0), pi->ipi6_ifindex);	dh6 = (struct dhcp6 *)rbuf;	dprintf(LOG_DEBUG, "%s" "receive %s from %s scope id %d %s", FNAME,		dhcp6msgstr(dh6->dh6_msgtype),		addr2str((struct sockaddr *)&from),		((struct sockaddr_in6 *)&from)->sin6_scope_id,		ifp->ifname);	/* get options */	dhcp6_init_options(&optinfo);	p = (struct dhcp6opt *)(dh6 + 1);	ep = (struct dhcp6opt *)((char *)dh6 + len);	if (dhcp6_get_options(p, ep, &optinfo) < 0) {		dprintf(LOG_INFO, "%s" "failed to parse options", FNAME);#ifdef TEST		return;#endif	}	switch(dh6->dh6_msgtype) {	case DH6_ADVERTISE:		(void)client6_recvadvert(ifp, dh6, len, &optinfo);		break;	case DH6_REPLY:		(void)client6_recvreply(ifp, dh6, len, &optinfo);		break;	default:		dprintf(LOG_INFO, "%s" "received an unexpected message (%s) "			"from %s", FNAME, dhcp6msgstr(dh6->dh6_msgtype),			addr2str((struct sockaddr *)&from));		break;	}	dhcp6_clear_options(&optinfo);	return;}static intclient6_recvadvert(ifp, dh6, len, optinfo0)	struct dhcp6_if *ifp;	struct dhcp6 *dh6;	ssize_t len;	struct dhcp6_optinfo *optinfo0;{	struct dhcp6_serverinfo *newserver;	struct dhcp6_event *ev;	struct dhcp6_listval *lv;	/* find the corresponding event based on the received xid */	ev = find_event_withid(ifp, ntohl(dh6->dh6_xid) & DH6_XIDMASK);	if (ev == NULL) {		dprintf(LOG_INFO, "%s" "XID mismatch", FNAME);		return -1;	}	/* if server policy doesn't allow rapid commit	if (ev->state != DHCP6S_SOLICIT ||	    (ifp->send_flags & DHCIFF_RAPID_COMMIT)) {	*/	if (ev->state != DHCP6S_SOLICIT) { 		dprintf(LOG_INFO, "%s" "unexpected advertise", FNAME);		return -1;	}		/* packet validation based on Section 15.3 of dhcpv6-26. */	if (optinfo0->serverID.duid_len == 0) {		dprintf(LOG_INFO, "%s" "no server ID option", FNAME);		return -1;	} else {		dprintf(LOG_DEBUG, "%s" "server ID: %s, pref=%2x", FNAME,			duidstr(&optinfo0->serverID),			optinfo0->pref);	}	if (optinfo0->clientID.duid_len == 0) {		dprintf(LOG_INFO, "%s" "no client ID option", FNAME);		return -1;	}	if (duidcmp(&optinfo0->clientID, &client_duid)) {		dprintf(LOG_INFO, "%s" "client DUID mismatch", FNAME);		return -1;	}	/*	 * The client MUST ignore any Advertise message that includes a Status	 * Code option containing any error.	 */	for (lv = TAILQ_FIRST(&optinfo0->stcode_list); lv;	     lv = TAILQ_NEXT(lv, link)) {		dprintf(LOG_INFO, "%s" "status code: %s",		    FNAME, dhcp6_stcodestr(lv->val_num));		if (lv->val_num != DH6OPT_STCODE_SUCCESS) {			return (-1);		}	}	/* ignore the server if it is known */	if (find_server(ifp, &optinfo0->serverID)) {		dprintf(LOG_INFO, "%s" "duplicated server (ID: %s)",			FNAME, duidstr(&optinfo0->serverID));		return -1;	}	newserver = allocate_newserver(ifp, optinfo0);	if (newserver == NULL)		return (-1);			/* if the server has an extremely high preference, just use it. */	if (newserver->pref == DH6OPT_PREF_MAX) {		ev->timeouts = 0;		ev->state = DHCP6S_REQUEST;		ifp->current_server = newserver;		dhcp6_set_timeoparam(ev);		dhcp6_reset_timer(ev);		client6_send(ev);	} else if (ifp->servers->next == NULL) {		struct timeval *rest, elapsed, tv_rt, tv_irt, timo;		/*		 * If this is the first advertise, adjust the timer so that		 * the client can collect other servers until IRT elapses.		 * XXX: we did not want to do such "low level" timer		 *      calculation here.		 */		rest = dhcp6_timer_rest(ev->timer);		tv_rt.tv_sec = (ev->retrans * 1000) / 1000000;		tv_rt.tv_usec = (ev->retrans * 1000) % 1000000;		tv_irt.tv_sec = (ev->init_retrans * 1000) / 1000000;		tv_irt.tv_usec = (ev->init_retrans * 1000) % 1000000;		timeval_sub(&tv_rt, rest, &elapsed);		if (TIMEVAL_LEQ(elapsed, tv_irt))			timeval_sub(&tv_irt, &elapsed, &timo);		else			timo.tv_sec = timo.tv_usec = 0;		dprintf(LOG_DEBUG, "%s" "reset timer for %s to %d.%06d",			FNAME, ifp->ifname,			(int)timo.tv_sec, (int)timo.tv_usec);		dhcp6_set_timer(&timo, ev->timer);	}	/* if the client send preferred addresses reqeust in SOLICIT */	/* XXX: client might have some local policy to select the addresses */	if (!TAILQ_EMPTY(&optinfo0->addr_list))		dhcp6_copy_list(&request_list, &optinfo0->addr_list);	return 0;}static struct dhcp6_serverinfo *find_server(ifp, duid)	struct dhcp6_if *ifp;	struct duid *duid;{	struct dhcp6_serverinfo *s;	for (s = ifp->servers; s; s = s->next) {		if (duidcmp(&s->optinfo.serverID, duid) == 0)			return (s);	}	return (NULL);}static struct dhcp6_serverinfo *allocate_newserver(ifp, optinfo)	struct dhcp6_if *ifp;	struct dhcp6_optinfo *optinfo;{	struct dhcp6_serverinfo *newserver, **sp;	/* keep the server */	if ((newserver = malloc(sizeof(*newserver))) == NULL) {		dprintf(LOG_ERR, "%s" "memory allocation failed for server",			FNAME);		return (NULL);	}	memset(newserver, 0, sizeof(*newserver));	dhcp6_init_options(&newserver->optinfo);	if (dhcp6_copy_options(&newserver->optinfo, optinfo)) {		dprintf(LOG_ERR, "%s" "failed to copy options", FNAME);		free(newserver);		return (NULL);	}	dprintf(LOG_DEBUG, "%s" "new server DUID %s, len %d ", 		FNAME, duidstr(&newserver->optinfo.serverID), 		newserver->optinfo.serverID.duid_len);	if (optinfo->pref != DH6OPT_PREF_UNDEF)		newserver->pref = optinfo->pref;	if (optinfo->flags & DHCIFF_UNICAST)		memcpy(&newserver->server_addr, &optinfo->server_addr,		       sizeof(newserver->server_addr));	newserver->active = 1;	for (sp = &ifp->servers; *sp; sp = &(*sp)->next) {		if ((*sp)->pref != DH6OPT_PREF_MAX &&		    (*sp)->pref < newserver->pref) {			break;		}	}	newserver->next = *sp;	*sp = newserver;	return newserver;}voidfree_servers(ifp)	struct dhcp6_if *ifp;{	struct dhcp6_serverinfo *sp, *sp_next;	/* free all servers we've seen so far */	for (sp = ifp->servers; sp; sp = sp_next) {		sp_next = sp->next;		dprintf(LOG_DEBUG, "%s" "removing server (ID: %s)",		    FNAME, duidstr(&sp->optinfo.serverID));		dhcp6_clear_options(&sp->optinfo);		free(sp);	}	ifp->servers = NULL;	ifp->current_server = NULL;}static intclient6_recvreply(ifp, dh6, len, optinfo)	struct dhcp6_if *ifp;	struct dhcp6 *dh6;	ssize_t len;	struct dhcp6_optinfo *optinfo;{	struct dhcp6_listval *lv;	struct dhcp6_event *ev;	int addr_status_code = DH6OPT_STCODE_UNSPECFAIL;	struct dhcp6_serverinfo *newserver;	int newstate = 0;	/* find the corresponding event based on the received xid */	dprintf(LOG_DEBUG, "%s" "reply message XID is (%x)",		FNAME, ntohl(dh6->dh6_xid) & DH6_XIDMASK);	ev = find_event_withid(ifp, ntohl(dh6->dh6_xid) & DH6_XIDMASK);	if (ev == NULL) {		dprintf(LOG_INFO, "%s" "XID mismatch", FNAME);		return -1;	}	if (!(DHCP6S_VALID_REPLY(ev->state)) &&	    (ev->state != DHCP6S_SOLICIT ||	     !(optinfo->flags & DHCIFF_RAPID_COMMIT))) {		dprintf(LOG_INFO, "%s" "unexpected reply", FNAME);		return -1;	}	dhcp6_clear_list(&request_list);	/* A Reply message must contain a Server ID option */	if (optinfo->serverID.duid_len == 0) {		dprintf(LOG_INFO, "%s" "no server ID option", FNAME);		return -1;	}	dprintf(LOG_DEBUG, "%s" "serverID is %s len is %d", FNAME,		duidstr(&optinfo->serverID), optinfo->serverID.duid_len); 

⌨️ 快捷键说明

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