From ebc0ec740280efd2ea7f22abbb84eda53ab06632 Mon Sep 17 00:00:00 2001 From: Dmitry Kozlov Date: Fri, 21 Nov 2014 15:46:17 +0300 Subject: dhcpv6: do not answer to REBIND if client did not get address yet --- accel-pppd/ipv6/dhcpv6.c | 98 ++++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c index a80b6222..62f20bb0 100644 --- a/accel-pppd/ipv6/dhcpv6.c +++ b/accel-pppd/ipv6/dhcpv6.c @@ -64,25 +64,25 @@ static void ev_ses_started(struct ap_session *ses) if (!ses->ipv6) return; - + sock = socket(AF_INET6, SOCK_DGRAM, 0); if (!sock) { log_ppp_error("dhcpv6: socket: %s\n", strerror(errno)); return; } - - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f)); + + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f)); if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ses->ifname, strlen(ses->ifname))) { log_ppp_error("ipv6_nd: setsockopt(SO_BINDTODEVICE): %s\n", strerror(errno)); close(sock); return; } - + memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_port = htons(DHCPV6_SERV_PORT); - + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) { log_ppp_error("dhcpv6: bind: %s\n", strerror(errno)); close(sock); @@ -99,13 +99,13 @@ static void ev_ses_started(struct ap_session *ses) close(sock); return; } - + fcntl(sock, F_SETFL, O_NONBLOCK); fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC); pd = _malloc(sizeof(*pd)); memset(pd, 0, sizeof(*pd)); - + pd->pd.key = &pd_key; list_add_tail(&pd->pd.entry, &ses->pd_list); @@ -140,10 +140,10 @@ static void ev_ses_finished(struct ap_session *ses) if (pd->clientid) _free(pd->clientid); - + if (ses->ipv6_dp) ipdb_put_ipv6_prefix(ses, ses->ipv6_dp); - + triton_md_unregister_handler(&pd->hnd, 1); _free(pd); @@ -261,7 +261,7 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i reply = dhcpv6_packet_alloc_reply(req, code); if (!reply) return; - + list_for_each_entry(opt, &req->opt_list, entry) { // IA_NA @@ -294,7 +294,7 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i build_addr(a, ses->ipv6->peer_intf_id, &ia_addr->addr); ia_addr->pref_lifetime = htonl(conf_pref_lifetime); - ia_addr->valid_lifetime = htonl(conf_valid_lifetime); + ia_addr->valid_lifetime = htonl(conf_valid_lifetime); } list_for_each_entry(opt2, &opt->opt_list, entry) { @@ -336,11 +336,11 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i opt1 = dhcpv6_option_alloc(reply, D6_OPTION_IA_PD, sizeof(struct dhcpv6_opt_ia_na) - sizeof(struct dhcpv6_opt_hdr)); memcpy(opt1->hdr + 1, opt->hdr + 1, ntohs(opt1->hdr->len)); - + ia_na = (struct dhcpv6_opt_ia_na *)opt1->hdr; ia_na->T1 = conf_pref_lifetime == -1 ? -1 : htonl(conf_pref_lifetime / 2); ia_na->T2 = conf_pref_lifetime == -1 ? -1 : htonl((conf_pref_lifetime * 4) / 5); - + if (!ses->ipv6_dp) ses->ipv6_dp = ipdb_get_ipv6_prefix(ses); @@ -361,11 +361,11 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i list_for_each_entry(a, &ses->ipv6_dp->prefix_list, entry) { opt2 = dhcpv6_nested_option_alloc(reply, opt1, D6_OPTION_IAPREFIX, sizeof(*ia_prefix) - sizeof(struct dhcpv6_opt_hdr)); ia_prefix = (struct dhcpv6_opt_ia_prefix *)opt2->hdr; - + memcpy(&ia_prefix->prefix, &a->addr, sizeof(a->addr)); ia_prefix->prefix_len = a->prefix_len; ia_prefix->pref_lifetime = htonl(conf_pref_lifetime); - ia_prefix->valid_lifetime = htonl(conf_valid_lifetime); + ia_prefix->valid_lifetime = htonl(conf_valid_lifetime); } list_for_each_entry(opt2, &opt->opt_list, entry) { @@ -396,7 +396,7 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i } } } - + //insert_status(reply, opt1, D6_STATUS_Success); } @@ -450,7 +450,7 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, reply = dhcpv6_packet_alloc_reply(req, code); if (!reply) return; - + list_for_each_entry(opt, &req->opt_list, entry) { // IA_NA @@ -472,7 +472,7 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, continue; f1 = 0; - + if (!f) { list_for_each_entry(a, &ses->ipv6->addr_list, entry) { build_addr(a, ses->ipv6->peer_intf_id, &addr); @@ -490,12 +490,12 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, ia_addr = (struct dhcpv6_opt_ia_addr *)opt3->hdr; if (f1) { ia_addr->pref_lifetime = htonl(conf_pref_lifetime); - ia_addr->valid_lifetime = htonl(conf_valid_lifetime); + ia_addr->valid_lifetime = htonl(conf_valid_lifetime); } else { ia_addr->pref_lifetime = 0; ia_addr->valid_lifetime = 0; - insert_status(reply, opt3, D6_STATUS_NotOnLink); + goto out; } } } @@ -510,14 +510,17 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, } else if (ntohs(opt->hdr->code) == D6_OPTION_IA_PD) { opt1 = dhcpv6_option_alloc(reply, D6_OPTION_IA_PD, sizeof(struct dhcpv6_opt_ia_na) - sizeof(struct dhcpv6_opt_hdr)); memcpy(opt1->hdr + 1, opt->hdr + 1, ntohs(opt1->hdr->len)); - + ia_na = (struct dhcpv6_opt_ia_na *)opt1->hdr; ia_na->T1 = conf_pref_lifetime == -1 ? -1 : htonl(conf_pref_lifetime / 2); ia_na->T2 = conf_pref_lifetime == -1 ? -1 : htonl((conf_pref_lifetime * 4) / 5); - + if (!ses->ipv6_dp) ses->ipv6_dp = ipdb_get_ipv6_prefix(req->ses); + if (!ses->ipv6_dp) + goto out; + f3 = 0; list_for_each_entry(opt2, &opt->opt_list, entry) { @@ -547,12 +550,12 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, if (f1) { ia_prefix->pref_lifetime = htonl(conf_pref_lifetime); - ia_prefix->valid_lifetime = htonl(conf_valid_lifetime); + ia_prefix->valid_lifetime = htonl(conf_valid_lifetime); } else { ia_prefix->pref_lifetime = 0; ia_prefix->valid_lifetime = 0; - insert_status(reply, opt3, D6_STATUS_NotOnLink); + goto out; } } } @@ -561,7 +564,6 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, pd->dp_iaid = ia_na->iaid; f2 = 1; } - // Option Request } else if (ntohs(opt->hdr->code) == D6_OPTION_ORO) insert_oro(reply, opt); @@ -579,6 +581,7 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, sendto(pd->hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&req->addr, sizeof(req->addr)); +out: dhcpv6_packet_free(reply); } @@ -633,7 +636,7 @@ static void dhcpv6_recv_request(struct dhcpv6_packet *req) log_ppp_error("dhcpv6: unmatched Client-ID option\n"); return; } - + dhcpv6_send_reply(req, pd, D6_REPLY); } @@ -661,20 +664,20 @@ static void dhcpv6_recv_renew(struct dhcpv6_packet *req) log_ppp_error("dhcpv6: no Request was received\n"); return; } - + if (req->clientid->hdr.len != pd->clientid->hdr.len || memcmp(req->clientid, pd->clientid, ntohs(pd->clientid->hdr.len) + sizeof(struct dhcpv6_opt_hdr))) { log_ppp_error("dhcpv6: unmatched Client-ID option\n"); return; } - + dhcpv6_send_reply(req, pd, D6_REPLY); } static void dhcpv6_recv_information_request(struct dhcpv6_packet *req) { struct dhcpv6_pd *pd = req->pd; - + if (req->rapid_commit) { log_ppp_error("dhcpv6: unexpected Rapid-Commit option\n"); return; @@ -699,14 +702,13 @@ static void dhcpv6_recv_rebind(struct dhcpv6_packet *req) return; } - if (!pd->clientid) { - pd->clientid = _malloc(sizeof(struct dhcpv6_opt_hdr) + ntohs(req->clientid->hdr.len)); - memcpy(pd->clientid, req->clientid, sizeof(struct dhcpv6_opt_hdr) + ntohs(req->clientid->hdr.len)); - } else if (pd->clientid->hdr.len != req->clientid->hdr.len || memcmp(pd->clientid, req->clientid, sizeof(struct dhcpv6_opt_hdr) + ntohs(req->clientid->hdr.len))) { + if (!pd->clientid) + return; + else if (pd->clientid->hdr.len != req->clientid->hdr.len || memcmp(pd->clientid, req->clientid, sizeof(struct dhcpv6_opt_hdr) + ntohs(req->clientid->hdr.len))) { log_ppp_error("dhcpv6: unmatched Client-ID option\n"); return; } - + req->serverid = &conf_serverid; dhcpv6_send_reply2(req, pd, D6_REPLY); @@ -808,19 +810,19 @@ static void add_dnssl(const char *val) n++; else n += 2; - + if (n > 255) { log_error("dnsv6: dnssl '%s' is too long\n", val); return; } - + if (!conf_dnssl) conf_dnssl = _malloc(n); else conf_dnssl = _realloc(conf_dnssl, conf_dnssl_size + n); - + buf = conf_dnssl + conf_dnssl_size; - + while (1) { ptr = strchr(val, '.'); if (!ptr) @@ -838,7 +840,7 @@ static void add_dnssl(const char *val) break; } } - + conf_dnssl_size += n; } @@ -846,12 +848,12 @@ static void load_dns(void) { struct conf_sect_t *s = conf_get_section("ipv6-dns"); struct conf_option_t *opt; - + if (!s) return; - + conf_dns_count = 0; - + if (conf_dnssl) _free(conf_dnssl); conf_dnssl = NULL; @@ -888,7 +890,7 @@ static uint64_t parse_serverid(const char *opt) if (sscanf(opt, "%x:%x:%x:%x", &n[0], &n[1], &n[2], &n[3]) != 4) goto err; - + for (i = 0; i < 4; i++) { if (n[i] < 0 || n[i] > 0xffff) goto err; @@ -910,19 +912,19 @@ static void load_config(void) opt = conf_get_opt("ipv6-dhcp", "verbose"); if (opt) conf_verbose = atoi(opt); - + opt = conf_get_opt("ipv6-dhcp", "pref-lifetime"); if (opt) conf_pref_lifetime = atoi(opt); - + opt = conf_get_opt("ipv6-dhcp", "valid-lifetime"); if (opt) conf_valid_lifetime = atoi(opt); - + opt = conf_get_opt("ipv6-dhcp", "route-via-gw"); if (opt) conf_route_via_gw = atoi(opt); - + opt = conf_get_opt("ipv6-dhcp", "server-id"); if (opt) id = parse_serverid(opt); @@ -935,7 +937,7 @@ static void load_config(void) conf_serverid.duid.u.ll.htype = htons(27); //conf_serverid.duid.u.llt.time = htonl(t - t0); *(uint64_t *)conf_serverid.duid.u.ll.addr = id; - + load_dns(); } -- cgit v1.2.3