12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541(*
* Copyright (c) 2011 Richard Mortier <mort@cantab.net>
*
* 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.
*)(* RFC1035, RFC1186 *)[@@@ocaml.warning"-32-37"]openPrintfopenOperators[%%cenumtypedigest_alg=|SHA1[@id1]|SHA256[@id2][@@uint8_t]][%%cenumtypegateway_tc=|NONE[@id0]|IPv4[@id1]|IPv6[@id2]|NAME[@id3][@@uint8_t]]typegateway=|IPv4ofIpaddr.V4.t|IPv6ofIpaddr.V6.t|NAMEofName.tletgateway_to_string=function|IPv4i->Ipaddr.V4.to_stringi|IPv6i->Ipaddr.V6.to_stringi|NAMEn->Name.to_stringn[%%cenumtypepubkey_alg=|RESERVED[@id0]|RSA[@id1]|DSS[@id2][@@uint8_t]][%%cenumtypeipseckey_alg=|DSA[@id1]|RSA[@id2][@@uint8_t]][%%cenumtypehash_alg=|SHA1[@id1][@@uint8_t]][%%cenumtypefp_type=|SHA1[@id1][@@uint8_t]][%%cenumtypednssec_alg=|RSAMD5[@id1]|DH[@id2]|DSA[@id3]|ECC[@id4]|RSASHA1[@id5]|RSANSEC3[@id7]|RSASHA256[@id8]|RSASHA512[@id10]|INDIRECT[@id252]|PRIVATEDNS[@id253]|PRIVATEOID[@id254][@@uint8_t]][%%cenumtyperr_type=|RR_UNUSED[@id0]|RR_A[@id1]|RR_NS[@id2]|RR_MD[@id3]|RR_MF[@id4]|RR_CNAME[@id5]|RR_SOA[@id6]|RR_MB[@id7]|RR_MG[@id8]|RR_MR[@id9]|RR_NULL[@id10]|RR_WKS[@id11]|RR_PTR[@id12]|RR_HINFO[@id13]|RR_MINFO[@id14]|RR_MX[@id15]|RR_TXT[@id16]|RR_RP[@id17]|RR_AFSDB[@id18]|RR_X25[@id19]|RR_ISDN[@id20]|RR_RT[@id21]|RR_NSAP[@id22]|RR_NSAPPTR[@id23]|RR_SIG[@id24]|RR_KEY[@id25]|RR_PX[@id26]|RR_GPOS[@id27]|RR_AAAA[@id28]|RR_LOC[@id29]|RR_NXT[@id30]|RR_EID[@id31]|RR_NIMLOC[@id32]|RR_SRV[@id33]|RR_ATMA[@id34]|RR_NAPTR[@id35]|RR_KM[@id36]|RR_CERT[@id37]|RR_A6[@id38]|RR_DNAME[@id39]|RR_SINK[@id40]|RR_OPT[@id41]|RR_APL[@id42]|RR_DS[@id43]|RR_SSHFP[@id44]|RR_IPSECKEY[@id45]|RR_RRSIG[@id46]|RR_NSEC[@id47]|RR_DNSKEY[@id48]|RR_NSEC3[@id50]|RR_NSEC3PARAM[@id51]|RR_SPF[@id99]|RR_UINFO[@id100]|RR_UID[@id101]|RR_GID[@id102]|RR_UNSPEC[@id103][@@uint8_t]](*
The Type Bit Maps field identifies the RRset types that exist at the
NSEC RR's owner name.
The RR type space is split into 256 window blocks, each representing
the low-order 8 bits of the 16-bit RR type space. Each block that
has at least one active RR type is encoded using a single octet
window number (from 0 to 255), a single octet bitmap length (from 1
to 32) indicating the number of octets used for the window block's
bitmap, and up to 32 octets (256 bits) of bitmap.
Blocks are present in the NSEC RR RDATA in increasing numerical
order.
Type Bit Maps Field = ( Window Block # | Bitmap Length | Bitmap )+
where "|" denotes concatenation.
Each bitmap encodes the low-order 8 bits of RR types within the
window block, in network bit order. The first bit is bit 0. For
window block 0, bit 1 corresponds to RR type 1 (A), bit 2 corresponds
to RR type 2 (NS), and so forth. For window block 1, bit 1
corresponds to RR type 257, and bit 2 to RR type 258. If a bit is
set, it indicates that an RRset of that type is present for the NSEC
RR's owner name. If a bit is clear, it indicates that no RRset of
that type is present for the NSEC RR's owner name.
Bits representing pseudo-types MUST be clear, as they do not appear
in zone data. If encountered, they MUST be ignored upon being read.
Blocks with no types present MUST NOT be included. Trailing zero
octets in the bitmap MUST be omitted. The length of each block's
bitmap is determined by the type code with the largest numerical
value, within that block, among the set of RR types present at the
NSEC RR's owner name. Trailing zero octets not specified MUST be
interpreted as zero octets.
The bitmap for the NSEC RR at a delegation point requires special
attention. Bits corresponding to the delegation NS RRset and the RR
types for which the parent zone has authoritative data MUST be set;
bits corresponding to any non-NS RRset for which the parent is not
authoritative MUST be clear.
A zone MUST NOT include an NSEC RR for any domain name that only
holds glue records.
*)typetype_bit_map=Cstruct.byte*Cstruct.byte*Cstruct.tlettype_bit_map_to_string(_tbm:type_bit_map):string="TYPE_BIT_MAP"typetype_bit_maps=type_bit_maplistlettype_bit_maps_to_string(tbms:type_bit_maps):string=tbms||>type_bit_map_to_string|>String.concat"; "typerdata=|AofIpaddr.V4.t|AAAAofIpaddr.V6.t|AFSDBofCstruct.uint16*Name.t|CNAMEofName.t|DNSKEYofCstruct.uint16*dnssec_alg*string|DSofCstruct.uint16*dnssec_alg*digest_alg*string|HINFOofstring*string|IPSECKEYofCstruct.byte*gateway_tc*ipseckey_alg*gateway*string|ISDNofstring*stringoption|MBofName.t|MDofName.t|MFofName.t|MGofName.t|MINFOofName.t*Name.t|MRofName.t|MXofCstruct.uint16*Name.t|NSofName.t|NSECofName.t(* uncompressed *)*type_bit_maps|NSEC3ofhash_alg*Cstruct.byte*Cstruct.uint16*Cstruct.byte*string*Cstruct.byte*string*type_bit_maps|NSEC3PARAMofhash_alg*Cstruct.byte*Cstruct.uint16*Cstruct.byte*string|PTRofName.t|RPofName.t*Name.t|RRSIGofrr_type*dnssec_alg*Cstruct.byte*int32*int32*int32*Cstruct.uint16*Name.t(* uncompressed *)*string|SIGofdnssec_alg*int32*int32*Cstruct.uint16*Name.t*string|RTofCstruct.uint16*Name.t|SOAofName.t*Name.t*int32*int32*int32*int32*int32|SRVofCstruct.uint16*Cstruct.uint16*Cstruct.uint16*Name.t|SSHFPofpubkey_alg*fp_type*string|TXTofstringlist|UNKNOWNofint*string(* | UNSPEC of string -- wikipedia says deprecated in the 90s *)|WKSofIpaddr.V4.t*Cstruct.byte*string|X25ofstring|EDNS0of(int*int*bool*((int*string)list))lethex_of_stringin_str=letout_str=ref""inlet_=String.iter(funch->out_str:=!out_str^(sprintf"%02x"(int_of_charch)))in_strin!out_strletrdata_to_string=function|Aip->sprintf"A (%s)"(Ipaddr.V4.to_stringip)|AAAAip->sprintf"AAAA (%s)"(Ipaddr.V6.to_stringip)|AFSDB(x,n)->sprintf"AFSDB (%d, %s)"x(Name.to_stringn)|CNAMEn->sprintf"CNAME (%s)"(Name.to_stringn)|DNSKEY(flags,alg,key)->(sprintf"DNSKEY (%d, %s, %s)"flags(dnssec_alg_to_stringalg)(Base64.encode_exnkey))|HINFO(cpu,os)->sprintf"HINFO (%s, %s)"cpuos|ISDN(a,sa)->sprintf"ISDN (%s, %s)"a(matchsawithNone->""|Somesa->sa)|MBn->sprintf"MB (%s)"(Name.to_stringn)|MDn->sprintf"MD (%s)"(Name.to_stringn)|MFn->sprintf"MF (%s)"(Name.to_stringn)|MGn->sprintf"MG (%s)"(Name.to_stringn)|MINFO(rm,em)->(sprintf"MINFO (%s, %s)"(Name.to_stringrm)(Name.to_stringem))|MRn->sprintf"MR (%s)"(Name.to_stringn)|MX(pref,name)->sprintf"MX (%d, %s)"pref(Name.to_stringname)|NSn->sprintf"NS (%s)"(Name.to_stringn)|PTRn->sprintf"PTR (%s)"(Name.to_stringn)|RP(mn,nn)->(sprintf"RP (%s, %s)"(Name.to_stringmn)(Name.to_stringnn))|RT(x,n)->sprintf"RT (%d, %s)"x(Name.to_stringn)|SOA(mn,rn,serial,refresh,retry,expire,minimum)->(sprintf"SOA (%s,%s, %ld,%ld,%ld,%ld,%ld)"(Name.to_stringmn)(Name.to_stringrn)serialrefreshretryexpireminimum)|SRV(x,y,z,n)->sprintf"SRV (%d,%d,%d, %s)"xyz(Name.to_stringn)|TXTsl->sprintf"TXT (%s)"(String.concat""sl)|UNKNOWN(x,bs)->sprintf"UNKNOWN (%d) '%s'"x(Base64.encode_exnbs)(* | UNSPEC bs -> sprintf "UNSPEC (%s)" bs*)|WKS(a,y,s)->sprintf"WKS (%s, %d, %s)"(Ipaddr.V4.to_stringa)(Cstruct.byte_to_inty)s|X25s->sprintf"X25 (%s)"s|EDNS0(len,_rcode,do_bit,_opts)->sprintf"EDNS0 (version:0, UDP: %d, flags: %s)"len(if(do_bit)then"do"else"")|RRSIG(typ,alg,lbl,orig_ttl,exp_ts,inc_ts,tag,name,sign)->sprintf"RRSIG (%s %s %d %ld %ld %ld %d %s %s)"(rr_type_to_stringtyp)(dnssec_alg_to_stringalg)(int_of_charlbl)orig_ttlexp_tsinc_tstag(Name.to_stringname)(Base64.encode_exnsign)|SIG(alg,exp_ts,inc_ts,tag,name,sign)->sprintf"SIG (UNUSED %s 0 0 %ld %ld %d %s %s)"(dnssec_alg_to_stringalg)exp_tsinc_tstag(Name.to_stringname)(Base64.encode_exnsign)|DS(keytag,alg,digest_t,digest)->(sprintf"DS (%d,%s,%s, '%s')"keytag(dnssec_alg_to_stringalg)(digest_alg_to_stringdigest_t)(hex_of_stringdigest))|IPSECKEY(precedence,gw_type,alg,gw,pubkey)->(sprintf"IPSECKEY (%d, %s,%s, %s, '%s')"(Cstruct.byte_to_intprecedence)(gateway_tc_to_stringgw_type)(ipseckey_alg_to_stringalg)(gateway_to_stringgw)pubkey)|NSEC(next_name,tbms)->(sprintf"NSEC (%s, %s)"(Name.to_stringnext_name)(type_bit_maps_to_stringtbms))|NSEC3(halg,flgs,iterations,salt_l,salt,hash_l,next_name,tbms)->(sprintf"NSEC3 (%s, %x, %d, %d,'%s', %d,'%s', %s)"(hash_alg_to_stringhalg)(Cstruct.byte_to_intflgs)iterations(Cstruct.byte_to_intsalt_l)salt(Cstruct.byte_to_inthash_l)next_name(type_bit_maps_to_stringtbms))|NSEC3PARAM(halg,flgs,iterations,salt_l,salt)->(sprintf"NSEC3PARAM (%s,%x, %d, %d, '%s')"(hash_alg_to_stringhalg)(Cstruct.byte_to_intflgs)iterations(Cstruct.byte_to_intsalt_l)salt)|SSHFP(alg,fpt,fp)->(sprintf"SSHFP (%s,%s, '%s')"(pubkey_alg_to_stringalg)(fp_type_to_stringfpt)fp)letrdata_to_rr_type=function|A_->RR_A|AAAA_->RR_AAAA|AFSDB_->RR_AFSDB|CNAME_->RR_CNAME|DNSKEY_->RR_DNSKEY|DS_->RR_DS|HINFO_->RR_HINFO|IPSECKEY_->RR_IPSECKEY|ISDN_->RR_ISDN|MB_->RR_MB|MD_->RR_MD|MF_->RR_MF|MG_->RR_MG|MINFO_->RR_MINFO|MR_->RR_MR|MX_->RR_MX|NS_->RR_NS|NSEC_->RR_NSEC|NSEC3_->RR_NSEC3|NSEC3PARAM_->RR_NSEC3PARAM|PTR_->RR_PTR|RP_->RR_RP|RRSIG_->RR_RRSIG|SIG_->RR_SIG|RT_->RR_RT|SOA_->RR_SOA|SRV_->RR_SRV|SSHFP_->RR_SSHFP|TXT_->RR_TXT|UNKNOWN_->RR_UNSPEC|WKS_->RR_WKS|X25_->RR_X25|EDNS0_->RR_OPT[%%cenumtyperr_class=|RR_IN[@id1]|RR_CS[@id2]|RR_CH[@id3]|RR_HS[@id4]|RR_ANY[@id0xff][@@uint8_t]]letrr_class_to_string=function|RR_IN->"IN"|RR_CS->"CS"|RR_CH->"CH"|RR_HS->"HS"|RR_ANY->"RR_ANY"letstring_to_rr_class=function|"IN"->SomeRR_IN|"CS"->SomeRR_CS|"CH"->SomeRR_CH|"HS"->SomeRR_HS|"ANY"->SomeRR_ANY|_->None[%%cstructtyperr={typ:uint16_t;cls:uint16_t;ttl:uint32_t;rdlen:uint16_t;}[@@big_endian]]typerr={name:Name.t;cls:rr_class;flush:bool;(* mDNS cache flush bit *)ttl:int32;rdata:rdata;}letrr_to_stringrr=sprintf"%s <%s%s|%ld> [%s]"(Name.to_stringrr.name)(rr_class_to_stringrr.cls)(ifrr.flushthen",flush"else"")rr.ttl(rdata_to_stringrr.rdata)typeq_type=|Q_A|Q_NS|Q_MD|Q_MF|Q_CNAME|Q_SOA|Q_MB|Q_MG|Q_MR|Q_NULL|Q_WKS|Q_PTR|Q_HINFO|Q_MINFO|Q_MX|Q_TXT|Q_RP|Q_AFSDB|Q_X25|Q_ISDN|Q_RT|Q_NSAP|Q_NSAPPTR|Q_SIG|Q_KEY|Q_PX|Q_GPOS|Q_AAAA|Q_LOC|Q_NXT|Q_EID|Q_NIMLOC|Q_SRV|Q_ATMA|Q_NAPTR|Q_KM|Q_CERT|Q_A6|Q_DNAME|Q_SINK|Q_OPT|Q_APL|Q_DS|Q_SSHFP|Q_IPSECKEY|Q_RRSIG|Q_NSEC|Q_DNSKEY|Q_NSEC3|Q_NSEC3PARAM|Q_SPF|Q_UINFO|Q_UID|Q_GID|Q_UNSPEC|Q_AXFR|Q_MAILB|Q_MAILA|Q_ANY_TYP|Q_TA|Q_DLV|Q_UNKNOWNofintletq_type_to_int=function|Q_A->1|Q_NS->2|Q_MD->3|Q_MF->4|Q_CNAME->5|Q_SOA->6|Q_MB->7|Q_MG->8|Q_MR->9|Q_NULL->10|Q_WKS->11|Q_PTR->12|Q_HINFO->13|Q_MINFO->14|Q_MX->15|Q_TXT->16|Q_RP->17|Q_AFSDB->18|Q_X25->19|Q_ISDN->20|Q_RT->21|Q_NSAP->22|Q_NSAPPTR->23|Q_SIG->24|Q_KEY->25|Q_PX->26|Q_GPOS->27|Q_AAAA->28|Q_LOC->29|Q_NXT->30|Q_EID->31|Q_NIMLOC->32|Q_SRV->33|Q_ATMA->34|Q_NAPTR->35|Q_KM->36|Q_CERT->37|Q_A6->38|Q_DNAME->39|Q_SINK->40|Q_OPT->41|Q_APL->42|Q_DS->43|Q_SSHFP->44|Q_IPSECKEY->45|Q_RRSIG->46|Q_NSEC->47|Q_DNSKEY->48|Q_NSEC3->50|Q_NSEC3PARAM->51|Q_SPF->99|Q_UINFO->100|Q_UID->101|Q_GID->102|Q_UNSPEC->103|Q_AXFR->252|Q_MAILB->253|Q_MAILA->254|Q_ANY_TYP->255|Q_TA->32768|Q_DLV->32769|Q_UNKNOWNid->idletint_to_q_type=function|1->Some(Q_A)|2->Some(Q_NS)|3->Some(Q_MD)|4->Some(Q_MF)|5->Some(Q_CNAME)|6->Some(Q_SOA)|7->Some(Q_MB)|8->Some(Q_MG)|9->Some(Q_MR)|10->Some(Q_NULL)|11->Some(Q_WKS)|12->Some(Q_PTR)|13->Some(Q_HINFO)|14->Some(Q_MINFO)|15->Some(Q_MX)|16->Some(Q_TXT)|17->Some(Q_RP)|18->Some(Q_AFSDB)|19->Some(Q_X25)|20->Some(Q_ISDN)|21->Some(Q_RT)|22->Some(Q_NSAP)|23->Some(Q_NSAPPTR)|24->Some(Q_SIG)|25->Some(Q_KEY)|26->Some(Q_PX)|27->Some(Q_GPOS)|28->Some(Q_AAAA)|29->Some(Q_LOC)|30->Some(Q_NXT)|31->Some(Q_EID)|32->Some(Q_NIMLOC)|33->Some(Q_SRV)|34->Some(Q_ATMA)|35->Some(Q_NAPTR)|36->Some(Q_KM)|37->Some(Q_CERT)|38->Some(Q_A6)|39->Some(Q_DNAME)|40->Some(Q_SINK)|41->Some(Q_OPT)|42->Some(Q_APL)|43->Some(Q_DS)|44->Some(Q_SSHFP)|45->Some(Q_IPSECKEY)|46->Some(Q_RRSIG)|47->Some(Q_NSEC)|48->Some(Q_DNSKEY)|50->Some(Q_NSEC3)|51->Some(Q_NSEC3PARAM)|99->Some(Q_SPF)|100->Some(Q_UINFO)|101->Some(Q_UID)|102->Some(Q_GID)|103->Some(Q_UNSPEC)|252->Some(Q_AXFR)|253->Some(Q_MAILB)|254->Some(Q_MAILA)|255->Some(Q_ANY_TYP)|32768->Some(Q_TA)|32769->Some(Q_DLV)|id->Some(Q_UNKNOWNid)letq_type_to_string=function|Q_A->"A"|Q_NS->"NS"|Q_MD->"MD"|Q_MF->"MF"|Q_CNAME->"CNAME"|Q_SOA->"SOA"|Q_MB->"MB"|Q_MG->"MG"|Q_MR->"MR"|Q_NULL->"NULL"|Q_WKS->"WKS"|Q_PTR->"PTR"|Q_HINFO->"HINFO"|Q_MINFO->"MINFO"|Q_MX->"MX"|Q_TXT->"TXT"|Q_RP->"RP"|Q_AFSDB->"AFSDB"|Q_X25->"X25"|Q_ISDN->"ISDN"|Q_RT->"RT"|Q_NSAP->"NSAP"|Q_NSAPPTR->"NSAPPTR"|Q_SIG->"SIG"|Q_KEY->"KEY"|Q_PX->"PX"|Q_GPOS->"GPOS"|Q_AAAA->"AAAA"|Q_LOC->"LOC"|Q_NXT->"NXT"|Q_EID->"EID"|Q_NIMLOC->"NIMLOC"|Q_SRV->"SRV"|Q_ATMA->"ATMA"|Q_NAPTR->"NAPTR"|Q_KM->"KM"|Q_CERT->"CERT"|Q_A6->"A6"|Q_DNAME->"DNAME"|Q_SINK->"SINK"|Q_OPT->"OPT"|Q_APL->"APL"|Q_DS->"DS"|Q_SSHFP->"SSHFP"|Q_IPSECKEY->"IPSECKEY"|Q_RRSIG->"RRSIG"|Q_NSEC->"NSEC"|Q_DNSKEY->"DNSKEY"|Q_NSEC3->"NSEC3"|Q_NSEC3PARAM->"NSEC3PARAM"|Q_SPF->"SPF"|Q_UINFO->"UINFO"|Q_UID->"UID"|Q_GID->"GID"|Q_UNSPEC->"UNSPEC"|Q_AXFR->"AXFR"|Q_MAILB->"MAILB"|Q_MAILA->"MAILA"|Q_ANY_TYP->"ANY_TYP"|Q_TA->"TA"|Q_DLV->"DLV"|Q_UNKNOWNid->(sprintf"TYPE%03d"id)letstring_to_q_type=function|"A"->Some(Q_A)|"NS"->Some(Q_NS)|"MD"->Some(Q_MD)|"MF"->Some(Q_MF)|"CNAME"->Some(Q_CNAME)|"SOA"->Some(Q_SOA)|"MB"->Some(Q_MB)|"MG"->Some(Q_MG)|"MR"->Some(Q_MR)|"NULL"->Some(Q_NULL)|"WKS"->Some(Q_WKS)|"PTR"->Some(Q_PTR)|"HINFO"->Some(Q_HINFO)|"MINFO"->Some(Q_MINFO)|"MX"->Some(Q_MX)|"TXT"->Some(Q_TXT)|"RP"->Some(Q_RP)|"AFSDB"->Some(Q_AFSDB)|"X25"->Some(Q_X25)|"ISDN"->Some(Q_ISDN)|"RT"->Some(Q_RT)|"NSAP"->Some(Q_NSAP)|"NSAPPTR"->Some(Q_NSAPPTR)|"SIG"->Some(Q_SIG)|"KEY"->Some(Q_KEY)|"PX"->Some(Q_PX)|"GPOS"->Some(Q_GPOS)|"AAAA"->Some(Q_AAAA)|"LOC"->Some(Q_LOC)|"NXT"->Some(Q_NXT)|"EID"->Some(Q_EID)|"NIMLOC"->Some(Q_NIMLOC)|"SRV"->Some(Q_SRV)|"ATMA"->Some(Q_ATMA)|"NAPTR"->Some(Q_NAPTR)|"KM"->Some(Q_KM)|"CERT"->Some(Q_CERT)|"A6"->Some(Q_A6)|"DNAME"->Some(Q_DNAME)|"SINK"->Some(Q_SINK)|"OPT"->Some(Q_OPT)|"APL"->Some(Q_APL)|"DS"->Some(Q_DS)|"SSHFP"->Some(Q_SSHFP)|"IPSECKEY"->Some(Q_IPSECKEY)|"RRSIG"->Some(Q_RRSIG)|"NSEC"->Some(Q_NSEC)|"DNSKEY"->Some(Q_DNSKEY)|"NSEC3"->Some(Q_NSEC3)|"NSEC3PARAM"->Some(Q_NSEC3PARAM)|"SPF"->Some(Q_SPF)|"UINFO"->Some(Q_UINFO)|"UID"->Some(Q_UID)|"GID"->Some(Q_GID)|"UNSPEC"->Some(Q_UNSPEC)|"AXFR"->Some(Q_AXFR)|"MAILB"->Some(Q_MAILB)|"MAILA"->Some(Q_MAILA)|"ANY_TYP"->Some(Q_ANY_TYP)|"TA"->Some(Q_TA)|"DLV"->Some(Q_DLV)|value->letlen=String.lengthvalueiniflen<5||String.subvalue04<>"TYPE"thenNoneelsetryleti=int_of_string(String.subvalue4(len-4))inSome(Q_UNKNOWNi)withFailure_->Noneletq_type_matches_rr_typeqtrrt=matchqt,rrtwith|Q_A,RR_A|Q_NS,RR_NS|Q_MD,RR_MD|Q_MF,RR_MF|Q_CNAME,RR_CNAME|Q_SOA,RR_SOA|Q_MB,RR_MB|Q_MG,RR_MG|Q_MR,RR_MR|Q_NULL,RR_NULL|Q_WKS,RR_WKS|Q_PTR,RR_PTR|Q_HINFO,RR_HINFO|Q_MINFO,RR_MINFO|Q_MX,RR_MX|Q_TXT,RR_TXT|Q_RP,RR_RP|Q_AFSDB,RR_AFSDB|Q_X25,RR_X25|Q_ISDN,RR_ISDN|Q_RT,RR_RT|Q_NSAP,RR_NSAP|Q_NSAPPTR,RR_NSAPPTR|Q_SIG,RR_SIG|Q_KEY,RR_KEY|Q_PX,RR_PX|Q_GPOS,RR_GPOS|Q_AAAA,RR_AAAA|Q_LOC,RR_LOC|Q_NXT,RR_NXT|Q_EID,RR_EID|Q_NIMLOC,RR_NIMLOC|Q_SRV,RR_SRV|Q_ATMA,RR_ATMA|Q_NAPTR,RR_NAPTR|Q_KM,RR_KM|Q_CERT,RR_CERT|Q_A6,RR_A6|Q_DNAME,RR_DNAME|Q_SINK,RR_SINK|Q_OPT,RR_OPT|Q_APL,RR_APL|Q_DS,RR_DS|Q_SSHFP,RR_SSHFP|Q_IPSECKEY,RR_IPSECKEY|Q_RRSIG,RR_RRSIG|Q_NSEC,RR_NSEC|Q_DNSKEY,RR_DNSKEY|Q_NSEC3,RR_NSEC3|Q_NSEC3PARAM,RR_NSEC3PARAM|Q_SPF,RR_SPF|Q_UINFO,RR_UINFO|Q_UID,RR_UID|Q_GID,RR_GID|Q_UNSPEC,RR_UNSPEC|Q_ANY_TYP,_->true|Q_A,_|Q_NS,_|Q_MD,_|Q_MF,_|Q_CNAME,_|Q_SOA,_|Q_MB,_|Q_MG,_|Q_MR,_|Q_NULL,_|Q_WKS,_|Q_PTR,_|Q_HINFO,_|Q_MINFO,_|Q_MX,_|Q_TXT,_|Q_RP,_|Q_AFSDB,_|Q_X25,_|Q_ISDN,_|Q_RT,_|Q_NSAP,_|Q_NSAPPTR,_|Q_SIG,_|Q_KEY,_|Q_PX,_|Q_GPOS,_|Q_AAAA,_|Q_LOC,_|Q_NXT,_|Q_EID,_|Q_NIMLOC,_|Q_SRV,_|Q_ATMA,_|Q_NAPTR,_|Q_KM,_|Q_CERT,_|Q_A6,_|Q_DNAME,_|Q_SINK,_|Q_OPT,_|Q_APL,_|Q_DS,_|Q_SSHFP,_|Q_IPSECKEY,_|Q_RRSIG,_|Q_NSEC,_|Q_DNSKEY,_|Q_NSEC3,_|Q_NSEC3PARAM,_|Q_SPF,_|Q_UINFO,_|Q_UID,_|Q_GID,_|Q_UNSPEC,_|Q_AXFR,_|Q_MAILA,_|Q_MAILB,_|Q_TA,_|Q_DLV,_|Q_UNKNOWN_,_->false(*let q_type_to_string x =
let x = q_type_to_string x in
String.sub x 2 (String.length x - 2)
let string_to_q_type x =
string_to_q_type ("Q_"^x) *)[%%cenumtypeq_class=|Q_IN[@id1]|Q_CS[@id2]|Q_CH[@id3]|Q_HS[@id4]|Q_NONE[@id254]|Q_ANY_CLS[@id255][@@uint8_t]]letq_class_to_stringx=letx=q_class_to_stringxinString.subx2(String.lengthx-2)letstring_to_q_classx=string_to_q_class("Q_"^x)typeq_unicast=Q_Normal|Q_mDNS_Unicastletq_unicast_to_stringx=matchxwith|Q_Normal->"Q_Normal"|Q_mDNS_Unicast->"Q_mDNS_Unicast"[%%cstructtypeq={typ:uint16_t;cls:uint16_t;}[@@big_endian]]typequestion={q_name:Name.t;q_type:q_type;q_class:q_class;q_unicast:q_unicast;}letmake_question?(q_class=Q_IN)?(q_unicast=Q_Normal)q_typeq_name={q_name;q_type;q_class;q_unicast;}letquestion_to_stringq=sprintf"%s. <%s|%s%s>"(Name.to_stringq.q_name)(q_type_to_stringq.q_type)(q_class_to_stringq.q_class)(ifq.q_unicast=Q_mDNS_Unicastthen"|QU"else"")letparse_questionnamesbasebuf=letq_name,(base,buf)=Name.parsenamesbasebufinletq_type=lettyp=get_q_typbufinmatchint_to_q_typetypwith|None->failwith(sprintf"parse_question: typ %d"typ)|Sometyp->typinletq_class,q_unicast=letcls=get_q_clsbufin(* mDNS uses bit 15 as the unicast-response bit *)letq_unicast=if(((clslsr15)land1)=1)thenQ_mDNS_UnicastelseQ_Normalinmatchint_to_q_class(clsland0x7FFF)with|None->failwith(sprintf"parse_question: cls %d"cls)|Somecls->cls,q_unicastin{q_name;q_type;q_class;q_unicast;},(base+sizeof_q,Cstruct.shiftbufsizeof_q)letmarshal_question?(_compress=true)(names,base,buf)q=letnames,base,buf=Name.marshalnamesbasebufq.q_nameinset_q_typbuf(q_type_to_intq.q_type);letq_unicast=(ifq.q_unicast=Q_mDNS_Unicastthen1else0)inset_q_clsbuf((q_unicastlsl15)lor(q_class_to_intq.q_class));names,base+sizeof_q,Cstruct.shiftbufsizeof_qexceptionNot_implementedletparse_rdatanamesbasetclsttlbuf=(** Drop remainder of buf to stop parsing and demuxing. *)letstop(x,_)=xin(** Extract (length, string) encoded strings, with remainder for
chaining. *)letparse_charstrbuf=letlen=Cstruct.get_uint8buf0inCstruct.to_string(Cstruct.subbuf1len),Cstruct.shiftbuf(1+len)inmatchtwith|RR_OPT->letrcode=Int32.to_int(Int32.shift_rightttl24)inletdo_bit=((Int32.logandttl0x8000l)=0x8000l)in(* TODO: add here some code to parse the options of the edns rr *)EDNS0(cls,rcode,do_bit,[])|RR_RRSIG->lettyp=leta=Cstruct.BE.get_uint16buf0inmatch(int_to_rr_typea)with|None->RR_UNSPEC|Somea->ainletalg=leta=Cstruct.get_uint8buf2inmatch(int_to_dnssec_alga)with|None->failwith(sprintf"parse_rdata: DNSKEY alg %d"a)|Somea->ainletlbl=char_of_int(Cstruct.get_uint8buf3)inletorig_ttl=Cstruct.BE.get_uint32buf4inletexp_ts=Cstruct.BE.get_uint32buf8inletinc_ts=Cstruct.BE.get_uint32buf12inlettag=Cstruct.BE.get_uint16buf16inletbuf=Cstruct.shiftbuf18inlet(name,(_len,buf))=Name.parsenames(base+18)bufinletsign=Cstruct.to_stringbufinRRSIG(typ,alg,lbl,orig_ttl,exp_ts,inc_ts,tag,name,sign)|RR_SIG->letalg=leta=Cstruct.get_uint8buf2inmatch(int_to_dnssec_alga)with|None->failwith(sprintf"parse_rdata: DNSKEY alg %d"a)|Somea->ainletexp_ts=Cstruct.BE.get_uint32buf8inletinc_ts=Cstruct.BE.get_uint32buf12inlettag=Cstruct.BE.get_uint16buf16inletbuf=Cstruct.shiftbuf18inlet(name,(_len,buf))=Name.parsenames(base+18)bufinletsign=Cstruct.to_stringbufinSIG(alg,exp_ts,inc_ts,tag,name,sign)|RR_A->ACstruct.(Ipaddr.V4.of_int32(BE.get_uint32buf0))|RR_AAAA->AAAA(Ipaddr.V6.of_int64Cstruct.((BE.get_uint64buf0),(BE.get_uint64buf8)))|RR_AFSDB->AFSDB(Cstruct.BE.get_uint16buf0,Cstruct.shiftbuf2|>Name.parsenames(base+2)|>stop)|RR_CNAME->CNAME(buf|>Name.parsenamesbase|>stop)|RR_DNSKEY->letflags=Cstruct.BE.get_uint16buf0inletalg=leta=Cstruct.get_uint8buf3inmatchint_to_dnssec_algawith|None->failwith(sprintf"parse_rdata: DNSKEY alg %d"a)|Somea->ainletkey=Cstruct.(shiftbuf4|>to_string)inDNSKEY(flags,alg,key)|RR_DS->lettag=Cstruct.BE.get_uint16buf0inletalg=match(int_to_dnssec_alg(Cstruct.get_uint8buf2))with|Somea->a|None->failwith"parse_rdata unsupported dnssec_alg id"inletdigest=match(int_to_digest_alg(Cstruct.get_uint8buf3))with|Somea->a|None->failwith"parse_rdata unsupported hash algorithm id"inletkey=Cstruct.(shiftbuf4|>to_string)inDS(tag,alg,digest,key)|RR_NSEC->let(name,(_base,buf))=Name.parsenamesbasebufinNSEC(name,[(char_of_int0),(char_of_int0),buf])|RR_HINFO->letcpu,buf=parse_charstrbufinletos=buf|>parse_charstr|>stopinHINFO(cpu,os)|RR_ISDN->leta,buf=parse_charstrbufinletsa=matchCstruct.lenbufwith|0->None|_->Some(buf|>parse_charstr|>stop)inISDN(a,sa)|RR_MB->MB(buf|>Name.parsenamesbase|>stop)|RR_MD->MD(buf|>Name.parsenamesbase|>stop)|RR_MF->MF(buf|>Name.parsenamesbase|>stop)|RR_MG->MG(buf|>Name.parsenamesbase|>stop)|RR_MINFO->letrm,(base,buf)=buf|>Name.parsenamesbaseinletem=buf|>Name.parsenamesbase|>stopinMINFO(rm,em)|RR_MR->MR(buf|>Name.parsenamesbase|>stop)|RR_MX->MX(Cstruct.BE.get_uint16buf0,Cstruct.shiftbuf2|>Name.parsenames(base+2)|>stop)|RR_NS->NS(buf|>Name.parsenamesbase|>stop)|RR_PTR->PTR(buf|>Name.parsenamesbase|>stop)|RR_RP->letmbox,(base,buf)=buf|>Name.parsenamesbaseinlettxt=buf|>Name.parsenamesbase|>stopinRP(mbox,txt)|RR_RT->RT(Cstruct.BE.get_uint16buf0,Cstruct.shiftbuf2|>Name.parsenames(base+2)|>stop)|RR_SOA->letmn,(base,buf)=Name.parsenamesbasebufinletrn,(_,buf)=Name.parsenamesbasebufinCstruct.BE.(SOA(mn,rn,get_uint32buf0,(* serial *)get_uint32buf4,(* refresh *)get_uint32buf8,(* retry *)get_uint32buf12,(* expire *)get_uint32buf16(* minimum *)))|RR_SRV->Cstruct.(BE.(SRV(get_uint16buf0,(* prio *)get_uint16buf2,(* weight *)get_uint16buf4,(* port *)shiftbuf6|>Name.parsenames(base+6)|>stop)))|RR_TXT->letstrings=letrecauxstringsbuf=matchCstruct.lenbufwith|0->List.revstrings|_len->lets,buf=parse_charstrbufinaux(s::strings)bufinaux[]bufinTXTstrings|RR_WKS->letaddr=Ipaddr.V4.of_int32(Cstruct.BE.get_uint32buf0)inletproto=Cstruct.get_uint8buf4inletbitmap=Cstruct.(shiftbuf5|>to_string)inWKS(addr,Cstruct.byteproto,bitmap)|RR_X25->letx25,_=parse_charstrbufinX25x25|_->raiseNot_implementedletmarshal_rdatanames?(compress=true)baserdbuf=function|Aip->Cstruct.BE.set_uint32rdbuf0(Ipaddr.V4.to_int32ip);RR_A,names,4|AAAAip->lets1,s2=Ipaddr.V6.to_int64ipinCstruct.BE.set_uint64rdbuf0s1;Cstruct.BE.set_uint64rdbuf8s2;RR_AAAA,names,16|AFSDB(x,name)->Cstruct.BE.set_uint16rdbuf0x;letnames,offset,_=Name.marshal~compressnames(base+2)(Cstruct.shiftrdbuf2)nameinRR_AFSDB,names,offset-base|CNAMEname->letnames,offset,_=Name.marshal~compressnamesbaserdbufnameinRR_CNAME,names,offset-base|DNSKEY(flags,alg,key)->Cstruct.BE.set_uint16rdbuf0flags;Cstruct.set_uint8rdbuf23;Cstruct.set_uint8rdbuf3(dnssec_alg_to_intalg);letslen=String.lengthkeyinCstruct.blit_from_stringkey0rdbuf4slen;RR_DNSKEY,names,4+slen|DS(tag,alg,digest,key)->Cstruct.BE.set_uint16rdbuf0tag;Cstruct.set_uint8rdbuf2(dnssec_alg_to_intalg);Cstruct.set_uint8rdbuf3(digest_alg_to_intdigest);letslen=String.lengthkeyinCstruct.blit_from_stringkey0rdbuf4slen;RR_DS,names,4+slen|RRSIG(typ,alg,lbl,orig_ttl,exp_ts,inc_ts,tag,name,sign)->let_=Cstruct.BE.set_uint16rdbuf0(rr_type_to_inttyp)inlet_=Cstruct.set_uint8rdbuf2(dnssec_alg_to_intalg)inlet_=Cstruct.set_uint8rdbuf3(int_of_charlbl)inlet_=Cstruct.BE.set_uint32rdbuf4orig_ttlinlet_=Cstruct.BE.set_uint32rdbuf8exp_tsinlet_=Cstruct.BE.set_uint32rdbuf12inc_tsinlet_=Cstruct.BE.set_uint16rdbuf16taginletrdbuf=Cstruct.shiftrdbuf18inlet(names,len,rdbuf)=Name.marshal~compressnames0rdbufnameinlet_=Cstruct.blit_from_stringsign0rdbuf0(String.lengthsign)inRR_RRSIG,names,(18+len+(String.lengthsign))|SIG(alg,exp_ts,inc_ts,tag,name,sign)->let_=Cstruct.BE.set_uint16rdbuf00inlet_=Cstruct.set_uint8rdbuf2(dnssec_alg_to_intalg)inlet_=Cstruct.set_uint8rdbuf30inlet_=Cstruct.BE.set_uint32rdbuf40linlet_=Cstruct.BE.set_uint32rdbuf8exp_tsinlet_=Cstruct.BE.set_uint32rdbuf12inc_tsinlet_=Cstruct.BE.set_uint16rdbuf16taginletrdbuf=Cstruct.shiftrdbuf18inlet(names,len,rdbuf)=Name.marshal~compressnames0rdbufnameinlet_=Cstruct.blit_from_stringsign0rdbuf0(String.lengthsign)inRR_SIG,names,(18+len+(String.lengthsign))|HINFO(cpu,os)->letcpustr,cpulen=charstrcpuinCstruct.blit_from_stringcpustr0rdbuf0cpulen;letosstr,oslen=charstrosinCstruct.blit_from_stringosstr0rdbufcpulenoslen;RR_HINFO,names,cpulen+oslen|ISDN(a,sa)->letastr,alen=charstrainCstruct.blit_from_stringastr0rdbuf0alen;letsastr,salen=matchsawith|None->"",0|Somesa->charstrsainCstruct.blit_from_stringsastr0rdbufalensalen;RR_ISDN,names,alen+salen|MBname->letnames,offset,_=Name.marshal~compressnamesbaserdbufnameinRR_MB,names,offset-base|MDname->letnames,offset,_=Name.marshal~compressnamesbaserdbufnameinRR_MD,names,offset-base|MFname->letnames,offset,_=Name.marshal~compressnamesbaserdbufnameinRR_MF,names,offset-base|MGname->letnames,offset,_=Name.marshal~compressnamesbaserdbufnameinRR_MG,names,offset-base|MINFO(rm,em)->letnames,offset,rdbuf=Name.marshal~compressnamesbaserdbufrminletnames,offset,_=Name.marshal~compressnamesoffsetrdbufeminRR_MINFO,names,offset-base|MRname->letnames,offset,_=Name.marshal~compressnamesbaserdbufnameinRR_MR,names,offset-base|MX(pref,xchg)->Cstruct.BE.set_uint16rdbuf0pref;letnames,offset,_=Name.marshal~compressnames(base+2)(Cstruct.shiftrdbuf2)xchginRR_MX,names,offset-base|NSname->letnames,offset,_=Name.marshal~compressnamesbaserdbufnameinRR_NS,names,offset-base|RP(mbox,txt)->letnames,offset,rdbuf=Name.marshal~compressnamesbaserdbufmboxinletnames,offset,_=Name.marshal~compressnamesoffsetrdbuftxtinRR_RP,names,offset-base|RT(x,name)->Cstruct.BE.set_uint16rdbuf0x;letnames,offset,_=Name.marshal~compressnames(base+2)(Cstruct.shiftrdbuf2)nameinRR_RT,names,offset-base|PTRname->letnames,offset,_=Name.marshal~compressnamesbaserdbufnameinRR_PTR,names,offset-base|SOA(mn,rn,serial,refresh,retry,expire,minimum)->letnames,offset,rdbuf=Name.marshal~compressnamesbaserdbufmninletnames,offset,rdbuf=Name.marshal~compressnamesoffsetrdbufrninCstruct.BE.set_uint32rdbuf0serial;Cstruct.BE.set_uint32rdbuf4refresh;Cstruct.BE.set_uint32rdbuf8retry;Cstruct.BE.set_uint32rdbuf12expire;Cstruct.BE.set_uint32rdbuf16minimum;RR_SOA,names,20+offset-base|SRV(prio,weight,port,name)->Cstruct.BE.set_uint16rdbuf0prio;Cstruct.BE.set_uint16rdbuf2weight;Cstruct.BE.set_uint16rdbuf4port;letnames,offset,_=Name.marshal~compressnames(base+6)(Cstruct.shiftrdbuf6)nameinRR_SRV,names,offset-base|TXTstrings->RR_TXT,names,List.fold_left(funaccs->lets,slen=charstrsinCstruct.blit_from_strings0rdbufaccslen;acc+slen)0strings|WKS(a,p,bm)->Cstruct.BE.set_uint32rdbuf0(Ipaddr.V4.to_int32a);Cstruct.set_uint8rdbuf4(Cstruct.byte_to_intp);letbmlen=String.lengthbminCstruct.blit_from_stringbm0rdbuf5bmlen;RR_WKS,names,5+bmlen|X25x25->lets,slen=charstrx25inCstruct.blit_from_strings0rdbuf0slen;RR_X25,names,slen|EDNS0(_len,_rcode,_do_bit,_)->RR_OPT,names,0|UNKNOWN(_typ,data)->Cstruct.blit_from_stringdata0rdbuf0(String.lengthdata);RR_UNSPEC,names,(String.lengthdata)|_->raiseNot_implementedletcompare_rdataa_rdatab_rdata=match(a_rdata,b_rdata)with|Aa_ip,Ab_ip->Ipaddr.V4.comparea_ipb_ip|AAAAa_ip,AAAAb_ip->Ipaddr.V6.comparea_ipb_ip|X25a,X25b->String.compareab|AFSDB(a_x,a_name),AFSDB(b_x,b_name)->if(a_x=b_x)thenName.dnssec_comparea_nameb_nameelsecomparea_xb_x|DNSKEY(a_f,a_a,a_k),DNSKEY(b_f,b_a,b_k)->if(a_f=b_f)then(if(dnssec_alg_to_inta_a)=(dnssec_alg_to_intb_a)thenString.comparea_kb_kelsecompare(dnssec_alg_to_inta_a)(dnssec_alg_to_intb_a))elsecomparea_fb_f|MBa,MBb|MDa,MDb|MFa,MFb|MGa,MGb|MRa,MRb|NSa,NSb|PTRa,PTRb|CNAMEa,CNAMEb->Name.dnssec_compareab|TXTa,TXTb->Name.dnssec_compare_strab(*| DS (tag, alg, digest, key) ->
| HINFO (cpu,os) ->
| ISDN (a,sa) ->
| MINFO (rm,em) ->
| MX (pref,xchg) ->
| RP (mbox,txt) ->
| RT (x, name) ->
| SOA (mn,rn, serial, refresh, retry, expire, minimum) ->
| SRV (prio, weight, port, name) ->
| WKS (a,p, bm) ->*)|RRSIG_,RRSIG_->failwith"cannot compare RRSIG"|EDNS0_,EDNS0_->failwith"cannot compare EDNS0"|_->failwith(sprintf"unsported rdata compare : %s - %s"(rdata_to_stringa_rdata)(rdata_to_stringb_rdata))letparse_rrnamesbasebuf=letname,(base,buf)=Name.parsenamesbasebufinlett=get_rr_typbufinmatchint_to_rr_typetwith|None->letttl=get_rr_ttlbufinletrdlen=get_rr_rdlenbufinletcls=matchint_to_rr_class(get_rr_clsbuf)with|None->failwith"invalid RR class"|Somecls->clsinletdata=Cstruct.to_string(Cstruct.subbufsizeof_rrrdlen)in({name;cls;flush=false;ttl;rdata=UNKNOWN(t,data)},((base+sizeof_rr+rdlen),Cstruct.shiftbuf(sizeof_rr+rdlen)))|Sometyp->letttl=get_rr_ttlbufinletrdlen=get_rr_rdlenbufinletcls=get_rr_clsbufinletrdata=letrdbuf=Cstruct.subbufsizeof_rrrdleninparse_rdatanames(base+sizeof_rr)typclsttlrdbufinmatchtypwith|RR_OPT->({name;cls=RR_IN;flush=false;ttl;rdata},((base+sizeof_rr+rdlen),Cstruct.shiftbuf(sizeof_rr+rdlen)))|_->(* mDNS uses bit 15 as cache flush flag *)letflush=(((clslsr15)land1)=1)inmatch((clsland0x7FFF)|>int_to_rr_class)with|Somecls->({name;cls;flush;ttl;rdata},((base+sizeof_rr+rdlen),Cstruct.shiftbuf(sizeof_rr+rdlen)))|None->failwith"parse_rr: unknown class"letmarshal_rr?(compress=true)(names,base,buf)rr=letnames,base,buf=Name.marshal~compressnamesbasebufrr.nameinletbase,rdbuf=base+sizeof_rr,Cstruct.shiftbufsizeof_rrinlett,names,rdlen=marshal_rdatanames~compressbaserdbufrr.rdatainset_rr_typbuf(rr_type_to_intt);set_rr_rdlenbufrdlen;(* in case the record is an edns field, we need to treat it specially
* for its ttl and class fields. *)let_=matchrr.rdatawith|EDNS0(len,rcode,do_bit,_)->let_=set_rr_clsbufleninletttl=Int32.logor(Int32.shift_left(Int32.of_intrcode)24)(Int32.shift_left(if(do_bit)then1lelse0l)15)inset_rr_ttlbufttl|UNKNOWN(typ,_)->set_rr_typbuftyp;let_=set_rr_clsbuf(rr_class_to_intrr.cls)inlet_=set_rr_ttlbufrr.ttlin()|_->letflush=(ifrr.flushthen1else0)inletcls=rr_class_to_intrr.clsinset_rr_clsbuf((flushlsl15)lorcls);set_rr_ttlbufrr.ttlinnames,base+rdlen,Cstruct.shiftbuf(sizeof_rr+rdlen)[%%cenumtypeqr=|Query[@id0]|Response[@id1][@@uint8_t]]typeopcode=|Standard(*ID: 0*)|Inverse(*ID: 1*)|Status(*ID: 2*)|Notify(*ID: 4*)|Update(*ID: 5*)|Reservedofint(*ID: either 3 or 6-15*)letopcode_to_intopcode=matchopcodewith|Standard->0|Inverse->1|Status->2|Notify->4|Update->5|Reservedk->matchkwith|0|1|2|4|5->failwith(sprintf"bad opcode: %d exists and is not reserved"k)|_->kletint_to_opcoden=matchnwith|0->Standard|1->Inverse|2->Status|4->Notify|5->Update|kwhenk<=15->Reservedk|k->failwith(sprintf"bad opcode: %d is not on 4 bits"k)letopcode_to_stringopcode=matchopcodewith|Standard->"Query"|Inverse->"IQuery"|Status->"Status"|Notify->"Notify"|Update->"Update"|Reservedk->sprintf"Reserved%d"k[%%cenumtypercode=|NoError[@id0]|FormErr[@id1]|ServFail[@id2]|NXDomain[@id3]|NotImp[@id4]|Refused[@id5]|YXDomain[@id6]|YXRRSet[@id7]|NXRRSet[@id8]|NotAuth[@id9]|NotZone[@id10]|BadVers[@id16]|BadKey[@id17]|BadTime[@id18]|BadMode[@id19]|BadName[@id20]|BadAlg[@id21][@@uint8_t]][%%cstructtypeh={id:uint16_t;detail:uint16_t;qdcount:uint16_t;ancount:uint16_t;nscount:uint16_t;arcount:uint16_t;}[@@big_endian]]typedetail={qr:qr;opcode:opcode;aa:bool;tc:bool;rd:bool;ra:bool;rcode:rcode;}letmarshal_detaild=(qr_to_intd.qrlsl15)lor(opcode_to_intd.opcodelsl11)lor(ifd.aathen1lsl10else0)lor(ifd.tcthen1lsl9else0)lor(ifd.rdthen1lsl8else0)lor(ifd.rathen1lsl7else0)lor(rcode_to_intd.rcode)letdetail_to_stringd=sprintf"%s:%d %s:%s:%s:%s %d"(qr_to_stringd.qr)(opcode_to_intd.opcode)(ifd.aathen"a"else"na")(* authoritative vs not *)(ifd.tcthen"t"else"c")(* truncated vs complete *)(ifd.rdthen"r"else"nr")(* recursive vs not *)(ifd.rathen"ra"else"rn")(* recursion available vs not *)(rcode_to_intd.rcode)letparse_detaild=letqr=match(dlsr15land1)|>int_to_qrwith|Someqr->qr|None->failwith"bad qr"inletopcode=int_to_opcode(dlsr11land0b0_1111)inletint_to_bool=function|0->false|_->trueinletaa=(dlsr10land1)|>int_to_boolinlettc=(dlsr9land1)|>int_to_boolinletrd=(dlsr8land1)|>int_to_boolinletra=(dlsr7land1)|>int_to_boolinletrcode=match(dland0b0_1111)|>int_to_rcodewith|Somercode->rcode|None->failwith"bad rcode"in{qr;opcode;aa;tc;rd;ra;rcode}typet={id:int;detail:detail;questions:questionlist;(* Cstruct.iter; *)answers:rrlist;(* Cstruct.iter; *)authorities:rrlist;(* Cstruct.iter; *)additionals:rrlist;(* Cstruct.iter; *)}letto_stringd=sprintf"%04x %s <qs:%s> <an:%s> <au:%s> <ad:%s>"d.id(detail_to_stringd.detail)(d.questions||>question_to_string|>String.concat",")(d.answers||>rr_to_string|>String.concat",")(d.authorities||>rr_to_string|>String.concat",")(d.additionals||>rr_to_string|>String.concat",")letparsebuf=letnames=Hashtbl.create32inletparsenfbasenbuf_typ=letrecauxaccnbasebuf=matchnwith|0->List.revacc,(base,buf)|_->letr,(base,buf)=fnamesbasebufinaux(r::acc)(n-1)basebufinaux[]nbasebufinletid=get_h_idbufinletdetail=get_h_detailbuf|>parse_detailinletqdcount=get_h_qdcountbufinletancount=get_h_ancountbufinletnscount=get_h_nscountbufinletarcount=get_h_arcountbufinletbase=sizeof_hinletbuf=Cstruct.shiftbufbaseinletquestions,(base,buf)=parsenparse_questionbaseqdcountbuf"question"inletanswers,(base,buf)=parsenparse_rrbaseancountbuf"answer"inletauthorities,(base,buf)=parsenparse_rrbasenscountbuf"auth"inletadditionals,_=parsenparse_rrbasearcountbuf"additional"inletdns={id;detail;questions;answers;authorities;additionals}in(* eprintf "RX: %s\n%!" (to_string dns); *)dnsletmarshal?(alloc=fun()->Cstruct.create4096)dns=lettxbuf=alloc()inletmarshalnfnamesbasebufvalues=List.fold_leftf(names,base,buf)valuesinset_h_idtxbufdns.id;set_h_detailtxbuf(marshal_detaildns.detail);set_h_qdcounttxbuf(List.lengthdns.questions);set_h_ancounttxbuf(List.lengthdns.answers);set_h_nscounttxbuf(List.lengthdns.authorities);set_h_arcounttxbuf(List.lengthdns.additionals);(** Map name (list of labels) to an offset. *)letnames=Name.Map.emptyinletbase,buf=sizeof_h,Cstruct.shifttxbufsizeof_hinletnames,base,buf=marshalnmarshal_questionnamesbasebufdns.questionsinletnames,base,buf=marshalnmarshal_rrnamesbasebufdns.answersinletnames,base,buf=marshalnmarshal_rrnamesbasebufdns.authoritiesinlet_,_,buf=marshalnmarshal_rrnamesbasebufdns.additionalsinlettxbuf=Cstruct.(subtxbuf0(lentxbuf-lenbuf))in(* Cstruct.hexdump txbuf; *)(* eprintf "TX: %s\n%!" (txbuf |> parse (Hashtbl.create 8) |> to_string); *)txbuf