diff options
author | Kozlov Dmitry <xeb@mail.ru> | 2011-09-02 18:10:43 +0400 |
---|---|---|
committer | Kozlov Dmitry <xeb@mail.ru> | 2011-09-02 18:10:43 +0400 |
commit | 88bd2cb7316507ac3918291650b5dfdd286523f9 (patch) | |
tree | 79de51c85e3a1f2aa53d6ef08286e28e68e35d0c /accel-pppd | |
parent | 75ad93405df49586c10ac3b4ba73559757190170 (diff) | |
parent | 09aa6f0728a0678acd6f1907d4b0b93334ace3c3 (diff) | |
download | accel-ppp-88bd2cb7316507ac3918291650b5dfdd286523f9.tar.gz accel-ppp-88bd2cb7316507ac3918291650b5dfdd286523f9.zip |
Merge branch 'master' of ssh://accel-ppp.git.sourceforge.net/gitroot/accel-ppp/accel-ppp
Diffstat (limited to 'accel-pppd')
-rw-r--r-- | accel-pppd/ipv6/dhcpv6.c | 221 | ||||
-rw-r--r-- | accel-pppd/ipv6/nd.c | 114 |
2 files changed, 310 insertions, 25 deletions
diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c index 7b37599d..22a4c8ef 100644 --- a/accel-pppd/ipv6/dhcpv6.c +++ b/accel-pppd/ipv6/dhcpv6.c @@ -207,12 +207,16 @@ static void insert_oro(struct dhcpv6_packet *reply, struct dhcpv6_option *opt) for (i = ntohs(opt->hdr->len) / 2, ptr = (uint16_t *)opt->hdr->data; i; i--, ptr++) { if (ntohs(*ptr) == D6_OPTION_DNS_SERVERS) { - opt1 = dhcpv6_option_alloc(reply, D6_OPTION_DNS_SERVERS, conf_dns_count * sizeof(addr)); - for (j = 0, addr_ptr = (struct in6_addr *)opt1->hdr->data; j < conf_dns_count; j++, addr_ptr++) - memcpy(addr_ptr, conf_dns + j, sizeof(addr)); + if (conf_dns_count) { + opt1 = dhcpv6_option_alloc(reply, D6_OPTION_DNS_SERVERS, conf_dns_count * sizeof(addr)); + for (j = 0, addr_ptr = (struct in6_addr *)opt1->hdr->data; j < conf_dns_count; j++, addr_ptr++) + memcpy(addr_ptr, conf_dns + j, sizeof(addr)); + } } else if (ntohs(*ptr) == D6_OPTION_DOMAIN_LIST) { - opt1 = dhcpv6_option_alloc(reply, D6_OPTION_DOMAIN_LIST, conf_dnssl_size); - memcpy(opt1->hdr->data, conf_dnssl, conf_dnssl_size); + if (conf_dnssl_size) { + opt1 = dhcpv6_option_alloc(reply, D6_OPTION_DOMAIN_LIST, conf_dnssl_size); + memcpy(opt1->hdr->data, conf_dnssl, conf_dnssl_size); + } } } } @@ -236,6 +240,9 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i // IA_NA if (ntohs(opt->hdr->code) == D6_OPTION_IA_NA) { + if (req->hdr->type == D6_INFORMATION_REQUEST) + continue; + opt1 = dhcpv6_option_alloc(reply, D6_OPTION_IA_NA, sizeof(struct dhcpv6_opt_ia_na) - sizeof(struct dhcpv6_opt_hdr)); memcpy(opt1->hdr + 1, opt->hdr + 1, ntohs(opt1->hdr->len)); @@ -298,6 +305,9 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i // IA_PD } else if (ntohs(opt->hdr->code) == D6_OPTION_IA_PD) { + if (req->hdr->type == D6_INFORMATION_REQUEST) + continue; + 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)); @@ -366,16 +376,170 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i // IA_TA } else if (ntohs(opt->hdr->code) == D6_OPTION_IA_TA) { + if (req->hdr->type == D6_INFORMATION_REQUEST) + continue; + opt1 = dhcpv6_option_alloc(reply, D6_OPTION_IA_TA, sizeof(struct dhcpv6_opt_ia_ta) - sizeof(struct dhcpv6_opt_hdr)); memcpy(opt1->hdr + 1, opt->hdr + 1, ntohs(opt1->hdr->len)); insert_status(reply, opt1, D6_STATUS_NoAddrsAvail); // Option Request - } else if (ntohs(opt->hdr->code) == D6_OPTION_ORO) + } else if (ntohs(opt->hdr->code) == D6_OPTION_ORO) { insert_oro(reply, opt); + + } else if (ntohs(opt->hdr->code) == D6_OPTION_RAPID_COMMIT) { + if (req->hdr->type == D6_SOLICIT) + dhcpv6_option_alloc(reply, D6_OPTION_RAPID_COMMIT, 0); + } } + + opt1 = dhcpv6_option_alloc(reply, D6_OPTION_PREFERENCE, 1); + *(uint8_t *)opt1->hdr->data = 255; + + //insert_status(reply, NULL, D6_STATUS_Success); + + if (conf_verbose) { + log_ppp_info2("send "); + dhcpv6_packet_print(reply, log_ppp_info2); + } + + dhcpv6_send(reply); + + dhcpv6_packet_free(reply); +} + +static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, int code) +{ + struct dhcpv6_packet *reply; + struct dhcpv6_option *opt, *opt1, *opt2, *opt3; + struct dhcpv6_opt_ia_na *ia_na; + struct dhcpv6_opt_ia_addr *ia_addr; + struct dhcpv6_opt_ia_prefix *ia_prefix; + struct ipv6db_addr_t *a; + struct in6_addr addr; + int f = 0, f1, f2 = 0, f3; + + reply = dhcpv6_packet_alloc_reply(req, code); + if (!reply) + return; + list_for_each_entry(opt, &req->opt_list, entry) { + + // IA_NA + if (ntohs(opt->hdr->code) == D6_OPTION_IA_NA) { + opt1 = dhcpv6_option_alloc(reply, D6_OPTION_IA_NA, 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); + + f3 = 0; + + list_for_each_entry(opt2, &opt->opt_list, entry) { + if (ntohs(opt2->hdr->code) == D6_OPTION_IAADDR) { + ia_addr = (struct dhcpv6_opt_ia_addr *)opt2->hdr; + + if (IN6_IS_ADDR_UNSPECIFIED(&ia_addr->addr)) + continue; + + f1 = 0; + + if (!f) { + list_for_each_entry(a, &req->ppp->ipv6->addr_list, entry) { + build_addr(a, req->ppp->ipv6->peer_intf_id, &addr); + if (memcmp(&addr, &ia_addr->addr, sizeof(addr))) + continue; + f1 = 1; + f3 = 1; + break; + } + } + + opt3 = dhcpv6_nested_option_alloc(reply, opt1, D6_OPTION_IAADDR, sizeof(*ia_addr) - sizeof(struct dhcpv6_opt_hdr)); + memcpy(opt3->hdr->data, opt2->hdr->data, sizeof(*ia_addr) - sizeof(struct dhcpv6_opt_hdr)); + + 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); + } else { + ia_addr->pref_lifetime = 0; + ia_addr->valid_lifetime = 0; + + insert_status(reply, opt3, D6_STATUS_NotOnLink); + } + } + } + + if (f3) { + pd->addr_iaid = ia_na->iaid; + f = 1; + } + + + // IA_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 (!pd->ipv6_dp) + pd->ipv6_dp = ipdb_get_ipv6_prefix(req->ppp); + + f3 = 0; + + list_for_each_entry(opt2, &opt->opt_list, entry) { + if (ntohs(opt2->hdr->code) == D6_OPTION_IAPREFIX) { + ia_prefix = (struct dhcpv6_opt_ia_prefix *)opt2->hdr; + + if (ia_prefix->prefix_len == 0 || IN6_IS_ADDR_UNSPECIFIED(&ia_prefix->prefix)) + continue; + + f1 = 0; + + if (!f2) { + list_for_each_entry(a, &pd->ipv6_dp->prefix_list, entry) { + if (a->prefix_len != ia_prefix->prefix_len) + continue; + if (memcmp(&a->addr, &ia_prefix->prefix, sizeof(a->addr))) + continue; + f1 = 1; + f3 = 1; + break; + } + } + + opt3 = dhcpv6_nested_option_alloc(reply, opt1, D6_OPTION_IAPREFIX, sizeof(*ia_prefix) - sizeof(struct dhcpv6_opt_hdr)); + memcpy(opt3->hdr->data, opt2->hdr->data, sizeof(*ia_prefix) - sizeof(struct dhcpv6_opt_hdr)); + ia_prefix = (struct dhcpv6_opt_ia_prefix *)opt3->hdr; + + if (f1) { + ia_prefix->pref_lifetime = htonl(conf_pref_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); + } + } + } + + if (f3) { + pd->dp_iaid = ia_na->iaid; + f2 = 1; + } + + // Option Request + } else if (ntohs(opt->hdr->code) == D6_OPTION_ORO) + insert_oro(reply, opt); + } + opt1 = dhcpv6_option_alloc(reply, D6_OPTION_PREFERENCE, 1); *(uint8_t *)opt1->hdr->data = 255; @@ -391,6 +555,7 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i dhcpv6_packet_free(reply); } + static void dhcpv6_recv_solicit(struct dhcpv6_packet *req) { struct dhcpv6_pd *pd = find_pd(req->ppp); @@ -488,9 +653,48 @@ static void dhcpv6_recv_renew(struct dhcpv6_packet *req) dhcpv6_send_reply(req, pd, D6_REPLY); } +static void dhcpv6_recv_information_request(struct dhcpv6_packet *req) +{ + struct dhcpv6_pd *pd = find_pd(req->ppp); + + if (req->rapid_commit) { + log_ppp_error("dhcpv6: unexpected Rapid-Commit option\n"); + return; + } + + req->serverid = &conf_serverid; + + dhcpv6_send_reply(req, pd, D6_REPLY); +} + static void dhcpv6_recv_rebind(struct dhcpv6_packet *req) { - // don't answer + struct dhcpv6_pd *pd = find_pd(req->ppp); + + if (!pd) + return; + + if (!req->clientid) { + log_ppp_error("dhcpv6: no Client-ID option\n"); + return; + } + + if (req->serverid) { + log_ppp_error("dhcpv6: unexcpected Server-ID option\n"); + 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))) { + log_ppp_error("dhcpv6: unmatched Client-ID option\n"); + return; + } + + req->serverid = &conf_serverid; + + dhcpv6_send_reply2(req, pd, D6_REPLY); } static void dhcpv6_recv_release(struct dhcpv6_packet *pkt) @@ -529,6 +733,9 @@ static void dhcpv6_recv_packet(struct dhcpv6_packet *pkt) case D6_DECLINE: dhcpv6_recv_decline(pkt); break; + case D6_INFORMATION_REQUEST: + dhcpv6_recv_information_request(pkt); + break; } dhcpv6_packet_free(pkt); diff --git a/accel-pppd/ipv6/nd.c b/accel-pppd/ipv6/nd.c index 07b0d2a5..1ef9bf7d 100644 --- a/accel-pppd/ipv6/nd.c +++ b/accel-pppd/ipv6/nd.c @@ -21,16 +21,27 @@ #define MAX_DNS_COUNT 3 -static int conf_init_ra = 3; -static int conf_init_ra_interval = 1; -static int conf_ra_interval = 60; -static int conf_router_lifetime = 300; -static int conf_rdnss_lifetime = 300; +static int conf_init_ra = 5; +static int conf_init_ra_interval = 3; +static int conf_rdnss_lifetime; static struct in6_addr conf_dns[MAX_DNS_COUNT]; static int conf_dns_count; static void *conf_dnssl; static int conf_dnssl_size; -static int conf_managed; + +static int conf_MaxRtrAdvInterval = 600; +static int conf_MinRtrAdvInterval; +static int conf_AdvManagedFlag; +static int conf_AdvOtherConfigFlag; +static int conf_AdvLinkMTU; +static int conf_AdvReachableTime; +static int conf_AdvRetransTimer; +static int conf_AdvCurHopLimit = 64; +static int conf_AdvDefaultLifetime; +static int conf_AdvPrefixValidLifetime = 2592000; +static int conf_AdvPrefixPreferredLifetime = 604800; +static int conf_AdvPrefixAutonomousFlag; + #undef ND_OPT_ROUTE_INFORMATION #define ND_OPT_ROUTE_INFORMATION 24 @@ -100,12 +111,13 @@ static void ipv6_nd_send_ra(struct ipv6_nd_handler_t *h, struct sockaddr_in6 *ad memset(adv, 0, sizeof(*adv)); adv->nd_ra_type = ND_ROUTER_ADVERT; - adv->nd_ra_curhoplimit = 64; - adv->nd_ra_router_lifetime = htons(conf_router_lifetime); + adv->nd_ra_curhoplimit = conf_AdvCurHopLimit; + adv->nd_ra_router_lifetime = htons(conf_AdvDefaultLifetime); adv->nd_ra_flags_reserved = - conf_managed ? ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER : 0; - //adv->nd_ra_reachable = 0; - //adv->nd_ra_retransmit = 0; + (conf_AdvManagedFlag ? ND_RA_FLAG_MANAGED : 0) | + (conf_AdvOtherConfigFlag ? ND_RA_FLAG_OTHER : 0); + adv->nd_ra_reachable = htonl(conf_AdvReachableTime); + adv->nd_ra_retransmit = htonl(conf_AdvRetransTimer); pinfo = (struct nd_opt_prefix_info *)(adv + 1); list_for_each_entry(a, &h->ppp->ipv6->addr_list, entry) { @@ -116,9 +128,9 @@ static void ipv6_nd_send_ra(struct ipv6_nd_handler_t *h, struct sockaddr_in6 *ad pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; pinfo->nd_opt_pi_len = 4; pinfo->nd_opt_pi_prefix_len = a->prefix_len; - pinfo->nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_ONLINK | ((a->flag_auto || !conf_managed) ? ND_OPT_PI_FLAG_AUTO : 0); - pinfo->nd_opt_pi_valid_time = 0xffffffff; - pinfo->nd_opt_pi_preferred_time = 0xffffffff; + pinfo->nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_ONLINK | ((a->flag_auto || conf_AdvPrefixAutonomousFlag) ? ND_OPT_PI_FLAG_AUTO : 0); + pinfo->nd_opt_pi_valid_time = htonl(conf_AdvPrefixValidLifetime); + pinfo->nd_opt_pi_preferred_time = htonl(conf_AdvPrefixPreferredLifetime); memcpy(&pinfo->nd_opt_pi_prefix, &a->addr, 8); pinfo++; } @@ -177,7 +189,7 @@ static void send_ra_timer(struct triton_timer_t *t) addr.sin6_scope_id = h->ppp->ifindex; if (h->ra_sent++ == conf_init_ra) { - h->timer.period = conf_ra_interval * 1000; + h->timer.period = conf_MaxRtrAdvInterval * 1000; triton_timer_mod(t, 0); } @@ -408,7 +420,7 @@ static void add_dnssl(const char *val) conf_dnssl_size += n; } -static void load_config(void) +static void load_dns(void) { struct conf_sect_t *s = conf_get_section("ipv6-dns"); struct conf_option_t *opt; @@ -428,6 +440,11 @@ static void load_config(void) add_dnssl(opt->val); continue; } + + if (!strcmp(opt->name, "lifetime")) { + conf_rdnss_lifetime = atoi(opt->val); + continue; + } if (!strcmp(opt->name, "dns") || !opt->val) { if (conf_dns_count == MAX_DNS_COUNT) @@ -442,14 +459,75 @@ static void load_config(void) } } +static void load_config(void) +{ + const char *opt; + + opt = conf_get_opt("ipv6-nd", "MaxRtrAdvInterval"); + if (opt) + conf_MaxRtrAdvInterval = atoi(opt); + + conf_MinRtrAdvInterval = 0.33 * conf_MaxRtrAdvInterval; + conf_AdvDefaultLifetime = 3 * conf_MaxRtrAdvInterval; + + conf_AdvManagedFlag = triton_module_loaded("ipv6_dhcp"); + conf_AdvOtherConfigFlag = triton_module_loaded("ipv6_dhcp"); + conf_AdvPrefixAutonomousFlag = !conf_AdvManagedFlag; + conf_rdnss_lifetime = conf_MaxRtrAdvInterval; + + opt = conf_get_opt("ipv6-nd", "MinRtrAdvInterval"); + if (opt) + conf_MinRtrAdvInterval = atoi(opt); + + opt = conf_get_opt("ipv6-nd", "AdvManagedFlag"); + if (opt) + conf_AdvManagedFlag = atoi(opt); + + opt = conf_get_opt("ipv6-nd", "AdvOtherConfigFlag"); + if (opt) + conf_AdvOtherConfigFlag = atoi(opt); + + opt = conf_get_opt("ipv6-nd", "AdvLinkMTU"); + if (opt) + conf_AdvLinkMTU = atoi(opt); + + opt = conf_get_opt("ipv6-nd", "AdvReachableTime"); + if (opt) + conf_AdvReachableTime = atoi(opt); + + opt = conf_get_opt("ipv6-nd", "AdvRetransTimer"); + if (opt) + conf_AdvRetransTimer = atoi(opt); + + opt = conf_get_opt("ipv6-nd", "AdvCurHopLimit"); + if (opt) + conf_AdvCurHopLimit = atoi(opt); + + opt = conf_get_opt("ipv6-nd", "AdvDefaultLifetime"); + if (opt) + conf_AdvDefaultLifetime = atoi(opt); + + opt = conf_get_opt("ipv6-nd", "AdvValidLifetime"); + if (opt) + conf_AdvPrefixValidLifetime = atoi(opt); + + opt = conf_get_opt("ipv6-nd", "AdvPreferredLifetime"); + if (opt) + conf_AdvPrefixPreferredLifetime = atoi(opt); + + opt = conf_get_opt("ipv6-nd", "AdvAutonomousFlag"); + if (opt) + conf_AdvPrefixAutonomousFlag = atoi(opt); + + load_dns(); +} + static void init(void) { buf_pool = mempool_create(BUF_SIZE); load_config(); - conf_managed = triton_module_loaded("ipv6_dhcp"); - triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); triton_event_register_handler(EV_PPP_STARTED, (triton_event_func)ev_ppp_started); triton_event_register_handler(EV_PPP_FINISHING, (triton_event_func)ev_ppp_finishing); |