123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122(*
* Copyright (c) 2012 Richard Mortier <mort@cantab.net>
* Copyright (c) 2013-2015 David Sheets <sheets@alum.mit.edu>
* Copyright (c) 2014 Anil Madhavapeddy <anil@recoil.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.
*)openLwt.InfixopenDnsopenOperatorsopenProtocolmoduleDP=Packettyperesult=AnswerofDP.t|Errorofexntypecommfn={txfn:Cstruct.t->unitLwt.t;rxfn:(Cstruct.t->Dns.Packet.toption)->DP.tLwt.t;timerfn:unit->unitLwt.t;cleanfn:unit->unitLwt.t;}letrecsend_reqtxfntimerfnq=function|0->Lwt.return_unit|count->txfnq>>=fun()->timerfn()>>=fun()->send_reqtxfntimerfnq(count-1)letsend_pktclient?alloc({txfn;rxfn;timerfn;_})pkt=letmoduleR=(valclient:CLIENT)inletcqpl=R.marshal?allocpktinletresl=List.map(fun(ctxt,q)->(* make a new socket for each request flavor *)(* start the requests in parallel and run them until success or timeout*)lett,w=Lwt.wait()inLwt.async(fun()->Lwt.pick[(send_reqtxfntimerfnq4>|=fun()->Error(R.timeoutctxt));(Lwt.catch(fun()->rxfn(R.parsectxt)>|=funr->Answerr)(funexn->Lwt.return(Errorexn)))]>|=Lwt.wakeupw);t)cqplin(* return an answer or all the errors if no request succeeded *)letrecselecterrors=function|[]->Lwt.fail(Dns_resolve_errorerrors)|ts->Lwt.nchoose_splitts>>=fun(rs,ts)->letrecfind_answererrors=function|[]->selecterrorsts|(Answera)::_->Lwt.returna|(Errore)::r->find_answer(e::errors)rinfind_answererrorsrsinselect[]reslletresolve_pktclient?alloc(commfn:commfn)pkt=Lwt.catch(fun()->send_pktclient?alloccommfnpkt>>=funr->commfn.cleanfn()>>=fun()->Lwt.returnr)(functionexn->commfn.cleanfn()>>=fun()->Lwt.failexn)letresolveclient?alloc?(dnssec=false)(commfn:commfn)(q_class:DP.q_class)(q_type:DP.q_type)(q_name:Name.t)=letid=(letmoduleR=(valclient:CLIENT)inR.get_id())inletq=Dns.Query.create~id~dnssecq_classq_typeq_nameinresolve_pktclient?alloccommfnqletgethostbyname?alloc?(q_class:DP.q_class=DP.Q_IN)?(q_type:DP.q_type=DP.Q_A)commfnname=letopenDPinletdomain=Name.of_stringnameinresolve(moduleDns.Protocol.Client)?alloccommfnq_classq_typedomain>|=funr->List.fold_left(funax->matchx.rdatawith|Aip->Ipaddr.V4ip::a|AAAAip->Ipaddr.V6ip::a|_->a)[]r.answers|>List.revletgethostbyaddr?alloc?(q_class:DP.q_class=DP.Q_IN)?(q_type:DP.q_type=DP.Q_PTR)commfnaddr=letaddr=Name.of_ipaddr(Ipaddr.V4addr)inletopenDPinresolve(moduleDns.Protocol.Client)?alloccommfnq_classq_typeaddr>|=funr->List.fold_left(funax->matchx.rdatawith|PTRn->(Name.to_stringn)::a|_->a)[]r.answers|>List.rev