📄 common.c
字号:
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 + -