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

📄 dhcp6s.c

📁 DHCPv6协议在Linux操作系统下的一个客户端实现。
💻 C
📖 第 1 页 / 共 2 页
字号:
	struct iovec iov;	char cmsgbuf[BUFSIZ];	struct cmsghdr *cm;	struct in6_pktinfo *pi = NULL;	struct dhcp6_if *ifp;	struct dhcp6 *dh6;	struct dhcp6_optinfo optinfo;	memset(&iov, 0, sizeof(iov));	memset(&mhdr, 0, sizeof(mhdr));	iov.iov_base = rdatabuf;	iov.iov_len = sizeof(rdatabuf);	mhdr.msg_name = &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 -1;	}	fromlen = mhdr.msg_namelen;	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 -1;	}	dprintf(LOG_DEBUG, "received message packet info addr is %s, scope id (%d)",	    in6addr2str(&pi->ipi6_addr, 0), (unsigned int)pi->ipi6_ifindex);	if ((ifp = find_ifconfbyid((unsigned int)pi->ipi6_ifindex)) == NULL) {		dprintf(LOG_INFO, "%s" "unexpected interface (%d)", FNAME,		    (unsigned int)pi->ipi6_ifindex);		return -1;	}	if (len < sizeof(*dh6)) {		dprintf(LOG_INFO, "%s" "short packet", FNAME);		return -1;	}		dh6 = (struct dhcp6 *)rdatabuf;	dprintf(LOG_DEBUG, "%s" "received %s from %s", FNAME,	    dhcp6msgstr(dh6->dh6_msgtype),	    addr2str((struct sockaddr *)&from));	/*	 * parse and validate options in the request	 */	dhcp6_init_options(&optinfo);	if (dhcp6_get_options((struct dhcp6opt *)(dh6 + 1),	    (struct dhcp6opt *)(rdatabuf + len), &optinfo) < 0) {		dprintf(LOG_INFO, "%s" "failed to parse options", FNAME);		return -1;	}	/* check host decl first */	host = dhcp6_allocate_host(ifp, globalgroup, &optinfo);	/* ToDo: allocate subnet after relay agent done	 * now assume client is on the same link as server	 * if the subnet couldn't be found return status code NotOnLink to client	 */	subnet = dhcp6_allocate_link(ifp, globalgroup, NULL);	if (!(DH6_VALID_MESSAGE(dh6->dh6_msgtype)))		dprintf(LOG_INFO, "%s" "unknown or unsupported msgtype %s",		    FNAME, dhcp6msgstr(dh6->dh6_msgtype));	else		server6_react_message(ifp, pi, dh6, &optinfo,			(struct sockaddr *)&from, fromlen);	dhcp6_clear_options(&optinfo);	return 0;}static intserver6_react_message(ifp, pi, dh6, optinfo, from, fromlen)	struct dhcp6_if *ifp;	struct in6_pktinfo *pi;	struct dhcp6 *dh6;	struct dhcp6_optinfo *optinfo;	struct sockaddr *from;	int fromlen;{	struct dhcp6_optinfo roptinfo;		int addr_flag = 0;	int addr_request = 0;	int resptype = DH6_REPLY;	int num = DH6OPT_STCODE_SUCCESS;	int sending_hint = 0;	/* message validation according to Section 18.2 of dhcpv6-28 */	/* the message must include a Client Identifier option */	if (optinfo->clientID.duid_len == 0) {		dprintf(LOG_INFO, "%s" "no server ID option", FNAME);		return -1;	} else {		dprintf(LOG_DEBUG, "%s" "client ID %s", FNAME,			duidstr(&optinfo->clientID));	}	/* the message must include a Server Identifier option in below messages*/	switch (dh6->dh6_msgtype) {	case DH6_REQUEST:	case DH6_RENEW:        case DH6_DECLINE:	case DH6_RELEASE:		if (optinfo->serverID.duid_len == 0) {			dprintf(LOG_INFO, "%s" "no server ID option", FNAME);			return -1;		}		/* the contents of the Server Identifier option must match ours */		if (duidcmp(&optinfo->serverID, &server_duid)) {			dprintf(LOG_INFO, "server ID %s mismatch %s", 				duidstr(&optinfo->serverID), duidstr(&server_duid));			return -1;		}		break;	default:		break;	}	/*	 * configure necessary options based on the options in request.	 */	dhcp6_init_options(&roptinfo);	/* server information option */	if (duidcpy(&roptinfo.serverID, &server_duid)) {		dprintf(LOG_ERR, "%s" "failed to copy server ID", FNAME);		goto fail;	}	/* copy client information back */	if (duidcpy(&roptinfo.clientID, &optinfo->clientID)) {		dprintf(LOG_ERR, "%s" "failed to copy client ID", FNAME);		goto fail;	}	/* if the client is not on the link */	if (host == NULL && subnet == NULL) {		num = DH6OPT_STCODE_NOTONLINK; 		/* Draft-28 18.2.2, drop the message if NotOnLink */		if (dh6->dh6_msgtype == DH6_CONFIRM || dh6->dh6_msgtype == DH6_REBIND)			goto fail;		else			goto send;	}	if (subnet) {		roptinfo.pref = subnet->linkscope.server_pref;		roptinfo.flags = (optinfo->flags & subnet->linkscope.allow_flags) |				subnet->linkscope.send_flags;		dnslist = subnet->linkscope.dnslist;	}	if (host) {		roptinfo.pref = host->hostscope.server_pref;		roptinfo.flags = (optinfo->flags & host->hostscope.allow_flags) |				host->hostscope.send_flags;		dnslist = host->hostscope.dnslist;	}	/* prohibit a mixture of old and new style of DNS server config */	if (!TAILQ_EMPTY(&arg_dnslist.addrlist)) {		if (!TAILQ_EMPTY(&dnslist.addrlist)) {			dprintf(LOG_INFO, "%s" "do not specify DNS servers "			    "both by command line and by configuration file.",			    FNAME);			exit(1);		}		dnslist = arg_dnslist;		TAILQ_INIT(&arg_dnslist.addrlist);	}	dprintf(LOG_DEBUG, "server preference is %2x", roptinfo.pref);	if (roptinfo.flags & DHCIFF_UNICAST) {		/* todo find the right server unicast address to client*/		/* get_linklocal(device, &roptinfo.server_addr) */		memcpy(&roptinfo.server_addr, &ifp->linklocal,		       sizeof(roptinfo.server_addr));		dprintf(LOG_DEBUG, "%s" "server address is %s",			FNAME, in6addr2str(&roptinfo.server_addr, 0));	}	/*	 * When the server receives a Request message via unicast from a	 * client to which the server has not sent a unicast option, the server	 * discards the Request message and responds with a Reply message	 * containing a Status Code option with value UseMulticast, a Server	 * Identifier option containing the server's DUID, the Client	 * Identifier option from the client message and no other options.	 * [dhcpv6-26 18.2.1]	 */	switch (dh6->dh6_msgtype) {	case DH6_REQUEST:	case DH6_RENEW:	case DH6_DECLINE:		if (!IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr)) {			if (!(roptinfo.flags & DHCIFF_UNICAST)) {				num = DH6OPT_STCODE_USEMULTICAST;				goto send;			} else				break;		} 	default:		if (!IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr)) {			num = DH6OPT_STCODE_USEMULTICAST;			goto send;		}		break;	}	switch (dh6->dh6_msgtype) {	case DH6_SOLICIT: 		/*		 * If the client has included a Rapid Commit option and the		 * server has been configured to respond with committed address		 * assignments and other resources, responds to the Solicit		 * with a Reply message.		 * [dhcpv6-28 Section 17.2.1]		 * [dhcpv6-28 Section 17.2.2]		 * If Solicit has IA option, responds to Solicit with a Advertise		 * message.		 */		if (optinfo->iaidinfo.iaid != 0 && !(roptinfo.flags & DHCIFF_INFO_ONLY)) {			memcpy(&roptinfo.iaidinfo, &optinfo->iaidinfo, 					sizeof(roptinfo.iaidinfo));			roptinfo.type = optinfo->type;			dprintf(LOG_DEBUG, "option type is %d", roptinfo.type);			addr_request = 1;			if (roptinfo.flags & DHCIFF_RAPID_COMMIT) {				resptype = DH6_REPLY;			} else {				resptype = DH6_ADVERTISE;				/* giving hint ?? */				sending_hint = 1;			}			}		break;	case DH6_INFORM_REQ:		/* don't response to info-req if there is any IA option */		if (optinfo->iaidinfo.iaid != 0)			goto fail;		/* DNS server */		if (dhcp6_copy_list(&roptinfo.dns_list.addrlist, &dnslist.addrlist)) {			dprintf(LOG_ERR, "%s" "failed to copy DNS servers", FNAME);			goto fail;		}		roptinfo.dns_list.domainlist = dnslist.domainlist;		break;	case DH6_REQUEST:		/* get iaid for that request client for that interface */		if (optinfo->iaidinfo.iaid != 0 && !(roptinfo.flags & DHCIFF_INFO_ONLY)) {			memcpy(&roptinfo.iaidinfo, &optinfo->iaidinfo, 					sizeof(roptinfo.iaidinfo));			roptinfo.type = optinfo->type;			addr_request = 1;		} 		break;	/*	 * Locates the client's binding and verifies that the information	 * from the client matches the information stored for that client.	 */	case DH6_RENEW:	case DH6_REBIND:	case DH6_DECLINE:	case DH6_RELEASE:	case DH6_CONFIRM:		roptinfo.type = optinfo->type;		/* XXX: how server knows the difference between rebind_confirm and rebind 		 * for prefix delegation ?*/		if (dh6->dh6_msgtype == DH6_RENEW || dh6->dh6_msgtype == DH6_REBIND)			addr_flag = ADDR_UPDATE;		if (dh6->dh6_msgtype == DH6_RELEASE)			addr_flag = ADDR_REMOVE;		if (dh6->dh6_msgtype == DH6_CONFIRM) {			/* DNS server */			addr_flag = ADDR_VALIDATE;			if (dhcp6_copy_list(&roptinfo.dns_list.addrlist, &dnslist.addrlist)) {				dprintf(LOG_ERR, "%s" "failed to copy DNS servers", FNAME);				goto fail;			}			roptinfo.dns_list.domainlist = dnslist.domainlist;		}		if (dh6->dh6_msgtype == DH6_DECLINE)			addr_flag = ADDR_ABANDON;	if (optinfo->iaidinfo.iaid != 0) {		if (!TAILQ_EMPTY(&optinfo->addr_list) && resptype != DH6_ADVERTISE) {			struct dhcp6_iaidaddr *iaidaddr;			memcpy(&roptinfo.iaidinfo, &optinfo->iaidinfo, 					sizeof(roptinfo.iaidinfo));			roptinfo.type = optinfo->type;			/* find bindings */			if ((iaidaddr = dhcp6_find_iaidaddr(&roptinfo)) == NULL) {				if (dh6->dh6_msgtype == DH6_REBIND)					goto fail;				num = DH6OPT_STCODE_NOBINDING;				dprintf(LOG_INFO, "%s" "Nobinding for client %s iaid %u",					FNAME, duidstr(&optinfo->clientID), 						optinfo->iaidinfo.iaid);				break;			}			if (addr_flag != ADDR_UPDATE) {				dhcp6_copy_list(&roptinfo.addr_list, &optinfo->addr_list);			} else {				/* get static host configuration */				if (host)					dhcp6_get_hostconf(&roptinfo, optinfo, iaidaddr, host);				/* allow dynamic address assginment for the host too */				if (optinfo->type == IAPD)					dhcp6_create_prefixlist(&roptinfo, 								optinfo, 								iaidaddr, 								subnet);				else					dhcp6_create_addrlist(&roptinfo, optinfo, 							iaidaddr, subnet);				/* in case there is not bindings available */				if (TAILQ_EMPTY(&roptinfo.addr_list)) {					num = DH6OPT_STCODE_NOBINDING;					dprintf(LOG_INFO, "%s" 					    "Bindings are not on link for client %s iaid %u",						FNAME, duidstr(&optinfo->clientID), 						roptinfo.iaidinfo.iaid);					break;				}			}			if (addr_flag == ADDR_VALIDATE) {				if (dhcp6_validate_bindings(&roptinfo, iaidaddr))					num = DH6OPT_STCODE_NOBINDING;				break;			} else {				/* do update if this is not a confirm */				if (dhcp6_update_iaidaddr(&roptinfo, addr_flag) 						!= 0) {					dprintf(LOG_INFO, "%s" 						"bindings failed for client %s iaid %u",						FNAME, duidstr(&optinfo->clientID), 							roptinfo.iaidinfo.iaid);					num = DH6OPT_STCODE_UNSPECFAIL;					break;				}			}			num = DH6OPT_STCODE_SUCCESS;		} else 			num = DH6OPT_STCODE_NOADDRAVAIL;	} else 		dprintf(LOG_ERR, "invalid message type");		break;	default:		break;	}	/* 	 * XXX: see if we have information for requested options, and if so, 	 * configure corresponding options. 	 */	/*	 * If the Request message contained an Option Request option, the	 * server MUST include options in the Reply message for any options in	 * the Option Request option the server is configured to return to the	 * client.	 * [dhcpv6-26 18.2.1]	 * Note: our current implementation always includes all information	 * that we can provide.  So we do not have to check the option request	 * options.	 */	if (addr_request == 1) {		int found_binding = 0;		struct dhcp6_iaidaddr *iaidaddr;		/* find bindings */		if ((iaidaddr = dhcp6_find_iaidaddr(&roptinfo)) != NULL) {			found_binding = 1;			addr_flag = ADDR_UPDATE;		}		if (host)			dhcp6_get_hostconf(&roptinfo, optinfo, iaidaddr, host);		/* valid and create addresses list */		if (optinfo->type == IAPD)			dhcp6_create_prefixlist(&roptinfo, optinfo, iaidaddr, subnet);		else			dhcp6_create_addrlist(&roptinfo, optinfo, iaidaddr, subnet);		if (TAILQ_EMPTY(&roptinfo.addr_list)) {			num = DH6OPT_STCODE_NOADDRAVAIL;		} else if (sending_hint == 0) {		/* valid client request address list */			if (found_binding) {			       if (dhcp6_update_iaidaddr(&roptinfo, addr_flag) != 0) {					dprintf(LOG_ERR,					"assigned ipv6address for client iaid %u failed",						roptinfo.iaidinfo.iaid);					num = DH6OPT_STCODE_UNSPECFAIL;			       } else					num = DH6OPT_STCODE_SUCCESS;			} else {			       	if (dhcp6_add_iaidaddr(&roptinfo) != 0) {					dprintf(LOG_ERR, 					"assigned ipv6address for client iaid %u failed",						roptinfo.iaidinfo.iaid);					num = DH6OPT_STCODE_UNSPECFAIL;				} else					num = DH6OPT_STCODE_SUCCESS;			}		}		/* DNS server */		if (dhcp6_copy_list(&roptinfo.dns_list.addrlist, &dnslist.addrlist)) {			dprintf(LOG_ERR, "%s" "failed to copy DNS servers", FNAME);			goto fail;		}		roptinfo.dns_list.domainlist = dnslist.domainlist;	}	/* add address status code */  send:	dprintf(LOG_DEBUG, " status code: %s", dhcp6_stcodestr(num));	if (dhcp6_add_listval(&roptinfo.stcode_list,	   	&num, DHCP6_LISTVAL_NUM) == NULL) {		dprintf(LOG_ERR, "%s" "failed to copy "	    		"status code", FNAME);		goto fail;	}	/* send a reply message. */	(void)server6_send(resptype, ifp, dh6, optinfo, from, fromlen,			   &roptinfo);	dhcp6_clear_options(&roptinfo);	return 0;  fail:	dhcp6_clear_options(&roptinfo);	return -1;}static intserver6_send(type, ifp, origmsg, optinfo, from, fromlen, roptinfo)	int type;	struct dhcp6_if *ifp;	struct dhcp6 *origmsg;	struct dhcp6_optinfo *optinfo, *roptinfo;	struct sockaddr *from;	int fromlen;{	char replybuf[BUFSIZ];	struct sockaddr_in6 dst;	int len, optlen;	struct dhcp6 *dh6;	if (sizeof(struct dhcp6) > sizeof(replybuf)) {		dprintf(LOG_ERR, "%s" "buffer size assumption failed", FNAME);		return (-1);	}	dh6 = (struct dhcp6 *)replybuf;	len = sizeof(*dh6);	memset(dh6, 0, sizeof(*dh6));	dh6->dh6_msgtypexid = origmsg->dh6_msgtypexid;	dh6->dh6_msgtype = (u_int8_t)type;	/* set options in the reply message */	if ((optlen = dhcp6_set_options((struct dhcp6opt *)(dh6 + 1),					(struct dhcp6opt *)(replybuf +							    sizeof(replybuf)),					roptinfo)) < 0) {		dprintf(LOG_INFO, "%s" "failed to construct reply options",			FNAME);		return (-1);	}	len += optlen;	/* specify the destination and send the reply */	dst = *sa6_any_downstream;	dst.sin6_addr = ((struct sockaddr_in6 *)from)->sin6_addr;	dst.sin6_scope_id = ((struct sockaddr_in6 *)from)->sin6_scope_id;	dprintf(LOG_DEBUG, "send destination address is %s, scope id is %d", 		addr2str((struct sockaddr *)&dst), dst.sin6_scope_id);	if (transmit_sa(outsock, &dst, replybuf, len) != 0) {		dprintf(LOG_ERR, "%s" "transmit %s to %s failed", FNAME,			dhcp6msgstr(type), addr2str((struct sockaddr *)&dst));		return (-1);	}	dprintf(LOG_DEBUG, "%s" "transmit %s to %s", FNAME,		dhcp6msgstr(type), addr2str((struct sockaddr *)&dst));	return 0;}static struct dhcp6_timer*check_lease_file_timo(void *arg){	double d;	struct timeval timo;	struct stat buf;	FILE *file;	stat(PATH_SERVER6_LEASE, &buf);	strcpy(server6_lease_temp, PATH_SERVER6_LEASE);	strcat(server6_lease_temp, "XXXXXX");		if (buf.st_size > MAX_FILE_SIZE) {		file = sync_leases(server6_lease_file, PATH_SERVER6_LEASE, server6_lease_temp);		if (file != NULL)			server6_lease_file = file;	}	d = DHCP6_SYNCFILE_TIME;	timo.tv_sec = (long)d;	timo.tv_usec = 0;	dhcp6_set_timer(&timo, sync_lease_timer);	return sync_lease_timer;}

⌨️ 快捷键说明

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