Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
loader.ml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382(* * Copyright (c) 2005-2006 Tim Deegan <tjd@phlegethon.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * dnsloader.ml -- how to build up a DNS trie from separate RRs * *) open RR open Trie open Printf (* Loader database: the DNS trie plus a hash table of other names in use *) type db = { trie: dnstrie; (* Names that have RRSets *) mutable names: (Name.key, dnsnode) Hashtbl.t; (* All other names *) } (* Get a new, empty database *) let new_db () = { trie = new_trie (); names = Hashtbl.create 101; } (* Throw away the known names: call when guaranteed no more updates *) let no_more_updates db = Hashtbl.clear db.names; db.names <- Hashtbl.create 1 (* Get the dnsnode that represents this name, making a new one if needed *) let get_target_dnsnode owner db = let key = Name.to_key owner in match simple_lookup key db.trie with Some n -> n | None -> try Hashtbl.find db.names key with Not_found -> let n = { owner = Name.hashcons owner; rrsets = []; } in Hashtbl.add db.names key n ; n (* Get the dnsnode that represents this name, making a new one if needed, inserting it into the trie, and returning both trie node and dnsnode *) let get_owner_dnsnode owner db = let pull_name tbl key owner () = try match Hashtbl.find tbl key with d -> Hashtbl.remove tbl key; d with Not_found -> { owner = Name.hashcons owner; rrsets = []; } in let key = Name.to_key owner in lookup_or_insert key db.trie (pull_name db.names key owner) (* How to add each type of RR to the database... *) exception TTLMismatch let add_rrset rrset owner db = (* Merge a new RRSet into a list of RRSets. Returns the new list and the ttl of the resulting RRset. Reverses the order of the RRsets in the list *) let merge_rrset new_rrset rrsets = let cfn a b = compare (Hashtbl.hash a) (Hashtbl.hash b) in let mfn n o = List.merge cfn (List.fast_sort cfn n) o in let rec do_merge new_ttl new_rdata rrsets_done rrsets_rest = match rrsets_rest with | [] -> (new_ttl, { ttl = new_ttl; rdata = new_rdata } :: rrsets_done ) | rrset :: rest -> match (new_rdata, rrset.rdata) with (A l1, A l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = A (mfn l1 l2) } :: rrsets_done)) | (NS l1, NS l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = NS (mfn l1 l2) } :: rrsets_done)) | (CNAME l1, CNAME l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = CNAME (mfn l1 l2) } :: rrsets_done)) | (SOA l1, SOA l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = SOA (mfn l1 l2) } :: rrsets_done)) | (MB l1, MB l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = MB (mfn l1 l2) } :: rrsets_done)) | (MG l1, MG l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = MG (mfn l1 l2) } :: rrsets_done)) | (MR l1, MR l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = MR (mfn l1 l2) } :: rrsets_done)) | (WKS l1, WKS l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = WKS (mfn l1 l2) } :: rrsets_done)) | (PTR l1, PTR l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = PTR (mfn l1 l2) } :: rrsets_done)) | (HINFO l1, HINFO l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = HINFO (mfn l1 l2) } :: rrsets_done)) | (MINFO l1, MINFO l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = MINFO (mfn l1 l2) } :: rrsets_done)) | (MX l1, MX l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = MX (mfn l1 l2) } :: rrsets_done)) | (TXT l1, TXT l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = TXT (mfn l1 l2) } :: rrsets_done)) | (RP l1, RP l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = RP (mfn l1 l2) } :: rrsets_done)) | (AFSDB l1, AFSDB l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = AFSDB (mfn l1 l2) } :: rrsets_done)) | (X25 l1, X25 l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = X25 (mfn l1 l2) } :: rrsets_done)) | (ISDN l1, ISDN l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = ISDN (mfn l1 l2) } :: rrsets_done)) | (RT l1, RT l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = RT (mfn l1 l2) } :: rrsets_done)) | (AAAA l1, AAAA l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = AAAA (mfn l1 l2) } :: rrsets_done)) | (SRV l1, SRV l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = SRV (mfn l1 l2) } :: rrsets_done)) (* | (UNSPEC l1, UNSPEC l2) -> *) (* (rrset.ttl, List.rev_append rest *) (* ({ ttl = rrset.ttl; rdata = UNSPEC (mfn l1 l2) } :: rrsets_done)) *) | (DNSKEY l1, DNSKEY l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = DNSKEY (mfn l1 l2) } :: rrsets_done)) | (DS l1, DS l2) -> (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = DS (mfn l1 l2) } :: rrsets_done)) | (Unknown (t1, l1), Unknown (t2, l2)) -> if t1 = t2 then (rrset.ttl, List.rev_append rest ({ ttl = rrset.ttl; rdata = Unknown (t1,(mfn l1 l2)) } :: rrsets_done)) else do_merge new_ttl new_rdata (rrset :: rrsets_done) rest | (_, _) -> do_merge new_ttl new_rdata (rrset :: rrsets_done) rest in do_merge new_rrset.ttl new_rrset.rdata [] rrsets in let ownernode = get_owner_dnsnode owner db in let (old_ttl, new_rrsets) = merge_rrset rrset ownernode.rrsets in ownernode.rrsets <- new_rrsets; if not (old_ttl = rrset.ttl) then raise TTLMismatch let add_generic_rr tcode str ttl owner db = let s = Name.hashcons_string str in add_rrset { ttl; rdata = Unknown (tcode, [ s ]) } owner db let add_a_rr ip ttl owner db = add_rrset { ttl; rdata = A [ ip ] } owner db let add_aaaa_rr ip ttl owner db = add_rrset { ttl; rdata = AAAA [ ip ] } owner db let add_ns_rr target ttl owner db = try let targetnode = get_target_dnsnode target db in add_rrset { ttl; rdata = NS [ targetnode ] } owner db; fix_flags (Name.to_key owner) db.trie with TTLMismatch -> fix_flags (Name.to_key owner) db.trie; raise TTLMismatch let add_cname_rr target ttl owner db = let targetnode = get_target_dnsnode target db in add_rrset { ttl; rdata = CNAME [ targetnode ] } owner db let add_soa_rr master rp serial refresh retry expiry min ttl owner db = try let masternode = get_target_dnsnode master db in let rpnode = get_target_dnsnode rp db in let rdata = (masternode, rpnode, serial, refresh, retry, expiry, min) in add_rrset { ttl; rdata = SOA [ rdata ] } owner db; fix_flags (Name.to_key owner) db.trie with TTLMismatch -> fix_flags (Name.to_key owner) db.trie; raise TTLMismatch let add_mb_rr target ttl owner db = let targetnode = get_target_dnsnode target db in add_rrset { ttl; rdata = MB [ targetnode ] } owner db let add_mg_rr target ttl owner db = let targetnode = get_target_dnsnode target db in add_rrset { ttl; rdata = MG [ targetnode ] } owner db let add_mr_rr target ttl owner db = let targetnode = get_target_dnsnode target db in add_rrset { ttl; rdata = MR [ targetnode ] } owner db let add_wks_rr addr prot bitmap ttl owner db = let b = Name.hashcons_string bitmap in add_rrset { ttl; rdata = WKS [ (addr, prot, b) ] } owner db let add_ptr_rr target ttl owner db = let targetnode = get_target_dnsnode target db in add_rrset { ttl; rdata = PTR [ targetnode ] } owner db let add_hinfo_rr cpu os ttl owner db = let c = Name.hashcons_string cpu in let o = Name.hashcons_string os in add_rrset { ttl; rdata = HINFO [ (c, o) ] } owner db let add_minfo_rr rmailbx emailbx ttl owner db = let rtarget = get_target_dnsnode rmailbx db in let etarget = get_target_dnsnode emailbx db in add_rrset { ttl; rdata = MINFO [ (rtarget, etarget) ] } owner db let add_mx_rr pri target ttl owner db = let pri = pri in let targetnode = get_target_dnsnode target db in add_rrset { ttl; rdata = MX [ (pri, targetnode) ] } owner db let add_txt_rr strl ttl owner db = let sl = List.map Name.hashcons_string strl in add_rrset { ttl; rdata = TXT [ sl ] } owner db let add_rp_rr mbox txt ttl owner db = let mtarget = get_target_dnsnode mbox db in let ttarget = get_target_dnsnode txt db in add_rrset { ttl; rdata = RP [ (mtarget, ttarget) ] } owner db let add_afsdb_rr subtype target ttl owner db = let st = subtype in let targetnode = get_target_dnsnode target db in add_rrset { ttl; rdata = AFSDB [ (st, targetnode) ] } owner db let add_x25_rr addr ttl owner db = let a = Name.hashcons_string addr in add_rrset { ttl; rdata = X25 [ a ] } owner db let add_isdn_rr addr sa ttl owner db = let a = Name.hashcons_string addr in let s = match sa with | None -> None | Some x -> Some (Name.hashcons_string x) in add_rrset { ttl; rdata = ISDN [ (a, s) ] } owner db let add_rt_rr pref target ttl owner db = let pref = pref in let targetnode = get_target_dnsnode target db in add_rrset { ttl; rdata = RT [ (pref, targetnode) ] } owner db let add_srv_rr pri weight port target ttl owner db = let pri = pri in let weight = weight in let port = port in let targetnode = get_target_dnsnode target db in add_rrset { ttl; rdata = SRV [ (pri, weight, port, targetnode) ] } owner db (* let add_unspec_rr str ttl owner db = *) (* let s = hashcons_charstring str in *) (* add_rrset { ttl; rdata = UNSPEC [ s ] } owner db *) let add_dnskey_rr flags typ key ttl owner db = let flags = flags in let typ = typ in let tmp = Base64.decode_exn key in let dnskey = Name.hashcons_string tmp in add_rrset { ttl; rdata = DNSKEY [ (flags, typ, dnskey) ] } owner db (** valeur entière d'un chiffre hexa *) let char_of_hex_value c = int_of_char c - ( if c >= '0' && c <= '9' then 48 (*int_of_char '0'*) else if c >= 'A' && c <= 'F' then 55 (* int_of_char 'A' - 10 *) else if c >= 'a' && c <= 'f' then 87 (* int_of_char 'a' - 10 *) else assert false ) let init n f = if n >= 0 then let s = Bytes.create n in for i = 0 to pred n do Bytes.set s i (f i) done ; s else let n = (- n) in let s = Bytes.create n in for i = pred n downto 0 do Bytes.set s i (f (n-i-1)) done ; s let string_of_hex s = let l = String.length s in if l land 1 = 1 then invalid_arg "Bytes.from_hex" ; init (l lsr 1) ( fun i -> let i = i lsl 1 in Char.chr ( (char_of_hex_value (String.get s i) lsl 4) + (char_of_hex_value (String.get s (i+1))) ) ) |> Bytes.to_string let add_ds_rr tag alg digest key ttl owner db = let alg = match (Packet.int_to_dnssec_alg alg) with | None -> failwith (sprintf "add_ds_rr: unsupported alg id %d" alg) | Some a -> a in let digest = match (Packet.int_to_digest_alg digest) with | Some a -> a | None -> failwith (sprintf "add_ds_rr : invalid hashing alg %d" digest) in let tmp = string_of_hex key in let ds = Name.hashcons_string tmp in add_rrset { ttl; rdata = DS [ (tag, alg, digest, ds) ] } owner db let add_rrsig_rr typ alg lbl orig_ttl exp_ts inc_ts tag name sign ttl owner db = let typ = match (Packet.string_to_rr_type ("RR_"^typ)) with | None -> failwith (sprintf "add_rrsig_rr failed: uknown type %s" typ) | Some a -> a in let alg = match (Packet.int_to_dnssec_alg alg) with | None -> failwith (sprintf "add_rrsig_rr failed: uknown dnssec alg %d" alg) | Some a -> a in (* TODO: Check if sign is in the future or if the sign has expired *) let sign = Base64.decode_exn sign in let rr = RRSIG [{ rrsig_type = typ; rrsig_alg = alg; rrsig_labels = char_of_int lbl; rrsig_ttl = orig_ttl; rrsig_expiry = exp_ts; rrsig_incept = inc_ts; rrsig_keytag = tag; rrsig_name = name; rrsig_sig = sign; }] in add_rrset { ttl; rdata = rr; } owner db (* State variables for the parser & lexer *) type parserstate = { mutable db: db; mutable paren: int; mutable filename: string; mutable lineno: int; mutable origin: Name.t; mutable ttl: int32; mutable owner: Name.t; } let new_state () = { db = new_db (); paren = 0; filename = ""; lineno = 1; ttl = Int32.of_int 3600; origin = Name.empty; owner = Name.empty; } let state = new_state ()