📄 dhcp6s.c
字号:
struct dhcp6_optinfo optinfo; memset(&iov, 0, sizeof(iov)); memset(&mhdr, 0, sizeof(mhdr)); iov.iov_base = rdatabuf; iov.iov_len = sizeof(rdatabuf); mhdr.msg_name = &from; mhdr.msg_namelen = sizeof(from); mhdr.msg_iov = &iov; mhdr.msg_iovlen = 1; mhdr.msg_control = (caddr_t)cmsgbuf; mhdr.msg_controllen = sizeof(cmsgbuf); if ((len = recvmsg(insock, &mhdr, 0)) < 0) { dprintf(LOG_ERR, "%s" "recvmsg: %s", FNAME, strerror(errno)); return -1; } for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr); cm; cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm)) { if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO && cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); } } if (pi == NULL) { dprintf(LOG_NOTICE, "%s" "failed to get packet info", FNAME); return -1; } if ((ifp = find_ifconfbyid((unsigned int)pi->ipi6_ifindex)) == NULL) { dprintf(LOG_INFO, "%s" "unexpected interface (%d)", FNAME, (unsigned int)pi->ipi6_ifindex); return; } if (len < sizeof(*dh6)) { dprintf(LOG_INFO, "%s" "short packet", FNAME); return -1; } dh6 = (struct dhcp6 *)rdatabuf; dprintf(LOG_DEBUG, "%s" "received %s from %s", FNAME, dhcp6msgstr(dh6->dh6_msgtype), addr2str((struct sockaddr *)&from)); /* * parse and validate options in the request */ dhcp6_init_options(&optinfo); if (dhcp6_get_options((struct dhcp6opt *)(dh6 + 1), (struct dhcp6opt *)(rdatabuf + len), &optinfo) < 0) { dprintf(LOG_INFO, "%s" "failed to parse options", FNAME); return -1; } switch (dh6->dh6_msgtype) { case DH6_SOLICIT: (void)server6_react_solicit(ifp, dh6, &optinfo, (struct sockaddr *)&from, fromlen); break; case DH6_REQUEST: (void)server6_react_request(ifp, pi, dh6, &optinfo, (struct sockaddr *)&from, fromlen); break; case DH6_RENEW: (void)server6_react_renew(ifp, pi, dh6, &optinfo, (struct sockaddr *)&from, fromlen); break; case DH6_REBIND: (void)server6_react_rebind(ifp, dh6, &optinfo, (struct sockaddr *)&from, fromlen); break; case DH6_INFORM_REQ: (void)server6_react_informreq(ifp, dh6, &optinfo, (struct sockaddr *)&from, fromlen); break; default: dprintf(LOG_INFO, "%s" "unknown or unsupported msgtype %s", FNAME, dhcp6msgstr(dh6->dh6_msgtype)); break; } dhcp6_clear_options(&optinfo); return 0;}static intserver6_react_solicit(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; struct host_conf *client_conf; struct dhcp6_listval *opt; struct dhcp6_list ret_prefix_list; int resptype, do_binding = 0, error; /* * Servers MUST discard any Solicit messages that do not include a * Client Identifier option. [dhcpv6-26 Section 15.2] */ if (optinfo->clientID.duid_len == 0) { dprintf(LOG_INFO, "%s" "no client ID option", FNAME); return(-1); } else { dprintf(LOG_DEBUG, "%s" "client ID %s", FNAME, duidstr(&optinfo->clientID)); } /* get per-host configuration for the client, if any. */ if ((client_conf = find_hostconf(&optinfo->clientID))) { dprintf(LOG_DEBUG, "%s" "found a host configuration for %s", FNAME, client_conf->name); } /* * configure necessary options based on the options in solicit. */ 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; } /* preference (if configured) */ if (ifp->server_pref != DH6OPT_PREF_UNDEF) roptinfo.pref = ifp->server_pref; /* DNS server */ if (dhcp6_copy_list(&roptinfo.dns_list, &dnslist)) { dprintf(LOG_ERR, "%s" "failed to copy DNS servers", FNAME); goto fail; } /* * see if we have information for requested options, and if so, * configure corresponding options. */ if (optinfo->rapidcommit && (ifp->allow_flags & DHCIFF_RAPID_COMMIT)) do_binding = 1; for (opt = TAILQ_FIRST(&optinfo->reqopt_list); opt; opt = TAILQ_NEXT(opt, link)) { switch(opt->val_num) { case DH6OPT_PREFIX_DELEGATION: create_conflist(DHCP6_CONFINFO_PREFIX, &optinfo->clientID, &roptinfo.prefix_list, client_conf ? &client_conf->prefix_list : NULL, TAILQ_EMPTY(&optinfo->prefix_list) ? NULL : &optinfo->prefix_list, do_binding); break; } } if (optinfo->rapidcommit && (ifp->allow_flags & DHCIFF_RAPID_COMMIT)) { /* * If the client has included a Rapid Commit option and the * server has been configured to respond with committed address * assignments and other resources, responds to the Solicit * with a Reply message. * [dhcpv6-26 Section 17.2.1] */ roptinfo.rapidcommit = 1; resptype = DH6_REPLY; } else resptype = DH6_ADVERTISE; error = server6_send(resptype, ifp, dh6, optinfo, from, fromlen, &roptinfo); dhcp6_clear_options(&roptinfo); return(error); fail: dhcp6_clear_options(&roptinfo); return -1;}static intserver6_react_request(ifp, pi, dh6, optinfo, from, fromlen) struct dhcp6_if *ifp; struct in6_pktinfo *pi; struct dhcp6 *dh6; struct dhcp6_optinfo *optinfo; struct sockaddr *from; int fromlen;{ struct dhcp6_optinfo roptinfo; struct host_conf *client_conf; struct dhcp6_listval *opt, *p; /* message validation according to Section 15.4 of dhcpv6-26 */ /* the message must include a Server Identifier option */ if (optinfo->serverID.duid_len == 0) { dprintf(LOG_INFO, "%s" "no server ID option", FNAME); return -1; } /* the contents of the Server Identifier option must match ours */ if (duidcmp(&optinfo->serverID, &server_duid)) { dprintf(LOG_INFO, "%s" "server ID mismatch", FNAME); return -1; } /* 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; } /* * 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; } /* * When the server receives a Request message via unicast from a * client to which the server has not sent a unicast option, the server * discards the Request message and responds with a Reply message * containing a Status Code option with value UseMulticast, a Server * Identifier option containing the server's DUID, the Client * Identifier option from the client message and no other options. * [dhcpv6-26 18.2.1] * (Our current implementation never sends a unicast option.) */ if (!IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr)) { int stcode = DH6OPT_STCODE_USEMULTICAST; dprintf(LOG_INFO, "%s" "unexpected unicast message from %s", FNAME, addr2str(from)); if (dhcp6_add_listval(&roptinfo.stcode_list, &stcode, DHCP6_LISTVAL_NUM) == NULL) { dprintf(LOG_ERR, "%s" "failed to add a status code", FNAME); goto fail; } server6_send(DH6_REPLY, ifp, dh6, optinfo, from, fromlen, &roptinfo); goto end; } /* get per-host configuration for the client, if any. */ if ((client_conf = find_hostconf(&optinfo->clientID))) { dprintf(LOG_DEBUG, "%s" "found a host configuration named %s", FNAME, client_conf->name); } /* * See if we have to make a binding of some configuration information * for the client. * (Note that our implementation does not assign addresses (nor will)). */ /* prefixes */ create_conflist(DHCP6_CONFINFO_PREFIX, &optinfo->clientID, &roptinfo.prefix_list, client_conf ? &client_conf->prefix_list : NULL, &optinfo->prefix_list, 1); /* * If the Request message contained an Option Request option, the * server MUST include options in the Reply message for any options in * the Option Request option the server is configured to return to the * client. * [dhcpv6-26 18.2.1] * Note: our current implementation always includes all information * that we can provide. So we do not have to check the option request * options. */#if 0 for (opt = TAILQ_FIRST(&optinfo->reqopt_list); opt; opt = TAILQ_NEXT(opt, link)) { ; }#endif /* * Adds options to the Reply message for any other configuration * information to be assigned to the client. */ /* DNS server */ if (dhcp6_copy_list(&roptinfo.dns_list, &dnslist)) { dprintf(LOG_ERR, "%s" "failed to copy DNS servers", FNAME); goto fail; } /* send a reply message. */ (void)server6_send(DH6_REPLY, ifp, dh6, optinfo, from, fromlen, &roptinfo); end: dhcp6_clear_options(&roptinfo); return 0; fail: dhcp6_clear_options(&roptinfo); return -1;}static intserver6_react_renew(ifp, pi, dh6, optinfo, from, fromlen) struct dhcp6_if *ifp; struct in6_pktinfo *pi; struct dhcp6 *dh6; struct dhcp6_optinfo *optinfo; struct sockaddr *from; int fromlen;{ struct dhcp6_optinfo roptinfo; struct dhcp6_listval *lv; struct dhcp6_binding *binding; int add_success = 0; /* message validation according to Section 15.6 of dhcpv6-26 */ /* the message must include a Server Identifier option */ if (optinfo->serverID.duid_len == 0) { dprintf(LOG_INFO, "%s" "no server ID option", FNAME); return -1; } /* the contents of the Server Identifier option must match ours */ if (duidcmp(&optinfo->serverID, &server_duid)) { dprintf(LOG_INFO, "%s" "server ID mismatch", FNAME); return -1; } /* 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; } /* * 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; } /* * When the server receives a Renew message via unicast from a * client to which the server has not sent a unicast option, the server * discards the Request message and responds with a Reply message * containing a status code option with value UseMulticast, a Server * Identifier option containing the server's DUID, the Client * Identifier option from the client message and no other options. * [dhcpv6-26 18.2.3] * (Our current implementation never sends a unicast option.) */ if (!IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr)) { int stcode = DH6OPT_STCODE_USEMULTICAST; dprintf(LOG_INFO, "%s" "unexpected unicast message from %s", FNAME, addr2str(from)); if (dhcp6_add_listval(&roptinfo.stcode_list, &stcode, DHCP6_LISTVAL_NUM) == NULL) { dprintf(LOG_ERR, "%s" "failed to add a status code", FNAME); goto fail; } server6_send(DH6_REPLY, ifp, dh6, optinfo, from, fromlen, &roptinfo); goto end; } /* * 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); /* include a Status Code option with value Success. */ if (!add_success) { int stcode = DH6OPT_STCODE_SUCCESS; if (dhcp6_add_listval(&roptinfo.stcode_list, &stcode, DHCP6_LISTVAL_NUM) == NULL) { dprintf(LOG_ERR, "%s" "failed to add a " "status code", FNAME); } add_success = 1; } /* add the prefix */ if (dhcp6_add_listval(&roptinfo.prefix_list, binding->val, DHCP6_LISTVAL_PREFIX6) == NULL) { dprintf(LOG_ERR, "%s" "failed to add a renewed prefix", FNAME); goto fail; } } (void)server6_send(DH6_REPLY, ifp, dh6, optinfo, from, fromlen, &roptinfo); end: dhcp6_clear_options(&roptinfo); return 0; fail: dhcp6_clear_options(&roptinfo); return -1;}static intserver6_react_rebind(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; struct dhcp6_listval *lv; struct dhcp6_binding *binding; int add_success = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -