summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKozlov Dmitry <dima@server>2011-08-23 18:02:22 +0400
committerKozlov Dmitry <dima@server>2011-08-23 18:02:22 +0400
commit9bc3fa4216fb2ad043232584b5a5e134e64830ed (patch)
tree910b5a0809a272d8525ff1ed2c1265b7f7d53c3d
parente281cbf20eb2e8f36ef5037e138fdf3798f1897d (diff)
downloadaccel-ppp-9bc3fa4216fb2ad043232584b5a5e134e64830ed.tar.gz
accel-ppp-9bc3fa4216fb2ad043232584b5a5e134e64830ed.zip
ppp: ipv6: multiple prefixes, route option, rdnss option implementation
-rw-r--r--accel-pppd/cli/show_sessions.c3
-rw-r--r--accel-pppd/cli/std_cmd.c3
-rw-r--r--accel-pppd/extra/ipv6pool.c37
-rw-r--r--accel-pppd/extra/net-snmp/sessionTable_data_access.c3
-rw-r--r--accel-pppd/extra/net-snmp/terminate.c3
-rw-r--r--accel-pppd/extra/pppd_compat.c5
-rw-r--r--accel-pppd/ipdb.h12
-rw-r--r--accel-pppd/ppp/ipcp_opt_ipaddr.c102
-rw-r--r--accel-pppd/ppp/ipv6_nd.c207
-rw-r--r--accel-pppd/ppp/ipv6cp_opt_intfid.c49
-rw-r--r--accel-pppd/ppp/ppp.h9
-rw-r--r--accel-pppd/radius/radius.c4
-rw-r--r--accel-pppd/radius/req.c6
-rw-r--r--rfc/rfc5006.txt675
14 files changed, 940 insertions, 178 deletions
diff --git a/accel-pppd/cli/show_sessions.c b/accel-pppd/cli/show_sessions.c
index d7a8a82..9019986 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 1c8e149..24e5228 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 306d5bd..5a1a606 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 847197a..0d38e5d 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 bd38577..abe92df 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 aa6f6b5..32a5def 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 3a717a1..69d5479 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 ac45ac7..f387069 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("<addr %s>",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 bec0ea3..e0ec842 100644
--- a/accel-pppd/ppp/ipv6_nd.c
+++ b/accel-pppd/ppp/ipv6_nd.c
@@ -7,18 +7,50 @@
#include <pthread.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
+#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#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 b55d3ff..9a9b9e3 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 4708578..f95893a 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 ae5948b..4200d62 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 b45a601..462e656 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 0000000..056f149
--- /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]
+