📄 server6_addr.c
字号:
if (ifaddr->type == IAPD) { if (sp->lease_addr.plen == ifaddr->plen) return (sp); } else if (ifaddr->type == IANA || ifaddr->type == IATA) return (sp); } } return (NULL);}struct dhcp6_timer *dhcp6_iaidaddr_timo(void *arg){ struct dhcp6_iaidaddr *sp = (struct dhcp6_iaidaddr *)arg; dprintf(LOG_DEBUG, "server6_iaidaddr timeout for %u, state=%d", sp->client6_info.iaidinfo.iaid, sp->state); switch(sp->state) { case ACTIVE: case EXPIRED: sp->state = EXPIRED; dhcp6_remove_iaidaddr(sp); default: break; } return (NULL);} struct dhcp6_timer *dhcp6_lease_timo(arg) void *arg;{ struct dhcp6_lease *sp = (struct dhcp6_lease *)arg; struct timeval timeo; double d; dprintf(LOG_DEBUG, "%s" "lease timeout for %s, state=%d", FNAME, in6addr2str(&sp->lease_addr.addr, 0), sp->state); switch(sp->state) { case ACTIVE: sp->state = EXPIRED; d = sp->lease_addr.validlifetime - sp->lease_addr.preferlifetime; timeo.tv_sec = (long)d; timeo.tv_usec = 0; dhcp6_set_timer(&timeo, sp->timer); break; case EXPIRED: case INVALID: sp->state = INVALID; dhcp6_remove_lease(sp); return (NULL); default: return (NULL); } return (sp->timer);}static voidget_random_bytes(u_int8_t seed[], int num){ int i; for (i = 0; i < num; i++) seed[i] = random(); return;}static void create_tempaddr(prefix, plen, tempaddr) struct in6_addr *prefix; int plen; struct in6_addr *tempaddr;{ int i, num_bytes; u_int8_t digest[16]; u_int8_t seed[16]; get_random_bytes(seed, 16); /* address mask */ memset(tempaddr, 0, sizeof(*tempaddr)); num_bytes = plen / 8; for (i = 0; i < num_bytes; i++) { tempaddr->s6_addr[i] = prefix->s6_addr[i]; } tempaddr->s6_addr[num_bytes] = (prefix->s6_addr[num_bytes] | (0xFF >> plen % 8)) & (seed[num_bytes] | ((0xFF << 8) - plen % 8)); for (i = num_bytes + 1; i < 16; i++) { tempaddr->s6_addr[i] = seed[i]; } return;}intdhcp6_get_hostconf(roptinfo, optinfo, iaidaddr, host) struct host_decl *host; struct dhcp6_iaidaddr *iaidaddr; struct dhcp6_optinfo *optinfo, *roptinfo;{ struct dhcp6_list *reply_list = &roptinfo->addr_list; struct dhcp6_list *req_list = &optinfo->addr_list; struct dhcp6_listval *lv, *lv_next; if (!(host->hostscope.allow_flags & DHCIFF_TEMP_ADDRS)) { roptinfo->iaidinfo.renewtime = host->hostscope.renew_time; roptinfo->iaidinfo.rebindtime = host->hostscope.rebind_time; roptinfo->type = optinfo->type; switch (optinfo->type) { case IANA: dhcp6_copy_list(reply_list, &host->addrlist); break; case IATA: break; case IAPD: dhcp6_copy_list(reply_list, &host->prefixlist); break; } } return 0;}intdhcp6_create_addrlist(roptinfo, optinfo, iaidaddr, subnet) struct dhcp6_optinfo *roptinfo; struct dhcp6_optinfo *optinfo; const struct dhcp6_iaidaddr *iaidaddr; const struct link_decl *subnet;{ struct dhcp6_listval *v6addr; struct v6addrseg *seg; struct dhcp6_list *reply_list = &roptinfo->addr_list; struct dhcp6_list *req_list = &optinfo->addr_list; int numaddr; struct dhcp6_listval *lv, *lv_next = NULL; roptinfo->iaidinfo.renewtime = subnet->linkscope.renew_time; roptinfo->iaidinfo.rebindtime = subnet->linkscope.rebind_time; roptinfo->type = optinfo->type; /* check the duplication */ for (lv = TAILQ_FIRST(req_list); lv; lv = lv_next) { lv_next = TAILQ_NEXT(lv, link); if (addr_on_addrlist(reply_list, &lv->val_dhcp6addr)) { TAILQ_REMOVE(req_list, lv, link); } } dhcp6_copy_list(reply_list, req_list); for (lv = TAILQ_FIRST(reply_list); lv; lv = lv_next) { lv_next = TAILQ_NEXT(lv, link); lv->val_dhcp6addr.type = optinfo->type; lv->val_dhcp6addr.status_code = DH6OPT_STCODE_UNDEFINE; lv->val_dhcp6addr.status_msg = NULL; } for (seg = subnet->seglist; seg; seg = seg->next) { numaddr = 0; for (lv = TAILQ_FIRST(reply_list); lv; lv = lv_next) { lv_next = TAILQ_NEXT(lv, link); /* skip checked segment */ if (lv->val_dhcp6addr.status_code == DH6OPT_STCODE_SUCCESS) continue; if (IN6_IS_ADDR_RESERVED(&lv->val_dhcp6addr.addr) || is_anycast(&lv->val_dhcp6addr.addr, seg->prefix.plen)) { lv->val_dhcp6addr.status_code = DH6OPT_STCODE_NOTONLINK; dprintf(LOG_DEBUG, "%s" " %s address not on link", FNAME, in6addr2str(&lv->val_dhcp6addr.addr, 0)); continue; } lv->val_dhcp6addr.type = optinfo->type; if (addr_on_segment(seg, &lv->val_dhcp6addr)) { if (numaddr == 0) { lv->val_dhcp6addr.type = optinfo->type; server6_get_addrpara(&lv->val_dhcp6addr, seg); numaddr += 1; } else { /* check the addr count per seg, we only allow one address * per segment, set the status code */ lv->val_dhcp6addr.status_code = DH6OPT_STCODE_NOADDRAVAIL; } } else { lv->val_dhcp6addr.status_code = DH6OPT_STCODE_NOTONLINK; dprintf(LOG_DEBUG, "%s" " %s address not on link", FNAME, in6addr2str(&lv->val_dhcp6addr.addr, 0)); } } if (iaidaddr != NULL) { struct dhcp6_lease *cl; for (cl = TAILQ_FIRST(&iaidaddr->lease_list); cl; cl = TAILQ_NEXT(cl, link)) { if (addr_on_segment(seg, &cl->lease_addr)) { if (addr_on_addrlist(reply_list, &cl->lease_addr)) { continue; } else if (numaddr == 0) { v6addr = (struct dhcp6_listval *)malloc(sizeof(*v6addr)); if (v6addr == NULL) { dprintf(LOG_ERR, "%s" "fail to allocate memory %s", FNAME, strerror(errno)); return (-1); } memset(v6addr, 0, sizeof(*v6addr)); memcpy(&v6addr->val_dhcp6addr, &cl->lease_addr, sizeof(v6addr->val_dhcp6addr)); v6addr->val_dhcp6addr.type = optinfo->type; server6_get_addrpara(&v6addr->val_dhcp6addr, seg); numaddr += 1; TAILQ_INSERT_TAIL(reply_list, v6addr, link); continue; } } } } if (numaddr == 0) { v6addr = (struct dhcp6_listval *)malloc(sizeof(*v6addr)); if (v6addr == NULL) { dprintf(LOG_ERR, "%s" "fail to allocate memory %s", FNAME, strerror(errno)); return (-1); } memset(v6addr, 0, sizeof(*v6addr)); v6addr->val_dhcp6addr.type = optinfo->type; server6_get_newaddr(optinfo->type, &v6addr->val_dhcp6addr, seg); if (IN6_IS_ADDR_UNSPECIFIED(&v6addr->val_dhcp6addr.addr)) { free(v6addr); continue; } TAILQ_INSERT_TAIL(reply_list, v6addr, link); } } return (0);}static intaddr_on_segment(seg, addr) struct v6addrseg *seg; struct dhcp6_addr *addr;{ int onseg = 0; struct v6addr *prefix; dprintf(LOG_DEBUG, "%s" " checking address %s on segment", FNAME, in6addr2str(&addr->addr, 0)); switch (addr->type) { case IATA: prefix = getprefix(&addr->addr, seg->prefix.plen); if (prefix && !memcmp(&seg->prefix, prefix, sizeof(seg->prefix))) { dprintf(LOG_DEBUG, "%s" " address is on link", FNAME); onseg = 1; } else onseg = 0; free(prefix); break; case IANA: if (ipv6addrcmp(&addr->addr, &seg->min) >= 0 && ipv6addrcmp(&seg->max, &addr->addr) >= 0) { dprintf(LOG_DEBUG, "%s" " address is on link", FNAME); onseg = 1; } else onseg = 0; break; default: break; } return onseg; }static void server6_get_newaddr(type, v6addr, seg) iatype_t type; struct dhcp6_addr *v6addr; struct v6addrseg *seg;{ struct in6_addr current; int round = 0; memcpy(¤t, &seg->free, sizeof(current)); do { v6addr->type = type; switch(type) { case IATA: /* assume the temp addr never being run out */ create_tempaddr(&seg->prefix.addr, seg->prefix.plen, &v6addr->addr); break; case IANA: memcpy(&v6addr->addr, &seg->free, sizeof(v6addr->addr)); if (round && IN6_ARE_ADDR_EQUAL(¤t, &v6addr->addr)) { memset(&v6addr->addr, 0, sizeof(v6addr->addr)); break; } inc_ipv6addr(&seg->free); if (ipv6addrcmp(&seg->free, &seg->max) == 1 ) { round = 1; memcpy(&seg->free, &seg->min, sizeof(seg->free)); } break; default: break; } } while ((hash_search(lease_hash_table, (void *)v6addr) != NULL) || (hash_search(host_addr_hash_table, (void *)&v6addr->addr) != NULL) || (is_anycast(&v6addr->addr, seg->prefix.plen))); if (IN6_IS_ADDR_UNSPECIFIED(&v6addr->addr)) { return; } dprintf(LOG_DEBUG, "new address %s is got", in6addr2str(&v6addr->addr, 0)); server6_get_addrpara(v6addr, seg); return;}static voidserver6_get_prefixpara(v6addr, seg) struct dhcp6_addr *v6addr; struct v6prefix *seg;{ v6addr->plen = seg->prefix.plen; if (seg->parainfo.prefer_life_time == 0 && seg->parainfo.valid_life_time == 0) { seg->parainfo.valid_life_time = DEFAULT_VALID_LIFE_TIME; seg->parainfo.prefer_life_time = DEFAULT_PREFERRED_LIFE_TIME; } else if (seg->parainfo.prefer_life_time == 0) { seg->parainfo.prefer_life_time = seg->parainfo.valid_life_time / 2; } else if (seg->parainfo.valid_life_time == 0) { seg->parainfo.valid_life_time = 2 * seg->parainfo.prefer_life_time; } dprintf(LOG_DEBUG, " preferlifetime %u, validlifetime %u", seg->parainfo.prefer_life_time, seg->parainfo.valid_life_time); dprintf(LOG_DEBUG, " renewtime %u, rebindtime %u", seg->parainfo.renew_time, seg->parainfo.rebind_time); v6addr->preferlifetime = seg->parainfo.prefer_life_time; v6addr->validlifetime = seg->parainfo.valid_life_time; v6addr->status_code = DH6OPT_STCODE_SUCCESS; v6addr->status_msg = NULL; return;}static voidserver6_get_addrpara(v6addr, seg) struct dhcp6_addr *v6addr; struct v6addrseg *seg;{ v6addr->plen = seg->prefix.plen; if (seg->parainfo.prefer_life_time == 0 && seg->parainfo.valid_life_time == 0) { seg->parainfo.valid_life_time = DEFAULT_VALID_LIFE_TIME; seg->parainfo.prefer_life_time = DEFAULT_PREFERRED_LIFE_TIME; } else if (seg->parainfo.prefer_life_time == 0) { seg->parainfo.prefer_life_time = seg->parainfo.valid_life_time / 2; } else if (seg->parainfo.valid_life_time == 0) { seg->parainfo.valid_life_time = 2 * seg->parainfo.prefer_life_time; } dprintf(LOG_DEBUG, " preferlifetime %u, validlifetime %u", seg->parainfo.prefer_life_time, seg->parainfo.valid_life_time); dprintf(LOG_DEBUG, " renewtime %u, rebindtime %u", seg->parainfo.renew_time, seg->parainfo.rebind_time); v6addr->preferlifetime = seg->parainfo.prefer_life_time; v6addr->validlifetime = seg->parainfo.valid_life_time; v6addr->status_code = DH6OPT_STCODE_SUCCESS; v6addr->status_msg = NULL; return;}intdhcp6_create_prefixlist(roptinfo, optinfo, iaidaddr, subnet) struct dhcp6_optinfo *roptinfo; const struct dhcp6_optinfo *optinfo; const struct dhcp6_iaidaddr *iaidaddr; const struct link_decl *subnet;{ struct dhcp6_listval *v6addr; struct v6prefix *prefix6; struct dhcp6_list *reply_list = &roptinfo->addr_list; const struct dhcp6_list *req_list = &optinfo->addr_list; struct dhcp6_listval *lv, *lv_next = NULL; /* XXX: ToDo check hostdecl first */ roptinfo->iaidinfo.renewtime = subnet->linkscope.renew_time; roptinfo->iaidinfo.rebindtime = subnet->linkscope.rebind_time; roptinfo->type = optinfo->type; for (prefix6 = subnet->prefixlist; prefix6; prefix6 = prefix6->next) { v6addr = (struct dhcp6_listval *)malloc(sizeof(*v6addr)); if (v6addr == NULL) { dprintf(LOG_ERR, "%s" "fail to allocate memory", FNAME); return (-1); } memset(v6addr, 0, sizeof(*v6addr)); /* XXX: ToDo: get new paras */ memcpy(&v6addr->val_dhcp6addr.addr, &prefix6->prefix.addr, sizeof(v6addr->val_dhcp6addr.addr)); v6addr->val_dhcp6addr.plen = prefix6->prefix.plen; v6addr->val_dhcp6addr.type = IAPD; server6_get_prefixpara(&v6addr->val_dhcp6addr, prefix6); dprintf(LOG_DEBUG, " get prefix %s/%d, " "preferlifetime %u, validlifetime %u", in6addr2str(&v6addr->val_dhcp6addr.addr, 0), v6addr->val_dhcp6addr.plen, v6addr->val_dhcp6addr.preferlifetime, v6addr->val_dhcp6addr.validlifetime); TAILQ_INSERT_TAIL(reply_list, v6addr, link); } for (prefix6 = subnet->prefixlist; prefix6; prefix6 = prefix6->next) { for (lv = TAILQ_FIRST(req_list); lv; lv = lv_next) { lv_next = TAILQ_NEXT(lv, link); if (IN6_IS_ADDR_RESERVED(&lv->val_dhcp6addr.addr) || is_anycast(&lv->val_dhcp6addr.addr, prefix6->prefix.plen) || !addr_on_addrlist(reply_list, &lv->val_dhcp6addr)) { lv->val_dhcp6addr.status_code = DH6OPT_STCODE_NOTONLINK; dprintf(LOG_DEBUG, " %s prefix not on link", in6addr2str(&lv->val_dhcp6addr.addr, 0)); lv->val_dhcp6addr.type = IAPD; TAILQ_INSERT_TAIL(reply_list, lv, link); } } } return (0);}struct host_decl *dhcp6_allocate_host(ifp, rootgroup, optinfo) struct dhcp6_if *ifp; struct rootgroup *rootgroup; struct dhcp6_optinfo *optinfo;{ struct host_decl *host = NULL; struct interface *ifnetwork; struct duid *duid = &optinfo->clientID; u_int32_t iaid = optinfo->iaidinfo.iaid; for (ifnetwork = rootgroup->iflist; ifnetwork; ifnetwork = ifnetwork->next) { if (strcmp(ifnetwork->name, ifp->ifname) != 0) continue; else { host = find_hostdecl(duid, iaid, ifnetwork->hostlist); break; } } return host;}struct link_decl *dhcp6_allocate_link(ifp, rootgroup, relay) struct dhcp6_if *ifp; struct rootgroup *rootgroup; struct in6_addr *relay;{ struct link_decl *link; struct interface *ifnetwork; ifnetwork = rootgroup->iflist; for (ifnetwork = rootgroup->iflist; ifnetwork; ifnetwork = ifnetwork->next) { if (strcmp(ifnetwork->name, ifp->ifname) != 0) continue; else { for (link = ifnetwork->linklist; link; link = link->next) { /* without relay agent support, so far we assume * that client and server on the same link, no relay */ struct v6addrlist *temp; if (relay == NULL) { if (link->relaylist != NULL) continue; else return link; } else { for (temp = link->relaylist; temp; temp = temp->next) { if (IN6_ARE_ADDR_EQUAL(relay, &temp->v6addr.addr)) return link; else continue; } } } } } return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -