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

📄 dhcp6s.c

📁 IPv6环境下的DHCP实现
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* message validation according to Section 15.7 of dhcpv6-26 */	/* 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;	}	/* the message must not include a server Identifier option */	if (optinfo->serverID.duid_len) {		dprintf(LOG_INFO, "%s" "server ID option is included in "		    "a rebind message", 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;	}	/*	 * 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);		/* add the prefix */		if (dhcp6_add_listval(&roptinfo.prefix_list, binding->val,		    DHCP6_LISTVAL_PREFIX6) == NULL) {			dprintf(LOG_ERR, "failed to add a rebound prefix",			    FNAME);			goto fail;		}	}	/* add other configuration information */	/* DNS server */	if (dhcp6_copy_list(&roptinfo.dns_list, &dnslist)) {		dprintf(LOG_ERR, "%s" "failed to copy DNS list");		goto fail;	}	/* how about other prefixes? */	(void)server6_send(DH6_REPLY, ifp, dh6, optinfo, from, fromlen,			   &roptinfo);	dhcp6_clear_options(&roptinfo);	return 0;  fail:	dhcp6_clear_options(&roptinfo);	return -1;}static intserver6_react_informreq(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;	int error;	/* if a server information is included, it must match ours. */	if (optinfo->serverID.duid_len &&	    duidcmp(&optinfo->serverID, &server_duid)) {		dprintf(LOG_INFO, "%s" "server DUID mismatch", 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 provided) */	if (optinfo->clientID.duid_id &&	    duidcpy(&roptinfo.clientID, &optinfo->clientID)) {		dprintf(LOG_ERR, "%s" "failed to copy client ID", FNAME);		goto fail;	}	/* DNS server */	if (dhcp6_copy_list(&roptinfo.dns_list, &dnslist)) {		dprintf(LOG_ERR, "%s" "failed to copy DNS servers", FNAME);		goto fail;	}	error = server6_send(DH6_REPLY, ifp, dh6, optinfo, from, fromlen,	    &roptinfo);	dhcp6_clear_options(&roptinfo);	return(error);  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;	if (transmit_sa(outsock, (struct sockaddr *)&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 intcreate_conflist(type, clientid, ret_list, conf_list, req_list, do_binding)	dhcp6_conftype_t type;	struct duid *clientid;	struct dhcp6_list *ret_list, *conf_list, *req_list;	int do_binding;{	struct dhcp6_listval *clv;	struct dhcp6_binding *binding;	void *val;	if (conf_list == NULL)		return 0;	/* sanity check about type */	switch(type) {	case DHCP6_CONFINFO_PREFIX:		break;	default:		dprintf(LOG_ERR, "%s" "unexpected configuration type(%d)",			FNAME, type);		exit(1);	}	for (clv = TAILQ_FIRST(conf_list); clv; clv = TAILQ_NEXT(clv, link)) {		struct dhcp6_listval *dl;		/* 		 * If the client explicitly specified a list of option values,		 * we only return those specified values (if authorized). 		 */		if (req_list) {			switch(type) {			case DHCP6_CONFINFO_PREFIX:				if (dhcp6_find_listval(req_list,				    &clv->val_prefix6,				    DHCP6_LISTVAL_PREFIX6) == NULL) {					continue;				}				break;			}		}		/*		 * TODO: check if the requesting router is authorized.		 */		;		/*		 * If we already have a binding for the prefix, the request		 * is probably being retransmitted or the information is being		 * renewed.  Then just update the timer of the binding.		 * Otherwise, create a binding for the prefix.		 */		if (do_binding) {			if ((binding = find_binding(clientid, type, &clv->uv)))				update_binding(binding);			else if ((binding = add_binding(clientid, type,							&clv->uv)) == NULL) {				dprintf(LOG_ERR, "%s" "failed to create a "					"binding");				continue;			}			val = binding->val;		} else			val = (void *)&clv->uv;		/* add the entry to the returned list */		if ((dl = malloc(sizeof(*dl))) == NULL) {			dprintf(LOG_ERR, "%s" "failed to allocate "				"memory for prefix", FNAME);			continue; /* XXX: remove binding? */		}		switch(type) {		case DHCP6_CONFINFO_PREFIX:			dl->val_prefix6 = *(struct dhcp6_prefix *)val;			break;		}		TAILQ_INSERT_TAIL(ret_list, dl, link);	}	return 0;}static struct dhcp6_binding *add_binding(clientid, type, val0)	struct duid *clientid;	dhcp6_conftype_t type;	void *val0;{	struct dhcp6_binding *binding = NULL;	u_int32_t duration = DHCP6_DURATITION_INFINITE;	char *val = NULL;	if ((binding = malloc(sizeof(*binding))) == NULL) {		dprintf(LOG_ERR, "%s" "failed to allocate memory", FNAME);		return(NULL);	}	memset(binding, 0, sizeof(*binding));	binding->type = type;	if (duidcpy(&binding->clientid, clientid)) {		dprintf(LOG_ERR, "%s" "failed to copy DUID");		goto fail;	}	switch(type) {	case DHCP6_CONFINFO_PREFIX:		duration = ((struct dhcp6_prefix *)val0)->duration;		if ((val = malloc(sizeof(struct dhcp6_prefix))) == NULL) {			dprintf(LOG_ERR, "%s" "failed to allocate memory for "				"prefix");			goto fail;		}		memcpy(val, val0, sizeof(struct dhcp6_prefix));		binding->val = val;		break;	default:		dprintf(LOG_ERR, "%s" "unexpected binding type(%d)", FNAME,			type);		exit(1);	}	binding->duration = duration;	if (duration != DHCP6_DURATITION_INFINITE) {		struct timeval timo;		binding->timer = dhcp6_add_timer(binding_timo, binding);		if (binding->timer == NULL) {			dprintf(LOG_ERR, "%s" "failed to add timer", FNAME);			goto fail;		}		timo.tv_sec = (long)duration;		timo.tv_usec = 0;		dhcp6_set_timer(&timo, binding->timer);	}	TAILQ_INSERT_TAIL(&dhcp6_binding_head, binding, link);	dprintf(LOG_DEBUG, "%s" "add a new binding %s for %s", FNAME,		bindingstr(binding), duidstr(clientid));	return(binding);  fail:	if (binding) {		duidfree(&binding->clientid);		free(binding);	}	if (val)		free(val);	return(NULL);}static struct dhcp6_binding *find_binding(clientid, type, val0)	struct duid *clientid;	dhcp6_conftype_t type;	void *val0;{	struct dhcp6_binding *bp;	struct dhcp6_prefix *pfx0, *pfx;	for (bp = TAILQ_FIRST(&dhcp6_binding_head); bp;	     bp = TAILQ_NEXT(bp, link)) {		if (bp->type != type ||		    duidcmp(&bp->clientid, clientid)) {			continue;		}		switch(type) {		case DHCP6_CONFINFO_PREFIX:			pfx0 = (struct dhcp6_prefix *)val0;			pfx = (struct dhcp6_prefix *)bp->val;			if (pfx0->plen == pfx->plen &&			    IN6_ARE_ADDR_EQUAL(&pfx0->addr, &pfx->addr)) {				return(bp);			}			break;		default:			dprintf(LOG_ERR,				"%s" "unexpected binding type(%d)", FNAME,				type);			exit(1);		}	}	return(NULL);}static voidupdate_binding(binding)	struct dhcp6_binding *binding;{	struct timeval timo;	/* if the lease duration is infinite, there's nothing to do. */	if (binding->duration == DHCP6_DURATITION_INFINITE)		return;	/* reset the timer with the duration */	timo.tv_sec = (long)binding->duration;	timo.tv_usec = 0;	dhcp6_set_timer(&timo, binding->timer);	dprintf(LOG_DEBUG, "%s" "update a binding %s for %s", FNAME,		bindingstr(binding), duidstr(&binding->clientid));}static voidremove_binding(binding)	struct dhcp6_binding *binding;{	void *val = binding->val;	dprintf(LOG_DEBUG, "%s" "removing a binding %s for %s", FNAME,		bindingstr(binding), duidstr(&binding->clientid));	if (binding->timer)		dhcp6_remove_timer(&binding->timer);	TAILQ_REMOVE(&dhcp6_binding_head, binding, link);	switch(binding->type) {	case DHCP6_CONFINFO_PREFIX:		dprintf(LOG_INFO, "%s" "remove prefix binding %s/%d for %s",			FNAME,			in6addr2str(&((struct dhcp6_prefix *)val)->addr, 0),			((struct dhcp6_prefix *)val)->plen,			duidstr(&binding->clientid));		free(binding->val);		break;	default:		dprintf(LOG_ERR, "%s" "unexpected binding type(%d)", FNAME,			binding->type);		exit(1);	}	duidfree(&binding->clientid);	free(binding);}static struct dhcp6_timer *binding_timo(arg)	void *arg;{	struct dhcp6_binding *binding = (struct dhcp6_binding *)arg;	remove_binding(binding);	return NULL;}static char *bindingstr(binding)	struct dhcp6_binding *binding;{	struct dhcp6_prefix *pfx;	static char strbuf[LINE_MAX];	/* XXX: thread unsafe */	switch(binding->type) {	case DHCP6_CONFINFO_PREFIX:		pfx = (struct dhcp6_prefix *)binding->val;		snprintf(strbuf, sizeof(strbuf),			 "[prefix: %s/%d, duration=%ld]",			 in6addr2str(&pfx->addr, 0), pfx->plen,			 binding->duration);		break;	default:		dprintf(LOG_ERR, "%s" "unexpected binding type(%d)", FNAME,			binding->type);		exit(1);	}	return(strbuf);}

⌨️ 快捷键说明

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