Skip to content

Commit 86b94b3

Browse files
committed
[WIP] Initial attempt at rfc8106
Signed-off-by: Jonathan Davies <[email protected]>
1 parent efbebdf commit 86b94b3

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

src/ipv6/ipv6_wire.ml

+9
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,15 @@ let get_opt_prefix_on_link buf =
103103
let get_opt_prefix_autonomous buf =
104104
get_opt_prefix_reserved1 buf land 0x40 <> 0
105105

106+
[%%cstruct
107+
type opt_rdnss_header = {
108+
ty: uint8_t;
109+
len: uint8_t;
110+
reserved: uint16_t;
111+
rdnss_lifetime: uint32_t;
112+
} [@@big_endian]
113+
]
114+
106115
[%%cstruct
107116
type opt = {
108117
ty: uint8_t;

src/ipv6/ndpv6.ml

+91
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ References:
3434
3535
- Multicast Listener Discovery Version 2 (MLDv2) for IPv6
3636
http://tools.ietf.org/html/rfc3810
37+
38+
- IPv6 Router Advertisement Options for DNS Configuration
39+
https://tools.ietf.org/html/rfc8106
3740
*)
3841

3942
let src = Logs.Src.create "ndpc6" ~doc:"Mirage IPv6 discovery"
@@ -255,12 +258,17 @@ type pfx =
255258
pfx_preferred_lifetime : time option;
256259
pfx_prefix : Ipaddr.Prefix.t }
257260

261+
type rdnss =
262+
{ rdnss_lifetime: time option;
263+
rdnss_addresses: Ipaddr.V6.t list }
264+
258265
type ra =
259266
{ ra_cur_hop_limit : int;
260267
ra_router_lifetime : time;
261268
ra_reachable_time : time option;
262269
ra_retrans_timer : time option;
263270
ra_slla : Macaddr.t option;
271+
ra_rdnss : rdnss list;
264272
ra_prefix : pfx list }
265273

266274
type na =
@@ -665,6 +673,60 @@ module NeighborCache = struct
665673
| Not_found -> false
666674
end
667675

676+
module RDNSSList = struct
677+
678+
type t =
679+
(Ipaddr.t * time) list
680+
681+
let empty =
682+
[]
683+
684+
let to_list rdnssl =
685+
List.map fst rdnssl
686+
687+
let add rdnssl ~now ?(lifetime = Duration.of_year 1) ip =
688+
(ip, Int64.add now lifetime) :: rdnssl
689+
690+
let tick rdnssl ~now =
691+
List.filter (fun (_, t) -> t > now) rdnssl
692+
693+
let handle_ra rdnssl ~now ~src ~lft =
694+
match List.mem_assoc src rdnssl with
695+
| true ->
696+
let rdnssl = List.remove_assoc src rdnssl in
697+
if lft > 0L then begin
698+
Log.info (fun f -> f "RA: Refreshing Nameserver: src=%a lft=%Lu" Ipaddr.pp src lft);
699+
(src, Int64.add now lft) :: rdnssl, []
700+
end else begin
701+
Log.info (fun f -> f "RA: Nameserver Expired: src=%a" Ipaddr.pp src);
702+
rdnssl, []
703+
end
704+
| false ->
705+
if lft > 0L then begin
706+
Log.debug (fun f -> f "RA: Adding Nameserver: src=%a" Ipaddr.pp src);
707+
(add rdnssl ~now ~lifetime:lft src), []
708+
end else
709+
rdnssl, []
710+
711+
let add rdnssl ~now:_ ip =
712+
match List.mem_assoc ip rdnssl with
713+
| true -> rdnssl
714+
| false -> (ip, Duration.of_year 1) :: rdnssl
715+
716+
let select rdnssl reachable ip =
717+
let rec loop = function
718+
| [] ->
719+
begin match rdnssl with
720+
| [] -> ip, rdnssl
721+
| (ip, _) as r :: rest ->
722+
ip, rest @ [r]
723+
end
724+
| (ip, _) :: _ when reachable ip -> ip, rdnssl
725+
| _ :: rest -> loop rest
726+
in
727+
loop rdnssl
728+
end
729+
668730
module RouterList = struct
669731

670732
type t =
@@ -741,6 +803,7 @@ module Parser = struct
741803
| TLLA of Macaddr.t
742804
| MTU of int
743805
| PREFIX of pfx
806+
| RDNSS of rdnss
744807

