📄 common.c
字号:
ratio = ratio / 2; return x + ((y - x) * (ratio - 1) / random() & (ratio - 1));}intprefix6_mask(in6, plen) struct in6_addr *in6; int plen;{ struct sockaddr_in6 mask6; int i; if (sa6_plen2mask(&mask6, plen)) return (-1); for (i = 0; i < 16; i++) in6->s6_addr[i] &= mask6.sin6_addr.s6_addr[i]; return (0);}intsa6_plen2mask(sa6, plen) struct sockaddr_in6 *sa6; int plen;{ u_char *cp; if (plen < 0 || plen > 128) return (-1); memset(sa6, 0, sizeof(*sa6)); sa6->sin6_family = AF_INET6; for (cp = (u_char *)&sa6->sin6_addr; plen > 7; plen -= 8) *cp++ = 0xff; *cp = 0xff << (8 - plen); return (0);}char *addr2str(sa) struct sockaddr *sa;{ static char addrbuf[8][NI_MAXHOST]; static int round = 0; char *cp; round = (round + 1) & 7; cp = addrbuf[round]; if (getnameinfo(sa, NI_MAXSERV, cp, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) dprintf(LOG_ERR, "%s getnameinfo return error", FNAME); return (cp);}char *in6addr2str(in6, scopeid) struct in6_addr *in6; int scopeid;{ struct sockaddr_in6 sa6; memset(&sa6, 0, sizeof(sa6)); sa6.sin6_family = AF_INET6; sa6.sin6_addr = *in6; sa6.sin6_scope_id = scopeid; return (addr2str((struct sockaddr *)&sa6));}/* return IPv6 address scope type. caller assumes that smaller is narrower. */intin6_scope(addr) struct in6_addr *addr;{ int scope; if (addr->s6_addr[0] == 0xfe) { scope = addr->s6_addr[1] & 0xc0; switch (scope) { case 0x80: return 2; /* link-local */ break; case 0xc0: return 5; /* site-local */ break; default: return 14; /* global: just in case */ break; } } /* multicast scope. just return the scope field */ if (addr->s6_addr[0] == 0xff) return (addr->s6_addr[1] & 0x0f); if (bcmp(&in6addr_loopback, addr, sizeof(addr) - 1) == 0) { if (addr->s6_addr[15] == 1) /* loopback */ return 1; if (addr->s6_addr[15] == 0) /* unspecified */ return 0; /* XXX: good value? */ } return 14; /* global */}static intin6_matchflags(addr, ifnam, flags) struct sockaddr *addr; char *ifnam; int flags;{ int s; struct ifreq ifr; if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { warn("in6_matchflags: socket(DGRAM6)"); return (-1); } memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); ifr.ifr_addr = *(struct sockaddr *)addr; if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { warn("in6_matchflags: ioctl(SIOCGIFFLAGS, %s)", addr2str(addr)); close(s); return (-1); } close(s); return (ifr.ifr_ifru.ifru_flags & flags);}intconfigure_duid(const char *str, struct duid *duid){ const char *cp; char *bp, *idbuf = NULL; int duidlen, slen; unsigned int x; /* calculate DUID len */ slen = strlen(str); if (slen < 2) goto bad; duidlen = 1; slen -= 2; if ((slen % 3) != 0) goto bad; duidlen += (slen / 3); if (duidlen > 256) { dprintf(LOG_ERR, "%s" "too long DUID (%d)", FNAME, duidlen); return (-1); } if ((idbuf = (char *)malloc(duidlen)) == NULL) { dprintf(LOG_ERR, "%s" "memory allocation failed", FNAME); return (-1); } for (cp = str, bp = idbuf; *cp;) { if (*cp == ':') { cp++; continue; } if (sscanf(cp, "%02x", &x) != 1) goto bad; *bp = x; cp += 2; bp++; } duid->duid_len = duidlen; duid->duid_id = idbuf; dprintf(LOG_DEBUG, "configure duid is %s", duidstr(duid)); return (0); bad: if (idbuf) free(idbuf); dprintf(LOG_ERR, "%s" "assumption failure (bad string)", FNAME); return (-1);}intget_duid(const char *idfile, const char *ifname, struct duid *duid){ FILE *fp = NULL; u_int16_t len = 0, hwtype; struct dhcp6_duid_type1 *dp; /* we only support the type1 DUID */ char tmpbuf[256]; /* DUID should be no more than 256 bytes */ if ((fp = fopen(idfile, "r")) == NULL && errno != ENOENT) dprintf(LOG_NOTICE, "%s" "failed to open DUID file: %s", FNAME, idfile); if (fp) { /* decode length */ if (fread(&len, sizeof(len), 1, fp) != 1) { dprintf(LOG_ERR, "%s" "DUID file corrupted", FNAME); goto fail; } } else { int l; if ((l = gethwid(tmpbuf, sizeof(tmpbuf), ifname, &hwtype)) < 0) { dprintf(LOG_INFO, "%s" "failed to get a hardware address", FNAME); goto fail; } len = l + sizeof(struct dhcp6_duid_type1); } memset(duid, 0, sizeof(*duid)); duid->duid_len = len; if ((duid->duid_id = (char *)malloc(len)) == NULL) { dprintf(LOG_ERR, "%s" "failed to allocate memory", FNAME); goto fail; } /* copy (and fill) the ID */ if (fp) { if (fread(duid->duid_id, len, 1, fp) != 1) { dprintf(LOG_ERR, "%s" "DUID file corrupted", FNAME); goto fail; } dprintf(LOG_DEBUG, "%s" "extracted an existing DUID from %s: %s", FNAME, idfile, duidstr(duid)); } else { u_int64_t t64; dp = (struct dhcp6_duid_type1 *)duid->duid_id; dp->dh6duid1_type = htons(1); /* type 1 */ dp->dh6duid1_hwtype = htons(hwtype); /* time is Jan 1, 2000 (UTC), modulo 2^32 */ t64 = (u_int64_t)(time(NULL) - 946684800); dp->dh6duid1_time = htonl((u_long)(t64 & 0xffffffff)); memcpy((void *)(dp + 1), tmpbuf, (len - sizeof(*dp))); dprintf(LOG_DEBUG, "%s" "generated a new DUID: %s", FNAME, duidstr(duid)); } /* save the (new) ID to the file for next time */ if (!fp) { if ((fp = fopen(idfile, "w+")) == NULL) { dprintf(LOG_ERR, "%s" "failed to open DUID file for save", FNAME); goto fail; } if ((fwrite(&len, sizeof(len), 1, fp)) != 1) { dprintf(LOG_ERR, "%s" "failed to save DUID", FNAME); goto fail; } if ((fwrite(duid->duid_id, len, 1, fp)) != 1) { dprintf(LOG_ERR, "%s" "failed to save DUID", FNAME); goto fail; } dprintf(LOG_DEBUG, "%s" "saved generated DUID to %s", FNAME, idfile); } if (fp) fclose(fp); return (0); fail: if (fp) fclose(fp); if (duid->duid_id != NULL) { duidfree(duid); } return (-1);}ssize_tgethwid(buf, len, ifname, hwtypep) char *buf; int len; const char *ifname; u_int16_t *hwtypep;{ int skfd; ssize_t l; struct ifreq if_hwaddr; if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0 )) < 0) return -1; strcpy(if_hwaddr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr) < 0) return -1; /* only support Ethernet */ switch (if_hwaddr.ifr_hwaddr.sa_family) { case ARPHRD_ETHER: case ARPHRD_IEEE802: *hwtypep = ARPHRD_ETHER; l = 6; break; case ARPHRD_PPP: *hwtypep = ARPHRD_PPP; l = 0; return l; default: dprintf(LOG_INFO, "dhcpv6 doesn't support hardware type %d", if_hwaddr.ifr_hwaddr.sa_family); return -1; /* XXX */ } memcpy(buf, if_hwaddr.ifr_hwaddr.sa_data, l); dprintf(LOG_DEBUG, "%s" "found an interface %s harware %x", FNAME, ifname, buf); return l;}voiddhcp6_init_options(optinfo) struct dhcp6_optinfo *optinfo;{ memset(optinfo, 0, sizeof(*optinfo)); /* for safety */ optinfo->clientID.duid_id = NULL; optinfo->serverID.duid_id = NULL; optinfo->pref = DH6OPT_PREF_UNDEF; TAILQ_INIT(&optinfo->addr_list); TAILQ_INIT(&optinfo->reqopt_list); TAILQ_INIT(&optinfo->stcode_list); TAILQ_INIT(&optinfo->dns_list.addrlist); optinfo->dns_list.domainlist = NULL;}voiddhcp6_clear_options(optinfo) struct dhcp6_optinfo *optinfo;{ struct domain_list *dlist, *dlist_next; duidfree(&optinfo->clientID); duidfree(&optinfo->serverID); dhcp6_clear_list(&optinfo->addr_list); dhcp6_clear_list(&optinfo->reqopt_list); dhcp6_clear_list(&optinfo->stcode_list); dhcp6_clear_list(&optinfo->dns_list.addrlist); if (dhcp6_mode == DHCP6_MODE_CLIENT) { for (dlist = optinfo->dns_list.domainlist; dlist; dlist = dlist_next) { dlist_next = dlist->next; free(dlist); } } optinfo->dns_list.domainlist = NULL; dhcp6_init_options(optinfo);}intdhcp6_copy_options(dst, src) struct dhcp6_optinfo *dst, *src;{ if (duidcpy(&dst->clientID, &src->clientID)) goto fail; if (duidcpy(&dst->serverID, &src->serverID)) goto fail; dst->flags = src->flags; if (dhcp6_copy_list(&dst->addr_list, &src->addr_list)) goto fail; if (dhcp6_copy_list(&dst->reqopt_list, &src->reqopt_list)) goto fail; if (dhcp6_copy_list(&dst->stcode_list, &src->stcode_list)) goto fail; if (dhcp6_copy_list(&dst->dns_list.addrlist, &src->dns_list.addrlist)) goto fail; memcpy(&dst->server_addr, &src->server_addr, sizeof(dst->server_addr)); dst->pref = src->pref; return 0; fail: /* cleanup temporary resources */ dhcp6_clear_options(dst); return -1;}intdhcp6_get_options(p, ep, optinfo) struct dhcp6opt *p, *ep; struct dhcp6_optinfo *optinfo;{ struct dhcp6opt *np, opth; int i, opt, optlen, reqopts, num; char *cp, *val; u_int16_t val16; for (; p + 1 <= ep; p = np) { struct duid duid0; /* * get the option header. XXX: since there is no guarantee * about the header alignment, we need to make a local copy. */ memcpy(&opth, p, sizeof(opth)); optlen = ntohs(opth.dh6opt_len); opt = ntohs(opth.dh6opt_type); cp = (char *)(p + 1); np = (struct dhcp6opt *)(cp + optlen); dprintf(LOG_DEBUG, "%s" "get DHCP option %s, len %d", FNAME, dhcp6optstr(opt), optlen); /* option length field overrun */ if (np > ep) { dprintf(LOG_INFO, "%s" "malformed DHCP options", FNAME); return -1; } switch (opt) { case DH6OPT_CLIENTID: if (optlen == 0) goto malformed; duid0.duid_len = optlen; duid0.duid_id = cp; dprintf(LOG_DEBUG, " DUID: %s", duidstr(&duid0)); if (duidcpy(&optinfo->clientID, &duid0)) { dprintf(LOG_ERR, "%s" "failed to copy DUID", FNAME); goto fail; } break; case DH6OPT_SERVERID: if (optlen == 0) goto malformed; duid0.duid_len = optlen; duid0.duid_id = cp; dprintf(LOG_DEBUG, " DUID: %s", duidstr(&duid0)); if (duidcpy(&optinfo->serverID, &duid0)) { dprintf(LOG_ERR, "%s" "failed to copy DUID", FNAME); goto fail; } break; case DH6OPT_ELAPSED_TIME: if (optlen != sizeof(u_int16_t)) goto malformed; memcpy(&val16, cp, sizeof(val16)); num = ntohs(val16); dprintf(LOG_DEBUG, " this message elapsed time is: %d", num); break; case DH6OPT_STATUS_CODE: if (optlen < sizeof(u_int16_t)) goto malformed; memcpy(&val16, cp, sizeof(val16)); num = ntohs(val16); dprintf(LOG_DEBUG, " this message status code: %s", dhcp6_stcodestr(num)); /* XXX: status message */ /* 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_ORO: if ((optlen % 2) != 0 || optlen == 0) goto malformed; reqopts = optlen / 2; for (i = 0, val = cp; i < reqopts; i++, val += sizeof(u_int16_t)) { u_int16_t opttype; memcpy(&opttype, val, sizeof(u_int16_t)); num = ntohs(opttype); dprintf(LOG_DEBUG, " requested option: %s", dhcp6optstr(num)); if (dhcp6_find_listval(&optinfo->reqopt_list, &num, DHCP6_LISTVAL_NUM)) { dprintf(LOG_INFO, "%s" "duplicated " "option type (%s)", FNAME,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -