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

📄 common.c

📁 DHCPv6协议在Linux操作系统下的一个客户端实现。
💻 C
📖 第 1 页 / 共 4 页
字号:
					    dhcp6optstr(opttype));					goto nextoption;				}				if (dhcp6_add_listval(&optinfo->reqopt_list,				    &num, DHCP6_LISTVAL_NUM) == NULL) {					dprintf(LOG_ERR, "%s" "failed to copy "					    "requested option", FNAME);					goto fail;				}			nextoption: ;			}			break;		case DH6OPT_PREFERENCE:			if (optlen != 1)				goto malformed;			optinfo->pref = (u_int8_t)*(u_char *)cp;			dprintf(LOG_DEBUG, "%s" "get option preferrence is %2x", 					FNAME, optinfo->pref);			break;		case DH6OPT_RAPID_COMMIT:			if (optlen != 0)				goto malformed;			optinfo->flags |= DHCIFF_RAPID_COMMIT;			break;		case DH6OPT_UNICAST:			if (optlen != sizeof(struct in6_addr)			    && dhcp6_mode != DHCP6_MODE_CLIENT)				goto malformed;			optinfo->flags |= DHCIFF_UNICAST;			memcpy(&optinfo->server_addr,			       (struct in6_addr *)cp, sizeof(struct in6_addr));			break;		case DH6OPT_IA_TA:			if (optlen < sizeof(u_int32_t))				goto malformed;			/* check iaid */			optinfo->flags |= DHCIFF_TEMP_ADDRS;			optinfo->type = IATA;			dprintf(LOG_DEBUG, "%s" "get option iaid is %u", 				FNAME, optinfo->iaidinfo.iaid);			optinfo->iaidinfo.iaid = ntohl(*(u_int32_t *)cp);			if (get_assigned_ipv6addrs(cp + 4, cp + optlen, optinfo))				goto fail;			break;		case DH6OPT_IA_NA:		case DH6OPT_IA_PD:			if (opt == DH6OPT_IA_NA)				optinfo->type = IANA;			else if (opt == DH6OPT_IA_PD)				optinfo->type = IAPD;			/* check iaid */			if (optlen < sizeof(struct dhcp6_iaid_info)) 				goto malformed;			optinfo->iaidinfo.iaid = ntohl(*(u_int32_t *)cp);			optinfo->iaidinfo.renewtime = 				ntohl(*(u_int32_t *)(cp + sizeof(u_int32_t)));			optinfo->iaidinfo.rebindtime = 				ntohl(*(u_int32_t *)(cp + 2 * sizeof(u_int32_t)));			dprintf(LOG_DEBUG, "get option iaid is %u, renewtime %u, "				"rebindtime %u", optinfo->iaidinfo.iaid,				optinfo->iaidinfo.renewtime, optinfo->iaidinfo.rebindtime);			if (get_assigned_ipv6addrs(cp + 3 * sizeof(u_int32_t), 						cp + optlen, optinfo))				goto fail;			break;		case DH6OPT_DNS_RESOLVERS:			if (optlen % sizeof(struct in6_addr) || optlen == 0)				goto malformed;			for (val = cp; val < cp + optlen;			     val += sizeof(struct in6_addr)) {				if (dhcp6_find_listval(&optinfo->dns_list.addrlist,				    val, DHCP6_LISTVAL_ADDR6)) {					dprintf(LOG_INFO, "%s" "duplicated "					    "DNS address (%s)", FNAME,					    in6addr2str((struct in6_addr *)val,						0));					goto nextdns;				}				if (dhcp6_add_listval(&optinfo->dns_list.addrlist,				    val, DHCP6_LISTVAL_ADDR6) == NULL) {					dprintf(LOG_ERR, "%s" "failed to copy "					    "DNS address", FNAME);					goto fail;				}			nextdns: ;			}			break;		case DH6OPT_DOMAIN_LIST:			if (optlen == 0)				goto malformed;			/* dependency on lib resolv */			for (val = cp; val < cp + optlen;) {				int n;				struct domain_list *dname, *dlist;				dname = malloc(sizeof(*dname));				if (dname == NULL) {					dprintf(LOG_ERR, "%s" "failed to allocate memory", 						FNAME);					goto fail;				}				n =  dn_expand(cp, cp + optlen, val, dname->name, MAXDNAME);				if (n < 0) 					goto malformed;				else {					val += n;					dprintf(LOG_DEBUG, "expand domain name %s, size %d", 						dname->name, strlen(dname->name));				}				dname->next = NULL;				if (optinfo->dns_list.domainlist == NULL) {					optinfo->dns_list.domainlist = dname;				} else {					for (dlist = optinfo->dns_list.domainlist; dlist;					     dlist = dlist->next) {						if (dlist->next == NULL) {							dlist->next = dname;							break;						}					}				}			}			break;		default:			/* no option specific behavior */			dprintf(LOG_INFO, "%s"			    "unknown or unexpected DHCP6 option %s, len %d",			    FNAME, dhcp6optstr(opt), optlen);			break;		}	}	return (0);  malformed:	dprintf(LOG_INFO, "%s" "malformed DHCP option: type %d, len %d",	    FNAME, opt, optlen);  fail:	dhcp6_clear_options(optinfo);	return (-1);}static intget_assigned_ipv6addrs(p, ep, optinfo)	char *p, *ep;	struct dhcp6_optinfo *optinfo;{	char *np, *cp;	struct dhcp6opt opth;	struct dhcp6_addr_info ai;	struct dhcp6_prefix_info pi;	struct dhcp6_addr addr6;	int optlen, opt;	u_int16_t val16;	int num;		for (; p + sizeof(struct dhcp6opt) <= ep; p = np) {		memcpy(&opth, p, sizeof(opth));		optlen =  ntohs(opth.dh6opt_len);		opt = ntohs(opth.dh6opt_type);		cp = p + sizeof(opth);		np = cp + optlen;		dprintf(LOG_DEBUG, "  IA address option: %s, "			"len %d", dhcp6optstr(opt), optlen);		if (np > ep) {			dprintf(LOG_INFO, "%s" "malformed DHCP options",			    FNAME);			return -1;		}		switch(opt) {		case DH6OPT_STATUS_CODE:			if (optlen < sizeof(val16))				goto malformed;			memcpy(&val16, cp, sizeof(val16));			num = ntohs(val16);			dprintf(LOG_INFO, "status code for this address is: %s",				dhcp6_stcodestr(num));			if (optlen > sizeof(val16)) {				dprintf(LOG_INFO, 					"status message for this address is: %-*s",					(int)(optlen-sizeof(val16)), p+(val16));			}			/* XXX: need to check duplication? */			if (dhcp6_add_listval(&optinfo->stcode_list,			    &num, DHCP6_LISTVAL_NUM) == NULL) {				dprintf(LOG_ERR, "%s" "failed to copy "				    "status code", FNAME);				goto fail;			}			break;		case DH6OPT_IADDR:			if (optlen < sizeof(ai) - sizeof(u_int32_t))				goto malformed;			memcpy(&ai, p, sizeof(ai));			/* copy the information into internal format */			memset(&addr6, 0, sizeof(addr6));			memcpy(&addr6.addr, (struct in6_addr *)cp, sizeof(struct in6_addr));			addr6.preferlifetime = ntohl(ai.preferlifetime);			addr6.validlifetime = ntohl(ai.validlifetime);			dprintf(LOG_DEBUG, "  get IAADR address information: "			    "%s preferlifetime %d validlifetime %d",			    in6addr2str(&addr6.addr, 0),			    addr6.preferlifetime, addr6.validlifetime);			/* It shouldn't happen, since Server will do the check before 			 * sending the data to clients */			if (addr6.preferlifetime > addr6.validlifetime) {				dprintf(LOG_INFO, "preferred life time"				    "(%d) is greater than valid life time"				    "(%d)", addr6.preferlifetime, addr6.validlifetime);				goto malformed;			}			if (optlen == sizeof(ai) - sizeof(u_int32_t)) {				addr6.status_code = DH6OPT_STCODE_UNDEFINE;				break;			}			/* address status code might be added after IADDA option */			memcpy(&opth, p + sizeof(ai), sizeof(opth));			optlen =  ntohs(opth.dh6opt_len);			opt = ntohs(opth.dh6opt_type);			switch(opt) {				case DH6OPT_STATUS_CODE:				if (optlen < sizeof(val16))					goto malformed;				memcpy(&val16, p + sizeof(ai) + sizeof(opth), sizeof(val16));				num = ntohs(val16);				dprintf(LOG_INFO, "status code for this address is: %s",					dhcp6_stcodestr(num));				addr6.status_code = num;				if (optlen > sizeof(val16)) {					dprintf(LOG_INFO, 						"status message for this address is: %-*s",						(int)(optlen-sizeof(val16)), p+(val16));				}				break;			default:				goto malformed;			}			break;		case DH6OPT_IAPREFIX:			if (optlen < sizeof(pi) - sizeof(u_int32_t))			       goto malformed;			memcpy(&pi, p, sizeof(pi));			/* copy the information into internal format */			memset(&addr6, 0, sizeof(addr6));			addr6.preferlifetime = ntohl(pi.preferlifetime);			addr6.validlifetime = ntohl(pi.validlifetime);			addr6.plen = pi.plen;			memcpy(&addr6.addr, &pi.prefix, sizeof(struct in6_addr));			dprintf(LOG_DEBUG, "  get IAPREFIX prefix information: "			    "%s/%d preferlifetime %d validlifetime %d",			    in6addr2str(&addr6.addr, 0), addr6.plen,			    addr6.preferlifetime, addr6.validlifetime);			/* It shouldn't happen, since Server will do the check before 			 * sending the data to clients */			if (addr6.preferlifetime > addr6.validlifetime) {				dprintf(LOG_INFO, "preferred life time"				    "(%d) is greater than valid life time"				    "(%d)", addr6.preferlifetime, addr6.validlifetime);				goto malformed;			}			if (optlen == sizeof(pi) - sizeof(u_int32_t)) {				addr6.status_code = DH6OPT_STCODE_UNDEFINE;				break;			}			/* address status code might be added after IADDA option */			memcpy(&opth, p + sizeof(pi), sizeof(opth));			optlen =  ntohs(opth.dh6opt_len);			opt = ntohs(opth.dh6opt_type);			switch(opt) {				case DH6OPT_STATUS_CODE:				if (optlen < sizeof(val16))					goto malformed;				memcpy(&val16, p + sizeof(pi) + sizeof(opth), sizeof(val16));				num = ntohs(val16);				dprintf(LOG_INFO, "status code for this prefix is: %s",					dhcp6_stcodestr(num));				addr6.status_code = num;				if (optlen > sizeof(val16)) {					dprintf(LOG_INFO, 						"status message for this prefix is: %-*s",						(int)(optlen-sizeof(val16)), p+(val16));				}				break;			default:				goto malformed;			}			break;		default:			goto malformed;		}		/* set up address type */		addr6.type = optinfo->type; 		if (dhcp6_find_listval(&optinfo->addr_list,				&addr6, DHCP6_LISTVAL_DHCP6ADDR)) {			dprintf(LOG_INFO, "duplicated address (%s/%d)", 				in6addr2str(&addr6.addr, 0), addr6.plen);			/* XXX: decline message */			continue;			}		if (dhcp6_add_listval(&optinfo->addr_list, &addr6,		    DHCP6_LISTVAL_DHCP6ADDR) == NULL) {			dprintf(LOG_ERR, "%s" "failed to copy an "			    "address", FNAME);			goto fail;		}	}	return (0);  malformed:	dprintf(LOG_INFO,		"  malformed IA option: type %d, len %d",		opt, optlen);  fail:	return (-1);}#define COPY_OPTION(t, l, v, p) do { \	if ((void *)(ep) - (void *)(p) < (l) + sizeof(struct dhcp6opt)) { \		dprintf(LOG_INFO, "%s" "option buffer short for %s", FNAME, dhcp6optstr((t))); \		goto fail; \	} \	opth.dh6opt_type = htons((t)); \	opth.dh6opt_len = htons((l)); \	memcpy((p), &opth, sizeof(opth)); \	if ((l)) \		memcpy((p) + 1, (v), (l)); \	(p) = (struct dhcp6opt *)((char *)((p) + 1) + (l)); \ 	(len) += sizeof(struct dhcp6opt) + (l); \	dprintf(LOG_DEBUG, "%s" "set %s", FNAME, dhcp6optstr((t))); \} while (0)intdhcp6_set_options(bp, ep, optinfo)	struct dhcp6opt *bp, *ep;	struct dhcp6_optinfo *optinfo;{	struct dhcp6opt *p = bp, opth;	struct dhcp6_listval *stcode;	int len = 0, optlen = 0;	char *tmpbuf = NULL;	if (optinfo->clientID.duid_len) {		COPY_OPTION(DH6OPT_CLIENTID, optinfo->clientID.duid_len,			    optinfo->clientID.duid_id, p);	}	if (optinfo->serverID.duid_len) {		COPY_OPTION(DH6OPT_SERVERID, optinfo->serverID.duid_len,			    optinfo->serverID.duid_id, p);	}	if (dhcp6_mode == DHCP6_MODE_CLIENT) 		COPY_OPTION(DH6OPT_ELAPSED_TIME, 2, &optinfo->elapsed_time, p);	if (optinfo->flags & DHCIFF_RAPID_COMMIT)		COPY_OPTION(DH6OPT_RAPID_COMMIT, 0, NULL, p);	if ((dhcp6_mode == DHCP6_MODE_SERVER) && (optinfo->flags & DHCIFF_UNICAST)) {		if (!IN6_IS_ADDR_UNSPECIFIED(&optinfo->server_addr)) {			COPY_OPTION(DH6OPT_UNICAST, sizeof(optinfo->server_addr),				    &optinfo->server_addr, p);		}	}	switch(optinfo->type) {	int buflen;	char *tp;	u_int32_t iaid;	struct dhcp6_iaid_info opt_iana;	struct dhcp6_iaid_info opt_iapd;	struct dhcp6_prefix_info pi;	struct dhcp6_addr_info ai;	struct dhcp6_status_info status;	struct dhcp6_listval *dp;	case IATA:	case IANA:		if (optinfo->iaidinfo.iaid == 0)			break;		if (optinfo->type == IATA) {			optlen = sizeof(iaid);			dprintf(LOG_DEBUG, "%s" "set IA_TA iaid information: %d", FNAME,				optinfo->iaidinfo.iaid);			iaid = htonl(optinfo->iaidinfo.iaid); 		} else if (optinfo->type == IANA) {			optlen = sizeof(opt_iana);			dprintf(LOG_DEBUG, "set IA_NA iaidinfo: "		   		"iaid %u renewtime %u rebindtime %u", 		   		optinfo->iaidinfo.iaid, optinfo->iaidinfo.renewtime, 		   		optinfo->iaidinfo.rebindtime);			opt_iana.iaid = htonl(optinfo->iaidinfo.iaid);			opt_iana.renewtime = htonl(optinfo->iaidinfo.renewtime);			opt_iana.rebindtime = htonl(optinfo->iaidinfo.rebindtime);		}		buflen = sizeof(opt_iana) + dhcp6_count_list(&optinfo->addr_list) *				(sizeof(ai) + sizeof(status));		tmpbuf = NULL;		if ((tmpbuf = malloc(buflen)) == NULL) {			dprintf(LOG_ERR, "%s"				"memory allocation failed for options", FNAME);			goto fail;		}		if (optinfo->type == IATA) 			memcpy(tmpbuf, &iaid, sizeof(iaid));		else			memcpy(tmpbuf, &opt_iana, sizeof(opt_iana));		tp = tmpbuf + optlen;		optlen += dhcp6_count_list(&optinfo->addr_list) * sizeof(ai);		if (!TAILQ_EMPTY(&optinfo->addr_list)) {			for (dp = TAILQ_FIRST(&optinfo->addr_list); dp; 			     dp = TAILQ_NEXT(dp, link)) {				int iaddr_len = 0;				memset(&ai, 0, sizeof(ai));				ai.dh6_ai_type = htons(DH6OPT_IADDR);				if (dp->val_dhcp6addr.status_code != DH6OPT_STCODE_UNDEFINE) 					iaddr_len = sizeof(ai) - sizeof(u_int32_t) 								+ sizeof(status);				else 					iaddr_len = sizeof(ai) - sizeof(u_int32_t);				ai.dh6_ai_len = htons(iaddr_len);				ai.preferlifetime = htonl(dp->val_dhcp6addr.preferlifetime);				ai.validlifetime = htonl(dp->val_dhcp6addr.validlifetime);				memcpy(&ai.addr, &dp->val_dhcp6addr.addr,			       		sizeof(ai.addr));				memcpy(tp, &ai, sizeof(ai));				tp += sizeof(ai);				dprintf(LOG_DEBUG, "set IADDR address option len %d: "			    		"%s preferlifetime %d validlifetime %d", 			    		iaddr_len, in6addr2str(&ai.addr, 0), 			    		ntohl(ai.preferlifetime), 					ntohl(ai.validlifetime));				/* set up address status code if any */				if (dp->val_dhcp6addr.status_code != DH6OPT_STCODE_UNDEFINE) {					status.dh6_status_type = htons(DH6OPT_STATUS_CODE);					status.dh6_status_len = 						htons(sizeof(status.dh6_status_code));					status.dh6_status_code = 						htons(dp->val_dhcp6addr.status_code);					memcpy(tp, &status, sizeof(status));					dprintf(LOG_DEBUG, "  this address status code: %s",			    		dhcp6_stcodestr(ntohs(status.dh6_status_code)));					optlen += sizeof(status);					tp += sizeof(status);					/* XXX: copy status message if any */				}			}		} else if (dhcp6_mode == DHCP6_MODE_SERVER) {			int num;			num = DH6OPT_STCODE_NOADDRAVAIL;			dprintf(LOG_DEBUG, "  status code: %s",			    dhcp6_stcodestr(num));			/* XXX: need to check duplication? */			if (dhcp6_add_listval(&optinfo->stcode_list,			    &num, DHCP6_LISTVAL_NUM) == NULL) {				dprintf(LOG_ERR, "%s" "failed to copy "				    "status code", FNAME);				goto fail;			}		}		if (optinfo->type == IATA)			COPY_OPTION(DH6OPT_IA_TA, optlen, tmpbuf, p);		else if (optinfo->type == IANA)			COPY_OPTION(DH6OPT_IA_NA, optlen, tmpbuf, p);		free(tmpbuf);		break;	case IAPD:		if (optinfo->iaidinfo.iaid == 0)			break;		optlen = sizeof(opt_iapd);		dprintf(LOG_DEBUG, "set IA_PD iaidinfo: "		 	"iaid %u renewtime %u rebindtime %u", 		  	optinfo->iaidinfo.iaid, optinfo->iaidinfo.renewtime, 		   	optinfo->iaidinfo.rebindtime);		opt_iapd.iaid = htonl(optinfo->iaidinfo.iaid);		opt_iapd.renewtime = htonl(optinfo->iaidinfo.renewtime);		opt_iapd.rebindtime = htonl(optinfo->iaidinfo.rebindtime);		buflen = sizeof(opt_iapd) + dhcp6_count_list(&optinfo->addr_list) *				(sizeof(pi) + sizeof(status));		tmpbuf = NULL;		if ((tmpbuf = malloc(buflen)) == NULL) {			dprintf(LOG_ERR, "%s"				"memory allocation failed for options", FNAME);			goto fail;		}		memcpy(tmpbuf, &opt_iapd, sizeof(opt_iapd));		tp = tmpbuf + optlen;		optlen += dhcp6_count_list(&optinfo->addr_list) * sizeof(pi);		if (!TAILQ_EMPTY(&optinfo->addr_list)) {			for (dp = TAILQ_FIRST(&optinfo->addr_list); dp; 			     dp = TAILQ_NEXT(dp, link)) {				int iaddr_len = 0;				memset(&pi, 0, sizeof(pi));				pi.dh6_pi_type = htons(DH6OPT_IAPREFIX);				if (dp->val_dhcp6addr.status_code != DH6OPT_STCODE_UNDEFINE) 					iaddr_len = sizeof(pi) - sizeof(u_int32_t) 						+ sizeof(status); 				else 					iaddr_len = sizeof(pi) - sizeof(u_int32_t);				pi.dh6_pi_len = htons(iaddr_len);				pi.preferlifetime = htonl(dp->val_dhcp6addr.preferlifetime);

⌨️ 快捷键说明

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