From 9bc3fa4216fb2ad043232584b5a5e134e64830ed Mon Sep 17 00:00:00 2001 From: Kozlov Dmitry Date: Tue, 23 Aug 2011 18:02:22 +0400 Subject: ppp: ipv6: multiple prefixes, route option, rdnss option implementation --- accel-pppd/cli/show_sessions.c | 3 +- accel-pppd/cli/std_cmd.c | 3 +- accel-pppd/extra/ipv6pool.c | 37 +- .../extra/net-snmp/sessionTable_data_access.c | 3 +- accel-pppd/extra/net-snmp/terminate.c | 3 +- accel-pppd/extra/pppd_compat.c | 5 +- accel-pppd/ipdb.h | 12 +- accel-pppd/ppp/ipcp_opt_ipaddr.c | 102 ++-- accel-pppd/ppp/ipv6_nd.c | 207 ++++--- accel-pppd/ppp/ipv6cp_opt_intfid.c | 49 +- accel-pppd/ppp/ppp.h | 9 +- accel-pppd/radius/radius.c | 4 +- accel-pppd/radius/req.c | 6 +- rfc/rfc5006.txt | 675 +++++++++++++++++++++ 14 files changed, 940 insertions(+), 178 deletions(-) create mode 100644 rfc/rfc5006.txt diff --git a/accel-pppd/cli/show_sessions.c b/accel-pppd/cli/show_sessions.c index d7a8a824..90199864 100644 --- a/accel-pppd/cli/show_sessions.c +++ b/accel-pppd/cli/show_sessions.c @@ -8,6 +8,7 @@ #include "triton.h" #include "events.h" #include "ppp.h" +#include "ipdb.h" #include "cli.h" #include "utils.h" #include "log.h" @@ -382,7 +383,7 @@ static void print_username(const struct ppp_t *ppp, char *buf) static void print_ip(const struct ppp_t *ppp, char *buf) { - u_inet_ntoa(ppp->peer_ipaddr, buf); + u_inet_ntoa(ppp->ipv4 ? ppp->ipv4->peer_addr : 0, buf); } static void print_type(const struct ppp_t *ppp, char *buf) diff --git a/accel-pppd/cli/std_cmd.c b/accel-pppd/cli/std_cmd.c index 1c8e149f..24e52283 100644 --- a/accel-pppd/cli/std_cmd.c +++ b/accel-pppd/cli/std_cmd.c @@ -9,6 +9,7 @@ #include "triton.h" #include "events.h" #include "ppp.h" +#include "ipdb.h" #include "cli.h" #include "utils.h" #include "log.h" @@ -166,7 +167,7 @@ static int terminate_exec2(int key, char * const *f, int f_cnt, void *cli) continue; break; case 1: - if (ppp->peer_ipaddr != ipaddr) + if (ppp->ipv4 && ppp->ipv4->peer_addr != ipaddr) continue; break; case 2: diff --git a/accel-pppd/extra/ipv6pool.c b/accel-pppd/extra/ipv6pool.c index 306d5bdd..5a1a6065 100644 --- a/accel-pppd/extra/ipv6pool.c +++ b/accel-pppd/extra/ipv6pool.c @@ -39,6 +39,7 @@ static void generate_pool(struct in6_addr *addr, int mask, int prefix_len) { struct ippool_item_t *it; uint64_t ip, endip, step; + struct ipv6db_addr_t *a; ip = be64toh(*(uint64_t *)addr->s6_addr); endip = ip | ((1llu << (64 - mask)) - 1); @@ -46,8 +47,13 @@ static void generate_pool(struct in6_addr *addr, int mask, int prefix_len) for (; ip <= endip; ip += step) { it = malloc(sizeof(*it)); - *(uint64_t *)it->it.addr.s6_addr = htobe64(ip); - it->it.prefix_len = prefix_len; + INIT_LIST_HEAD(&it->it.addr_list); + INIT_LIST_HEAD(&it->it.route_list); + a = malloc(sizeof(*a)); + memset(a, 0, sizeof(*a)); + *(uint64_t *)a->addr.s6_addr = htobe64(ip); + a->prefix_len = prefix_len; + list_add_tail(&a->entry, &it->it.addr_list); list_add_tail(&it->entry, &ippool); } } @@ -97,27 +103,36 @@ err: _free(val); } -static void generate_intf_id(struct ppp_t *ppp, struct in6_addr *addr) +static uint64_t generate_intf_id(struct ppp_t *ppp) { char str[4]; int i, n; + union { + uint64_t intf_id; + uint16_t addr16[4]; + } u; switch (conf_intf_id) { case INTF_ID_FIXED: - *(uint64_t *)(&addr->s6_addr32[2]) = conf_intf_id_val; + return conf_intf_id_val; break; case INTF_ID_RANDOM: - read(urandom_fd, &addr->s6_addr32[2], 8); + read(urandom_fd, &u, sizeof(u)); break; case INTF_ID_CSID: break; case INTF_ID_IPV4: - for (i = 0; i < 4; i++) { - sprintf(str, "%i", (ppp->peer_ipaddr >> (i*8)) & 0xff); - sscanf(str, "%x", &n); - addr->s6_addr16[4 + i] = htons(n); - } + if (ppp->ipv4) { + for (i = 0; i < 4; i++) { + sprintf(str, "%i", (ppp->ipv4->peer_addr >> (i*8)) & 0xff); + sscanf(str, "%x", &n); + u.addr16[i] = htons(n); + } + } else + read(urandom_fd, &u, sizeof(u)); } + + return u.intf_id; } static struct ipv6db_item_t *get_ip(struct ppp_t *ppp) @@ -133,7 +148,7 @@ static struct ipv6db_item_t *get_ip(struct ppp_t *ppp) spin_unlock(&pool_lock); if (it) - generate_intf_id(ppp, &it->it.addr); + it->it.intf_id = generate_intf_id(ppp); return it ? &it->it : NULL; } diff --git a/accel-pppd/extra/net-snmp/sessionTable_data_access.c b/accel-pppd/extra/net-snmp/sessionTable_data_access.c index 847197af..0d38e5df 100644 --- a/accel-pppd/extra/net-snmp/sessionTable_data_access.c +++ b/accel-pppd/extra/net-snmp/sessionTable_data_access.c @@ -16,6 +16,7 @@ #include "sessionTable_data_access.h" #include "ppp.h" +#include "ipdb.h" /** @ingroup interface * @addtogroup data_access data_access: Routines to access data @@ -227,7 +228,7 @@ sessionTable_container_load(netsnmp_container *container) else ppp->username = strdup(""); - rowreq_ctx->data->peer_addr = ppp->peer_ipaddr; + rowreq_ctx->data->peer_addr = ppp->ipv4 ? ppp->ipv4->peer_addr : 0; rowreq_ctx->data->type = ppp->ctrl->type; rowreq_ctx->data->state = ppp->state; rowreq_ctx->data->uptime = (ppp->stop_time ? ppp->stop_time : t) - ppp->start_time; diff --git a/accel-pppd/extra/net-snmp/terminate.c b/accel-pppd/extra/net-snmp/terminate.c index bd385772..abe92df0 100644 --- a/accel-pppd/extra/net-snmp/terminate.c +++ b/accel-pppd/extra/net-snmp/terminate.c @@ -12,6 +12,7 @@ #include "triton.h" #include "ppp.h" +#include "ipdb.h" #include "terminate.h" @@ -65,7 +66,7 @@ static void terminate_by_ip(const char *val, size_t len) pthread_rwlock_rdlock(&ppp_lock); list_for_each_entry(ppp, &ppp_list, entry) { - if (ppp->peer_ipaddr != addr) + if (!ppp->ipv4 || ppp->ipv4->peer_addr != addr) continue; triton_context_call(ppp->ctrl->ctx, (triton_event_func)__terminate, ppp); break; diff --git a/accel-pppd/extra/pppd_compat.c b/accel-pppd/extra/pppd_compat.c index aa6f6b59..32a5def9 100644 --- a/accel-pppd/extra/pppd_compat.c +++ b/accel-pppd/extra/pppd_compat.c @@ -14,6 +14,7 @@ #include "events.h" #include "ppp.h" +#include "ipdb.h" #include "log.h" #include "utils.h" #include "sigchld.h" @@ -480,8 +481,8 @@ static void fill_argv(char **argv, struct ppp_t *ppp, char *path) argv[1] = ppp->ifname; argv[2] = "none"; argv[3] = "0"; - u_inet_ntoa(ppp->ipaddr, argv[4]); - u_inet_ntoa(ppp->peer_ipaddr, argv[5]); + u_inet_ntoa(ppp->ipv4 ? ppp->ipv4->addr : 0, argv[4]); + u_inet_ntoa(ppp->ipv4 ? ppp->ipv4->peer_addr : 0, argv[5]); argv[6] = ppp->ctrl->calling_station_id; argv[7] = NULL; } diff --git a/accel-pppd/ipdb.h b/accel-pppd/ipdb.h index 3a717a15..69d54792 100644 --- a/accel-pppd/ipdb.h +++ b/accel-pppd/ipdb.h @@ -13,13 +13,21 @@ struct ipv4db_item_t in_addr_t peer_addr; }; -struct ipv6db_item_t +struct ipv6db_addr_t { - struct ipdb_t *owner; + struct list_head entry; struct in6_addr addr; int prefix_len; }; +struct ipv6db_item_t +{ + struct ipdb_t *owner; + uint64_t intf_id; + struct list_head addr_list; + struct list_head route_list; +}; + struct ipdb_t { diff --git a/accel-pppd/ppp/ipcp_opt_ipaddr.c b/accel-pppd/ppp/ipcp_opt_ipaddr.c index ac45ac7c..f3870691 100644 --- a/accel-pppd/ppp/ipcp_opt_ipaddr.c +++ b/accel-pppd/ppp/ipcp_opt_ipaddr.c @@ -30,36 +30,36 @@ static void ipaddr_print(void (*print)(const char *fmt,...),struct ipcp_option_t struct ipaddr_option_t { struct ipcp_option_t opt; - struct ipv4db_item_t *ip; + struct ppp_t *ppp; int started:1; }; -static struct ipcp_option_handler_t ipaddr_opt_hnd= -{ - .init=ipaddr_init, - .send_conf_req=ipaddr_send_conf_req, - .send_conf_nak=ipaddr_send_conf_nak, - .recv_conf_req=ipaddr_recv_conf_req, - .free=ipaddr_free, - .print=ipaddr_print, +static struct ipcp_option_handler_t ipaddr_opt_hnd = { + .init = ipaddr_init, + .send_conf_req = ipaddr_send_conf_req, + .send_conf_nak = ipaddr_send_conf_nak, + .recv_conf_req = ipaddr_recv_conf_req, + .free = ipaddr_free, + .print = ipaddr_print, }; static struct ipcp_option_t *ipaddr_init(struct ppp_ipcp_t *ipcp) { - struct ipaddr_option_t *ipaddr_opt=_malloc(sizeof(*ipaddr_opt)); - memset(ipaddr_opt,0,sizeof(*ipaddr_opt)); - ipaddr_opt->opt.id=CI_ADDR; - ipaddr_opt->opt.len=6; + struct ipaddr_option_t *ipaddr_opt = _malloc(sizeof(*ipaddr_opt)); + memset(ipaddr_opt, 0, sizeof(*ipaddr_opt)); + ipaddr_opt->opt.id = CI_ADDR; + ipaddr_opt->opt.len = 6; + ipaddr_opt->ppp = ipcp->ppp; return &ipaddr_opt->opt; } static void ipaddr_free(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt) { - struct ipaddr_option_t *ipaddr_opt=container_of(opt,typeof(*ipaddr_opt),opt); + struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt); - if (ipaddr_opt->ip) - ipdb_put_ipv4(ipcp->ppp, ipaddr_opt->ip); + if (ipcp->ppp->ipv4) + ipdb_put_ipv4(ipcp->ppp, ipcp->ppp->ipv4); _free(ipaddr_opt); } @@ -71,8 +71,8 @@ static int check_exists(struct ppp_t *self_ppp, in_addr_t addr) pthread_rwlock_rdlock(&ppp_lock); list_for_each_entry(ppp, &ppp_list, entry) { - if (!ppp->terminating && ppp->peer_ipaddr == addr && ppp != self_ppp) { - log_ppp_warn("ppp:ipcp: requested IP already assigned to %s\n", ppp->ifname); + if (!ppp->terminating && ppp->ipv4 && ppp->ipv4->peer_addr == addr && ppp != self_ppp) { + log_ppp_warn("ppp: requested IPv4 address already assigned to %s\n", ppp->ifname); r = 1; break; } @@ -84,74 +84,63 @@ static int check_exists(struct ppp_t *self_ppp, in_addr_t addr) static int ipaddr_send_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr) { - struct ipaddr_option_t *ipaddr_opt=container_of(opt,typeof(*ipaddr_opt),opt); - struct ipcp_opt32_t *opt32=(struct ipcp_opt32_t*)ptr; + struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt); + struct ipcp_opt32_t *opt32 = (struct ipcp_opt32_t *)ptr; - if (!ipaddr_opt->ip) { - ipaddr_opt->ip = ipdb_get_ipv4(ipcp->ppp); - if (!ipaddr_opt->ip) { - log_ppp_warn("ppp:ipcp: no free IP address\n"); + if (!ipcp->ppp->ipv4) { + ipcp->ppp->ipv4 = ipdb_get_ipv4(ipcp->ppp); + if (!ipcp->ppp->ipv4) { + log_ppp_warn("ppp: no free IPv4 address\n"); return -1; } } - if (iprange_tunnel_check(ipaddr_opt->ip->peer_addr)) { + if (iprange_tunnel_check(ipcp->ppp->ipv4->peer_addr)) { log_ppp_warn("ppp:ipcp: to avoid kernel soft lockup requested IP cannot be assigned (%i.%i.%i.%i)\n", - ipaddr_opt->ip->peer_addr&0xff, - (ipaddr_opt->ip->peer_addr >> 8)&0xff, - (ipaddr_opt->ip->peer_addr >> 16)&0xff, - (ipaddr_opt->ip->peer_addr >> 24)&0xff); + ipcp->ppp->ipv4->peer_addr&0xff, + (ipcp->ppp->ipv4->peer_addr >> 8)&0xff, + (ipcp->ppp->ipv4->peer_addr >> 16)&0xff, + (ipcp->ppp->ipv4->peer_addr >> 24)&0xff); return -1; } - if (conf_check_exists && check_exists(ipcp->ppp, ipaddr_opt->ip->peer_addr)) + if (conf_check_exists && check_exists(ipcp->ppp, ipcp->ppp->ipv4->peer_addr)) return -1; - ipcp->ppp->ipaddr = ipaddr_opt->ip->addr; - ipcp->ppp->peer_ipaddr = ipaddr_opt->ip->peer_addr; - - opt32->hdr.id=CI_ADDR; - opt32->hdr.len=6; - opt32->val=ipaddr_opt->ip->addr; + opt32->hdr.id = CI_ADDR; + opt32->hdr.len = 6; + opt32->val = ipcp->ppp->ipv4->addr; return 6; } static int ipaddr_send_conf_nak(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr) { - struct ipaddr_option_t *ipaddr_opt=container_of(opt,typeof(*ipaddr_opt),opt); - struct ipcp_opt32_t *opt32=(struct ipcp_opt32_t*)ptr; - opt32->hdr.id=CI_ADDR; - opt32->hdr.len=6; - opt32->val=ipaddr_opt->ip->peer_addr; + struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt); + struct ipcp_opt32_t *opt32 = (struct ipcp_opt32_t *)ptr; + opt32->hdr.id = CI_ADDR; + opt32->hdr.len = 6; + opt32->val = ipcp->ppp->ipv4->peer_addr; return 6; } static int ipaddr_recv_conf_req(struct ppp_ipcp_t *ipcp, struct ipcp_option_t *opt, uint8_t *ptr) { - struct ipaddr_option_t *ipaddr_opt = container_of(opt,typeof(*ipaddr_opt), opt); - struct ipcp_opt32_t *opt32 = (struct ipcp_opt32_t*)ptr; + struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt); + struct ipcp_opt32_t *opt32 = (struct ipcp_opt32_t *)ptr; if (opt32->hdr.len != 6) return IPCP_OPT_REJ; - if (ipaddr_opt->ip->peer_addr == opt32->val) { - //ipcp->ppp->ipaddr = ipaddr_opt->ip->addr; - //ipcp->ppp->peer_ipaddr = ipaddr_opt->ip->peer_addr; + if (ipcp->ppp->ipv4->peer_addr == opt32->val) { ipcp->delay_ack = ccp_ipcp_started(ipcp->ppp); return IPCP_OPT_ACK; } - /*if (!ipaddr_opt->peer_addr) { - ipaddr_opt->peer_addr = opt32->val; - goto ack; - }*/ - return IPCP_OPT_NAK; } static void if_up(struct ppp_t *ppp) { - struct ipaddr_option_t *ipaddr_opt = container_of(ipcp_find_option(ppp, &ipaddr_opt_hnd), typeof(*ipaddr_opt), opt); struct ifreq ifr; struct sockaddr_in addr; struct npioctl np; @@ -162,13 +151,13 @@ static void if_up(struct ppp_t *ppp) strcpy(ifr.ifr_name, ppp->ifname); addr.sin_family = AF_INET; - addr.sin_addr.s_addr = ipaddr_opt->ip->addr; + addr.sin_addr.s_addr = ppp->ipv4->addr; memcpy(&ifr.ifr_addr,&addr,sizeof(addr)); if (ioctl(sock_fd, SIOCSIFADDR, &ifr)) log_ppp_error("ipcp: failed to set PA address: %s\n", strerror(errno)); - addr.sin_addr.s_addr = ipaddr_opt->ip->peer_addr; + addr.sin_addr.s_addr = ppp->ipv4->peer_addr; memcpy(&ifr.ifr_dstaddr,&addr,sizeof(addr)); if (ioctl(sock_fd, SIOCSIFDSTADDR, &ifr)) @@ -205,8 +194,8 @@ static void ipaddr_print(void (*print)(const char *fmt,...),struct ipcp_option_t if (ptr) in.s_addr = opt32->val; - else if (ipaddr_opt->ip) - in.s_addr = ipaddr_opt->ip->addr; + else if (ipaddr_opt->ppp->ipv4) + in.s_addr = ipaddr_opt->ppp->ipv4->addr; print("",inet_ntoa(in)); } @@ -229,3 +218,4 @@ static void ipaddr_opt_init() } DEFINE_INIT(4, ipaddr_opt_init); + diff --git a/accel-pppd/ppp/ipv6_nd.c b/accel-pppd/ppp/ipv6_nd.c index bec0ea3c..e0ec842e 100644 --- a/accel-pppd/ppp/ipv6_nd.c +++ b/accel-pppd/ppp/ipv6_nd.c @@ -7,18 +7,50 @@ #include #include #include +#include #include #include #include "log.h" #include "ppp.h" #include "events.h" +#include "mempool.h" +#include "ipdb.h" #include "memdebug.h" +#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 struct in6_addr conf_dns[MAX_DNS_COUNT]; +static int conf_dns_count; + +#undef ND_OPT_ROUTE_INFORMATION +#define ND_OPT_ROUTE_INFORMATION 24 +struct nd_opt_route_info_local /* route information */ +{ + uint8_t nd_opt_ri_type; + uint8_t nd_opt_ri_len; + uint8_t nd_opt_ri_prefix_len; + uint8_t nd_opt_ri_flags_reserved; + uint32_t nd_opt_ri_lifetime; + struct in6_addr nd_opt_ri_prefix; +}; + +#undef ND_OPT_RDNSS_INFORMATION +#define ND_OPT_RDNSS_INFORMATION 25 +struct nd_opt_rdnss_info_local +{ + uint8_t nd_opt_rdnssi_type; + uint8_t nd_opt_rdnssi_len; + uint16_t nd_opt_rdnssi_pref_flag_reserved; + uint32_t nd_opt_rdnssi_lifetime; + struct in6_addr nd_opt_rdnssi[0]; +}; struct ipv6_nd_handler_t { @@ -32,84 +64,112 @@ struct ipv6_nd_handler_t static void *pd_key; #define BUF_SIZE 1024 +static mempool_t buf_pool; -static void ipv6_nd_send_ra(struct ipv6_nd_handler_t *h) +static void ipv6_nd_send_ra(struct ipv6_nd_handler_t *h, struct sockaddr_in6 *addr) { - void *buf = _malloc(BUF_SIZE); + void *buf = mempool_alloc(buf_pool), *endptr; struct nd_router_advert *adv = buf; struct nd_opt_prefix_info *pinfo; - //struct nd_opt_route_info *rinfo; - //struct nd_opt_rdnss_info_local *rdnssinfo; + struct nd_opt_route_info_local *rinfo; + struct nd_opt_rdnss_info_local *rdnssinfo; + struct in6_addr *rdnss_addr; //struct nd_opt_mtu *mtu; - struct sockaddr_in6 addr; + struct ipv6db_addr_t *a; + int i; + + if (!buf) { + log_emerg("out of memory\n"); + return; + } memset(adv, 0, sizeof(*adv)); adv->nd_ra_type = ND_ROUTER_ADVERT; adv->nd_ra_curhoplimit = 64; - adv->nd_ra_router_lifetime = htons(1); + adv->nd_ra_router_lifetime = htons(conf_router_lifetime); //adv->nd_ra_reachable = 0; //adv->nd_ra_retransmit = 0; pinfo = (struct nd_opt_prefix_info *)(adv + 1); - memset(pinfo, 0, sizeof(*pinfo)); - pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; - pinfo->nd_opt_pi_len = 4; - pinfo->nd_opt_pi_prefix_len = h->ppp->ipv6_prefix_len; - pinfo->nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO; - pinfo->nd_opt_pi_valid_time = 0xffffffff; - pinfo->nd_opt_pi_preferred_time = 0xffffffff; - memcpy(&pinfo->nd_opt_pi_prefix, &h->ppp->ipv6_addr, 8); + list_for_each_entry(a, &h->ppp->ipv6->addr_list, entry) { + memset(pinfo, 0, sizeof(*pinfo)); + 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 | ND_OPT_PI_FLAG_AUTO; + pinfo->nd_opt_pi_valid_time = 0xffffffff; + pinfo->nd_opt_pi_preferred_time = 0xffffffff; + memcpy(&pinfo->nd_opt_pi_prefix, &a->addr, 8); + pinfo++; + } + + rinfo = (struct nd_opt_route_info_local *)pinfo; + list_for_each_entry(a, &h->ppp->ipv6->route_list, entry) { + memset(rinfo, 0, sizeof(*rinfo)); + rinfo->nd_opt_ri_type = ND_OPT_ROUTE_INFORMATION; + rinfo->nd_opt_ri_len = 3; + rinfo->nd_opt_ri_prefix_len = a->prefix_len; + rinfo->nd_opt_ri_lifetime = 0xffffffff; + memcpy(&rinfo->nd_opt_ri_prefix, &a->addr, 8); + rinfo++; + } + + if (conf_dns_count) { + rdnssinfo = (struct nd_opt_rdnss_info_local *)rinfo; + memset(rdnssinfo, 0, sizeof(*rdnssinfo)); + rdnssinfo->nd_opt_rdnssi_type = ND_OPT_RDNSS_INFORMATION; + rdnssinfo->nd_opt_rdnssi_len = 1 + 2 * conf_dns_count; + rdnssinfo->nd_opt_rdnssi_lifetime = htonl(conf_rdnss_lifetime); + rdnss_addr = (struct in6_addr *)rdnssinfo->nd_opt_rdnssi; + for (i = 0; i < conf_dns_count; i++) { + memcpy(rdnss_addr, &conf_dns[i], sizeof(*rdnss_addr)); + rdnss_addr++; + } + } else + rdnss_addr = (struct in6_addr *)rinfo; + + endptr = rdnss_addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_addr.s6_addr32[0] = htonl(0xff020000); - addr.sin6_addr.s6_addr32[3] = htonl(0x1); - addr.sin6_scope_id = h->ppp->ifindex; - sendto(h->hnd.fd, buf, (void *)(pinfo + 1) - buf, 0, (struct sockaddr *)&addr, sizeof(addr)); + sendto(h->hnd.fd, buf, endptr - buf, 0, (struct sockaddr *)addr, sizeof(*addr)); - _free(buf); + mempool_free(buf); } static void send_ra_timer(struct triton_timer_t *t) { struct ipv6_nd_handler_t *h = container_of(t, typeof(*h), timer); + struct sockaddr_in6 addr; + + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr.s6_addr32[0] = htonl(0xff020000); + addr.sin6_addr.s6_addr32[3] = htonl(0x1); + addr.sin6_scope_id = h->ppp->ifindex; if (h->ra_sent++ == conf_init_ra) { h->timer.period = conf_ra_interval * 1000; triton_timer_mod(t, 0); } - ipv6_nd_send_ra(h); + ipv6_nd_send_ra(h, &addr); } static int ipv6_nd_read(struct triton_md_handler_t *_h) { struct ipv6_nd_handler_t *h = container_of(_h, typeof(*h), hnd); - struct msghdr mhdr; - int chdr_len; - struct iovec iov; - struct cmsghdr *chdr, *cmsg; - struct in6_pktinfo *pkt_info; - struct icmp6_hdr *icmph; - void *buf; + struct icmp6_hdr *icmph = mempool_alloc(buf_pool); int n; + struct sockaddr_in6 addr; + socklen_t addr_len = sizeof(addr); - chdr_len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); - chdr = _malloc(chdr_len); - buf = _malloc(BUF_SIZE); - - iov.iov_len = BUF_SIZE; - iov.iov_base = buf; - - memset(&mhdr, 0, sizeof(mhdr)); - mhdr.msg_iov = &iov; - mhdr.msg_iovlen = 1; - mhdr.msg_control = chdr; - mhdr.msg_controllen = chdr_len; + if (!icmph) { + log_emerg("out of memory\n"); + return 0; + } while (1) { - n = recvmsg(h->hnd.fd, &mhdr, 0); + n = recvfrom(h->hnd.fd, icmph, BUF_SIZE, 0, &addr, &addr_len); if (n == -1) { if (errno == EAGAIN) break; @@ -117,50 +177,30 @@ static int ipv6_nd_read(struct triton_md_handler_t *_h) continue; } - pkt_info = NULL; - for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) { - if (cmsg->cmsg_level == IPPROTO_IPV6 && - cmsg->cmsg_type == IPV6_PKTINFO) { - if (cmsg->cmsg_len != CMSG_LEN(sizeof(*pkt_info))) - log_ppp_warn("ipv6_nd: received invalid IPV6_PKTINFO\n"); - else - pkt_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); - break; - } - } - - if (!pkt_info) { - log_ppp_warn("ipv6_nd: no IPV6_PKTINFO\n"); - continue; - } - if (n < sizeof(*icmph)) { log_ppp_warn("ipv6_nd: received short icmp packet (%i)\n", n); continue; } - icmph = buf; - if (icmph->icmp6_type != ND_ROUTER_SOLICIT) { log_ppp_warn("ipv6_nd: received unexcpected icmp packet (%i)\n", icmph->icmp6_type); continue; } - /*if (!IN6_IS_ADDR_LINKLOCAL(&pkt_info->ipi6_addr)) { + if (!IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr)) { log_ppp_warn("ipv6_nd: received icmp packet from non link-local address\n"); continue; - }*/ + } - /*if (*(uint64_t *)(pkt_info->ipi6_addr.s6_addr + 8) != *(uint64_t *)(h->ppp->ipv6_addr.s6_addr + 8)) { + /*if (*(uint64_t *)(addr.sin6_addr.s6_addr + 8) != *(uint64_t *)(h->ppp->ipv6_addr.s6_addr + 8)) { log_ppp_warn("ipv6_nd: received icmp packet from unknown address\n"); continue; }*/ - ipv6_nd_send_ra(h); + ipv6_nd_send_ra(h, &addr); } - _free(chdr); - _free(buf); + mempool_free(icmph); return 0; } @@ -192,12 +232,6 @@ int ppp_ipv6_nd_start(struct ppp_t *ppp, uint64_t intf_id) goto out_err; } - val = 1; - if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val))) { - log_ppp_error("ipv6_nd: setsockopt(IPV6_PKTINFO): %s\n", strerror(errno)); - goto out_err; - } - val = 2; if (setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val))) { log_ppp_error("ipv6_nd: setsockopt(IPV6_CHECKSUM): %s\n", strerror(errno)); @@ -299,10 +333,35 @@ static void ev_ppp_finishing(struct ppp_t *ppp) _free(h); } +static void load_config(void) +{ + struct conf_sect_t *s = conf_get_section("dnsv6"); + struct conf_option_t *opt; + + if (!s) + return; + + conf_dns_count = 0; + + list_for_each_entry(opt, &s->items, entry) { + if (inet_pton(AF_INET6, opt->name, &conf_dns[conf_dns_count]) == 0) { + log_error("dnsv6: faild to parse '%s'\n", opt->name); + continue; + } + if (++conf_dns_count == MAX_DNS_COUNT) + break; + } +} + static void init(void) { + buf_pool = mempool_create(BUF_SIZE); + + load_config(); + + 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); } -DEFINE_INIT(0, init); +DEFINE_INIT(5, init); diff --git a/accel-pppd/ppp/ipv6cp_opt_intfid.c b/accel-pppd/ppp/ipv6cp_opt_intfid.c index b55d3fff..9a9b9e37 100644 --- a/accel-pppd/ppp/ipv6cp_opt_intfid.c +++ b/accel-pppd/ppp/ipv6cp_opt_intfid.c @@ -45,7 +45,6 @@ struct ipaddr_option_t { struct ipv6cp_option_t opt; uint64_t intf_id; - struct ipv6db_item_t *ip; int started:1; }; @@ -87,25 +86,33 @@ static void ipaddr_free(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_option_t *opt _free(ipaddr_opt); } -static int check_exists(struct ppp_t *self_ppp, struct in6_addr *addr) +static int check_exists(struct ppp_t *self_ppp) { struct ppp_t *ppp; + struct ipv6db_addr_t *a1, *a2; int r = 0; pthread_rwlock_rdlock(&ppp_lock); list_for_each_entry(ppp, &ppp_list, entry) { if (ppp->terminating) continue; + if (!ppp->ipv6) + continue; if (ppp == self_ppp) continue; - if (addr->s6_addr32[0] == ppp->ipv6_addr.s6_addr32[0] && - addr->s6_addr32[1] == ppp->ipv6_addr.s6_addr32[1]) { - log_ppp_warn("ppp:ipv6cp: requested IP already assigned to %s\n", ppp->ifname); - r = 1; - break; + list_for_each_entry(a1, &ppp->ipv6->addr_list, entry) { + list_for_each_entry(a2, &self_ppp->ipv6->addr_list, entry) { + if (a1->addr.s6_addr32[0] == a2->addr.s6_addr32[0] && + a1->addr.s6_addr32[1] == a2->addr.s6_addr32[1]) { + log_ppp_warn("ppp: requested IPv6 address already assigned to %s\n", ppp->ifname); + r = 1; + goto out; + } + } } } +out: pthread_rwlock_unlock(&ppp_lock); return r; @@ -116,20 +123,17 @@ static int ipaddr_send_conf_req(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_optio struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt); struct ipv6cp_opt64_t *opt64 = (struct ipv6cp_opt64_t *)ptr; - if (!ipaddr_opt->ip) { - ipaddr_opt->ip = ipdb_get_ipv6(ipv6cp->ppp); - if (!ipaddr_opt->ip) { - log_ppp_warn("ppp:ipv6cp: no free IP address\n"); + if (!ipv6cp->ppp->ipv6) { + ipv6cp->ppp->ipv6 = ipdb_get_ipv6(ipv6cp->ppp); + if (!ipv6cp->ppp->ipv6) { + log_ppp_warn("ppp: no free IPv6 address\n"); return -1; } } - if (conf_check_exists && check_exists(ipv6cp->ppp, &ipaddr_opt->ip->addr)) + if (conf_check_exists && check_exists(ipv6cp->ppp)) return -1; - ipv6cp->ppp->ipv6_addr = ipaddr_opt->ip->addr; - ipv6cp->ppp->ipv6_prefix_len = ipaddr_opt->ip->prefix_len; - opt64->hdr.id = CI_INTFID; opt64->hdr.len = 10; opt64->val = ipaddr_opt->intf_id; @@ -142,7 +146,7 @@ static int ipaddr_send_conf_nak(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_optio struct ipv6cp_opt64_t *opt64 = (struct ipv6cp_opt64_t *)ptr; opt64->hdr.id = CI_INTFID; opt64->hdr.len = 10; - opt64->val = *(uint64_t *)(&ipaddr_opt->ip->addr.s6_addr32[2]); + opt64->val = ipv6cp->ppp->ipv6->intf_id; return 10; } @@ -151,11 +155,12 @@ static int ipaddr_recv_conf_req(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_optio struct ipaddr_option_t *ipaddr_opt = container_of(opt, typeof(*ipaddr_opt), opt); struct ipv6cp_opt64_t *opt64 = (struct ipv6cp_opt64_t* )ptr; struct in6_ifreq ifr6; + struct ipv6db_addr_t *a; if (opt64->hdr.len != 10) return IPV6CP_OPT_REJ; - if (*(uint64_t *)(&ipaddr_opt->ip->addr.s6_addr32[2]) == opt64->val) + if (ipv6cp->ppp->ipv6->intf_id == opt64->val) goto ack; return IPV6CP_OPT_NAK; @@ -188,11 +193,13 @@ ack: return IPV6CP_OPT_REJ; } - memcpy(ifr6.ifr6_addr.s6_addr, ipaddr_opt->ip->addr.s6_addr, 8); + list_for_each_entry(a, &ipv6cp->ppp->ipv6->addr_list, entry) { + memcpy(ifr6.ifr6_addr.s6_addr, a->addr.s6_addr, 8); - if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6)) { - log_ppp_error("ppp:ipv6cp: ioctl(SIOCSIFADDR): %s\n", strerror(errno)); - return IPV6CP_OPT_REJ; + if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6)) { + log_ppp_error("ppp:ipv6cp: ioctl(SIOCSIFADDR): %s\n", strerror(errno)); + return IPV6CP_OPT_REJ; + } } if (ppp_ipv6_nd_start(ipv6cp->ppp, ipaddr_opt->intf_id)) diff --git a/accel-pppd/ppp/ppp.h b/accel-pppd/ppp/ppp.h index 4708578e..f95893ab 100644 --- a/accel-pppd/ppp/ppp.h +++ b/accel-pppd/ppp/ppp.h @@ -62,6 +62,9 @@ struct ppp_t; +struct ipv4db_item_t; +struct ipv6db_item_t; + struct ppp_ctrl_t { struct triton_context_t *ctx; @@ -100,10 +103,8 @@ struct ppp_t time_t start_time; time_t stop_time; char *username; - in_addr_t ipaddr; - in_addr_t peer_ipaddr; - struct in6_addr ipv6_addr; - int ipv6_prefix_len; + struct ipv4db_item_t *ipv4; + struct ipv6db_item_t *ipv6; struct ppp_ctrl_t *ctrl; diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c index ae5948b0..4200d621 100644 --- a/accel-pppd/radius/radius.c +++ b/accel-pppd/radius/radius.c @@ -174,7 +174,7 @@ static struct ipv4db_item_t *get_ipv4(struct ppp_t *ppp) static struct ipv6db_item_t *get_ipv6(struct ppp_t *ppp) { - struct radius_pd_t *rpd = find_pd(ppp); + //struct radius_pd_t *rpd = find_pd(ppp); //if (memcmp(&rpd->ipv6_addr.peer_addr, &in6addr_any, sizeof(in6addr_any))) // return &rpd->ipv6_addr; @@ -302,7 +302,7 @@ struct radius_pd_t *rad_find_session(const char *sessionid, const char *username continue; if (port_id >= 0 && port_id != rpd->ppp->unit_idx) continue; - if (ipaddr && ipaddr != rpd->ppp->peer_ipaddr) + if (ipaddr && rpd->ppp->ipv4 && ipaddr != rpd->ppp->ipv4->peer_addr) continue; if (csid && rpd->ppp->ctrl->calling_station_id && strcmp(csid, rpd->ppp->ctrl->calling_station_id)) continue; diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c index b45a601b..462e656b 100644 --- a/accel-pppd/radius/req.c +++ b/accel-pppd/radius/req.c @@ -130,8 +130,10 @@ int rad_req_acct_fill(struct rad_req_t *req) if (rad_packet_add_int(req->pack, NULL, "Acct-Delay-Time", 0)) return -1; } - if (rad_packet_add_ipaddr(req->pack, NULL, "Framed-IP-Address", req->rpd->ppp->peer_ipaddr)) - return -1; + if (req->rpd->ppp->ipv4) { + if (rad_packet_add_ipaddr(req->pack, NULL, "Framed-IP-Address", req->rpd->ppp->ipv4->peer_addr)) + return -1; + } return 0; } diff --git a/rfc/rfc5006.txt b/rfc/rfc5006.txt new file mode 100644 index 00000000..056f149e --- /dev/null +++ b/rfc/rfc5006.txt @@ -0,0 +1,675 @@ + + + + + + +Network Working Group J. Jeong, Ed. +Request for Comments: 5006 ETRI/University of Minnesota +Category: Experimental S. Park + SAMSUNG Electronics + L. Beloeil + France Telecom R&D + S. Madanapalli + Ordyn Technologies + September 2007 + + + IPv6 Router Advertisement Option for DNS Configuration + +Status of This Memo + + This memo defines an Experimental Protocol for the Internet + community. It does not specify an Internet standard of any kind. + Discussion and suggestions for improvement are requested. + Distribution of this memo is unlimited. + +Abstract + + This document specifies a new IPv6 Router Advertisement option to + allow IPv6 routers to advertise DNS recursive server addresses to + IPv6 hosts. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2 + 1.1. Applicability Statements . . . . . . . . . . . . . . . . . 2 + 1.2. Coexistence of RDNSS Option and DHCP Option . . . . . . . 2 + 2. Definitions . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 3. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 4. Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 5. Neighbor Discovery Extension . . . . . . . . . . . . . . . . . 4 + 5.1. Recursive DNS Server Option . . . . . . . . . . . . . . . 4 + 5.2. Procedure of DNS Configuration . . . . . . . . . . . . . . 5 + 5.2.1. Procedure in IPv6 Host . . . . . . . . . . . . . . . . 5 + 6. Implementation Considerations . . . . . . . . . . . . . . . . 6 + 6.1. DNS Server List Management . . . . . . . . . . . . . . . . 6 + 6.2. Synchronization between DNS Server List and Resolver + Repository . . . . . . . . . . . . . . . . . . . . . . . . 7 + 7. Security Considerations . . . . . . . . . . . . . . . . . . . 8 + 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 8 + 9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 8 + 10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 9 + 10.1. Normative References . . . . . . . . . . . . . . . . . . . 9 + 10.2. Informative References . . . . . . . . . . . . . . . . . . 9 + + + +Jeong, et al. Experimental [Page 1] + +RFC 5006 IPv6 RA Option for DNS Configuration September 2007 + + +1. Introduction + + Neighbor Discovery (ND) for IP Version 6 and IPv6 Stateless Address + Autoconfiguration provide ways to configure either fixed or mobile + nodes with one or more IPv6 addresses, default routers and some other + parameters [2][3]. To support the access to additional services in + the Internet that are identified by a DNS name, such as a web server, + the configuration of at least one recursive DNS server is also needed + for DNS name resolution. + + It is infeasible for nomadic hosts, such as laptops, to be configured + manually with a DNS resolver each time they connect to a different + wireless LAN (WLAN) such as IEEE 802.11 a/b/g [12]-[15]. Normally, + DHCP [6]-[8] is used to locate such resolvers. This document + provides an alternate, experimental mechanism which uses a new IPv6 + Router Advertisement (RA) option to allow IPv6 routers to advertise + DNS recursive server addresses to IPv6 hosts. + +1.1. Applicability Statements + + The only standards-track DNS configuration mechanism in the IETF is + DHCP, and its support in hosts and routers is necessary for reasons + of interoperability. + + RA-based DNS configuration is a useful, optional alternative in + networks where an IPv6 host's address is autoconfigured through IPv6 + stateless address autoconfiguration, and where the delays in + acquiring server addresses and communicating with the servers are + critical. RA-based DNS configuration allows the host to acquire the + nearest server addresses on every link. Furthermore, it learns these + addresses from the same RA message that provides configuration + information for the link, thereby avoiding an additional protocol + run. This can be beneficial in some mobile environments, such as + with Mobile IPv6 [10]. + + The advantages and disadvantages of the RA-based approach are + discussed in [9] along with other approaches, such as the DHCP and + well-known anycast addresses approaches. + +1.2. Coexistence of RDNSS Option and DHCP Option + + The RDNSS (Recursive DNS Server) option and DHCP option can be used + together [9]. To order the RA and DHCP approaches, the O (Other + stateful configuration) flag can be used in the RA message [2]. If + no RDNSS option is included in the RA messages, an IPv6 host may + perform DNS configuration through DHCPv6 [6]-[8] regardless of + whether the O flag is set or not. + + + + +Jeong, et al. Experimental [Page 2] + +RFC 5006 IPv6 RA Option for DNS Configuration September 2007 + + +2. Definitions + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [1]. + +3. Terminology + + This document uses the terminology described in [2] and [3]. In + addition, four new terms are defined below: + + o Recursive DNS Server (RDNSS): Server which provides a recursive + DNS resolution service for translating domain names into IP + addresses as defined in [4] and [5]. + + o RDNSS Option: IPv6 RA option to deliver the RDNSS information to + IPv6 hosts [2]. + + o DNS Server List: A data structure for managing DNS Server + Information in the IPv6 protocol stack in addition to the Neighbor + Cache and Destination Cache for Neighbor Discovery [2]. + + o Resolver Repository: Configuration repository with RDNSS addresses + that a DNS resolver on the host uses for DNS name resolution; for + example, the Unix resolver file (i.e., /etc/resolv.conf) and + Windows registry. + +4. Overview + + This document defines a new ND option called RDNSS option that + contains the addresses of recursive DNS servers. Existing ND + transport mechanisms (i.e., advertisements and solicitations) are + used. This works in the same way that hosts learn about routers and + prefixes. An IPv6 host can configure the IPv6 addresses of one or + more RDNSSes via RA messages periodically sent by a router or + solicited by a Router Solicitation (RS). + + Through the RDNSS option, along with the prefix information option + based on the ND protocol ([2] and [3]), an IPv6 host can perform + network configuration of its IPv6 address and RDNSS simultaneously + without needing a separate message exchange for the RDNSS + information. The RA option for RDNSS can be used on any network that + supports the use of ND. + + This approach requires RDNSS information to be configured in the + routers sending the advertisements. The configuration of RDNSS + addresses in the routers can be done by manual configuration. The + automatic configuration or redistribution of RDNSS information is + + + +Jeong, et al. Experimental [Page 3] + +RFC 5006 IPv6 RA Option for DNS Configuration September 2007 + + + possible by running a DHCPv6 client on the router [6]-[8]. The + automatic configuration of RDNSS addresses in routers is out of scope + for this document. + +5. Neighbor Discovery Extension + + The IPv6 DNS configuration mechanism in this document needs a new ND + option in Neighbor Discovery: the Recursive DNS Server (RDNSS) + option. + +5.1. Recursive DNS Server Option + + The RDNSS option contains one or more IPv6 addresses of recursive DNS + servers. All of the addresses share the same lifetime value. If it + is desirable to have different lifetime values, multiple RDNSS + options can be used. Figure 1 shows the format of the RDNSS option. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Length | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Lifetime | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + : Addresses of IPv6 Recursive DNS Servers : + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 1: Recursive DNS Server (RDNSS) Option Format + + Fields: + + Type 8-bit identifier of the RDNSS option type as assigned + by the IANA: 25 + + Length 8-bit unsigned integer. The length of the option + (including the Type and Length fields) is in units of + 8 octets. The minimum value is 3 if one IPv6 address + is contained in the option. Every additional RDNSS + address increases the length by 2. The Length field + is used by the receiver to determine the number of + IPv6 addresses in the option. + + + + + + + + +Jeong, et al. Experimental [Page 4] + +RFC 5006 IPv6 RA Option for DNS Configuration September 2007 + + + Lifetime 32-bit unsigned integer. The maximum time, in + seconds (relative to the time the packet is sent), + over which this RDNSS address MAY be used for name + resolution. Hosts MAY send a Router Solicitation to + ensure the RDNSS information is fresh before the + interval expires. In order to provide fixed hosts + with stable DNS service and allow mobile hosts to + prefer local RDNSSes to remote RDNSSes, the value of + Lifetime should be at least as long as the Maximum RA + Interval (MaxRtrAdvInterval) in RFC 4861, and be at + most as long as two times MaxRtrAdvInterval; Lifetime + SHOULD be bounded as follows: MaxRtrAdvInterval <= + Lifetime <= 2*MaxRtrAdvInterval. A value of all one + bits (0xffffffff) represents infinity. A value of + zero means that the RDNSS address MUST no longer be + used. + + Addresses of IPv6 Recursive DNS Servers + One or more 128-bit IPv6 addresses of the recursive + DNS servers. The number of addresses is determined + by the Length field. That is, the number of + addresses is equal to (Length - 1) / 2. + +5.2. Procedure of DNS Configuration + + The procedure of DNS configuration through the RDNSS option is the + same as with any other ND option [2]. + +5.2.1. Procedure in IPv6 Host + + When an IPv6 host receives an RDNSS option through RA, it checks + whether the option is valid. + + o If the RDNSS option is valid, the host SHOULD copy the option's + value into the DNS Server List and the Resolver Repository as long + as the value of the Length field is greater than or equal to the + minimum value (3). The host MAY ignore additional RDNSS addresses + within an RDNSS option and/or additional RDNSS options within an + RA when it has gathered a sufficient number of RDNSS addresses. + + o If the RDNSS option is invalid (e.g., the Length field has a value + less than 3), the host SHOULD discard the option. + + + + + + + + + +Jeong, et al. Experimental [Page 5] + +RFC 5006 IPv6 RA Option for DNS Configuration September 2007 + + +6. Implementation Considerations + + Note: This non-normative section gives some hints for implementing + the processing of the RDNSS option in an IPv6 host. + + For the configuration and management of RDNSS information, the + advertised RDNSS addresses can be stored and managed in both the DNS + Server List and the Resolver Repository. + + In environments where the RDNSS information is stored in user space + and ND runs in the kernel, it is necessary to synchronize the DNS + Server List of RDNSS addresses in kernel space and the Resolver + Repository in user space. For the synchronization, an implementation + where ND works in the kernel should provide a write operation for + updating RDNSS information from the kernel to the Resolver + Repository. One simple approach is to have a daemon (or a program + that is called at defined intervals) that keeps monitoring the + lifetime of RDNSS addresses all the time. Whenever there is an + expired entry in the DNS Server List, the daemon can delete the + corresponding entry from the Resolver Repository. + +6.1. DNS Server List Management + + The kernel or user-space process (depending on where RAs are + processed) should maintain a data structure called a DNS Server List + which keeps the list of RDNSS addresses. Each entry in the DNS + Server List consists of an RDNSS address and Expiration-time as + follows: + + o RDNSS address: IPv6 address of the Recursive DNS Server, which is + available for recursive DNS resolution service in the network + advertising the RDNSS option; such a network is called site in + this document. + + o Expiration-time: The time when this entry becomes invalid. + Expiration-time is set to the value of the Lifetime field of the + RDNSS option plus the current system time. Whenever a new RDNSS + option with the same address is received, this field is updated to + have a new expiration time. When Expiration-time becomes less + than the current system time, this entry is regarded as expired. + + Note: An RDNSS address MUST be used only as long as both the RA + router lifetime and the RDNSS option lifetime have not expired. + The reason is that the RDNSS may not be currently reachable or may + not provide service to the host's current address (e.g., due to + network ingress filtering [16][17]). + + + + + +Jeong, et al. Experimental [Page 6] + +RFC 5006 IPv6 RA Option for DNS Configuration September 2007 + + +6.2. Synchronization between DNS Server List and Resolver Repository + + When an IPv6 host receives the information of multiple RDNSS + addresses within a site through an RA message with RDNSS option(s), + it stores the RDNSS addresses (in order) into both the DNS Server + List and the Resolver Repository. The processing of the RDNSS + option(s) included in an RA message is as follows: + + Step (a): Receive and parse the RDNSS option(s). For the RDNSS + addresses in each RDNSS option, perform Step (b) through Step (d). + Note that Step (e) is performed whenever an entry expires in the + DNS Server List. + + Step (b): For each RDNSS address, check the following: If the + RDNSS address already exists in the DNS Server List and the RDNSS + option's Lifetime field is set to zero, delete the corresponding + RDNSS entry from both the DNS Server List and the Resolver + Repository in order to prevent the RDNSS address from being used + any more for certain reasons in network management, e.g., the + breakdown of the RDNSS or a renumbering situation. The processing + of this RDNSS address is finished here. Otherwise, go to Step + (c). + + Step (c): For each RDNSS address, if it already exists in the DNS + Server List, then just update the value of the Expiration-time + field according to the procedure specified in the second bullet of + Section 6.1. Otherwise, go to Step (d). + + Step (d): For each RDNSS address, if it does not exist in the DNS + Server List, register the RDNSS address and lifetime with the DNS + Server List and then insert the RDNSS address in front of the + Resolver Repository. In the case where the data structure for the + DNS Server List is full of RDNSS entries, delete from the DNS + Server List the entry with the shortest expiration time (i.e., the + entry that will expire first). The corresponding RDNSS address is + also deleted from the Resolver Repository. In the order in the + RDNSS option, position the newly added RDNSS addresses in front of + the Resolver Repository so that the new RDNSS addresses may be + preferred according to their order in the RDNSS option for the DNS + name resolution. The processing of these RDNSS addresses is + finished here. Note that, in the case where there are several + routers advertising RDNSS option(s) in a subnet, the RDNSSes that + have been announced recently are preferred. + + Step (e): Delete each expired entry from the DNS Server List, and + delete the RDNSS address corresponding to the entry from the + Resolver Repository. + + + + +Jeong, et al. Experimental [Page 7] + +RFC 5006 IPv6 RA Option for DNS Configuration September 2007 + + +7. Security Considerations + + The security of the RA option for RDNSS might be worse than ND + protocol security [2]. However, any new vulnerability in this RA + option is not known yet. In this context, it can be claimed that the + vulnerability of ND is not worse and is a subset of the attacks that + any node attached to a LAN can do independently of ND. A malicious + node on a LAN can promiscuously receive packets for any router's MAC + address and send packets with the router's MAC address as the source + MAC address in the L2 header. As a result, L2 switches send packets + addressed to the router to the malicious node. Also, this attack can + send redirects that tell the hosts to send their traffic somewhere + else. The malicious node can send unsolicited RA or Neighbor + Advertisement (NA) replies, answer RS or Neighbor Solicitation (NS) + requests, etc. Also, an attacker could configure a host to send out + an RA with a fraudulent RDNSS address, which is presumably an easier + avenue of attack than becoming a rogue router and having to process + all traffic for the subnet. It is necessary to disable the RA RDNSS + option in both routers and clients administratively to avoid this + problem. All of this can be done independently of implementing ND. + Therefore, it can be claimed that the RA option for RDNSS has + vulnerabilities similar to those existing in current mechanisms. + + If the Secure Neighbor Discovery (SEND) protocol is used as a + security mechanism for ND, all the ND options including the RDNSS + option are automatically included in the signatures [11], so the + RDNSS transport is integrity-protected. However, since any valid + SEND node can still insert RDNSS options, SEND cannot verify who is + or is not authorized to send the options. + +8. IANA Considerations + + The IANA has assigned a new IPv6 Neighbor Discovery Option type for + the RDNSS option defined in this document. + + Option Name Type + RDNSS option 25 + + The IANA registry for these options is: + + http://www.iana.org/assignments/icmpv6-parameters + +9. Acknowledgements + + This document has greatly benefited from inputs by Robert Hinden, + Pekka Savola, Iljitsch van Beijnum, Brian Haberman and Tim Chown. + The authors appreciate their contributions. + + + + +Jeong, et al. Experimental [Page 8] + +RFC 5006 IPv6 RA Option for DNS Configuration September 2007 + + +10. References + +10.1. Normative References + + [1] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", BCP 14, RFC 2119, March 1997. + + [2] Narten, T., Nordmark, E., Simpson, W., and H. Soliman, + "Neighbor Discovery for IP version 6 (IPv6)", RFC 4861, + September 2007. + + [3] Thomson, S., Narten, T., and T. Jinmei, "IPv6 Stateless Address + Autoconfiguration", RFC 4862, September 2007. + +10.2. Informative References + + [4] Mockapetris, P., "Domain Names - Concepts and Facilities", + RFC 1034, November 1987. + + [5] Mockapetris, P., "Domain Names - Implementation and + Specification", RFC 1035, November 1987. + + [6] Droms, R., Ed., "Dynamic Host Configuration Protocol for IPv6 + (DHCPv6)", RFC 3315, July 2003. + + [7] Droms, R., "Stateless Dynamic Host Configuration Protocol + (DHCP) Service for IPv6", RFC 3736, April 2004. + + [8] Droms, R., Ed., "DNS Configuration options for Dynamic Host + Configuration Protocol for IPv6 (DHCPv6)", RFC 3646, + December 2003. + + [9] Jeong, J., Ed., "IPv6 Host Configuration of DNS Server + Information Approaches", RFC 4339, February 2006. + + [10] Johnson, D., Perkins, C., and J. Arkko, "Mobility Support in + IPv6", RFC 3775, June 2004. + + [11] Arkko, J., Ed., "SEcure Neighbor Discovery (SEND)", RFC 3971, + March 2005. + + [12] ANSI/IEEE Std 802.11, "Part 11: Wireless LAN Medium Access + Control (MAC) and Physical Layer (PHY) Specifications", + March 1999. + + [13] IEEE Std 802.11a, "Part 11: Wireless LAN Medium Access Control + (MAC) and Physical Layer (PHY) specifications: High-speed + Physical Layer in the 5 GHZ Band", September 1999. + + + +Jeong, et al. Experimental [Page 9] + +RFC 5006 IPv6 RA Option for DNS Configuration September 2007 + + + [14] IEEE Std 802.11b, "Part 11: Wireless LAN Medium Access Control + (MAC) and Physical Layer (PHY) specifications: Higher-Speed + Physical Layer Extension in the 2.4 GHz Band", September 1999. + + [15] IEEE P802.11g/D8.2, "Part 11: Wireless LAN Medium Access + Control (MAC) and Physical Layer (PHY) specifications: Further + Higher Data Rate Extension in the 2.4 GHz Band", April 2003. + + [16] Damas, J. and F. Neves, "Preventing Use of Recursive + Nameservers in Reflector Attacks", Work in Progress, July 2007. + + [17] Ferguson, P. and D. Senie, "Network Ingress Filtering: + Defeating Denial of Service Attacks which employ IP Source + Address Spoofing", BCP 38, RFC 2827, May 2000. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Jeong, et al. Experimental [Page 10] + +RFC 5006 IPv6 RA Option for DNS Configuration September 2007 + + +Authors' Addresses + + Jaehoon Paul Jeong (editor) + ETRI/Department of Computer Science and Engineering + University of Minnesota + 117 Pleasant Street SE + Minneapolis, MN 55455 + USA + + Phone: +1 651 587 7774 + Fax: +1 612 625 0572 + EMail: jjeong@cs.umn.edu + URI: http://www.cs.umn.edu/~jjeong/ + + + Soohong Daniel Park + Mobile Convergence Laboratory + SAMSUNG Electronics + 416 Maetan-3dong, Yeongtong-Gu + Suwon, Gyeonggi-Do 443-742 + Korea + + Phone: +82 31 200 4508 + EMail: soohong.park@samsung.com + + + Luc Beloeil + France Telecom R&D + 42, rue des coutures + BP 6243 + 14066 CAEN Cedex 4 + France + + Phone: +33 02 3175 9391 + EMail: luc.beloeil@orange-ftgroup.com + + + Syam Madanapalli + Ordyn Technologies + 1st Floor, Creator Building, ITPL + Bangalore - 560066 + India + + Phone: +91-80-40383000 + EMail: smadanapalli@gmail.com + + + + + + +Jeong, et al. Experimental [Page 11] + +RFC 5006 IPv6 RA Option for DNS Configuration September 2007 + + +Full Copyright Statement + + Copyright (C) The IETF Trust (2007). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + + + + + + + + + + + + +Jeong, et al. Experimental [Page 12] + -- cgit v1.2.3