summaryrefslogtreecommitdiff
path: root/accel-pppd
diff options
context:
space:
mode:
authorKozlov Dmitry <xeb@mail.ru>2011-09-02 18:10:43 +0400
committerKozlov Dmitry <xeb@mail.ru>2011-09-02 18:10:43 +0400
commit88bd2cb7316507ac3918291650b5dfdd286523f9 (patch)
tree79de51c85e3a1f2aa53d6ef08286e28e68e35d0c /accel-pppd
parent75ad93405df49586c10ac3b4ba73559757190170 (diff)
parent09aa6f0728a0678acd6f1907d4b0b93334ace3c3 (diff)
downloadaccel-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.c221
-rw-r--r--accel-pppd/ipv6/nd.c114
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);