📄 dhcp6s.c
字号:
/* message validation according to Section 15.7 of dhcpv6-26 */ /* the message must include a Client Identifier option */ if (optinfo->clientID.duid_len == 0) { dprintf(LOG_INFO, "%s" "no server ID option", FNAME); return -1; } /* the message must not include a server Identifier option */ if (optinfo->serverID.duid_len) { dprintf(LOG_INFO, "%s" "server ID option is included in " "a rebind message", FNAME); return -1; } /* * configure necessary options based on the options in request. */ dhcp6_init_options(&roptinfo); /* server information option */ if (duidcpy(&roptinfo.serverID, &server_duid)) { dprintf(LOG_ERR, "%s" "failed to copy server ID", FNAME); goto fail; } /* copy client information back */ if (duidcpy(&roptinfo.clientID, &optinfo->clientID)) { dprintf(LOG_ERR, "%s" "failed to copy client ID", FNAME); goto fail; } /* * Locates the client's binding and verifies that the information * from the client matches the information stored for that client. */ /* prefixes */ for (lv = TAILQ_FIRST(&optinfo->prefix_list); lv; lv = TAILQ_NEXT(lv, link)) { binding = find_binding(&optinfo->clientID, DHCP6_CONFINFO_PREFIX, &lv->val_prefix6); if (binding == NULL) { dprintf(LOG_INFO, "%s" "can't find a binding of prefix" " %s/%d for %s", FNAME, in6addr2str(&lv->val_prefix6.addr, 0), lv->val_prefix6.plen, duidstr(&optinfo->clientID)); continue; /* XXX: is this okay? */ } /* we always extend the requested binding. */ update_binding(binding); /* add the prefix */ if (dhcp6_add_listval(&roptinfo.prefix_list, binding->val, DHCP6_LISTVAL_PREFIX6) == NULL) { dprintf(LOG_ERR, "failed to add a rebound prefix", FNAME); goto fail; } } /* add other configuration information */ /* DNS server */ if (dhcp6_copy_list(&roptinfo.dns_list, &dnslist)) { dprintf(LOG_ERR, "%s" "failed to copy DNS list"); goto fail; } /* how about other prefixes? */ (void)server6_send(DH6_REPLY, ifp, dh6, optinfo, from, fromlen, &roptinfo); dhcp6_clear_options(&roptinfo); return 0; fail: dhcp6_clear_options(&roptinfo); return -1;}static intserver6_react_informreq(ifp, dh6, optinfo, from, fromlen) struct dhcp6_if *ifp; struct dhcp6 *dh6; struct dhcp6_optinfo *optinfo; struct sockaddr *from; int fromlen;{ struct dhcp6_optinfo roptinfo; int error; /* if a server information is included, it must match ours. */ if (optinfo->serverID.duid_len && duidcmp(&optinfo->serverID, &server_duid)) { dprintf(LOG_INFO, "%s" "server DUID mismatch", FNAME); return(-1); } /* * configure necessary options based on the options in request. */ dhcp6_init_options(&roptinfo); /* server information option */ if (duidcpy(&roptinfo.serverID, &server_duid)) { dprintf(LOG_ERR, "%s" "failed to copy server ID", FNAME); goto fail; } /* copy client information back (if provided) */ if (optinfo->clientID.duid_id && duidcpy(&roptinfo.clientID, &optinfo->clientID)) { dprintf(LOG_ERR, "%s" "failed to copy client ID", FNAME); goto fail; } /* DNS server */ if (dhcp6_copy_list(&roptinfo.dns_list, &dnslist)) { dprintf(LOG_ERR, "%s" "failed to copy DNS servers", FNAME); goto fail; } error = server6_send(DH6_REPLY, ifp, dh6, optinfo, from, fromlen, &roptinfo); dhcp6_clear_options(&roptinfo); return(error); fail: dhcp6_clear_options(&roptinfo); return -1;}static intserver6_send(type, ifp, origmsg, optinfo, from, fromlen, roptinfo) int type; struct dhcp6_if *ifp; struct dhcp6 *origmsg; struct dhcp6_optinfo *optinfo, *roptinfo; struct sockaddr *from; int fromlen;{ char replybuf[BUFSIZ]; struct sockaddr_in6 dst; int len, optlen; struct dhcp6 *dh6; if (sizeof(struct dhcp6) > sizeof(replybuf)) { dprintf(LOG_ERR, "%s" "buffer size assumption failed", FNAME); return(-1); } dh6 = (struct dhcp6 *)replybuf; len = sizeof(*dh6); memset(dh6, 0, sizeof(*dh6)); dh6->dh6_msgtypexid = origmsg->dh6_msgtypexid; dh6->dh6_msgtype = (u_int8_t)type; /* set options in the reply message */ if ((optlen = dhcp6_set_options((struct dhcp6opt *)(dh6 + 1), (struct dhcp6opt *)(replybuf + sizeof(replybuf)), roptinfo)) < 0) { dprintf(LOG_INFO, "%s" "failed to construct reply options", FNAME); return(-1); } len += optlen; /* specify the destination and send the reply */ dst = *sa6_any_downstream; dst.sin6_addr = ((struct sockaddr_in6 *)from)->sin6_addr; dst.sin6_scope_id = ((struct sockaddr_in6 *)from)->sin6_scope_id; if (transmit_sa(outsock, (struct sockaddr *)&dst, replybuf, len) != 0) { dprintf(LOG_ERR, "%s" "transmit %s to %s failed", FNAME, dhcp6msgstr(type), addr2str((struct sockaddr *)&dst)); return(-1); } dprintf(LOG_DEBUG, "%s" "transmit %s to %s", FNAME, dhcp6msgstr(type), addr2str((struct sockaddr *)&dst)); return 0;}static intcreate_conflist(type, clientid, ret_list, conf_list, req_list, do_binding) dhcp6_conftype_t type; struct duid *clientid; struct dhcp6_list *ret_list, *conf_list, *req_list; int do_binding;{ struct dhcp6_listval *clv; struct dhcp6_binding *binding; void *val; if (conf_list == NULL) return 0; /* sanity check about type */ switch(type) { case DHCP6_CONFINFO_PREFIX: break; default: dprintf(LOG_ERR, "%s" "unexpected configuration type(%d)", FNAME, type); exit(1); } for (clv = TAILQ_FIRST(conf_list); clv; clv = TAILQ_NEXT(clv, link)) { struct dhcp6_listval *dl; /* * If the client explicitly specified a list of option values, * we only return those specified values (if authorized). */ if (req_list) { switch(type) { case DHCP6_CONFINFO_PREFIX: if (dhcp6_find_listval(req_list, &clv->val_prefix6, DHCP6_LISTVAL_PREFIX6) == NULL) { continue; } break; } } /* * TODO: check if the requesting router is authorized. */ ; /* * If we already have a binding for the prefix, the request * is probably being retransmitted or the information is being * renewed. Then just update the timer of the binding. * Otherwise, create a binding for the prefix. */ if (do_binding) { if ((binding = find_binding(clientid, type, &clv->uv))) update_binding(binding); else if ((binding = add_binding(clientid, type, &clv->uv)) == NULL) { dprintf(LOG_ERR, "%s" "failed to create a " "binding"); continue; } val = binding->val; } else val = (void *)&clv->uv; /* add the entry to the returned list */ if ((dl = malloc(sizeof(*dl))) == NULL) { dprintf(LOG_ERR, "%s" "failed to allocate " "memory for prefix", FNAME); continue; /* XXX: remove binding? */ } switch(type) { case DHCP6_CONFINFO_PREFIX: dl->val_prefix6 = *(struct dhcp6_prefix *)val; break; } TAILQ_INSERT_TAIL(ret_list, dl, link); } return 0;}static struct dhcp6_binding *add_binding(clientid, type, val0) struct duid *clientid; dhcp6_conftype_t type; void *val0;{ struct dhcp6_binding *binding = NULL; u_int32_t duration = DHCP6_DURATITION_INFINITE; char *val = NULL; if ((binding = malloc(sizeof(*binding))) == NULL) { dprintf(LOG_ERR, "%s" "failed to allocate memory", FNAME); return(NULL); } memset(binding, 0, sizeof(*binding)); binding->type = type; if (duidcpy(&binding->clientid, clientid)) { dprintf(LOG_ERR, "%s" "failed to copy DUID"); goto fail; } switch(type) { case DHCP6_CONFINFO_PREFIX: duration = ((struct dhcp6_prefix *)val0)->duration; if ((val = malloc(sizeof(struct dhcp6_prefix))) == NULL) { dprintf(LOG_ERR, "%s" "failed to allocate memory for " "prefix"); goto fail; } memcpy(val, val0, sizeof(struct dhcp6_prefix)); binding->val = val; break; default: dprintf(LOG_ERR, "%s" "unexpected binding type(%d)", FNAME, type); exit(1); } binding->duration = duration; if (duration != DHCP6_DURATITION_INFINITE) { struct timeval timo; binding->timer = dhcp6_add_timer(binding_timo, binding); if (binding->timer == NULL) { dprintf(LOG_ERR, "%s" "failed to add timer", FNAME); goto fail; } timo.tv_sec = (long)duration; timo.tv_usec = 0; dhcp6_set_timer(&timo, binding->timer); } TAILQ_INSERT_TAIL(&dhcp6_binding_head, binding, link); dprintf(LOG_DEBUG, "%s" "add a new binding %s for %s", FNAME, bindingstr(binding), duidstr(clientid)); return(binding); fail: if (binding) { duidfree(&binding->clientid); free(binding); } if (val) free(val); return(NULL);}static struct dhcp6_binding *find_binding(clientid, type, val0) struct duid *clientid; dhcp6_conftype_t type; void *val0;{ struct dhcp6_binding *bp; struct dhcp6_prefix *pfx0, *pfx; for (bp = TAILQ_FIRST(&dhcp6_binding_head); bp; bp = TAILQ_NEXT(bp, link)) { if (bp->type != type || duidcmp(&bp->clientid, clientid)) { continue; } switch(type) { case DHCP6_CONFINFO_PREFIX: pfx0 = (struct dhcp6_prefix *)val0; pfx = (struct dhcp6_prefix *)bp->val; if (pfx0->plen == pfx->plen && IN6_ARE_ADDR_EQUAL(&pfx0->addr, &pfx->addr)) { return(bp); } break; default: dprintf(LOG_ERR, "%s" "unexpected binding type(%d)", FNAME, type); exit(1); } } return(NULL);}static voidupdate_binding(binding) struct dhcp6_binding *binding;{ struct timeval timo; /* if the lease duration is infinite, there's nothing to do. */ if (binding->duration == DHCP6_DURATITION_INFINITE) return; /* reset the timer with the duration */ timo.tv_sec = (long)binding->duration; timo.tv_usec = 0; dhcp6_set_timer(&timo, binding->timer); dprintf(LOG_DEBUG, "%s" "update a binding %s for %s", FNAME, bindingstr(binding), duidstr(&binding->clientid));}static voidremove_binding(binding) struct dhcp6_binding *binding;{ void *val = binding->val; dprintf(LOG_DEBUG, "%s" "removing a binding %s for %s", FNAME, bindingstr(binding), duidstr(&binding->clientid)); if (binding->timer) dhcp6_remove_timer(&binding->timer); TAILQ_REMOVE(&dhcp6_binding_head, binding, link); switch(binding->type) { case DHCP6_CONFINFO_PREFIX: dprintf(LOG_INFO, "%s" "remove prefix binding %s/%d for %s", FNAME, in6addr2str(&((struct dhcp6_prefix *)val)->addr, 0), ((struct dhcp6_prefix *)val)->plen, duidstr(&binding->clientid)); free(binding->val); break; default: dprintf(LOG_ERR, "%s" "unexpected binding type(%d)", FNAME, binding->type); exit(1); } duidfree(&binding->clientid); free(binding);}static struct dhcp6_timer *binding_timo(arg) void *arg;{ struct dhcp6_binding *binding = (struct dhcp6_binding *)arg; remove_binding(binding); return NULL;}static char *bindingstr(binding) struct dhcp6_binding *binding;{ struct dhcp6_prefix *pfx; static char strbuf[LINE_MAX]; /* XXX: thread unsafe */ switch(binding->type) { case DHCP6_CONFINFO_PREFIX: pfx = (struct dhcp6_prefix *)binding->val; snprintf(strbuf, sizeof(strbuf), "[prefix: %s/%d, duration=%ld]", in6addr2str(&pfx->addr, 0), pfx->plen, binding->duration); break; default: dprintf(LOG_ERR, "%s" "unexpected binding type(%d)", FNAME, binding->type); exit(1); } return(strbuf);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -