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 + -
显示快捷键?