123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382(*
* 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
*
*)openRRopenTrieopenPrintf(* Loader database: the DNS trie plus a hash table of other names in use *)typedb={trie:dnstrie;(* Names that have RRSets *)mutablenames:(Name.key,dnsnode)Hashtbl.t;(* All other names *)}(* Get a new, empty database *)letnew_db()={trie=new_trie();names=Hashtbl.create101;}(* Throw away the known names: call when guaranteed no more updates *)letno_more_updatesdb=Hashtbl.cleardb.names;db.names<-Hashtbl.create1(* Get the dnsnode that represents this name, making a new one if needed *)letget_target_dnsnodeownerdb=letkey=Name.to_keyownerinmatchsimple_lookupkeydb.triewithSomen->n|None->tryHashtbl.finddb.nameskeywithNot_found->letn={owner=Name.hashconsowner;rrsets=[];}inHashtbl.adddb.nameskeyn;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 *)letget_owner_dnsnodeownerdb=letpull_nametblkeyowner()=trymatchHashtbl.findtblkeywithd->Hashtbl.removetblkey;dwithNot_found->{owner=Name.hashconsowner;rrsets=[];}inletkey=Name.to_keyownerinlookup_or_insertkeydb.trie(pull_namedb.nameskeyowner)(* How to add each type of RR to the database... *)exceptionTTLMismatchletadd_rrsetrrsetownerdb=(* 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 *)letmerge_rrsetnew_rrsetrrsets=letcfnab=compare(Hashtbl.hasha)(Hashtbl.hashb)inletmfnno=List.mergecfn(List.fast_sortcfnn)oinletrecdo_mergenew_ttlnew_rdatarrsets_donerrsets_rest=matchrrsets_restwith|[]->(new_ttl,{ttl=new_ttl;rdata=new_rdata}::rrsets_done)|rrset::rest->match(new_rdata,rrset.rdata)with(Al1,Al2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=A(mfnl1l2)}::rrsets_done))|(NSl1,NSl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=NS(mfnl1l2)}::rrsets_done))|(CNAMEl1,CNAMEl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=CNAME(mfnl1l2)}::rrsets_done))|(SOAl1,SOAl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=SOA(mfnl1l2)}::rrsets_done))|(MBl1,MBl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=MB(mfnl1l2)}::rrsets_done))|(MGl1,MGl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=MG(mfnl1l2)}::rrsets_done))|(MRl1,MRl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=MR(mfnl1l2)}::rrsets_done))|(WKSl1,WKSl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=WKS(mfnl1l2)}::rrsets_done))|(PTRl1,PTRl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=PTR(mfnl1l2)}::rrsets_done))|(HINFOl1,HINFOl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=HINFO(mfnl1l2)}::rrsets_done))|(MINFOl1,MINFOl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=MINFO(mfnl1l2)}::rrsets_done))|(MXl1,MXl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=MX(mfnl1l2)}::rrsets_done))|(TXTl1,TXTl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=TXT(mfnl1l2)}::rrsets_done))|(RPl1,RPl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=RP(mfnl1l2)}::rrsets_done))|(AFSDBl1,AFSDBl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=AFSDB(mfnl1l2)}::rrsets_done))|(X25l1,X25l2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=X25(mfnl1l2)}::rrsets_done))|(ISDNl1,ISDNl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=ISDN(mfnl1l2)}::rrsets_done))|(RTl1,RTl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=RT(mfnl1l2)}::rrsets_done))|(AAAAl1,AAAAl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=AAAA(mfnl1l2)}::rrsets_done))|(SRVl1,SRVl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=SRV(mfnl1l2)}::rrsets_done))(* | (UNSPEC l1, UNSPEC l2) -> *)(* (rrset.ttl, List.rev_append rest *)(* ({ ttl = rrset.ttl; rdata = UNSPEC (mfn l1 l2) } :: rrsets_done)) *)|(DNSKEYl1,DNSKEYl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=DNSKEY(mfnl1l2)}::rrsets_done))|(DSl1,DSl2)->(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=DS(mfnl1l2)}::rrsets_done))|(Unknown(t1,l1),Unknown(t2,l2))->ift1=t2then(rrset.ttl,List.rev_appendrest({ttl=rrset.ttl;rdata=Unknown(t1,(mfnl1l2))}::rrsets_done))elsedo_mergenew_ttlnew_rdata(rrset::rrsets_done)rest|(_,_)->do_mergenew_ttlnew_rdata(rrset::rrsets_done)restindo_mergenew_rrset.ttlnew_rrset.rdata[]rrsetsinletownernode=get_owner_dnsnodeownerdbinlet(old_ttl,new_rrsets)=merge_rrsetrrsetownernode.rrsetsinownernode.rrsets<-new_rrsets;ifnot(old_ttl=rrset.ttl)thenraiseTTLMismatchletadd_generic_rrtcodestrttlownerdb=lets=Name.hashcons_stringstrinadd_rrset{ttl;rdata=Unknown(tcode,[s])}ownerdbletadd_a_rripttlownerdb=add_rrset{ttl;rdata=A[ip]}ownerdbletadd_aaaa_rripttlownerdb=add_rrset{ttl;rdata=AAAA[ip]}ownerdbletadd_ns_rrtargetttlownerdb=trylettargetnode=get_target_dnsnodetargetdbinadd_rrset{ttl;rdata=NS[targetnode]}ownerdb;fix_flags(Name.to_keyowner)db.triewithTTLMismatch->fix_flags(Name.to_keyowner)db.trie;raiseTTLMismatchletadd_cname_rrtargetttlownerdb=lettargetnode=get_target_dnsnodetargetdbinadd_rrset{ttl;rdata=CNAME[targetnode]}ownerdbletadd_soa_rrmasterrpserialrefreshretryexpiryminttlownerdb=tryletmasternode=get_target_dnsnodemasterdbinletrpnode=get_target_dnsnoderpdbinletrdata=(masternode,rpnode,serial,refresh,retry,expiry,min)inadd_rrset{ttl;rdata=SOA[rdata]}ownerdb;fix_flags(Name.to_keyowner)db.triewithTTLMismatch->fix_flags(Name.to_keyowner)db.trie;raiseTTLMismatchletadd_mb_rrtargetttlownerdb=lettargetnode=get_target_dnsnodetargetdbinadd_rrset{ttl;rdata=MB[targetnode]}ownerdbletadd_mg_rrtargetttlownerdb=lettargetnode=get_target_dnsnodetargetdbinadd_rrset{ttl;rdata=MG[targetnode]}ownerdbletadd_mr_rrtargetttlownerdb=lettargetnode=get_target_dnsnodetargetdbinadd_rrset{ttl;rdata=MR[targetnode]}ownerdbletadd_wks_rraddrprotbitmapttlownerdb=letb=Name.hashcons_stringbitmapinadd_rrset{ttl;rdata=WKS[(addr,prot,b)]}ownerdbletadd_ptr_rrtargetttlownerdb=lettargetnode=get_target_dnsnodetargetdbinadd_rrset{ttl;rdata=PTR[targetnode]}ownerdbletadd_hinfo_rrcpuosttlownerdb=letc=Name.hashcons_stringcpuinleto=Name.hashcons_stringosinadd_rrset{ttl;rdata=HINFO[(c,o)]}ownerdbletadd_minfo_rrrmailbxemailbxttlownerdb=letrtarget=get_target_dnsnodermailbxdbinletetarget=get_target_dnsnodeemailbxdbinadd_rrset{ttl;rdata=MINFO[(rtarget,etarget)]}ownerdbletadd_mx_rrpritargetttlownerdb=letpri=priinlettargetnode=get_target_dnsnodetargetdbinadd_rrset{ttl;rdata=MX[(pri,targetnode)]}ownerdbletadd_txt_rrstrlttlownerdb=letsl=List.mapName.hashcons_stringstrlinadd_rrset{ttl;rdata=TXT[sl]}ownerdbletadd_rp_rrmboxtxtttlownerdb=letmtarget=get_target_dnsnodemboxdbinletttarget=get_target_dnsnodetxtdbinadd_rrset{ttl;rdata=RP[(mtarget,ttarget)]}ownerdbletadd_afsdb_rrsubtypetargetttlownerdb=letst=subtypeinlettargetnode=get_target_dnsnodetargetdbinadd_rrset{ttl;rdata=AFSDB[(st,targetnode)]}ownerdbletadd_x25_rraddrttlownerdb=leta=Name.hashcons_stringaddrinadd_rrset{ttl;rdata=X25[a]}ownerdbletadd_isdn_rraddrsattlownerdb=leta=Name.hashcons_stringaddrinlets=matchsawith|None->None|Somex->Some(Name.hashcons_stringx)inadd_rrset{ttl;rdata=ISDN[(a,s)]}ownerdbletadd_rt_rrpreftargetttlownerdb=letpref=prefinlettargetnode=get_target_dnsnodetargetdbinadd_rrset{ttl;rdata=RT[(pref,targetnode)]}ownerdbletadd_srv_rrpriweightporttargetttlownerdb=letpri=priinletweight=weightinletport=portinlettargetnode=get_target_dnsnodetargetdbinadd_rrset{ttl;rdata=SRV[(pri,weight,port,targetnode)]}ownerdb(* let add_unspec_rr str ttl owner db = *)(* let s = hashcons_charstring str in *)(* add_rrset { ttl; rdata = UNSPEC [ s ] } owner db *)letadd_dnskey_rrflagstypkeyttlownerdb=letflags=flagsinlettyp=typinlettmp=Base64.decode_exnkeyinletdnskey=Name.hashcons_stringtmpinadd_rrset{ttl;rdata=DNSKEY[(flags,typ,dnskey)]}ownerdb(** valeur entière d'un chiffre hexa *)letchar_of_hex_valuec=int_of_charc-(ifc>='0'&&c<='9'then48(*int_of_char '0'*)elseifc>='A'&&c<='F'then55(* int_of_char 'A' - 10 *)elseifc>='a'&&c<='f'then87(* int_of_char 'a' - 10
*)elseassertfalse)letinitnf=ifn>=0thenlets=Bytes.createninfori=0topredndoBytes.setsi(fi)done;selseletn=(-n)inlets=Bytes.createninfori=predndownto0doBytes.setsi(f(n-i-1))done;sletstring_of_hexs=letl=String.lengthsiniflland1=1theninvalid_arg"Bytes.from_hex";init(llsr1)(funi->leti=ilsl1inChar.chr((char_of_hex_value(String.getsi)lsl4)+(char_of_hex_value(String.gets(i+1)))))|>Bytes.to_stringletadd_ds_rrtagalgdigestkeyttlownerdb=letalg=match(Packet.int_to_dnssec_algalg)with|None->failwith(sprintf"add_ds_rr: unsupported alg id %d"alg)|Somea->ainletdigest=match(Packet.int_to_digest_algdigest)with|Somea->a|None->failwith(sprintf"add_ds_rr : invalid hashing alg %d"digest)inlettmp=string_of_hexkeyinletds=Name.hashcons_stringtmpinadd_rrset{ttl;rdata=DS[(tag,alg,digest,ds)]}ownerdbletadd_rrsig_rrtypalglblorig_ttlexp_tsinc_tstagnamesignttlownerdb=lettyp=match(Packet.string_to_rr_type("RR_"^typ))with|None->failwith(sprintf"add_rrsig_rr failed: uknown type %s"typ)|Somea->ainletalg=match(Packet.int_to_dnssec_algalg)with|None->failwith(sprintf"add_rrsig_rr failed: uknown dnssec alg %d"alg)|Somea->ain(* TODO: Check if sign is in the future or if the sign has expired *)letsign=Base64.decode_exnsigninletrr=RRSIG[{rrsig_type=typ;rrsig_alg=alg;rrsig_labels=char_of_intlbl;rrsig_ttl=orig_ttl;rrsig_expiry=exp_ts;rrsig_incept=inc_ts;rrsig_keytag=tag;rrsig_name=name;rrsig_sig=sign;}]inadd_rrset{ttl;rdata=rr;}ownerdb(* State variables for the parser & lexer *)typeparserstate={mutabledb:db;mutableparen:int;mutablefilename:string;mutablelineno:int;mutableorigin:Name.t;mutablettl:int32;mutableowner:Name.t;}letnew_state()={db=new_db();paren=0;filename="";lineno=1;ttl=Int32.of_int3600;origin=Name.empty;owner=Name.empty;}letstate=new_state()