Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file mdns_resolver_mirage.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227(*
* Copyright (c) 2015 Luke Dunstan <LukeDunstan81@gmail.com>
*
* 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.
*)openLwtopenDnsopenOperatorsopenDns_resolveropenResultmoduleDP=Dns.Packetletdefault_ns=Ipaddr.V4.of_string_exn"224.0.0.251"letdefault_port=5353moduletypeS=Dns_resolver_mirage.SmoduleClient:Dns.Protocol.CLIENT=structtypecontext=DP.tletget_id()=0letmarshal?allocq=[q,DP.marshal?allocq]letpacket_matchesquerypacket=letopenDPinletrr_answers_questionqrr=q.q_name=rr.name&&q_type_matches_rr_typeq.q_type(rdata_to_rr_typerr.rdata)&&q.q_class=Q_IN&&rr.cls=RR_INinletrecrrlist_answers_questionqrrlist=matchrrlistwith|[]->false|rr::tl->rr_answers_questionqrr||rrlist_answers_questionqtlinletrecrrlist_answers_questionsqsrrlist=matchqswith|[]->false|q::tl->rrlist_answers_questionqrrlist||rrlist_answers_questionstlrrlistinpacket.detail.qr=Response&&packet.detail.opcode=Standard&&packet.detail.rcode=NoError&&rrlist_answers_questionsquery.questionspacket.answersletparseqbuf=letpkt=DP.parsebufinifpacket_matchesqpktthenSomepktelseNonelettimeout_id=Dns.Protocol.Dns_resolve_timeoutendmoduleMake(Time:Mirage_time_lwt.S)(S:Mirage_stack_lwt.V4)=structtypestack=S.ttypeendp=Ipaddr.V4.t*inttypet={s:S.t;res:(endp,Dns_resolver.commfn)Hashtbl.t;}letcreates=letres=Hashtbl.create3in{s;res}letconnect_to_resolver{s;res}((dst,dst_port)asendp)=letudp=S.udpv4sintryHashtbl.findresendpwithNot_found->lettimerfn()=Time.sleep_ns(Duration.of_sec5)inletmvar=Lwt_mvar.create_empty()inletsrc_port=default_portinletcallback~src:_~dst:_~src_portbuf=(* TODO: ignore responses that are not from the local link *)(* Ignore responses that are not from port 5353 *)ifsrc_port=dst_portthenLwt_mvar.putmvarbufelsereturn_unitinletcleanfn()=return()in(* FIXME: can't coexist with server yet because both listen on port 5353 *)S.listen_udpv4s~port:src_portcallback;lettxfnbuf=S.UDPV4.write~src_port~dst~dst_portudpbuf>>=function|Errore->Fmt.kstrffail_with"Attempting to communicate with remote resolver: %a"S.UDPV4.pp_errore|Ok()->Lwt.return_unitinletrecrxfnf=Lwt_mvar.takemvar>>=funbuf->matchfbufwith|None->rxfnf|Somepacket->returnpacketinletcommfn={txfn;rxfn;timerfn;cleanfn}inHashtbl.addresendpcommfn;commfnletcreate_packetq_classq_typeq_name=letopenDns.Packetinletdetail={qr=Query;opcode=Standard;aa=false;tc=false;rd=false;ra=false;rcode=NoError;}inletquestion={q_name;q_type;q_class;q_unicast=Q_Normal}in{id=0;detail;questions=[question];answers=[];authorities=[];additionals=[];}letresolveclienttserverdns_port(q_class:DP.q_class)(q_type:DP.q_type)(q_name:Name.t)=letcommfn=connect_to_resolvert(server,dns_port)inletq=create_packetq_classq_typeq_nameinresolve_pktclientcommfnqletgethostbynamet?(server=default_ns)?(dns_port=default_port)?(q_class:DP.q_class=DP.Q_IN)?(q_type:DP.q_type=DP.Q_A)name=(* TODO: duplicates Dns_resolver.gethostbyname *)letopenDPinletdomain=Name.of_stringnameinresolve(moduleClient)tserverdns_portq_classq_typedomain>|=funr->List.fold_left(funax->matchx.rdatawith|Aip->Ipaddr.V4ip::a|AAAAip->Ipaddr.V6ip::a|_->a)[]r.answers|>List.revletgethostbyaddrt?(server=default_ns)?(dns_port=default_port)?(q_class:DP.q_class=DP.Q_IN)?(q_type:DP.q_type=DP.Q_PTR)addr=(* TODO: duplicates Dns_resolver.gethostbyaddr *)letaddr=Name.of_ipaddr(Ipaddr.V4addr)inletopenDPinresolve(moduleClient)tserverdns_portq_classq_typeaddr>|=funr->List.fold_left(funax->matchx.rdatawith|PTRn->(Name.to_stringn)::a|_->a)[]r.answers|>List.revendmoduleChain(Local:S)(Next:Swithtypestack=Local.stack)=structtypet={local:Local.t;next:Next.t;}typestack=Local.stackletcreatestack={local=Local.createstack;next=Next.createstack}letrecstarts_withlabelsprefix=matchlabels,prefixwith|(_l,[])->true|([],_ph::_pt)->false|(lh::lt,ph::pt)->iflh=phthenstarts_withltptelsefalseletends_withlabelssuffix=starts_with(List.revlabels)(List.revsuffix)letis_localname=ends_with(Name.to_string_listname)["local"]letis_link_localname=ends_with(Name.to_string_listname)["254";"169";"in-addr";"arpa"]letresolveclienttserverdns_port(q_class:DP.q_class)(q_type:DP.q_type)(q_name:Name.t)=ifis_localq_name||is_link_localq_namethenLocal.resolveclientt.localserverdns_portq_classq_typeq_nameelseNext.resolveclientt.nextserverdns_portq_classq_typeq_nameletgethostbynamet?(server=default_ns)?(dns_port=default_port)?(q_class:DP.q_class=DP.Q_IN)?(q_type:DP.q_type=DP.Q_A)name=letdomain=Name.of_stringnameinifis_localdomainthenLocal.gethostbynamet.local~server~dns_port~q_class~q_typenameelseNext.gethostbynamet.next~server~dns_port~q_class~q_typenameletgethostbyaddrt?(server=default_ns)?(dns_port=default_port)?(q_class:DP.q_class=DP.Q_IN)?(q_type:DP.q_type=DP.Q_PTR)addr=letdomain=Name.of_ipaddr(Ipaddr.V4addr)inifis_link_localdomainthenLocal.gethostbyaddrt.local~server~dns_port~q_class~q_typeaddrelseNext.gethostbyaddrt.next~server~dns_port~q_class~q_typeaddrend