745808
let rec parse_options1 opts =
746809
if Cstruct.length opts >= Ipv6_wire.sizeof_opt then
@@ -777,6 +840,25 @@ module Parser = struct
777840
{pfx_on_link; pfx_autonomous; pfx_valid_lifetime; pfx_preferred_lifetime; pfx_prefix}
778841
in
779842
PREFIX pfx :: parse_options1 opts
843+
| 25, 3 ->
844+
let rdnss_lifetime =
845+
let n = Ipv6_wire.get_opt_rdnss_header_rdnss_lifetime opt in
846+
match n with
847+
| 0l -> None
848+
| n -> Some (Int64.of_int32 n)
849+
in
850+
let decode_ns off = Ipaddr_cstruct.V6.of_cstruct_exn (Cstruct.shift opt off) in
851+
let rec collect_ns acc = function
852+
| 0 -> acc
853+
| n ->
854+
let ns = decode_ns (Ipv6_wire.sizeof_opt_rdnss_header + n * 16) in
855+
collect_ns (ns :: acc) (n - 1)
856+
in
857+
let rdnss_addresses = collect_ns [] (Ipv6_wire.get_opt_rdnss_header_len opt - 1) in
858+
let rdnss =
859+
{rdnss_lifetime; rdnss_addresses}
860+
in
861+
RDNSS rdnss :: parse_options1 opts
780862
| ty, len ->
781863
Log.info (fun f -> f "ND6: Unsupported ND option in RA: ty=%d len=%d" ty len);
782864
parse_options1 opts
@@ -1133,6 +1215,7 @@ let local ~handle_ra ~now ~random mac =
11331215
let ctx =
11341216
{ neighbor_cache = NeighborCache.empty;
11351217
prefix_list = PrefixList.link_local;
1218+
rdnss_list = RDNSSList.empty;
11361219
router_list = RouterList.empty;
11371220
mac = mac;
11381221
address_list = AddressList.empty;
@@ -1315,6 +1398,7 @@ let tick ~now ctx =
13151398
let address_list, actions = AddressList.tick ctx.address_list ~now ~retrans_timer in
13161399
let prefix_list = PrefixList.tick ctx.prefix_list ~now in
13171400
let neighbor_cache, actions' = NeighborCache.tick ctx.neighbor_cache ~now ~retrans_timer in
1401+
let rdnss_list = RDNSSList.tick ctx.rdnss_list ~now in
13181402
let router_list = RouterList.tick ctx.router_list ~now in
13191403
let ctx = {ctx with address_list; prefix_list; neighbor_cache; router_list} in
13201404
let actions = actions @ actions' in
@@ -1327,6 +1411,13 @@ let add_prefix ~now ctx pfx =
13271411
let get_prefix ctx =
13281412
PrefixList.to_list ctx.prefix_list
13291413

1414+
let add_rdnss ~now ctx ips =
1415+
let rdnss_list = List.fold_left (RDNSSList.add ~now) ctx.rdnss_list ips in
1416+
{ctx with rdnss_list}
1417+
1418+
let get_rdnss ctx =
1419+
RDNSSList.to_list ctx.rdnss_list
1420+
13301421
let add_routers ~now ctx ips =
13311422
let router_list = List.fold_left (RouterList.add ~now) ctx.router_list ips in
13321423
{ctx with router_list}

src/ipv6/ndpv6.mli

+8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
type buffer = Cstruct.t
1818
type ipaddr = Ipaddr.V6.t
1919
type prefix = Ipaddr.V6.Prefix.t
20+
type rdnss = Ipaddr.V6.t list
2021
type time = int64
2122

2223
val ipaddr_of_cstruct : buffer -> ipaddr
@@ -74,6 +75,13 @@ val add_prefix : now:time -> context -> prefix -> context
7475
val get_prefix : context -> prefix list
7576
(** [get_prefix ctx] returns the list of local prefixes known to [ctx]. *)
7677

78+
val add_rdnss : now:time -> context -> ipaddr list -> context
79+
(** [add_rdnss ~now ctx ips] adds a list of nameserver addresses to [ctx] to be
80+
used as nameservers. *)
81+
82+
val get_rdnss : context -> ipaddr list
83+
(** [get_rdnss ctx] returns the list of nameserver addresses known to [ctx]. *)
84+
7785
val add_routers : now:time -> context -> ipaddr list -> context
7886
(** [add_routers ~now ctx ips] adds a list of gateways to [ctx] to be used for
7987
routing. *)

0 commit comments

Comments
 (0)