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

📄 dhcp6s.c

📁 IPv6环境下的DHCP实现
💻 C
📖 第 1 页 / 共 3 页
字号:
	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;	}	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;	}	if ((ifp = find_ifconfbyid((unsigned int)pi->ipi6_ifindex)) == NULL) {		dprintf(LOG_INFO, "%s" "unexpected interface (%d)", FNAME,		    (unsigned int)pi->ipi6_ifindex);		return;	}	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;	}	switch (dh6->dh6_msgtype) {	case DH6_SOLICIT:		(void)server6_react_solicit(ifp, dh6, &optinfo,		    (struct sockaddr *)&from, fromlen);		break;	case DH6_REQUEST:		(void)server6_react_request(ifp, pi, dh6, &optinfo,		    (struct sockaddr *)&from, fromlen);		break;	case DH6_RENEW:		(void)server6_react_renew(ifp, pi, dh6, &optinfo,		    (struct sockaddr *)&from, fromlen);		break;	case DH6_REBIND:		(void)server6_react_rebind(ifp, dh6, &optinfo,		    (struct sockaddr *)&from, fromlen);		break;	case DH6_INFORM_REQ:		(void)server6_react_informreq(ifp, dh6, &optinfo,		    (struct sockaddr *)&from, fromlen);		break;	default:		dprintf(LOG_INFO, "%s" "unknown or unsupported msgtype %s",		    FNAME, dhcp6msgstr(dh6->dh6_msgtype));		break;	}	dhcp6_clear_options(&optinfo);	return 0;}static intserver6_react_solicit(ifp, dh6, optinfo, from, fromlen)	struct dhcp6_if *ifp;	struct dhcp6 *dh6;	struct dhcp6_optinfo *optinfo;	struct sockaddr *from;	int fromlen;{	struct dhcp6_optinfo roptinfo;	struct host_conf *client_conf;	struct dhcp6_listval *opt;	struct dhcp6_list ret_prefix_list;	int resptype, do_binding = 0, error;	/*	 * Servers MUST discard any Solicit messages that do not include a	 * Client Identifier option. [dhcpv6-26 Section 15.2]	 */	if (optinfo->clientID.duid_len == 0) {		dprintf(LOG_INFO, "%s" "no client ID option", FNAME);		return(-1);	} else {		dprintf(LOG_DEBUG, "%s" "client ID %s", FNAME,			duidstr(&optinfo->clientID));	}	/* get per-host configuration for the client, if any. */	if ((client_conf = find_hostconf(&optinfo->clientID))) {		dprintf(LOG_DEBUG, "%s" "found a host configuration for %s",			FNAME, client_conf->name);	}	/*	 * configure necessary options based on the options in solicit.	 */	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 provided) */	if (optinfo->clientID.duid_id &&	    duidcpy(&roptinfo.clientID, &optinfo->clientID)) {		dprintf(LOG_ERR, "%s" "failed to copy client ID", FNAME);		goto fail;	}	/* preference (if configured) */	if (ifp->server_pref != DH6OPT_PREF_UNDEF)		roptinfo.pref = ifp->server_pref;	/* DNS server */	if (dhcp6_copy_list(&roptinfo.dns_list, &dnslist)) {		dprintf(LOG_ERR, "%s" "failed to copy DNS servers", FNAME);		goto fail;	}	/*	 * see if we have information for requested options, and if so,	 * configure corresponding options.	 */	if (optinfo->rapidcommit && (ifp->allow_flags & DHCIFF_RAPID_COMMIT))		do_binding = 1;	for (opt = TAILQ_FIRST(&optinfo->reqopt_list); opt;	     opt = TAILQ_NEXT(opt, link)) {		switch(opt->val_num) {		case DH6OPT_PREFIX_DELEGATION:			create_conflist(DHCP6_CONFINFO_PREFIX,			    &optinfo->clientID, &roptinfo.prefix_list,			    client_conf ? &client_conf->prefix_list : NULL,			    TAILQ_EMPTY(&optinfo->prefix_list) ?			    NULL : &optinfo->prefix_list,			    do_binding);			break;		}	}	if (optinfo->rapidcommit && (ifp->allow_flags & DHCIFF_RAPID_COMMIT)) {		/*		 * 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-26 Section 17.2.1]		 */		roptinfo.rapidcommit = 1;		resptype = DH6_REPLY;	} else		resptype = DH6_ADVERTISE;	error = server6_send(resptype, ifp, dh6, optinfo, from, fromlen,			     &roptinfo);	dhcp6_clear_options(&roptinfo);	return(error);  fail:	dhcp6_clear_options(&roptinfo);	return -1;}static intserver6_react_request(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;	struct host_conf *client_conf;	struct dhcp6_listval *opt, *p;	/* message validation according to Section 15.4 of dhcpv6-26 */	/* the message must include a Server Identifier option */	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, "%s" "server ID mismatch", FNAME);		return -1;	}	/* 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;	}	/*	 * 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;	}	/*	 * 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]	 * (Our current implementation never sends a unicast option.)	 */	if (!IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr)) {		int stcode = DH6OPT_STCODE_USEMULTICAST;		dprintf(LOG_INFO, "%s" "unexpected unicast message from %s",		    FNAME, addr2str(from));		if (dhcp6_add_listval(&roptinfo.stcode_list, &stcode,		    DHCP6_LISTVAL_NUM) == NULL) {			dprintf(LOG_ERR, "%s" "failed to add a status code",			    FNAME);			goto fail;		}		server6_send(DH6_REPLY, ifp, dh6, optinfo, from,		    fromlen, &roptinfo);		goto end;	}	/* get per-host configuration for the client, if any. */	if ((client_conf = find_hostconf(&optinfo->clientID))) {		dprintf(LOG_DEBUG, "%s" "found a host configuration named %s",			FNAME, client_conf->name);	}	/*	 * See if we have to make a binding of some configuration information	 * for the client.	 * (Note that our implementation does not assign addresses (nor will)).	 */	/* prefixes */	create_conflist(DHCP6_CONFINFO_PREFIX,	    &optinfo->clientID, &roptinfo.prefix_list,	    client_conf ? &client_conf->prefix_list : NULL,	    &optinfo->prefix_list,	    1);	/*	 * 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 0	for (opt = TAILQ_FIRST(&optinfo->reqopt_list); opt;	     opt = TAILQ_NEXT(opt, link)) {		;	}#endif	/*	 * Adds options to the Reply message for any other configuration	 * information to be assigned to the client.	 */	/* DNS server */	if (dhcp6_copy_list(&roptinfo.dns_list, &dnslist)) {		dprintf(LOG_ERR, "%s" "failed to copy DNS servers", FNAME);		goto fail;	}	/* send a reply message. */	(void)server6_send(DH6_REPLY, ifp, dh6, optinfo, from, fromlen,			   &roptinfo);  end:	dhcp6_clear_options(&roptinfo);	return 0;  fail:	dhcp6_clear_options(&roptinfo);	return -1;}static intserver6_react_renew(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;	struct dhcp6_listval *lv;	struct dhcp6_binding *binding;	int add_success = 0;	/* message validation according to Section 15.6 of dhcpv6-26 */	/* the message must include a Server Identifier option */	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, "%s" "server ID mismatch", FNAME);		return -1;	}	/* 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;	}	/*	 * 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;	}	/*	 * When the server receives a Renew 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.3]	 * (Our current implementation never sends a unicast option.)	 */	if (!IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr)) {		int stcode = DH6OPT_STCODE_USEMULTICAST;		dprintf(LOG_INFO, "%s" "unexpected unicast message from %s",		    FNAME, addr2str(from));		if (dhcp6_add_listval(&roptinfo.stcode_list, &stcode,		    DHCP6_LISTVAL_NUM) == NULL) {			dprintf(LOG_ERR, "%s" "failed to add a status code",			    FNAME);			goto fail;		}		server6_send(DH6_REPLY, ifp, dh6, optinfo, from,		    fromlen, &roptinfo);		goto end;	}	/*	 * Locates the client's binding and verifies that the information	 * from the client matches the information stored for that client.	 */	/* prefixes */	for (lv = TAILQ_FIRST(&optinfo->prefix_list); lv;	     lv = TAILQ_NEXT(lv, link)) {		binding = find_binding(&optinfo->clientID,				       DHCP6_CONFINFO_PREFIX,				       &lv->val_prefix6);		if (binding == NULL) {			dprintf(LOG_INFO, "%s" "can't find a binding of prefix"				" %s/%d for %s", FNAME,				in6addr2str(&lv->val_prefix6.addr, 0),				lv->val_prefix6.plen,				duidstr(&optinfo->clientID));			continue; /* XXX: is this okay? */		}		/* we always extend the requested binding. */		update_binding(binding);		/* include a Status Code option with value Success. */		if (!add_success) {			int stcode = DH6OPT_STCODE_SUCCESS;			if (dhcp6_add_listval(&roptinfo.stcode_list,			    &stcode, DHCP6_LISTVAL_NUM) == NULL) {				dprintf(LOG_ERR, "%s" "failed to add a "				    "status code", FNAME);			}			add_success = 1;		}		/* add the prefix */		if (dhcp6_add_listval(&roptinfo.prefix_list, binding->val,		    DHCP6_LISTVAL_PREFIX6) == NULL) {			dprintf(LOG_ERR, "%s" "failed to add a renewed prefix",			    FNAME);			goto fail;		}	}	(void)server6_send(DH6_REPLY, ifp, dh6, optinfo, from, fromlen,			   &roptinfo);  end:	dhcp6_clear_options(&roptinfo);	return 0;  fail:	dhcp6_clear_options(&roptinfo);	return -1;}static intserver6_react_rebind(ifp, dh6, optinfo, from, fromlen)	struct dhcp6_if *ifp;	struct dhcp6 *dh6;	struct dhcp6_optinfo *optinfo;	struct sockaddr *from;	int fromlen;{	struct dhcp6_optinfo roptinfo;	struct dhcp6_listval *lv;	struct dhcp6_binding *binding;	int add_success = 0;

⌨️ 快捷键说明

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