common.c

来自「IPv6环境下的DHCP实现」· C语言 代码 · 共 1,486 行 · 第 1/3 页

C
1,486
字号
			} else {				dprintf(LOG_DEBUG, "  prefix information: "				    "%s/%d duration infinity",				    in6addr2str(&prefix.addr, 0),				    prefix.plen);			}			if (dhcp6_find_listval(&optinfo->prefix_list,			    &prefix, DHCP6_LISTVAL_PREFIX6)) {				dprintf(LOG_INFO, "%s" "duplicated "				    "prefix (%s/%d)", FNAME,				    in6addr2str(&prefix.addr, 0),				    prefix.plen);				goto nextoption;			}			if (dhcp6_add_listval(&optinfo->prefix_list, &prefix,			    DHCP6_LISTVAL_PREFIX6) == NULL) {				dprintf(LOG_ERR, "%s" "failed to copy a "				    "prefix", FNAME);				goto fail;			}		}	  nextoption:	}	return(0);  malformed:	dprintf(LOG_INFO,		"  malformed prefix delegation 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;	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 (optinfo->rapidcommit)		COPY_OPTION(DH6OPT_RAPID_COMMIT, 0, NULL, p);	if (optinfo->pref != DH6OPT_PREF_UNDEF) {		u_int8_t p8 = (u_int8_t)optinfo->pref;		COPY_OPTION(DH6OPT_PREFERENCE, sizeof(p8), &p8, p);	}	for (stcode = TAILQ_FIRST(&optinfo->stcode_list); stcode;	     stcode = TAILQ_NEXT(stcode, link)) {		u_int16_t code;		code = htons(stcode->val_num);		COPY_OPTION(DH6OPT_STATUS_CODE, sizeof(code), &code, p);	}	if (!TAILQ_EMPTY(&optinfo->reqopt_list)) {		struct dhcp6_listval *opt;		u_int16_t *valp;		tmpbuf = NULL;		optlen = dhcp6_count_list(&optinfo->reqopt_list) *			sizeof(u_int16_t);		if ((tmpbuf = malloc(optlen)) == NULL) {			dprintf(LOG_ERR, "%s"			    "memory allocation failed for options", FNAME);			goto fail;		}		valp = (u_int16_t *)tmpbuf;		for (opt = TAILQ_FIRST(&optinfo->reqopt_list); opt;		     opt = TAILQ_NEXT(opt, link), valp++) {			*valp = htons((u_int16_t)opt->val_num);		}		COPY_OPTION(DH6OPT_ORO, optlen, tmpbuf, p);		free(tmpbuf);	}	if (!TAILQ_EMPTY(&optinfo->dns_list)) {		struct in6_addr *in6;		struct dhcp6_listval *d;		tmpbuf = NULL;		optlen = dhcp6_count_list(&optinfo->dns_list) *			sizeof(struct in6_addr);		if ((tmpbuf = malloc(optlen)) == NULL) {			dprintf(LOG_ERR, "%s"			    "memory allocation failed for DNS options", FNAME);			goto fail;		}		in6 = (struct in6_addr *)tmpbuf;		for (d = TAILQ_FIRST(&optinfo->dns_list); d;		     d = TAILQ_NEXT(d, link), in6++) {			memcpy(in6, &d->val_addr6, sizeof(*in6));		}		COPY_OPTION(DH6OPT_DNS, optlen, tmpbuf, p);		free(tmpbuf);	}	if (!TAILQ_EMPTY(&optinfo->prefix_list)) {		int pfxs;		char *tp;		struct dhcp6_listval *dp;		struct dhcp6_prefix_info pi;		tmpbuf = NULL;		optlen = dhcp6_count_list(&optinfo->prefix_list) *			sizeof(struct dhcp6_prefix_info);		if ((tmpbuf = malloc(optlen)) == NULL) {			dprintf(LOG_ERR, "%s"				"memory allocation failed for options", FNAME);			goto fail;		}		for (dp = TAILQ_FIRST(&optinfo->prefix_list), tp = tmpbuf; dp;		     dp = TAILQ_NEXT(dp, link), tp += sizeof(pi)) {			/*			 * XXX: We need a temporary structure due to alignment			 * issue.			 */			memset(&pi, 0, sizeof(pi));			pi.dh6_pi_type = htons(DH6OPT_PREFIX_INFORMATION);			pi.dh6_pi_len = htons(sizeof(pi) - 4);			pi.dh6_pi_duration = htonl(dp->val_prefix6.duration);			pi.dh6_pi_plen = dp->val_prefix6.plen;			memcpy(&pi.dh6_pi_paddr, &dp->val_prefix6.addr,			       sizeof(struct in6_addr));			memcpy(tp, &pi, sizeof(pi));		}		COPY_OPTION(DH6OPT_PREFIX_DELEGATION, optlen, tmpbuf, p);		free(tmpbuf);		     	}	return(len);  fail:	if (tmpbuf)		free(tmpbuf);	return(-1);}#undef COPY_OPTIONvoiddhcp6_set_timeoparam(ev)	struct dhcp6_event *ev;{	ev->retrans = 0;	ev->init_retrans = 0;	ev->max_retrans_cnt = 0;	ev->max_retrans_dur = 0;	ev->max_retrans_time = 0;	switch(ev->state) {	case DHCP6S_SOLICIT:		ev->init_retrans = SOL_TIMEOUT;		ev->max_retrans_time = SOL_MAX_RT;		break;	case DHCP6S_INFOREQ:		ev->init_retrans = INF_TIMEOUT;		ev->max_retrans_time = INF_MAX_RT;		break;	case DHCP6S_REQUEST:		ev->init_retrans = REQ_TIMEOUT;		ev->max_retrans_time = REQ_MAX_RT;		ev->max_retrans_cnt = REQ_MAX_RC;		break;	case DHCP6S_RENEW:		ev->init_retrans = REN_TIMEOUT;		ev->max_retrans_time = REN_MAX_RT;		break;	case DHCP6S_REBIND:		ev->init_retrans = REB_TIMEOUT;		ev->max_retrans_time = REB_MAX_RT;		break;	default:		dprintf(LOG_INFO, "%s" "unexpected event state %d on %s",		    FNAME, ev->state, ev->ifp->ifname);		exit(1);	}}voiddhcp6_reset_timer(ev)	struct dhcp6_event *ev;{	double n, r;	char *statestr;	struct timeval interval;	switch(ev->state) {	case DHCP6S_INIT:		/*		 * The first Solicit message from the client on the interface		 * MUST be delayed by a random amount of time between		 * MIN_SOL_DELAY and MAX_SOL_DELAY.		 * [dhcpv6-24 17.1.2]		 */		ev->retrans = (random() % (MAX_SOL_DELAY - MIN_SOL_DELAY)) +			MIN_SOL_DELAY;		break;	default:		if (ev->state == DHCP6S_SOLICIT && ev->timeouts == 0) {			/*			 * The first RT MUST be selected to be strictly			 * greater than IRT by choosing RAND to be strictly			 * greater than 0.			 * [dhcpv6-24 17.1.2]			 */			r = (double)((random() % 1000) + 1) / 10000;			n = ev->init_retrans + r * ev->init_retrans;		} else {			r = (double)((random() % 2000) - 1000) / 10000;			if (ev->timeouts == 0) {				n = ev->init_retrans + r * ev->init_retrans;			} else				n = 2 * ev->retrans + r * ev->retrans;		}		if (ev->max_retrans_time && n > ev->max_retrans_time)			n = ev->max_retrans_time + r * ev->max_retrans_time;		ev->retrans = (long)n;		break;	}	switch(ev->state) {	case DHCP6S_INIT:		statestr = "INIT";		break;	case DHCP6S_SOLICIT:		statestr = "SOLICIT";		break;	case DHCP6S_INFOREQ:		statestr = "INFOREQ";		break;	case DHCP6S_REQUEST:		statestr = "REQUEST";		break;	case DHCP6S_RENEW:		statestr = "RENEW";		break;	case DHCP6S_REBIND:		statestr = "REBIND";		break;	case DHCP6S_IDLE:		statestr = "IDLE";		break;	default:		statestr = "???"; /* XXX */		break;	}	interval.tv_sec = (ev->retrans * 1000) / 1000000;	interval.tv_usec = (ev->retrans * 1000) % 1000000;	dhcp6_set_timer(&interval, ev->timer);	dprintf(LOG_DEBUG, "%s" "reset a timer on %s, "		"state=%s, timeo=%d, retrans=%d", FNAME,		ev->ifp->ifname, statestr, ev->timeouts, ev->retrans);}intduidcpy(dd, ds)	struct duid *dd, *ds;{	dd->duid_len = ds->duid_len;	if ((dd->duid_id = malloc(dd->duid_len)) == NULL) {		dprintf(LOG_ERR, "%s" "memory allocation failed", FNAME);		return(-1);	}	memcpy(dd->duid_id, ds->duid_id, dd->duid_len);	return(0);}intduidcmp(d1, d2)	struct duid *d1, *d2;{	if (d1->duid_len == d2->duid_len) {		return(memcmp(d1->duid_id, d2->duid_id, d1->duid_len));	} else		return(-1);}voidduidfree(duid)	struct duid *duid;{	if (duid->duid_id)		free(duid->duid_id);	duid->duid_len = 0;}char *dhcp6optstr(type)	int type;{	static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */	if (type > 65535)		return "INVALID option";	switch(type) {	case DH6OPT_CLIENTID:		return "client ID";	case DH6OPT_SERVERID:		return "server ID";	case DH6OPT_ORO:		return "option request";	case DH6OPT_PREFERENCE:		return "preference";	case DH6OPT_STATUS_CODE:		return "status code";	case DH6OPT_RAPID_COMMIT:		return "rapid commit";	case DH6OPT_DNS:		return "DNS";	case DH6OPT_PREFIX_DELEGATION:		return "prefix delegation";	case DH6OPT_PREFIX_INFORMATION:		return "prefix information";	default:		sprintf(genstr, "opt_%d", type);		return(genstr);	}}char *dhcp6msgstr(type)	int type;{	static char genstr[sizeof("msg255") + 1]; /* XXX thread unsafe */	if (type > 255)		return "INVALID msg";	switch(type) {	case DH6_SOLICIT:		return "solicit";	case DH6_ADVERTISE:		return "advertise";	case DH6_RENEW:		return "renew";	case DH6_REBIND:		return "rebind";	case DH6_REQUEST:		return "request";	case DH6_REPLY:		return "reply";	case DH6_INFORM_REQ:		return "information request";	default:		sprintf(genstr, "msg%d", type);		return(genstr);	}}char *dhcp6_stcodestr(code)	int code;{	static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */	if (code > 255)		return "INVALID code";	switch(code) {	case DH6OPT_STCODE_SUCCESS:		return "success";	case DH6OPT_STCODE_UNSPECFAIL:		return "unspec failure";	case DH6OPT_STCODE_AUTHFAILED:		return "auth fail";	case DH6OPT_STCODE_ADDRUNAVAIL:		return "address unavailable";	case DH6OPT_STCODE_NOADDRAVAIL:		return "no addresses";	case DH6OPT_STCODE_NOBINDING:		return "no binding";	case DH6OPT_STCODE_CONFNOMATCH:		return "confirm no match";	case DH6OPT_STCODE_NOTONLINK:		return "not on-link";	case DH6OPT_STCODE_USEMULTICAST:		return "use multicast";	default:		sprintf(genstr, "code%d", code);		return(genstr);	}}char *duidstr(duid)	struct duid *duid;{	int i;	char *cp;	static char duidstr[sizeof("xx:") * 256 + sizeof("...")];	cp = duidstr;	for (i = 0; i < duid->duid_len && i <= 256; i++) {		cp += sprintf(cp, "%s%02x", i == 0 ? "" : ":",			      duid->duid_id[i] & 0xff);	}	if (i < duid->duid_len)		sprintf(cp, "%s", "...");	return(duidstr);}voidsetloglevel(debuglevel)	int debuglevel;{	if (foreground) {		switch(debuglevel) {		case 0:			debug_thresh = LOG_ERR;			break;		case 1:			debug_thresh = LOG_INFO;			break;		default:			debug_thresh = LOG_DEBUG;			break;		}	} else {		switch(debuglevel) {		case 0:			setlogmask(LOG_UPTO(LOG_ERR));			break;		case 1:			setlogmask(LOG_UPTO(LOG_INFO));			break;		}	}}voiddprintf(int level, const char *fmt, ...){	va_list ap;	char logbuf[LINE_MAX];	va_start(ap, fmt);	vsnprintf(logbuf, sizeof(logbuf), fmt, ap);	if (foreground && debug_thresh >= level) {		time_t now;		struct tm *tm_now;		if ((now = time(NULL)) < 0)			exit(1); /* XXX */		tm_now = localtime(&now);		fprintf(stderr, "%04d/%02d/%02d %02d:%02d:%02d %s\n",			tm_now->tm_year + 1900, tm_now->tm_mon,			tm_now->tm_mday,			tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec,			logbuf);	} else		syslog(level, "%s", logbuf);}

⌨️ 快捷键说明

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