123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "net/dns/dns_transaction.h"
- #include <stdint.h>
- #include <limits>
- #include <memory>
- #include <utility>
- #include <vector>
- #include "base/base64url.h"
- #include "base/bind.h"
- #include "base/containers/circular_deque.h"
- #include "base/memory/raw_ptr.h"
- #include "base/numerics/safe_math.h"
- #include "base/rand_util.h"
- #include "base/run_loop.h"
- #include "base/strings/string_util.h"
- #include "base/strings/stringprintf.h"
- #include "base/sys_byteorder.h"
- #include "base/test/bind.h"
- #include "base/test/metrics/histogram_tester.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/time/time.h"
- #include "base/values.h"
- #include "net/base/idempotency.h"
- #include "net/base/ip_address.h"
- #include "net/base/port_util.h"
- #include "net/base/upload_bytes_element_reader.h"
- #include "net/base/url_util.h"
- #include "net/cookies/cookie_access_result.h"
- #include "net/cookies/cookie_util.h"
- #include "net/dns/dns_config.h"
- #include "net/dns/dns_query.h"
- #include "net/dns/dns_response.h"
- #include "net/dns/dns_server_iterator.h"
- #include "net/dns/dns_session.h"
- #include "net/dns/dns_test_util.h"
- #include "net/dns/dns_util.h"
- #include "net/dns/public/dns_over_https_config.h"
- #include "net/dns/public/dns_over_https_server_config.h"
- #include "net/dns/public/dns_protocol.h"
- #include "net/dns/public/secure_dns_policy.h"
- #include "net/dns/resolve_context.h"
- #include "net/http/http_util.h"
- #include "net/log/net_log.h"
- #include "net/log/net_log_capture_mode.h"
- #include "net/log/net_log_with_source.h"
- #include "net/proxy_resolution/proxy_config_service_fixed.h"
- #include "net/socket/socket_test_util.h"
- #include "net/test/gtest_util.h"
- #include "net/test/test_with_task_environment.h"
- #include "net/test/url_request/url_request_failed_job.h"
- #include "net/third_party/uri_template/uri_template.h"
- #include "net/url_request/url_request_context.h"
- #include "net/url_request/url_request_context_builder.h"
- #include "net/url_request/url_request_filter.h"
- #include "net/url_request/url_request_interceptor.h"
- #include "net/url_request/url_request_test_util.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- using net::test::IsOk;
- namespace net {
- namespace {
- base::TimeDelta kFallbackPeriod = base::Seconds(1);
- const char kMockHostname[] = "mock.http";
- // Like `net::DNSDomainFromDot()` except allows converting more names than
- // accepted by that utility.
- std::string DomainFromDot(base::StringPiece dotted_name) {
- std::string dns_name;
- while (true) {
- size_t next_dot = dotted_name.find('.');
- if (next_dot == base::StringPiece::npos) {
- dns_name.append(1, base::checked_cast<base::StringPiece::value_type>(
- dotted_name.size()));
- dns_name.append(static_cast<std::string>(dotted_name));
- dns_name.append(1, 0);
- return dns_name;
- } else {
- dns_name.append(
- 1, base::checked_cast<base::StringPiece::value_type>(next_dot));
- dns_name.append(
- static_cast<std::string>(dotted_name.substr(0, next_dot)));
- dotted_name = dotted_name.substr(next_dot + 1);
- }
- }
- }
- enum class Transport { UDP, TCP, HTTPS };
- // A SocketDataProvider builder.
- class DnsSocketData {
- public:
- // The ctor takes parameters for the DnsQuery.
- DnsSocketData(uint16_t id,
- const char* dotted_name,
- uint16_t qtype,
- IoMode mode,
- Transport transport,
- const OptRecordRdata* opt_rdata = nullptr,
- DnsQuery::PaddingStrategy padding_strategy =
- DnsQuery::PaddingStrategy::NONE)
- : query_(std::make_unique<DnsQuery>(id,
- DomainFromDot(dotted_name),
- qtype,
- opt_rdata,
- padding_strategy)),
- transport_(transport) {
- if (Transport::TCP == transport_) {
- auto length = std::make_unique<uint16_t>();
- *length = base::HostToNet16(query_->io_buffer()->size());
- writes_.emplace_back(mode, reinterpret_cast<const char*>(length.get()),
- sizeof(uint16_t), num_reads_and_writes());
- lengths_.push_back(std::move(length));
- }
- writes_.emplace_back(mode, query_->io_buffer()->data(),
- query_->io_buffer()->size(), num_reads_and_writes());
- }
- DnsSocketData(const DnsSocketData&) = delete;
- DnsSocketData& operator=(const DnsSocketData&) = delete;
- ~DnsSocketData() = default;
- // All responses must be added before GetProvider.
- // Adds pre-built DnsResponse. |tcp_length| will be used in TCP mode only.
- void AddResponseWithLength(std::unique_ptr<DnsResponse> response,
- IoMode mode,
- uint16_t tcp_length) {
- CHECK(!provider_.get());
- if (Transport::TCP == transport_) {
- auto length = std::make_unique<uint16_t>();
- *length = base::HostToNet16(tcp_length);
- reads_.emplace_back(mode, reinterpret_cast<const char*>(length.get()),
- sizeof(uint16_t), num_reads_and_writes());
- lengths_.push_back(std::move(length));
- }
- reads_.emplace_back(mode, response->io_buffer()->data(),
- response->io_buffer_size(), num_reads_and_writes());
- responses_.push_back(std::move(response));
- }
- // Adds pre-built DnsResponse.
- void AddResponse(std::unique_ptr<DnsResponse> response, IoMode mode) {
- uint16_t tcp_length = response->io_buffer_size();
- AddResponseWithLength(std::move(response), mode, tcp_length);
- }
- // Adds pre-built response from |data| buffer.
- void AddResponseData(const uint8_t* data, size_t length, IoMode mode) {
- CHECK(!provider_.get());
- AddResponse(std::make_unique<DnsResponse>(
- reinterpret_cast<const char*>(data), length, 0),
- mode);
- }
- // Adds pre-built response from |data| buffer.
- void AddResponseData(const uint8_t* data,
- size_t length,
- int offset,
- IoMode mode) {
- CHECK(!provider_.get());
- AddResponse(
- std::make_unique<DnsResponse>(reinterpret_cast<const char*>(data),
- length - offset, offset),
- mode);
- }
- // Add no-answer (RCODE only) response matching the query.
- void AddRcode(int rcode, IoMode mode) {
- auto response = std::make_unique<DnsResponse>(
- query_->io_buffer()->data(), query_->io_buffer()->size(), 0);
- dns_protocol::Header* header =
- reinterpret_cast<dns_protocol::Header*>(response->io_buffer()->data());
- header->flags |= base::HostToNet16(dns_protocol::kFlagResponse | rcode);
- AddResponse(std::move(response), mode);
- }
- // Add error response.
- void AddReadError(int error, IoMode mode) {
- reads_.emplace_back(mode, error, num_reads_and_writes());
- }
- // Build, if needed, and return the SocketDataProvider. No new responses
- // should be added afterwards.
- SequencedSocketData* GetProvider() {
- if (provider_.get())
- return provider_.get();
- // Terminate the reads with ERR_IO_PENDING to prevent overrun and default to
- // timeout.
- if (transport_ != Transport::HTTPS) {
- reads_.emplace_back(SYNCHRONOUS, ERR_IO_PENDING,
- writes_.size() + reads_.size());
- }
- provider_ = std::make_unique<SequencedSocketData>(reads_, writes_);
- if (Transport::TCP == transport_ || Transport::HTTPS == transport_) {
- provider_->set_connect_data(MockConnect(reads_[0].mode, OK));
- }
- return provider_.get();
- }
- uint16_t query_id() const { return query_->id(); }
- IOBufferWithSize* query_buffer() { return query_->io_buffer(); }
- private:
- size_t num_reads_and_writes() const { return reads_.size() + writes_.size(); }
- std::unique_ptr<DnsQuery> query_;
- Transport transport_;
- std::vector<std::unique_ptr<uint16_t>> lengths_;
- std::vector<std::unique_ptr<DnsResponse>> responses_;
- std::vector<MockWrite> writes_;
- std::vector<MockRead> reads_;
- std::unique_ptr<SequencedSocketData> provider_;
- };
- class TestSocketFactory;
- // A variant of MockUDPClientSocket which always fails to Connect.
- class FailingUDPClientSocket : public MockUDPClientSocket {
- public:
- FailingUDPClientSocket(SocketDataProvider* data, net::NetLog* net_log)
- : MockUDPClientSocket(data, net_log) {}
- FailingUDPClientSocket(const FailingUDPClientSocket&) = delete;
- FailingUDPClientSocket& operator=(const FailingUDPClientSocket&) = delete;
- ~FailingUDPClientSocket() override = default;
- int Connect(const IPEndPoint& endpoint) override {
- return ERR_CONNECTION_REFUSED;
- }
- };
- // A variant of MockUDPClientSocket which notifies the factory OnConnect.
- class TestUDPClientSocket : public MockUDPClientSocket {
- public:
- TestUDPClientSocket(TestSocketFactory* factory,
- SocketDataProvider* data,
- net::NetLog* net_log)
- : MockUDPClientSocket(data, net_log), factory_(factory) {}
- TestUDPClientSocket(const TestUDPClientSocket&) = delete;
- TestUDPClientSocket& operator=(const TestUDPClientSocket&) = delete;
- ~TestUDPClientSocket() override = default;
- int Connect(const IPEndPoint& endpoint) override;
- private:
- raw_ptr<TestSocketFactory> factory_;
- };
- // Creates TestUDPClientSockets and keeps endpoints reported via OnConnect.
- class TestSocketFactory : public MockClientSocketFactory {
- public:
- TestSocketFactory() = default;
- ~TestSocketFactory() override = default;
- std::unique_ptr<DatagramClientSocket> CreateDatagramClientSocket(
- DatagramSocket::BindType bind_type,
- NetLog* net_log,
- const NetLogSource& source) override {
- if (fail_next_socket_) {
- fail_next_socket_ = false;
- return std::make_unique<FailingUDPClientSocket>(&empty_data_, net_log);
- }
- SocketDataProvider* data_provider = mock_data().GetNext();
- auto socket =
- std::make_unique<TestUDPClientSocket>(this, data_provider, net_log);
- // Even using DEFAULT_BIND, actual sockets have been measured to very rarely
- // repeat the same source port multiple times in a row. Need to mimic that
- // functionality here, so DnsUdpTracker doesn't misdiagnose repeated port
- // as low entropy.
- if (diverse_source_ports_)
- socket->set_source_port(next_source_port_++);
- return socket;
- }
- void OnConnect(const IPEndPoint& endpoint) {
- remote_endpoints_.emplace_back(endpoint);
- }
- struct RemoteNameserver {
- explicit RemoteNameserver(IPEndPoint insecure_nameserver)
- : insecure_nameserver(insecure_nameserver) {}
- explicit RemoteNameserver(DnsOverHttpsServerConfig secure_nameserver)
- : secure_nameserver(secure_nameserver) {}
- absl::optional<IPEndPoint> insecure_nameserver;
- absl::optional<DnsOverHttpsServerConfig> secure_nameserver;
- };
- std::vector<RemoteNameserver> remote_endpoints_;
- bool fail_next_socket_ = false;
- bool diverse_source_ports_ = true;
- private:
- StaticSocketDataProvider empty_data_;
- uint16_t next_source_port_ = 123;
- };
- int TestUDPClientSocket::Connect(const IPEndPoint& endpoint) {
- factory_->OnConnect(endpoint);
- return MockUDPClientSocket::Connect(endpoint);
- }
- // Helper class that holds a DnsTransaction and handles OnTransactionComplete.
- class TransactionHelper {
- public:
- // If |expected_answer_count| < 0 then it is the expected net error.
- explicit TransactionHelper(int expected_answer_count)
- : expected_answer_count_(expected_answer_count) {}
- // Mark that the transaction shall be destroyed immediately upon callback.
- void set_cancel_in_callback() { cancel_in_callback_ = true; }
- void StartTransaction(DnsTransactionFactory* factory,
- const char* hostname,
- uint16_t qtype,
- bool secure,
- ResolveContext* context) {
- std::unique_ptr<DnsTransaction> transaction = factory->CreateTransaction(
- hostname, qtype,
- NetLogWithSource::Make(net::NetLog::Get(), net::NetLogSourceType::NONE),
- secure, factory->GetSecureDnsModeForTest(), context,
- true /* fast_timeout */);
- transaction->SetRequestPriority(DEFAULT_PRIORITY);
- EXPECT_EQ(qtype, transaction->GetType());
- StartTransaction(std::move(transaction));
- }
- void StartTransaction(std::unique_ptr<DnsTransaction> transaction) {
- EXPECT_FALSE(transaction_);
- transaction_ = std::move(transaction);
- qtype_ = transaction_->GetType();
- transaction_->Start(base::BindOnce(
- &TransactionHelper::OnTransactionComplete, base::Unretained(this)));
- }
- void Cancel() {
- ASSERT_TRUE(transaction_.get() != nullptr);
- transaction_.reset(nullptr);
- }
- void OnTransactionComplete(int rv, const DnsResponse* response) {
- EXPECT_FALSE(completed_);
- completed_ = true;
- response_ = response;
- transaction_complete_run_loop_.Quit();
- if (cancel_in_callback_) {
- Cancel();
- return;
- }
- if (response)
- EXPECT_TRUE(response->IsValid());
- if (expected_answer_count_ >= 0) {
- ASSERT_THAT(rv, IsOk());
- ASSERT_TRUE(response != nullptr);
- EXPECT_EQ(static_cast<unsigned>(expected_answer_count_),
- response->answer_count());
- EXPECT_EQ(qtype_, response->GetSingleQType());
- DnsRecordParser parser = response->Parser();
- DnsResourceRecord record;
- for (int i = 0; i < expected_answer_count_; ++i) {
- EXPECT_TRUE(parser.ReadRecord(&record));
- }
- } else {
- EXPECT_EQ(expected_answer_count_, rv);
- }
- }
- bool has_completed() const { return completed_; }
- const DnsResponse* response() const { return response_; }
- // Runs until the completion callback is called. Transaction must have already
- // been started or this will never complete.
- void RunUntilComplete() {
- DCHECK(transaction_);
- DCHECK(!transaction_complete_run_loop_.running());
- transaction_complete_run_loop_.Run();
- DCHECK(has_completed());
- }
- private:
- uint16_t qtype_ = 0;
- std::unique_ptr<DnsTransaction> transaction_;
- raw_ptr<const DnsResponse> response_ = nullptr;
- int expected_answer_count_;
- bool cancel_in_callback_ = false;
- base::RunLoop transaction_complete_run_loop_;
- bool completed_ = false;
- };
- // Callback that allows a test to modify HttpResponseinfo
- // before the response is sent to the requester. This allows
- // response headers to be changed.
- using ResponseModifierCallback =
- base::RepeatingCallback<void(URLRequest* request, HttpResponseInfo* info)>;
- // Callback that allows the test to substitute its own implementation
- // of URLRequestJob to handle the request.
- using DohJobMakerCallback = base::RepeatingCallback<std::unique_ptr<
- URLRequestJob>(URLRequest* request, SocketDataProvider* data_provider)>;
- // Callback to notify that URLRequestJob::Start has been called.
- using UrlRequestStartedCallback = base::RepeatingCallback<void()>;
- // Subclass of URLRequestJob which takes a SocketDataProvider with data
- // representing both a DNS over HTTPS query and response.
- class URLRequestMockDohJob : public URLRequestJob, public AsyncSocket {
- public:
- URLRequestMockDohJob(
- URLRequest* request,
- SocketDataProvider* data_provider,
- ResponseModifierCallback response_modifier = ResponseModifierCallback(),
- UrlRequestStartedCallback on_start = UrlRequestStartedCallback())
- : URLRequestJob(request),
- data_provider_(data_provider),
- response_modifier_(response_modifier),
- on_start_(on_start) {
- data_provider_->Initialize(this);
- MatchQueryData(request, data_provider);
- }
- // Compare the query contained in either the POST body or the body
- // parameter of the GET query to the write data of the SocketDataProvider.
- static void MatchQueryData(URLRequest* request,
- SocketDataProvider* data_provider) {
- std::string decoded_query;
- if (request->method() == "GET") {
- std::string encoded_query;
- EXPECT_TRUE(GetValueForKeyInQuery(request->url(), "dns", &encoded_query));
- EXPECT_GT(encoded_query.size(), 0ul);
- EXPECT_TRUE(base::Base64UrlDecode(
- encoded_query, base::Base64UrlDecodePolicy::IGNORE_PADDING,
- &decoded_query));
- } else if (request->method() == "POST") {
- EXPECT_EQ(IDEMPOTENT, request->GetIdempotency());
- const UploadDataStream* stream = request->get_upload_for_testing();
- auto* readers = stream->GetElementReaders();
- EXPECT_TRUE(readers);
- EXPECT_FALSE(readers->empty());
- for (auto& reader : *readers) {
- const UploadBytesElementReader* byte_reader = reader->AsBytesReader();
- decoded_query +=
- std::string(byte_reader->bytes(), byte_reader->length());
- }
- }
- std::string query(decoded_query);
- MockWriteResult result(SYNCHRONOUS, 1);
- while (result.result > 0 && query.length() > 0) {
- result = data_provider->OnWrite(query);
- if (result.result > 0)
- query = query.substr(result.result);
- }
- }
- static std::string GetMockHttpsUrl(const std::string& path) {
- return "https://" + (kMockHostname + ("/" + path));
- }
- // URLRequestJob implementation:
- void Start() override {
- if (on_start_)
- on_start_.Run();
- // Start reading asynchronously so that all error reporting and data
- // callbacks happen as they would for network requests.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&URLRequestMockDohJob::StartAsync,
- weak_factory_.GetWeakPtr()));
- }
- URLRequestMockDohJob(const URLRequestMockDohJob&) = delete;
- URLRequestMockDohJob& operator=(const URLRequestMockDohJob&) = delete;
- ~URLRequestMockDohJob() override {
- if (data_provider_)
- data_provider_->DetachSocket();
- }
- int ReadRawData(IOBuffer* buf, int buf_size) override {
- if (!data_provider_)
- return ERR_FAILED;
- if (leftover_data_len_ > 0) {
- int rv = DoBufferCopy(leftover_data_, leftover_data_len_, buf, buf_size);
- return rv;
- }
- if (data_provider_->AllReadDataConsumed())
- return 0;
- MockRead read = data_provider_->OnRead();
- if (read.result < ERR_IO_PENDING)
- return read.result;
- if (read.result == ERR_IO_PENDING) {
- pending_buf_ = buf;
- pending_buf_size_ = buf_size;
- return ERR_IO_PENDING;
- }
- return DoBufferCopy(read.data, read.data_len, buf, buf_size);
- }
- void GetResponseInfo(HttpResponseInfo* info) override {
- // Send back mock headers.
- std::string raw_headers;
- raw_headers.append(
- "HTTP/1.1 200 OK\n"
- "Content-type: application/dns-message\n");
- if (content_length_ > 0) {
- raw_headers.append(base::StringPrintf("Content-Length: %1d\n",
- static_cast<int>(content_length_)));
- }
- info->headers = base::MakeRefCounted<HttpResponseHeaders>(
- HttpUtil::AssembleRawHeaders(raw_headers));
- if (response_modifier_)
- response_modifier_.Run(request(), info);
- }
- // AsyncSocket implementation:
- void OnReadComplete(const MockRead& data) override {
- EXPECT_NE(data.result, ERR_IO_PENDING);
- if (data.result < 0)
- return ReadRawDataComplete(data.result);
- ReadRawDataComplete(DoBufferCopy(data.data, data.data_len, pending_buf_,
- pending_buf_size_));
- }
- void OnWriteComplete(int rv) override {}
- void OnConnectComplete(const MockConnect& data) override {}
- void OnDataProviderDestroyed() override { data_provider_ = nullptr; }
- private:
- void StartAsync() {
- if (!request_)
- return;
- if (content_length_)
- set_expected_content_size(content_length_);
- NotifyHeadersComplete();
- }
- int DoBufferCopy(const char* data,
- int data_len,
- IOBuffer* buf,
- int buf_size) {
- if (data_len > buf_size) {
- memcpy(buf->data(), data, buf_size);
- leftover_data_ = data + buf_size;
- leftover_data_len_ = data_len - buf_size;
- return buf_size;
- }
- memcpy(buf->data(), data, data_len);
- return data_len;
- }
- const int content_length_ = 0;
- const char* leftover_data_;
- int leftover_data_len_ = 0;
- raw_ptr<SocketDataProvider> data_provider_;
- const ResponseModifierCallback response_modifier_;
- const UrlRequestStartedCallback on_start_;
- raw_ptr<IOBuffer> pending_buf_;
- int pending_buf_size_;
- base::WeakPtrFactory<URLRequestMockDohJob> weak_factory_{this};
- };
- class DnsTransactionTestBase : public testing::Test {
- public:
- DnsTransactionTestBase() = default;
- ~DnsTransactionTestBase() override {
- // All queued transaction IDs should be used by a transaction calling
- // GetNextId().
- CHECK(transaction_ids_.empty());
- }
- // Generates |nameservers| for DnsConfig.
- void ConfigureNumServers(size_t num_servers) {
- CHECK_LE(num_servers, 255u);
- config_.nameservers.clear();
- for (size_t i = 0; i < num_servers; ++i) {
- config_.nameservers.emplace_back(IPAddress(192, 168, 1, i),
- dns_protocol::kDefaultPort);
- }
- }
- // Configures the DnsConfig DNS-over-HTTPS server(s), which either
- // accept GET or POST requests based on use_post. If a
- // ResponseModifierCallback is provided it will be called to construct the
- // HTTPResponse.
- void ConfigureDohServers(bool use_post,
- size_t num_doh_servers = 1,
- bool make_available = true) {
- GURL url(URLRequestMockDohJob::GetMockHttpsUrl("doh_test"));
- URLRequestFilter* filter = URLRequestFilter::GetInstance();
- filter->AddHostnameInterceptor(url.scheme(), url.host(),
- std::make_unique<DohJobInterceptor>(this));
- CHECK_LE(num_doh_servers, 255u);
- std::vector<string> templates;
- templates.reserve(num_doh_servers);
- for (size_t i = 0; i < num_doh_servers; ++i) {
- templates.push_back(URLRequestMockDohJob::GetMockHttpsUrl(
- base::StringPrintf("doh_test_%zu", i)) +
- (use_post ? "" : "{?dns}"));
- }
- config_.doh_config =
- *DnsOverHttpsConfig::FromTemplatesForTesting(std::move(templates));
- ConfigureFactory();
- if (make_available) {
- for (size_t server_index = 0; server_index < num_doh_servers;
- ++server_index) {
- resolve_context_->RecordServerSuccess(
- server_index, true /* is_doh_server */, session_.get());
- }
- }
- }
- // Called after fully configuring |config|.
- void ConfigureFactory() {
- session_ = base::MakeRefCounted<DnsSession>(
- config_,
- base::BindRepeating(&DnsTransactionTestBase::GetNextId,
- base::Unretained(this)),
- nullptr /* NetLog */);
- resolve_context_->InvalidateCachesAndPerSessionData(
- session_.get(), false /* network_change */);
- transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get());
- }
- void AddSocketData(std::unique_ptr<DnsSocketData> data,
- bool enqueue_transaction_id = true) {
- CHECK(socket_factory_.get());
- if (enqueue_transaction_id)
- transaction_ids_.push_back(data->query_id());
- socket_factory_->AddSocketDataProvider(data->GetProvider());
- socket_data_.push_back(std::move(data));
- }
- // Add expected query for |dotted_name| and |qtype| with |id| and response
- // taken verbatim from |data| of |data_length| bytes. The transaction id in
- // |data| should equal |id|, unless testing mismatched response.
- void AddQueryAndResponse(uint16_t id,
- const char* dotted_name,
- uint16_t qtype,
- const uint8_t* response_data,
- size_t response_length,
- IoMode mode,
- Transport transport,
- const OptRecordRdata* opt_rdata = nullptr,
- DnsQuery::PaddingStrategy padding_strategy =
- DnsQuery::PaddingStrategy::NONE,
- bool enqueue_transaction_id = true) {
- CHECK(socket_factory_.get());
- auto data = std::make_unique<DnsSocketData>(
- id, dotted_name, qtype, mode, transport, opt_rdata, padding_strategy);
- data->AddResponseData(response_data, response_length, mode);
- AddSocketData(std::move(data), enqueue_transaction_id);
- }
- void AddQueryAndErrorResponse(uint16_t id,
- const char* dotted_name,
- uint16_t qtype,
- int error,
- IoMode mode,
- Transport transport,
- const OptRecordRdata* opt_rdata = nullptr,
- DnsQuery::PaddingStrategy padding_strategy =
- DnsQuery::PaddingStrategy::NONE,
- bool enqueue_transaction_id = true) {
- CHECK(socket_factory_.get());
- auto data = std::make_unique<DnsSocketData>(
- id, dotted_name, qtype, mode, transport, opt_rdata, padding_strategy);
- data->AddReadError(error, mode);
- AddSocketData(std::move(data), enqueue_transaction_id);
- }
- void AddAsyncQueryAndResponse(uint16_t id,
- const char* dotted_name,
- uint16_t qtype,
- const uint8_t* data,
- size_t data_length,
- const OptRecordRdata* opt_rdata = nullptr) {
- AddQueryAndResponse(id, dotted_name, qtype, data, data_length, ASYNC,
- Transport::UDP, opt_rdata);
- }
- void AddSyncQueryAndResponse(uint16_t id,
- const char* dotted_name,
- uint16_t qtype,
- const uint8_t* data,
- size_t data_length,
- const OptRecordRdata* opt_rdata = nullptr) {
- AddQueryAndResponse(id, dotted_name, qtype, data, data_length, SYNCHRONOUS,
- Transport::UDP, opt_rdata);
- }
- // Add expected query of |dotted_name| and |qtype| and no response.
- void AddHangingQuery(
- const char* dotted_name,
- uint16_t qtype,
- DnsQuery::PaddingStrategy padding_strategy =
- DnsQuery::PaddingStrategy::NONE,
- uint16_t id = base::RandInt(0, std::numeric_limits<uint16_t>::max()),
- bool enqueue_transaction_id = true) {
- auto data = std::make_unique<DnsSocketData>(
- id, dotted_name, qtype, ASYNC, Transport::UDP, nullptr /* opt_rdata */,
- padding_strategy);
- AddSocketData(std::move(data), enqueue_transaction_id);
- }
- // Add expected query of |dotted_name| and |qtype| and matching response with
- // no answer and RCODE set to |rcode|. The id will be generated randomly.
- void AddQueryAndRcode(
- const char* dotted_name,
- uint16_t qtype,
- int rcode,
- IoMode mode,
- Transport trans,
- DnsQuery::PaddingStrategy padding_strategy =
- DnsQuery::PaddingStrategy::NONE,
- uint16_t id = base::RandInt(0, std::numeric_limits<uint16_t>::max()),
- bool enqueue_transaction_id = true) {
- CHECK_NE(dns_protocol::kRcodeNOERROR, rcode);
- auto data = std::make_unique<DnsSocketData>(id, dotted_name, qtype, mode,
- trans, nullptr /* opt_rdata */,
- padding_strategy);
- data->AddRcode(rcode, mode);
- AddSocketData(std::move(data), enqueue_transaction_id);
- }
- void AddAsyncQueryAndRcode(const char* dotted_name,
- uint16_t qtype,
- int rcode) {
- AddQueryAndRcode(dotted_name, qtype, rcode, ASYNC, Transport::UDP);
- }
- void AddSyncQueryAndRcode(const char* dotted_name,
- uint16_t qtype,
- int rcode) {
- AddQueryAndRcode(dotted_name, qtype, rcode, SYNCHRONOUS, Transport::UDP);
- }
- // Checks if the sockets were connected in the order matching the indices in
- // |servers|.
- void CheckServerOrder(const size_t* servers, size_t num_attempts) {
- ASSERT_EQ(num_attempts, socket_factory_->remote_endpoints_.size());
- auto num_insecure_nameservers = session_->config().nameservers.size();
- for (size_t i = 0; i < num_attempts; ++i) {
- if (servers[i] < num_insecure_nameservers) {
- // Check insecure server match.
- EXPECT_EQ(
- socket_factory_->remote_endpoints_[i].insecure_nameserver.value(),
- session_->config().nameservers[servers[i]]);
- } else {
- // Check secure server match.
- EXPECT_EQ(
- socket_factory_->remote_endpoints_[i].secure_nameserver.value(),
- session_->config()
- .doh_config.servers()[servers[i] - num_insecure_nameservers]);
- }
- }
- }
- std::unique_ptr<URLRequestJob> MaybeInterceptRequest(URLRequest* request) {
- // If the path indicates a redirect, skip checking the list of
- // configured servers, because it won't be there and we still want
- // to handle it.
- bool server_found = request->url().path() == "/redirect-destination";
- for (auto server : config_.doh_config.servers()) {
- if (server_found)
- break;
- std::string url_base =
- GetURLFromTemplateWithoutParameters(server.server_template());
- if (server.use_post() && request->method() == "POST") {
- if (url_base == request->url().spec()) {
- server_found = true;
- socket_factory_->remote_endpoints_.emplace_back(server);
- }
- } else if (!server.use_post() && request->method() == "GET") {
- std::string prefix = url_base + "?dns=";
- auto mispair = std::mismatch(prefix.begin(), prefix.end(),
- request->url().spec().begin());
- if (mispair.first == prefix.end()) {
- server_found = true;
- socket_factory_->remote_endpoints_.emplace_back(server);
- }
- }
- }
- EXPECT_TRUE(server_found);
- EXPECT_TRUE(
- request->isolation_info().network_isolation_key().IsTransient());
- // All DoH requests for the same ResolveContext should use the same
- // IsolationInfo, so network objects like sockets can be reused between
- // requests.
- if (!expect_multiple_isolation_infos_) {
- if (!isolation_info_) {
- isolation_info_ =
- std::make_unique<IsolationInfo>(request->isolation_info());
- } else {
- EXPECT_TRUE(
- isolation_info_->IsEqualForTesting(request->isolation_info()));
- }
- }
- EXPECT_FALSE(request->allow_credentials());
- EXPECT_EQ(SecureDnsPolicy::kBootstrap, request->secure_dns_policy());
- std::string accept;
- EXPECT_TRUE(request->extra_request_headers().GetHeader("Accept", &accept));
- EXPECT_EQ(accept, "application/dns-message");
- std::string language;
- EXPECT_TRUE(request->extra_request_headers().GetHeader("Accept-Language",
- &language));
- EXPECT_EQ(language, "*");
- std::string user_agent;
- EXPECT_TRUE(
- request->extra_request_headers().GetHeader("User-Agent", &user_agent));
- EXPECT_EQ(user_agent, "Chrome");
- SocketDataProvider* provider = socket_factory_->mock_data().GetNext();
- if (doh_job_maker_)
- return doh_job_maker_.Run(request, provider);
- return std::make_unique<URLRequestMockDohJob>(
- request, provider, response_modifier_, on_start_);
- }
- class DohJobInterceptor : public URLRequestInterceptor {
- public:
- explicit DohJobInterceptor(DnsTransactionTestBase* test) : test_(test) {}
- DohJobInterceptor(const DohJobInterceptor&) = delete;
- DohJobInterceptor& operator=(const DohJobInterceptor&) = delete;
- ~DohJobInterceptor() override = default;
- // URLRequestInterceptor implementation:
- std::unique_ptr<URLRequestJob> MaybeInterceptRequest(
- URLRequest* request) const override {
- return test_->MaybeInterceptRequest(request);
- }
- private:
- raw_ptr<DnsTransactionTestBase> test_;
- };
- void SetResponseModifierCallback(ResponseModifierCallback response_modifier) {
- response_modifier_ = response_modifier;
- }
- void SetDohJobMakerCallback(DohJobMakerCallback doh_job_maker) {
- doh_job_maker_ = doh_job_maker;
- }
- void SetUrlRequestStartedCallback(UrlRequestStartedCallback on_start) {
- on_start_ = on_start;
- }
- void SetUp() override {
- // By default set one server,
- ConfigureNumServers(1);
- // and no retransmissions,
- config_.attempts = 1;
- // and an arbitrary fallback period.
- config_.fallback_period = kFallbackPeriod;
- auto context_builder = CreateTestURLRequestContextBuilder();
- socket_factory_ = std::make_unique<TestSocketFactory>();
- context_builder->set_client_socket_factory_for_testing(
- socket_factory_.get());
- request_context_ = context_builder->Build();
- resolve_context_ = std::make_unique<ResolveContext>(
- request_context_.get(), false /* enable_caching */);
- ConfigureFactory();
- }
- void TearDown() override {
- // Check that all socket data was at least written to.
- for (size_t i = 0; i < socket_data_.size(); ++i) {
- EXPECT_TRUE(socket_data_[i]->GetProvider()->AllWriteDataConsumed()) << i;
- }
- URLRequestFilter* filter = URLRequestFilter::GetInstance();
- filter->ClearHandlers();
- }
- void set_expect_multiple_isolation_infos(
- bool expect_multiple_isolation_infos) {
- expect_multiple_isolation_infos_ = expect_multiple_isolation_infos;
- }
- protected:
- int GetNextId(int min, int max) {
- EXPECT_FALSE(transaction_ids_.empty());
- int id = transaction_ids_.front();
- transaction_ids_.pop_front();
- EXPECT_GE(id, min);
- EXPECT_LE(id, max);
- return id;
- }
- DnsConfig config_;
- std::vector<std::unique_ptr<DnsSocketData>> socket_data_;
- base::circular_deque<int> transaction_ids_;
- std::unique_ptr<TestSocketFactory> socket_factory_;
- std::unique_ptr<URLRequestContext> request_context_;
- std::unique_ptr<ResolveContext> resolve_context_;
- scoped_refptr<DnsSession> session_;
- std::unique_ptr<DnsTransactionFactory> transaction_factory_;
- ResponseModifierCallback response_modifier_;
- UrlRequestStartedCallback on_start_;
- DohJobMakerCallback doh_job_maker_;
- // Whether multiple IsolationInfos should be expected (due to there being
- // multiple RequestContexts in use).
- bool expect_multiple_isolation_infos_ = false;
- // IsolationInfo used by DoH requests. Populated on first DoH request, and
- // compared to IsolationInfo used by all subsequent requests, unless
- // |expect_multiple_isolation_infos_| is true.
- std::unique_ptr<IsolationInfo> isolation_info_;
- };
- class DnsTransactionTest : public DnsTransactionTestBase,
- public WithTaskEnvironment {
- public:
- DnsTransactionTest() = default;
- ~DnsTransactionTest() override = default;
- };
- class DnsTransactionTestWithMockTime : public DnsTransactionTestBase,
- public WithTaskEnvironment {
- protected:
- DnsTransactionTestWithMockTime()
- : WithTaskEnvironment(
- base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
- ~DnsTransactionTestWithMockTime() override = default;
- };
- TEST_F(DnsTransactionTest, Lookup) {
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
- kT0ResponseDatagram, std::size(kT0ResponseDatagram));
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, LookupWithEDNSOption) {
- OptRecordRdata expected_opt_rdata;
- transaction_factory_->AddEDNSOption(
- OptRecordRdata::UnknownOpt::CreateForTesting(123, "\xbe\xef"));
- expected_opt_rdata.AddOpt(
- OptRecordRdata::UnknownOpt::CreateForTesting(123, "\xbe\xef"));
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
- kT0ResponseDatagram, std::size(kT0ResponseDatagram),
- &expected_opt_rdata);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, LookupWithMultipleEDNSOptions) {
- OptRecordRdata expected_opt_rdata;
- std::vector<std::pair<uint16_t, std::string>> params = {
- // Two options with the same code, to check that both are included.
- std::pair<uint16_t, std::string>(1, "\xde\xad"),
- std::pair<uint16_t, std::string>(1, "\xbe\xef"),
- // Try a different code and different length of data.
- std::pair<uint16_t, std::string>(2, "\xff")};
- for (auto& param : params) {
- transaction_factory_->AddEDNSOption(
- OptRecordRdata::UnknownOpt::CreateForTesting(param.first,
- param.second));
- expected_opt_rdata.AddOpt(OptRecordRdata::UnknownOpt::CreateForTesting(
- param.first, param.second));
- }
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
- kT0ResponseDatagram, std::size(kT0ResponseDatagram),
- &expected_opt_rdata);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- // Concurrent lookup tests assume that DnsTransaction::Start immediately
- // consumes a socket from ClientSocketFactory.
- TEST_F(DnsTransactionTest, ConcurrentLookup) {
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
- kT0ResponseDatagram, std::size(kT0ResponseDatagram));
- AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
- kT1ResponseDatagram, std::size(kT1ResponseDatagram));
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- TransactionHelper helper1(kT1RecordCount);
- helper1.StartTransaction(transaction_factory_.get(), kT1HostName, kT1Qtype,
- false /* secure */, resolve_context_.get());
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(helper0.has_completed());
- EXPECT_TRUE(helper1.has_completed());
- }
- TEST_F(DnsTransactionTest, CancelLookup) {
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
- kT0ResponseDatagram, std::size(kT0ResponseDatagram));
- AddAsyncQueryAndResponse(1 /* id */, kT1HostName, kT1Qtype,
- kT1ResponseDatagram, std::size(kT1ResponseDatagram));
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- TransactionHelper helper1(kT1RecordCount);
- helper1.StartTransaction(transaction_factory_.get(), kT1HostName, kT1Qtype,
- false /* secure */, resolve_context_.get());
- helper0.Cancel();
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(helper0.has_completed());
- EXPECT_TRUE(helper1.has_completed());
- }
- TEST_F(DnsTransactionTest, DestroyFactory) {
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
- kT0ResponseDatagram, std::size(kT0ResponseDatagram));
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- // Destroying the client does not affect running requests.
- transaction_factory_.reset(nullptr);
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, CancelFromCallback) {
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
- kT0ResponseDatagram, std::size(kT0ResponseDatagram));
- TransactionHelper helper0(kT0RecordCount);
- helper0.set_cancel_in_callback();
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, MismatchedResponseSync) {
- config_.attempts = 2;
- ConfigureFactory();
- // First attempt receives mismatched response synchronously.
- auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
- SYNCHRONOUS, Transport::UDP);
- data->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
- SYNCHRONOUS);
- AddSocketData(std::move(data));
- // Second attempt receives valid response synchronously.
- auto data1 = std::make_unique<DnsSocketData>(
- 0 /* id */, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::UDP);
- data1->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
- SYNCHRONOUS);
- AddSocketData(std::move(data1));
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, MismatchedResponseAsync) {
- config_.attempts = 2;
- ConfigureFactory();
- // First attempt receives mismatched response asynchronously.
- auto data0 = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName,
- kT0Qtype, ASYNC, Transport::UDP);
- data0->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
- ASYNC);
- AddSocketData(std::move(data0));
- // Second attempt receives valid response asynchronously.
- auto data1 = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName,
- kT0Qtype, ASYNC, Transport::UDP);
- data1->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
- ASYNC);
- AddSocketData(std::move(data1));
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- // Test that responses are not accepted when only the response ID mismatches.
- // Tests against incorrect transaction ID validation, which is anti-pattern #1
- // from the "NAME:WRECK" report:
- // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
- TEST_F(DnsTransactionTest, MismatchedResponseFail) {
- ConfigureFactory();
- // Attempt receives mismatched response and fails because only one attempt is
- // allowed.
- AddAsyncQueryAndResponse(1 /* id */, kT0HostName, kT0Qtype,
- kT0ResponseDatagram, std::size(kT0ResponseDatagram));
- TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, MismatchedResponseNxdomain) {
- config_.attempts = 2;
- ConfigureFactory();
- // First attempt receives mismatched response followed by valid NXDOMAIN
- // response.
- // Second attempt receives valid NXDOMAIN response.
- auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
- SYNCHRONOUS, Transport::UDP);
- data->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
- SYNCHRONOUS);
- data->AddRcode(dns_protocol::kRcodeNXDOMAIN, ASYNC);
- AddSocketData(std::move(data));
- AddSyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
- TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, ServerFail) {
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
- TransactionHelper helper0(ERR_DNS_SERVER_FAILED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- ASSERT_NE(helper0.response(), nullptr);
- EXPECT_EQ(helper0.response()->rcode(), dns_protocol::kRcodeSERVFAIL);
- }
- TEST_F(DnsTransactionTest, NoDomain) {
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
- TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTestWithMockTime, Timeout_FastTimeout) {
- config_.attempts = 3;
- ConfigureFactory();
- AddHangingQuery(kT0HostName, kT0Qtype);
- AddHangingQuery(kT0HostName, kT0Qtype);
- AddHangingQuery(kT0HostName, kT0Qtype);
- TransactionHelper helper0(ERR_DNS_TIMED_OUT);
- std::unique_ptr<DnsTransaction> transaction =
- transaction_factory_->CreateTransaction(
- kT0HostName, kT0Qtype, NetLogWithSource(), false /* secure */,
- SecureDnsMode::kOff, resolve_context_.get(), true /* fast_timeout */);
- helper0.StartTransaction(std::move(transaction));
- // Finish when the third attempt expires its fallback period.
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(helper0.has_completed());
- FastForwardBy(
- resolve_context_->NextClassicFallbackPeriod(0, 0, session_.get()));
- EXPECT_FALSE(helper0.has_completed());
- FastForwardBy(
- resolve_context_->NextClassicFallbackPeriod(0, 1, session_.get()));
- EXPECT_FALSE(helper0.has_completed());
- FastForwardBy(
- resolve_context_->NextClassicFallbackPeriod(0, 2, session_.get()));
- EXPECT_TRUE(helper0.has_completed());
- }
- TEST_F(DnsTransactionTestWithMockTime, ServerFallbackAndRotate) {
- // Test that we fallback on both server failure and fallback period
- // expiration.
- config_.attempts = 2;
- // The next request should start from the next server.
- config_.rotate = true;
- ConfigureNumServers(3);
- ConfigureFactory();
- // Responses for first request.
- AddHangingQuery(kT0HostName, kT0Qtype);
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
- AddHangingQuery(kT0HostName, kT0Qtype);
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL);
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
- // Responses for second request.
- AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL);
- AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeSERVFAIL);
- AddAsyncQueryAndRcode(kT1HostName, kT1Qtype, dns_protocol::kRcodeNXDOMAIN);
- TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
- TransactionHelper helper1(ERR_NAME_NOT_RESOLVED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(helper0.has_completed());
- FastForwardUntilNoTasksRemain();
- EXPECT_TRUE(helper0.has_completed());
- helper1.StartTransaction(transaction_factory_.get(), kT1HostName, kT1Qtype,
- false /* secure */, resolve_context_.get());
- helper1.RunUntilComplete();
- size_t kOrder[] = {
- // The first transaction.
- 0,
- 1,
- 2,
- 0,
- 1,
- // The second transaction starts from the next server, and 0 is skipped
- // because it already has 2 consecutive failures.
- 1,
- 2,
- 1,
- };
- CheckServerOrder(kOrder, std::size(kOrder));
- }
- TEST_F(DnsTransactionTest, SuffixSearchAboveNdots) {
- config_.ndots = 2;
- config_.search.push_back("a");
- config_.search.push_back("b");
- config_.search.push_back("c");
- config_.rotate = true;
- ConfigureNumServers(2);
- ConfigureFactory();
- AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- AddAsyncQueryAndRcode("x.y.z.b", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- AddAsyncQueryAndRcode("x.y.z.c", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
- helper0.StartTransaction(transaction_factory_.get(), "x.y.z",
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper0.RunUntilComplete();
- // Also check if suffix search causes server rotation.
- size_t kOrder0[] = {0, 1, 0, 1};
- CheckServerOrder(kOrder0, std::size(kOrder0));
- }
- TEST_F(DnsTransactionTest, SuffixSearchBelowNdots) {
- config_.ndots = 2;
- config_.search.push_back("a");
- config_.search.push_back("b");
- config_.search.push_back("c");
- ConfigureFactory();
- // Responses for first transaction.
- AddAsyncQueryAndRcode("x.y.a", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- AddAsyncQueryAndRcode("x.y.b", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- AddAsyncQueryAndRcode("x.y.c", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- // Responses for second transaction.
- AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- // Responses for third transaction.
- AddAsyncQueryAndRcode("x", dns_protocol::kTypeAAAA,
- dns_protocol::kRcodeNXDOMAIN);
- TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
- helper0.StartTransaction(transaction_factory_.get(), "x.y",
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper0.RunUntilComplete();
- // A single-label name.
- TransactionHelper helper1(ERR_NAME_NOT_RESOLVED);
- helper1.StartTransaction(transaction_factory_.get(), "x",
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper1.RunUntilComplete();
- // A fully-qualified name.
- TransactionHelper helper2(ERR_NAME_NOT_RESOLVED);
- helper2.StartTransaction(transaction_factory_.get(), "x.",
- dns_protocol::kTypeAAAA, false /* secure */,
- resolve_context_.get());
- helper2.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, EmptySuffixSearch) {
- // Responses for first transaction.
- AddAsyncQueryAndRcode("x", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- // A fully-qualified name.
- TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
- helper0.StartTransaction(transaction_factory_.get(), "x.",
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper0.RunUntilComplete();
- // A single label name is not even attempted.
- TransactionHelper helper1(ERR_DNS_SEARCH_EMPTY);
- helper1.StartTransaction(transaction_factory_.get(), "singlelabel",
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper1.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, DontAppendToMultiLabelName) {
- config_.search.push_back("a");
- config_.search.push_back("b");
- config_.search.push_back("c");
- config_.append_to_multi_label_name = false;
- ConfigureFactory();
- // Responses for first transaction.
- AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- // Responses for second transaction.
- AddAsyncQueryAndRcode("x.y", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- // Responses for third transaction.
- AddAsyncQueryAndRcode("x.a", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- AddAsyncQueryAndRcode("x.b", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- AddAsyncQueryAndRcode("x.c", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
- helper0.StartTransaction(transaction_factory_.get(), "x.y.z",
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper0.RunUntilComplete();
- TransactionHelper helper1(ERR_NAME_NOT_RESOLVED);
- helper1.StartTransaction(transaction_factory_.get(), "x.y",
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper1.RunUntilComplete();
- TransactionHelper helper2(ERR_NAME_NOT_RESOLVED);
- helper2.StartTransaction(transaction_factory_.get(), "x",
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper2.RunUntilComplete();
- }
- const uint8_t kResponseNoData[] = {
- 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
- // Question
- 0x01, 'x', 0x01, 'y', 0x01, 'z', 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01,
- // Authority section, SOA record, TTL 0x3E6
- 0x01, 'z', 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0xE6,
- // Minimal RDATA, 18 bytes
- 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- };
- TEST_F(DnsTransactionTest, SuffixSearchStop) {
- config_.ndots = 2;
- config_.search.push_back("a");
- config_.search.push_back("b");
- config_.search.push_back("c");
- ConfigureFactory();
- AddAsyncQueryAndRcode("x.y.z", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- AddAsyncQueryAndRcode("x.y.z.a", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- AddAsyncQueryAndResponse(0 /* id */, "x.y.z.b", dns_protocol::kTypeA,
- kResponseNoData, std::size(kResponseNoData));
- TransactionHelper helper0(0 /* answers */);
- helper0.StartTransaction(transaction_factory_.get(), "x.y.z",
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, SyncFirstQuery) {
- config_.search.push_back("lab.ccs.neu.edu");
- config_.search.push_back("ccs.neu.edu");
- ConfigureFactory();
- AddSyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
- kT0ResponseDatagram, std::size(kT0ResponseDatagram));
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, SyncFirstQueryWithSearch) {
- config_.search.push_back("lab.ccs.neu.edu");
- config_.search.push_back("ccs.neu.edu");
- ConfigureFactory();
- AddSyncQueryAndRcode("www.lab.ccs.neu.edu", kT2Qtype,
- dns_protocol::kRcodeNXDOMAIN);
- // "www.ccs.neu.edu"
- AddAsyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
- kT2ResponseDatagram, std::size(kT2ResponseDatagram));
- TransactionHelper helper0(kT2RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), "www", kT2Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, SyncSearchQuery) {
- config_.search.push_back("lab.ccs.neu.edu");
- config_.search.push_back("ccs.neu.edu");
- ConfigureFactory();
- AddAsyncQueryAndRcode("www.lab.ccs.neu.edu", dns_protocol::kTypeA,
- dns_protocol::kRcodeNXDOMAIN);
- AddSyncQueryAndResponse(2 /* id */, kT2HostName, kT2Qtype,
- kT2ResponseDatagram, std::size(kT2ResponseDatagram));
- TransactionHelper helper0(kT2RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), "www", kT2Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, ConnectFailure) {
- // Prep socket factory for a single socket with connection failure.
- MockConnect connect_data;
- connect_data.result = ERR_FAILED;
- StaticSocketDataProvider data_provider;
- data_provider.set_connect_data(connect_data);
- socket_factory_->AddSocketDataProvider(&data_provider);
- transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
- TransactionHelper helper0(ERR_CONNECTION_REFUSED);
- helper0.StartTransaction(transaction_factory_.get(), "www.chromium.org",
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper0.RunUntilComplete();
- EXPECT_FALSE(helper0.response());
- EXPECT_FALSE(session_->udp_tracker()->low_entropy());
- }
- TEST_F(DnsTransactionTest, ConnectFailure_SocketLimitReached) {
- // Prep socket factory for a single socket with connection failure.
- MockConnect connect_data;
- connect_data.result = ERR_INSUFFICIENT_RESOURCES;
- StaticSocketDataProvider data_provider;
- data_provider.set_connect_data(connect_data);
- socket_factory_->AddSocketDataProvider(&data_provider);
- transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
- TransactionHelper helper0(ERR_CONNECTION_REFUSED);
- helper0.StartTransaction(transaction_factory_.get(), "www.chromium.org",
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper0.RunUntilComplete();
- EXPECT_FALSE(helper0.response());
- EXPECT_TRUE(session_->udp_tracker()->low_entropy());
- }
- TEST_F(DnsTransactionTest, ConnectFailureFollowedBySuccess) {
- // Retry after server failure.
- config_.attempts = 2;
- ConfigureFactory();
- // First server connection attempt fails.
- transaction_ids_.push_back(0); // Needed to make a DnsUDPAttempt.
- socket_factory_->fail_next_socket_ = true;
- // Second DNS query succeeds.
- AddAsyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
- kT0ResponseDatagram, std::size(kT0ResponseDatagram));
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsGetLookup) {
- ConfigureDohServers(false /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsGetFailure) {
- ConfigureDohServers(false /* use_post */);
- AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
- SYNCHRONOUS, Transport::HTTPS,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_DNS_SERVER_FAILED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- ASSERT_NE(helper0.response(), nullptr);
- EXPECT_EQ(helper0.response()->rcode(), dns_protocol::kRcodeSERVFAIL);
- }
- TEST_F(DnsTransactionTest, HttpsGetMalformed) {
- ConfigureDohServers(false /* use_post */);
- // Use T1 response, which is malformed for a T0 request.
- AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT1ResponseDatagram,
- std::size(kT1ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsPostLookup) {
- ConfigureDohServers(true /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsPostFailure) {
- ConfigureDohServers(true /* use_post */);
- AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
- SYNCHRONOUS, Transport::HTTPS,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_DNS_SERVER_FAILED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- ASSERT_NE(helper0.response(), nullptr);
- EXPECT_EQ(helper0.response()->rcode(), dns_protocol::kRcodeSERVFAIL);
- }
- TEST_F(DnsTransactionTest, HttpsPostMalformed) {
- ConfigureDohServers(true /* use_post */);
- // Use T1 response, which is malformed for a T0 request.
- AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT1ResponseDatagram,
- std::size(kT1ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsPostLookupAsync) {
- ConfigureDohServers(true /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- std::unique_ptr<URLRequestJob> DohJobMakerCallbackFailLookup(
- URLRequest* request,
- SocketDataProvider* data) {
- URLRequestMockDohJob::MatchQueryData(request, data);
- return std::make_unique<URLRequestFailedJob>(
- request, URLRequestFailedJob::START, ERR_NAME_NOT_RESOLVED);
- }
- TEST_F(DnsTransactionTest, HttpsPostLookupFailDohServerLookup) {
- ConfigureDohServers(true /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_DNS_SECURE_RESOLVER_HOSTNAME_RESOLUTION_FAILED);
- SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailLookup));
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- std::unique_ptr<URLRequestJob> DohJobMakerCallbackFailStart(
- URLRequest* request,
- SocketDataProvider* data) {
- URLRequestMockDohJob::MatchQueryData(request, data);
- return std::make_unique<URLRequestFailedJob>(
- request, URLRequestFailedJob::START, ERR_FAILED);
- }
- TEST_F(DnsTransactionTest, HttpsPostLookupFailStart) {
- ConfigureDohServers(true /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_FAILED);
- SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailStart));
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- std::unique_ptr<URLRequestJob> DohJobMakerCallbackFailSync(
- URLRequest* request,
- SocketDataProvider* data) {
- URLRequestMockDohJob::MatchQueryData(request, data);
- return std::make_unique<URLRequestFailedJob>(
- request, URLRequestFailedJob::READ_SYNC, ERR_FAILED);
- }
- TEST_F(DnsTransactionTest, HttpsPostLookupFailSync) {
- ConfigureDohServers(true /* use_post */);
- auto data = std::make_unique<DnsSocketData>(
- 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddResponseWithLength(std::make_unique<DnsResponse>(), SYNCHRONOUS, 0);
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
- SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailSync));
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- std::unique_ptr<URLRequestJob> DohJobMakerCallbackFailAsync(
- URLRequest* request,
- SocketDataProvider* data) {
- URLRequestMockDohJob::MatchQueryData(request, data);
- return std::make_unique<URLRequestFailedJob>(
- request, URLRequestFailedJob::READ_ASYNC, ERR_FAILED);
- }
- TEST_F(DnsTransactionTest, HttpsPostLookupFailAsync) {
- ConfigureDohServers(true /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
- SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailAsync));
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsPostLookup2Sync) {
- ConfigureDohServers(true /* use_post */);
- auto data = std::make_unique<DnsSocketData>(
- 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddResponseData(kT0ResponseDatagram, 20, SYNCHRONOUS);
- data->AddResponseData(kT0ResponseDatagram + 20,
- std::size(kT0ResponseDatagram) - 20, SYNCHRONOUS);
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsPostLookup2Async) {
- ConfigureDohServers(true /* use_post */);
- auto data = std::make_unique<DnsSocketData>(
- 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddResponseData(kT0ResponseDatagram, 20, ASYNC);
- data->AddResponseData(kT0ResponseDatagram + 20,
- std::size(kT0ResponseDatagram) - 20, ASYNC);
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsPostLookupAsyncWithAsyncZeroRead) {
- ConfigureDohServers(true /* use_post */);
- auto data = std::make_unique<DnsSocketData>(
- 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
- ASYNC);
- data->AddResponseData(kT0ResponseDatagram, 0, ASYNC);
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsPostLookupSyncWithAsyncZeroRead) {
- ConfigureDohServers(true /* use_post */);
- auto data = std::make_unique<DnsSocketData>(
- 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
- SYNCHRONOUS);
- data->AddResponseData(kT0ResponseDatagram, 0, ASYNC);
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsPostLookupAsyncThenSync) {
- ConfigureDohServers(true /* use_post */);
- auto data = std::make_unique<DnsSocketData>(
- 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddResponseData(kT0ResponseDatagram, 20, ASYNC);
- data->AddResponseData(kT0ResponseDatagram + 20,
- std::size(kT0ResponseDatagram) - 20, SYNCHRONOUS);
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsPostLookupAsyncThenSyncError) {
- ConfigureDohServers(true /* use_post */);
- auto data = std::make_unique<DnsSocketData>(
- 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddResponseData(kT0ResponseDatagram, 20, ASYNC);
- data->AddReadError(ERR_FAILED, SYNCHRONOUS);
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_FAILED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsPostLookupAsyncThenAsyncError) {
- ConfigureDohServers(true /* use_post */);
- auto data = std::make_unique<DnsSocketData>(
- 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddResponseData(kT0ResponseDatagram, 20, ASYNC);
- data->AddReadError(ERR_FAILED, ASYNC);
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_FAILED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsPostLookupSyncThenAsyncError) {
- ConfigureDohServers(true /* use_post */);
- auto data = std::make_unique<DnsSocketData>(
- 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddResponseData(kT0ResponseDatagram, 20, SYNCHRONOUS);
- data->AddReadError(ERR_FAILED, ASYNC);
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_FAILED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsPostLookupSyncThenSyncError) {
- ConfigureDohServers(true /* use_post */);
- auto data = std::make_unique<DnsSocketData>(
- 0, kT0HostName, kT0Qtype, SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddResponseData(kT0ResponseDatagram, 20, SYNCHRONOUS);
- data->AddReadError(ERR_FAILED, SYNCHRONOUS);
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_FAILED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsNotAvailable) {
- ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
- false /* make_available */);
- ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- TransactionHelper helper0(ERR_BLOCKED_BY_CLIENT);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, HttpsMarkHttpsBad) {
- config_.attempts = 1;
- ConfigureDohServers(true /* use_post */, 3);
- AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
- SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
- SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndErrorResponse(0 /* id */, kT0HostName, kT0Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndErrorResponse(0 /* id */, kT0HostName, kT0Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- TransactionHelper helper1(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- // UDP server 0 is our only UDP server, so it will be good. HTTPS
- // servers 0 and 1 failed and will be marked bad. HTTPS server 2 succeeded
- // so it will be good.
- // The expected order of the HTTPS servers is therefore 2, 0, then 1.
- {
- std::unique_ptr<DnsServerIterator> classic_itr =
- resolve_context_->GetClassicDnsIterator(session_->config(),
- session_.get());
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- EXPECT_TRUE(classic_itr->AttemptAvailable());
- EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 2u);
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
- }
- size_t kOrder0[] = {1, 2, 3};
- CheckServerOrder(kOrder0, std::size(kOrder0));
- helper1.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper1.RunUntilComplete();
- // UDP server 0 is still our only UDP server, so it will be good by
- // definition. HTTPS server 2 started out as good, so it was tried first and
- // failed. HTTPS server 0 then had the oldest failure so it would be the next
- // good server and then it failed so it's marked bad. Next attempt was HTTPS
- // server 1, which succeeded so it's good. The expected order of the HTTPS
- // servers is therefore 1, 2, then 0.
- {
- std::unique_ptr<DnsServerIterator> classic_itr =
- resolve_context_->GetClassicDnsIterator(session_->config(),
- session_.get());
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- EXPECT_EQ(classic_itr->GetNextAttemptIndex(), 0u);
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 2u);
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- size_t kOrder1[] = {
- 1, 2, 3, /* transaction0 */
- 3, 1, 2 /* transaction1 */
- };
- CheckServerOrder(kOrder1, std::size(kOrder1));
- }
- TEST_F(DnsTransactionTest, HttpsPostFailThenHTTPFallback) {
- ConfigureDohServers(true /* use_post */, 2);
- AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL, ASYNC,
- Transport::HTTPS,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- size_t kOrder0[] = {1, 2};
- CheckServerOrder(kOrder0, std::size(kOrder0));
- }
- TEST_F(DnsTransactionTest, HttpsPostFailTwice) {
- config_.attempts = 3;
- ConfigureDohServers(true /* use_post */, 2);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_FAILED);
- SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailStart));
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- size_t kOrder0[] = {1, 2};
- CheckServerOrder(kOrder0, std::size(kOrder0));
- }
- TEST_F(DnsTransactionTest, HttpsNotAvailableThenHttpFallback) {
- ConfigureDohServers(true /* use_post */, 2 /* num_doh_servers */,
- false /* make_available */);
- // Make just server 1 available.
- resolve_context_->RecordServerSuccess(
- 1u /* server_index */, true /* is_doh_server*/, session_.get());
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- }
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- size_t kOrder0[] = {2};
- CheckServerOrder(kOrder0, std::size(kOrder0));
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- }
- }
- // Fail first DoH server, then no fallbacks marked available in AUTOMATIC mode.
- TEST_F(DnsTransactionTest, HttpsFailureThenNotAvailable_Automatic) {
- config_.secure_dns_mode = SecureDnsMode::kAutomatic;
- ConfigureDohServers(true /* use_post */, 3 /* num_doh_servers */,
- false /* make_available */);
- // Make just server 0 available.
- resolve_context_->RecordServerSuccess(
- 0u /* server_index */, true /* is_doh_server*/, session_.get());
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- }
- AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
- SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_CONNECTION_REFUSED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- // Expect fallback not attempted because other servers not available in
- // AUTOMATIC mode until they have recorded a success.
- size_t kOrder0[] = {1};
- CheckServerOrder(kOrder0, std::size(kOrder0));
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- }
- }
- // Test a secure transaction failure in SECURE mode when other DoH servers are
- // only available for fallback because of
- TEST_F(DnsTransactionTest, HttpsFailureThenNotAvailable_Secure) {
- config_.secure_dns_mode = SecureDnsMode::kSecure;
- ConfigureDohServers(true /* use_post */, 3 /* num_doh_servers */,
- false /* make_available */);
- // Make just server 0 available.
- resolve_context_->RecordServerSuccess(
- 0u /* server_index */, true /* is_doh_server*/, session_.get());
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kSecure, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 1u);
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 2u);
- }
- AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
- SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
- SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
- SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_CONNECTION_REFUSED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- // Expect fallback to attempt all servers because SECURE mode does not require
- // server availability.
- size_t kOrder0[] = {1, 2, 3};
- CheckServerOrder(kOrder0, std::size(kOrder0));
- // Expect server 0 to be preferred due to least recent failure.
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kSecure, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- }
- TEST_F(DnsTransactionTest, MaxHttpsFailures_NonConsecutive) {
- config_.attempts = 1;
- ConfigureDohServers(false /* use_post */);
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit - 1; i++) {
- AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
- SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper failure(ERR_CONNECTION_REFUSED);
- failure.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- failure.RunUntilComplete();
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- // A success should reset the failure counter for DoH.
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper success(kT0RecordCount);
- success.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- success.RunUntilComplete();
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- // One more failure should not pass the threshold because failures were reset.
- AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
- SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper last_failure(ERR_CONNECTION_REFUSED);
- last_failure.StartTransaction(transaction_factory_.get(), kT0HostName,
- kT0Qtype, true /* secure */,
- resolve_context_.get());
- last_failure.RunUntilComplete();
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- }
- TEST_F(DnsTransactionTest, MaxHttpsFailures_Consecutive) {
- config_.attempts = 1;
- ConfigureDohServers(false /* use_post */);
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit - 1; i++) {
- AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
- SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper failure(ERR_CONNECTION_REFUSED);
- failure.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- failure.RunUntilComplete();
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- // One more failure should pass the threshold.
- AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
- SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper last_failure(ERR_CONNECTION_REFUSED);
- last_failure.StartTransaction(transaction_factory_.get(), kT0HostName,
- kT0Qtype, true /* secure */,
- resolve_context_.get());
- last_failure.RunUntilComplete();
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- }
- }
- // Test that a secure transaction started before a DoH server becomes
- // unavailable can complete and make the server available again.
- TEST_F(DnsTransactionTest, SuccessfulTransactionStartedBeforeUnavailable) {
- ConfigureDohServers(false /* use_post */);
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- // Create a socket data to first return ERR_IO_PENDING. This will pause the
- // response and not return the second response until
- // SequencedSocketData::Resume() is called.
- auto data = std::make_unique<DnsSocketData>(
- 0, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddReadError(ERR_IO_PENDING, ASYNC);
- data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
- ASYNC);
- SequencedSocketData* sequenced_socket_data = data->GetProvider();
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- TransactionHelper delayed_success(kT0RecordCount);
- delayed_success.StartTransaction(transaction_factory_.get(), kT0HostName,
- kT0Qtype, true /* secure */,
- resolve_context_.get());
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(delayed_success.has_completed());
- // Trigger DoH server unavailability with a bunch of failures.
- for (size_t i = 0; i < ResolveContext::kAutomaticModeFailureLimit; i++) {
- AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
- SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper failure(ERR_CONNECTION_REFUSED);
- failure.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- failure.RunUntilComplete();
- }
- EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- // Resume first query.
- ASSERT_FALSE(delayed_success.has_completed());
- sequenced_socket_data->Resume();
- delayed_success.RunUntilComplete();
- // Expect DoH server is available again.
- EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- }
- void MakeResponseWithCookie(URLRequest* request, HttpResponseInfo* info) {
- info->headers->AddHeader("Set-Cookie", "test-cookie=you-fail");
- }
- class CookieCallback {
- public:
- CookieCallback() : loop_to_quit_(std::make_unique<base::RunLoop>()) {}
- void SetCookieCallback(CookieAccessResult result) {
- result_ = result.status.IsInclude();
- loop_to_quit_->Quit();
- }
- CookieCallback(const CookieCallback&) = delete;
- CookieCallback& operator=(const CookieCallback&) = delete;
- void GetCookieListCallback(
- const net::CookieAccessResultList& list,
- const net::CookieAccessResultList& excluded_cookies) {
- list_ = cookie_util::StripAccessResults(list);
- loop_to_quit_->Quit();
- }
- void Reset() { loop_to_quit_ = std::make_unique<base::RunLoop>(); }
- void WaitUntilDone() { loop_to_quit_->Run(); }
- size_t cookie_list_size() { return list_.size(); }
- private:
- net::CookieList list_;
- bool result_ = false;
- std::unique_ptr<base::RunLoop> loop_to_quit_;
- };
- TEST_F(DnsTransactionTest, HttpsPostTestNoCookies) {
- ConfigureDohServers(true /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- TransactionHelper helper1(kT0RecordCount);
- SetResponseModifierCallback(base::BindRepeating(MakeResponseWithCookie));
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- CookieCallback callback;
- request_context_->cookie_store()->GetCookieListWithOptionsAsync(
- GURL(GetURLFromTemplateWithoutParameters(
- config_.doh_config.servers()[0].server_template())),
- CookieOptions::MakeAllInclusive(), CookiePartitionKeyCollection(),
- base::BindOnce(&CookieCallback::GetCookieListCallback,
- base::Unretained(&callback)));
- callback.WaitUntilDone();
- EXPECT_EQ(0u, callback.cookie_list_size());
- callback.Reset();
- GURL cookie_url(GetURLFromTemplateWithoutParameters(
- config_.doh_config.servers()[0].server_template()));
- auto cookie = CanonicalCookie::Create(
- cookie_url, "test-cookie=you-still-fail", base::Time::Now(),
- absl::nullopt /* server_time */,
- absl::nullopt /* cookie_partition_key */);
- request_context_->cookie_store()->SetCanonicalCookieAsync(
- std::move(cookie), cookie_url, CookieOptions(),
- base::BindOnce(&CookieCallback::SetCookieCallback,
- base::Unretained(&callback)));
- helper1.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper1.RunUntilComplete();
- }
- void MakeResponseWithoutLength(URLRequest* request, HttpResponseInfo* info) {
- info->headers->RemoveHeader("Content-Length");
- }
- TEST_F(DnsTransactionTest, HttpsPostNoContentLength) {
- ConfigureDohServers(true /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- SetResponseModifierCallback(base::BindRepeating(MakeResponseWithoutLength));
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- void MakeResponseWithBadRequestResponse(URLRequest* request,
- HttpResponseInfo* info) {
- info->headers->ReplaceStatusLine("HTTP/1.1 400 Bad Request");
- }
- TEST_F(DnsTransactionTest, HttpsPostWithBadRequestResponse) {
- ConfigureDohServers(true /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
- SetResponseModifierCallback(
- base::BindRepeating(MakeResponseWithBadRequestResponse));
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- void MakeResponseWrongType(URLRequest* request, HttpResponseInfo* info) {
- info->headers->RemoveHeader("Content-Type");
- info->headers->AddHeader("Content-Type", "text/html");
- }
- TEST_F(DnsTransactionTest, HttpsPostWithWrongType) {
- ConfigureDohServers(true /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
- SetResponseModifierCallback(base::BindRepeating(MakeResponseWrongType));
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- void MakeResponseRedirect(URLRequest* request, HttpResponseInfo* info) {
- if (request->url_chain().size() < 2) {
- info->headers->ReplaceStatusLine("HTTP/1.1 302 Found");
- info->headers->AddHeader("Location",
- "/redirect-destination?" + request->url().query());
- }
- }
- TEST_F(DnsTransactionTest, HttpsGetRedirect) {
- ConfigureDohServers(false /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- SetResponseModifierCallback(base::BindRepeating(MakeResponseRedirect));
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- void MakeResponseNoType(URLRequest* request, HttpResponseInfo* info) {
- info->headers->RemoveHeader("Content-Type");
- }
- TEST_F(DnsTransactionTest, HttpsPostWithNoType) {
- ConfigureDohServers(true /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
- SetResponseModifierCallback(base::BindRepeating(MakeResponseNoType));
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, CanLookupDohServerName) {
- config_.search.push_back("http");
- ConfigureDohServers(true /* use_post */);
- AddQueryAndErrorResponse(0, kMockHostname, dns_protocol::kTypeA,
- ERR_NAME_NOT_RESOLVED, SYNCHRONOUS, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
- helper0.StartTransaction(transaction_factory_.get(), "mock",
- dns_protocol::kTypeA, true /* secure */,
- resolve_context_.get());
- helper0.RunUntilComplete();
- }
- class CountingObserver : public net::NetLog::ThreadSafeObserver {
- public:
- CountingObserver() = default;
- ~CountingObserver() override {
- if (net_log())
- net_log()->RemoveObserver(this);
- }
- void OnAddEntry(const NetLogEntry& entry) override {
- ++count_;
- if (!entry.params.is_none() && entry.params.is_dict())
- dict_count_++;
- }
- int count() const { return count_; }
- int dict_count() const { return dict_count_; }
- private:
- int count_ = 0;
- int dict_count_ = 0;
- };
- // Flaky on MSAN. https://crbug.com/1245953
- #if defined(MEMORY_SANITIZER)
- #define MAYBE_HttpsPostLookupWithLog \
- DISABLED_HttpsPostLookupWithLog
- #else
- #define MAYBE_HttpsPostLookupWithLog \
- HttpsPostLookupWithLog
- #endif
- TEST_F(DnsTransactionTest, MAYBE_HttpsPostLookupWithLog) {
- ConfigureDohServers(true /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- CountingObserver observer;
- NetLog::Get()->AddObserver(&observer, NetLogCaptureMode::kEverything);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(observer.count(), 14);
- EXPECT_EQ(observer.dict_count(), 6);
- }
- // Test for when a slow DoH response is delayed until after the initial fallback
- // period (but succeeds before the full timeout period).
- TEST_F(DnsTransactionTestWithMockTime, SlowHttpsResponse_SingleAttempt) {
- config_.doh_attempts = 1;
- ConfigureDohServers(false /* use_post */);
- // Assume fallback period is less than timeout.
- ASSERT_LT(resolve_context_->NextDohFallbackPeriod(0 /* doh_server_index */,
- session_.get()),
- resolve_context_->SecureTransactionTimeout(SecureDnsMode::kSecure,
- session_.get()));
- // Simulate a slow response by using an ERR_IO_PENDING read error to delay
- // until SequencedSocketData::Resume() is called.
- auto data = std::make_unique<DnsSocketData>(
- 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddReadError(ERR_IO_PENDING, ASYNC);
- data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
- ASYNC);
- SequencedSocketData* sequenced_socket_data = data->GetProvider();
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- TransactionHelper helper(kT0RecordCount);
- std::unique_ptr<DnsTransaction> transaction =
- transaction_factory_->CreateTransaction(
- kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
- SecureDnsMode::kSecure, resolve_context_.get(),
- false /* fast_timeout */);
- helper.StartTransaction(std::move(transaction));
- base::RunLoop().RunUntilIdle();
- ASSERT_FALSE(helper.has_completed());
- FastForwardBy(resolve_context_->NextDohFallbackPeriod(
- 0 /* doh_server_index */, session_.get()));
- EXPECT_FALSE(helper.has_completed());
- sequenced_socket_data->Resume();
- helper.RunUntilComplete();
- }
- // Test for when a slow DoH response is delayed until after the initial fallback
- // period but fast timeout is enabled, resulting in timeout failure.
- TEST_F(DnsTransactionTestWithMockTime,
- SlowHttpsResponse_SingleAttempt_FastTimeout) {
- config_.doh_attempts = 1;
- ConfigureDohServers(false /* use_post */);
- AddHangingQuery(kT0HostName, kT0Qtype,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- TransactionHelper helper(ERR_DNS_TIMED_OUT);
- std::unique_ptr<DnsTransaction> transaction =
- transaction_factory_->CreateTransaction(
- kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
- SecureDnsMode::kSecure, resolve_context_.get(),
- true /* fast_timeout */);
- helper.StartTransaction(std::move(transaction));
- base::RunLoop().RunUntilIdle();
- ASSERT_FALSE(helper.has_completed());
- // Only one attempt configured and fast timeout enabled, so expect immediate
- // failure after fallback period.
- FastForwardBy(resolve_context_->NextDohFallbackPeriod(
- 0 /* doh_server_index */, session_.get()));
- EXPECT_TRUE(helper.has_completed());
- }
- // Test for when a slow DoH response is delayed until after the initial fallback
- // period but a retry is configured.
- TEST_F(DnsTransactionTestWithMockTime, SlowHttpsResponse_TwoAttempts) {
- config_.doh_attempts = 2;
- ConfigureDohServers(false /* use_post */);
- // Simulate a slow response by using an ERR_IO_PENDING read error to delay
- // until SequencedSocketData::Resume() is called.
- auto data = std::make_unique<DnsSocketData>(
- 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddReadError(ERR_IO_PENDING, ASYNC);
- data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
- ASYNC);
- SequencedSocketData* sequenced_socket_data = data->GetProvider();
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- TransactionHelper helper(kT0RecordCount);
- std::unique_ptr<DnsTransaction> transaction =
- transaction_factory_->CreateTransaction(
- kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
- SecureDnsMode::kSecure, resolve_context_.get(),
- false /* fast_timeout */);
- helper.StartTransaction(std::move(transaction));
- base::RunLoop().RunUntilIdle();
- ASSERT_FALSE(helper.has_completed());
- ASSERT_TRUE(sequenced_socket_data->IsPaused());
- // Another attempt configured, so transaction should not fail after initial
- // fallback period. Setup the second attempt to never receive a response.
- AddHangingQuery(kT0HostName, kT0Qtype,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- FastForwardBy(resolve_context_->NextDohFallbackPeriod(
- 0 /* doh_server_index */, session_.get()));
- EXPECT_FALSE(helper.has_completed());
- // Expect first attempt to continue in parallel with retry, so expect the
- // transaction to complete when the first query is allowed to resume.
- sequenced_socket_data->Resume();
- helper.RunUntilComplete();
- }
- // Test for when a slow DoH response is delayed until after the full timeout
- // period.
- TEST_F(DnsTransactionTestWithMockTime, HttpsTimeout) {
- config_.doh_attempts = 1;
- ConfigureDohServers(false /* use_post */);
- // Assume fallback period is less than timeout.
- ASSERT_LT(resolve_context_->NextDohFallbackPeriod(0 /* doh_server_index */,
- session_.get()),
- resolve_context_->SecureTransactionTimeout(SecureDnsMode::kSecure,
- session_.get()));
- AddHangingQuery(kT0HostName, kT0Qtype,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- TransactionHelper helper(ERR_DNS_TIMED_OUT);
- std::unique_ptr<DnsTransaction> transaction =
- transaction_factory_->CreateTransaction(
- kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
- SecureDnsMode::kSecure, resolve_context_.get(),
- false /* fast_timeout */);
- helper.StartTransaction(std::move(transaction));
- base::RunLoop().RunUntilIdle();
- ASSERT_FALSE(helper.has_completed());
- // Stop a tiny bit short to ensure transaction doesn't finish early.
- const base::TimeDelta kTimeHoldback = base::Milliseconds(5);
- base::TimeDelta timeout = resolve_context_->SecureTransactionTimeout(
- SecureDnsMode::kSecure, session_.get());
- ASSERT_LT(kTimeHoldback, timeout);
- FastForwardBy(timeout - kTimeHoldback);
- EXPECT_FALSE(helper.has_completed());
- FastForwardBy(kTimeHoldback);
- EXPECT_TRUE(helper.has_completed());
- }
- // Test for when two slow DoH responses are delayed until after the full timeout
- // period.
- TEST_F(DnsTransactionTestWithMockTime, HttpsTimeout2) {
- config_.doh_attempts = 2;
- ConfigureDohServers(false /* use_post */);
- // Assume fallback period is less than timeout.
- ASSERT_LT(resolve_context_->NextDohFallbackPeriod(0 /* doh_server_index */,
- session_.get()),
- resolve_context_->SecureTransactionTimeout(SecureDnsMode::kSecure,
- session_.get()));
- AddHangingQuery(kT0HostName, kT0Qtype,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- AddHangingQuery(kT0HostName, kT0Qtype,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- TransactionHelper helper(ERR_DNS_TIMED_OUT);
- std::unique_ptr<DnsTransaction> transaction =
- transaction_factory_->CreateTransaction(
- kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
- SecureDnsMode::kSecure, resolve_context_.get(),
- false /* fast_timeout */);
- helper.StartTransaction(std::move(transaction));
- base::RunLoop().RunUntilIdle();
- ASSERT_FALSE(helper.has_completed());
- base::TimeDelta fallback_period = resolve_context_->NextDohFallbackPeriod(
- 0 /* doh_server_index */, session_.get());
- FastForwardBy(fallback_period);
- EXPECT_FALSE(helper.has_completed());
- // Timeout is from start of transaction, so need to keep track of the
- // remainder after other fast forwards.
- base::TimeDelta timeout = resolve_context_->SecureTransactionTimeout(
- SecureDnsMode::kSecure, session_.get());
- base::TimeDelta timeout_remainder = timeout - fallback_period;
- // Fallback period for second attempt.
- fallback_period = resolve_context_->NextDohFallbackPeriod(
- 0 /* doh_server_index */, session_.get());
- ASSERT_LT(fallback_period, timeout_remainder);
- FastForwardBy(fallback_period);
- EXPECT_FALSE(helper.has_completed());
- timeout_remainder -= fallback_period;
- // Stop a tiny bit short to ensure transaction doesn't finish early.
- const base::TimeDelta kTimeHoldback = base::Milliseconds(5);
- ASSERT_LT(kTimeHoldback, timeout_remainder);
- FastForwardBy(timeout_remainder - kTimeHoldback);
- EXPECT_FALSE(helper.has_completed());
- FastForwardBy(kTimeHoldback);
- EXPECT_TRUE(helper.has_completed());
- }
- // Test for when attempt fallback periods go beyond the full timeout period.
- TEST_F(DnsTransactionTestWithMockTime, LongHttpsTimeouts) {
- const int kNumAttempts = 20;
- config_.doh_attempts = kNumAttempts;
- ConfigureDohServers(false /* use_post */);
- // Assume sum of fallback periods is greater than timeout.
- ASSERT_GT(kNumAttempts * resolve_context_->NextDohFallbackPeriod(
- 0 /* doh_server_index */, session_.get()),
- resolve_context_->SecureTransactionTimeout(SecureDnsMode::kSecure,
- session_.get()));
- for (int i = 0; i < kNumAttempts; ++i) {
- AddHangingQuery(kT0HostName, kT0Qtype,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- }
- TransactionHelper helper(ERR_DNS_TIMED_OUT);
- std::unique_ptr<DnsTransaction> transaction =
- transaction_factory_->CreateTransaction(
- kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
- SecureDnsMode::kSecure, resolve_context_.get(),
- false /* fast_timeout */);
- helper.StartTransaction(std::move(transaction));
- base::RunLoop().RunUntilIdle();
- ASSERT_FALSE(helper.has_completed());
- for (int i = 0; i < kNumAttempts - 1; ++i) {
- FastForwardBy(resolve_context_->NextDohFallbackPeriod(
- 0 /* doh_server_index */, session_.get()));
- EXPECT_FALSE(helper.has_completed());
- }
- // Expect transaction to time out immediately after the last fallback period.
- FastForwardBy(resolve_context_->NextDohFallbackPeriod(
- 0 /* doh_server_index */, session_.get()));
- EXPECT_TRUE(helper.has_completed());
- }
- // Test for when the last of multiple HTTPS attempts fails (SERVFAIL) before
- // a previous attempt succeeds.
- TEST_F(DnsTransactionTestWithMockTime, LastHttpsAttemptFails) {
- config_.doh_attempts = 2;
- ConfigureDohServers(false /* use_post */);
- // Simulate a slow response by using an ERR_IO_PENDING read error to delay
- // until SequencedSocketData::Resume() is called.
- auto data = std::make_unique<DnsSocketData>(
- 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddReadError(ERR_IO_PENDING, ASYNC);
- data->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
- ASYNC);
- SequencedSocketData* sequenced_socket_data = data->GetProvider();
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
- SYNCHRONOUS, Transport::HTTPS,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- TransactionHelper helper(kT0RecordCount);
- std::unique_ptr<DnsTransaction> transaction =
- transaction_factory_->CreateTransaction(
- kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
- SecureDnsMode::kSecure, resolve_context_.get(),
- false /* fast_timeout */);
- helper.StartTransaction(std::move(transaction));
- // Wait for one timeout period to start (and fail) the second attempt.
- FastForwardBy(resolve_context_->NextDohFallbackPeriod(
- 0 /* doh_server_index */, session_.get()));
- EXPECT_FALSE(helper.has_completed());
- // Complete the first attempt and expect immediate success.
- sequenced_socket_data->Resume();
- helper.RunUntilComplete();
- }
- // Test for when the last of multiple HTTPS attempts fails (SERVFAIL), and a
- // previous attempt never completes.
- TEST_F(DnsTransactionTestWithMockTime, LastHttpsAttemptFails_Timeout) {
- config_.doh_attempts = 2;
- ConfigureDohServers(false /* use_post */);
- AddHangingQuery(kT0HostName, kT0Qtype,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
- SYNCHRONOUS, Transport::HTTPS,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- TransactionHelper helper(ERR_DNS_TIMED_OUT);
- std::unique_ptr<DnsTransaction> transaction =
- transaction_factory_->CreateTransaction(
- kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
- SecureDnsMode::kSecure, resolve_context_.get(),
- false /* fast_timeout */);
- helper.StartTransaction(std::move(transaction));
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(helper.has_completed());
- // Second attempt fails immediately after first fallback period, but because
- // fast timeout is disabled, the transaction will attempt to wait for the
- // first attempt.
- base::TimeDelta fallback_period = resolve_context_->NextDohFallbackPeriod(
- 0 /* doh_server_index */, session_.get());
- FastForwardBy(fallback_period);
- EXPECT_FALSE(helper.has_completed());
- // Timeout is from start of transaction, so need to keep track of the
- // remainder after other fast forwards.
- base::TimeDelta timeout = resolve_context_->SecureTransactionTimeout(
- SecureDnsMode::kSecure, session_.get());
- base::TimeDelta timeout_remainder = timeout - fallback_period;
- // Stop a tiny bit short to ensure transaction doesn't finish early.
- const base::TimeDelta kTimeHoldback = base::Milliseconds(5);
- ASSERT_LT(kTimeHoldback, timeout_remainder);
- FastForwardBy(timeout_remainder - kTimeHoldback);
- EXPECT_FALSE(helper.has_completed());
- FastForwardBy(kTimeHoldback);
- EXPECT_TRUE(helper.has_completed());
- }
- // Test for when the last of multiple HTTPS attempts fails (SERVFAIL) before
- // a previous attempt can complete, but fast timeouts is enabled.
- TEST_F(DnsTransactionTestWithMockTime, LastHttpsAttemptFails_FastTimeout) {
- config_.doh_attempts = 2;
- ConfigureDohServers(false /* use_post */);
- AddHangingQuery(kT0HostName, kT0Qtype,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
- SYNCHRONOUS, Transport::HTTPS,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- TransactionHelper helper(ERR_DNS_SERVER_FAILED);
- std::unique_ptr<DnsTransaction> transaction =
- transaction_factory_->CreateTransaction(
- kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
- SecureDnsMode::kSecure, resolve_context_.get(),
- true /* fast_timeout */);
- helper.StartTransaction(std::move(transaction));
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(helper.has_completed());
- // With fast timeout enabled, expect the transaction to complete with failure
- // immediately on failure of the last transaction.
- FastForwardBy(resolve_context_->NextDohFallbackPeriod(
- 0 /* doh_server_index */, session_.get()));
- EXPECT_TRUE(helper.has_completed());
- }
- // Test for when the last of multiple HTTPS attempts fails (SERVFAIL) before
- // a previous attempt later fails as well.
- TEST_F(DnsTransactionTestWithMockTime, LastHttpsAttemptFailsFirst) {
- config_.doh_attempts = 2;
- ConfigureDohServers(false /* use_post */);
- // Simulate a slow response by using an ERR_IO_PENDING read error to delay
- // until SequencedSocketData::Resume() is called.
- auto data = std::make_unique<DnsSocketData>(
- 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddReadError(ERR_IO_PENDING, ASYNC);
- data->AddRcode(dns_protocol::kRcodeSERVFAIL, ASYNC);
- SequencedSocketData* sequenced_socket_data = data->GetProvider();
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
- SYNCHRONOUS, Transport::HTTPS,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- TransactionHelper helper(ERR_DNS_SERVER_FAILED);
- std::unique_ptr<DnsTransaction> transaction =
- transaction_factory_->CreateTransaction(
- kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
- SecureDnsMode::kSecure, resolve_context_.get(),
- false /* fast_timeout */);
- helper.StartTransaction(std::move(transaction));
- // Wait for one timeout period to start (and fail) the second attempt.
- FastForwardBy(resolve_context_->NextDohFallbackPeriod(
- 0 /* doh_server_index */, session_.get()));
- EXPECT_FALSE(helper.has_completed());
- // Complete the first attempt and expect immediate completion.
- sequenced_socket_data->Resume();
- helper.RunUntilComplete();
- }
- // Test for when multiple HTTPS attempts fail (SERVFAIL) in order, making the
- // last started attempt also the last attempt to be pending.
- TEST_F(DnsTransactionTestWithMockTime, LastHttpsAttemptFailsLast) {
- config_.doh_attempts = 2;
- ConfigureDohServers(false /* use_post */);
- AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
- SYNCHRONOUS, Transport::HTTPS,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL,
- SYNCHRONOUS, Transport::HTTPS,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128, 0 /* id */,
- false /* enqueue_transaction_id */);
- TransactionHelper helper(ERR_DNS_SERVER_FAILED);
- std::unique_ptr<DnsTransaction> transaction =
- transaction_factory_->CreateTransaction(
- kT0HostName, kT0Qtype, NetLogWithSource(), true /* secure */,
- SecureDnsMode::kSecure, resolve_context_.get(),
- false /* fast_timeout */);
- helper.StartTransaction(std::move(transaction));
- // Expect both attempts will run quickly without waiting for fallbacks or
- // transaction timeout.
- helper.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, TcpLookup_UdpRetry) {
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
- AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), ASYNC, Transport::TCP);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, TcpLookup_LowEntropy) {
- socket_factory_->diverse_source_ports_ = false;
- for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
- AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), ASYNC, Transport::UDP);
- }
- AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), ASYNC, Transport::TCP);
- for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
- TransactionHelper udp_helper(kT0RecordCount);
- udp_helper.StartTransaction(transaction_factory_.get(), kT0HostName,
- kT0Qtype, false /* secure */,
- resolve_context_.get());
- udp_helper.RunUntilComplete();
- }
- ASSERT_TRUE(session_->udp_tracker()->low_entropy());
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- EXPECT_TRUE(session_->udp_tracker()->low_entropy());
- }
- TEST_F(DnsTransactionTest, TCPFailure) {
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
- AddQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeSERVFAIL, ASYNC,
- Transport::TCP);
- TransactionHelper helper0(ERR_DNS_SERVER_FAILED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- ASSERT_NE(helper0.response(), nullptr);
- EXPECT_EQ(helper0.response()->rcode(), dns_protocol::kRcodeSERVFAIL);
- }
- TEST_F(DnsTransactionTest, TCPMalformed) {
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
- auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
- ASYNC, Transport::TCP);
- // Valid response but length too short.
- // This must be truncated in the question section. The DnsResponse doesn't
- // examine the answer section until asked to parse it, so truncating it in
- // the answer section would result in the DnsTransaction itself succeeding.
- data->AddResponseWithLength(
- std::make_unique<DnsResponse>(
- reinterpret_cast<const char*>(kT0ResponseDatagram),
- std::size(kT0ResponseDatagram), 0),
- ASYNC, static_cast<uint16_t>(kT0QuerySize - 1));
- AddSocketData(std::move(data));
- TransactionHelper helper0(ERR_DNS_MALFORMED_RESPONSE);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTestWithMockTime, TcpTimeout_UdpRetry) {
- ConfigureFactory();
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
- AddSocketData(std::make_unique<DnsSocketData>(
- 1 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::TCP));
- TransactionHelper helper0(ERR_DNS_TIMED_OUT);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(helper0.has_completed());
- FastForwardUntilNoTasksRemain();
- EXPECT_TRUE(helper0.has_completed());
- }
- TEST_F(DnsTransactionTestWithMockTime, TcpTimeout_LowEntropy) {
- ConfigureFactory();
- socket_factory_->diverse_source_ports_ = false;
- for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
- AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), ASYNC, Transport::UDP);
- }
- AddSocketData(std::make_unique<DnsSocketData>(
- 1 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::TCP));
- for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
- TransactionHelper udp_helper(kT0RecordCount);
- udp_helper.StartTransaction(transaction_factory_.get(), kT0HostName,
- kT0Qtype, false /* secure */,
- resolve_context_.get());
- udp_helper.RunUntilComplete();
- }
- ASSERT_TRUE(session_->udp_tracker()->low_entropy());
- TransactionHelper helper0(ERR_DNS_TIMED_OUT);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(helper0.has_completed());
- FastForwardUntilNoTasksRemain();
- EXPECT_TRUE(helper0.has_completed());
- }
- TEST_F(DnsTransactionTest, TCPReadReturnsZeroAsync) {
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
- auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
- ASYNC, Transport::TCP);
- // Return all but the last byte of the response.
- data->AddResponseWithLength(
- std::make_unique<DnsResponse>(
- reinterpret_cast<const char*>(kT0ResponseDatagram),
- std::size(kT0ResponseDatagram) - 1, 0),
- ASYNC, static_cast<uint16_t>(std::size(kT0ResponseDatagram)));
- // Then return a 0-length read.
- data->AddReadError(0, ASYNC);
- AddSocketData(std::move(data));
- TransactionHelper helper0(ERR_CONNECTION_CLOSED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, TCPReadReturnsZeroSynchronous) {
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
- auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
- ASYNC, Transport::TCP);
- // Return all but the last byte of the response.
- data->AddResponseWithLength(
- std::make_unique<DnsResponse>(
- reinterpret_cast<const char*>(kT0ResponseDatagram),
- std::size(kT0ResponseDatagram) - 1, 0),
- SYNCHRONOUS, static_cast<uint16_t>(std::size(kT0ResponseDatagram)));
- // Then return a 0-length read.
- data->AddReadError(0, SYNCHRONOUS);
- AddSocketData(std::move(data));
- TransactionHelper helper0(ERR_CONNECTION_CLOSED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, TCPConnectionClosedAsync) {
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
- auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
- ASYNC, Transport::TCP);
- data->AddReadError(ERR_CONNECTION_CLOSED, ASYNC);
- AddSocketData(std::move(data));
- TransactionHelper helper0(ERR_CONNECTION_CLOSED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, TCPConnectionClosedSynchronous) {
- AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
- dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
- auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
- ASYNC, Transport::TCP);
- data->AddReadError(ERR_CONNECTION_CLOSED, SYNCHRONOUS);
- AddSocketData(std::move(data));
- TransactionHelper helper0(ERR_CONNECTION_CLOSED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, MismatchedThenNxdomainThenTCP) {
- config_.attempts = 2;
- ConfigureFactory();
- auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
- SYNCHRONOUS, Transport::UDP);
- // First attempt gets a mismatched response.
- data->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
- SYNCHRONOUS);
- // Second read from first attempt gets TCP required.
- data->AddRcode(dns_protocol::kFlagTC, ASYNC);
- AddSocketData(std::move(data));
- // Second attempt gets NXDOMAIN, which happens before the TCP required.
- AddSyncQueryAndRcode(kT0HostName, kT0Qtype, dns_protocol::kRcodeNXDOMAIN);
- TransactionHelper helper0(ERR_NAME_NOT_RESOLVED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, MismatchedThenOkThenTCP) {
- config_.attempts = 2;
- ConfigureFactory();
- auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
- SYNCHRONOUS, Transport::UDP);
- // First attempt gets a mismatched response.
- data->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
- SYNCHRONOUS);
- // Second read from first attempt gets TCP required.
- data->AddRcode(dns_protocol::kFlagTC, ASYNC);
- AddSocketData(std::move(data));
- // Second attempt gets a valid response, which happens before the TCP
- // required.
- AddSyncQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype,
- kT0ResponseDatagram, std::size(kT0ResponseDatagram));
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, MismatchedThenRefusedThenTCP) {
- // Set up the expected sequence of events:
- // 1) First attempt (UDP) gets a synchronous mismatched response. On such
- // malformed responses, DnsTransaction triggers an immediate retry to read
- // again from the socket within the same "attempt".
- // 2) Second read (within the first attempt) starts. Test is configured to
- // give an asynchronous TCP required response which will complete later.
- // On asynchronous action after a malformed response, the attempt will
- // immediately produce a retriable error result while the retry continues,
- // thus forking the running attempts.
- // 3) Error result triggers a second attempt (UDP) which test gives a
- // synchronous ERR_CONNECTION_REFUSED, which is a retriable error, but
- // DnsTransaction has exhausted max retries (2 attempts), so this result
- // gets posted as the result of the transaction and other running attempts
- // should be cancelled.
- // 4) First attempt should be cancelled when the transaction result is posted,
- // so first attempt's second read should never complete. If it did
- // complete, it would complete with a TCP-required error, and
- // DnsTransaction would start a TCP attempt and clear previous attempts. It
- // would be very bad if that then cleared the attempt posted as the final
- // result, as result handling does not expect that memory to go away.
- config_.attempts = 2;
- ConfigureFactory();
- // Attempt 1.
- auto data = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName, kT0Qtype,
- SYNCHRONOUS, Transport::UDP);
- data->AddResponseData(kT1ResponseDatagram, std::size(kT1ResponseDatagram),
- SYNCHRONOUS);
- data->AddRcode(dns_protocol::kFlagTC, ASYNC);
- AddSocketData(std::move(data));
- // Attempt 2.
- AddQueryAndErrorResponse(0 /* id */, kT0HostName, kT0Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS, Transport::UDP);
- TransactionHelper helper0(ERR_CONNECTION_REFUSED);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- helper0.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, InvalidQuery) {
- ConfigureFactory();
- TransactionHelper helper0(ERR_INVALID_ARGUMENT);
- helper0.StartTransaction(transaction_factory_.get(), ".",
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper0.RunUntilComplete();
- TransactionHelper helper1(ERR_INVALID_ARGUMENT);
- helper1.StartTransaction(transaction_factory_.get(), "foo,bar.com",
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper1.RunUntilComplete();
- }
- TEST_F(DnsTransactionTest, CheckAsync) {
- ConfigureDohServers(false /* use_post */);
- AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- bool started = false;
- SetUrlRequestStartedCallback(
- base::BindLambdaForTesting([&] { started = true; }));
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- EXPECT_FALSE(started);
- EXPECT_FALSE(helper0.has_completed());
- helper0.RunUntilComplete();
- EXPECT_TRUE(started);
- }
- TEST_F(DnsTransactionTest, EarlyCancel) {
- ConfigureDohServers(false /* use_post */);
- TransactionHelper helper0(0);
- SetUrlRequestStartedCallback(base::BindRepeating([] { FAIL(); }));
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- EXPECT_FALSE(helper0.has_completed());
- helper0.Cancel();
- base::RunLoop().RunUntilIdle();
- }
- TEST_F(DnsTransactionTestWithMockTime, ProbeUntilSuccess) {
- ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
- false /* make_available */);
- AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- std::unique_ptr<DnsProbeRunner> runner =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- runner->Start(false /* network_change */);
- // The first probe happens without any delay.
- RunUntilIdle();
- std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- // Expect the server to still be unavailable after the second probe.
- FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- // Expect the server to be available after the successful third probe.
- FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- // Test that if a probe attempt hangs, additional probes will still run on
- // schedule
- TEST_F(DnsTransactionTestWithMockTime, HungProbe) {
- ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
- false /* make_available */);
- // Create a socket data to first return ERR_IO_PENDING. This will pause the
- // probe and not return the error until SequencedSocketData::Resume() is
- // called.
- auto data = std::make_unique<DnsSocketData>(
- 0 /* id */, kT4HostName, kT4Qtype, ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data->AddReadError(ERR_IO_PENDING, ASYNC);
- data->AddReadError(ERR_CONNECTION_REFUSED, ASYNC);
- data->AddResponseData(kT4ResponseDatagram, std::size(kT4ResponseDatagram),
- ASYNC);
- SequencedSocketData* sequenced_socket_data = data->GetProvider();
- AddSocketData(std::move(data), false /* enqueue_transaction_id */);
- // Add success for second probe.
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- std::unique_ptr<DnsProbeRunner> runner =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- runner->Start(false /* network_change */);
- // The first probe starts without any delay, but doesn't finish.
- RunUntilIdle();
- EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- // Second probe succeeds.
- FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
- EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- // Probe runner self-cancels on next cycle.
- FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
- EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
- // Expect no effect when the hung probe wakes up and fails.
- sequenced_socket_data->Resume();
- RunUntilIdle();
- EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
- }
- TEST_F(DnsTransactionTestWithMockTime, ProbeMultipleServers) {
- ConfigureDohServers(true /* use_post */, 2 /* num_doh_servers */,
- false /* make_available */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
- 1u /* doh_server_index */, session_.get()));
- std::unique_ptr<DnsProbeRunner> runner =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- runner->Start(true /* network_change */);
- // The first probes happens without any delay and succeeds for only one server
- RunUntilIdle();
- EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
- 1u /* doh_server_index */, session_.get()));
- // On second round of probing, probes for first server should self-cancel and
- // second server should become available.
- FastForwardBy(
- runner->GetDelayUntilNextProbeForTest(0u /* doh_server_index */));
- EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0u /* doh_server_index */),
- base::TimeDelta());
- FastForwardBy(
- runner->GetDelayUntilNextProbeForTest(1u /* doh_server_index */));
- EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
- 1u /* doh_server_index */, session_.get()));
- // Expect server 2 probes to self-cancel on next cycle.
- FastForwardBy(runner->GetDelayUntilNextProbeForTest(1u));
- EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(1u), base::TimeDelta());
- }
- TEST_F(DnsTransactionTestWithMockTime, MultipleProbeRunners) {
- ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
- false /* make_available */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- std::unique_ptr<DnsProbeRunner> runner1 =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- std::unique_ptr<DnsProbeRunner> runner2 =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- runner1->Start(true /* network_change */);
- runner2->Start(true /* network_change */);
- // The first two probes (one for each runner) happen without any delay
- // and mark the first server good.
- RunUntilIdle();
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- // Both probes expected to self-cancel on next scheduled run.
- FastForwardBy(runner1->GetDelayUntilNextProbeForTest(0));
- FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
- EXPECT_EQ(runner1->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
- EXPECT_EQ(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
- }
- TEST_F(DnsTransactionTestWithMockTime, MultipleProbeRunners_SeparateContexts) {
- // Each RequestContext uses its own transient IsolationInfo. Since there's
- // typically only one RequestContext per URLRequestContext, there's no
- // advantage in using the same IsolationInfo across RequestContexts.
- set_expect_multiple_isolation_infos(true);
- ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
- false /* make_available */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- auto request_context2 = CreateTestURLRequestContextBuilder()->Build();
- ResolveContext context2(request_context2.get(), false /* enable_caching */);
- context2.InvalidateCachesAndPerSessionData(session_.get(),
- false /* network_change */);
- std::unique_ptr<DnsProbeRunner> runner1 =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- std::unique_ptr<DnsProbeRunner> runner2 =
- transaction_factory_->CreateDohProbeRunner(&context2);
- runner1->Start(false /* network_change */);
- runner2->Start(false /* network_change */);
- // The first two probes (one for each runner) happen without any delay.
- // Probe for first context succeeds and second fails.
- RunUntilIdle();
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- {
- std::unique_ptr<DnsServerIterator> doh_itr2 = context2.GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- EXPECT_FALSE(doh_itr2->AttemptAvailable());
- }
- // First probe runner expected to be compete and self-cancel on next run.
- FastForwardBy(runner1->GetDelayUntilNextProbeForTest(0));
- EXPECT_EQ(runner1->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
- // Expect second runner to succeed on its second probe.
- FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
- {
- std::unique_ptr<DnsServerIterator> doh_itr2 = context2.GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr2->AttemptAvailable());
- EXPECT_EQ(doh_itr2->GetNextAttemptIndex(), 0u);
- }
- FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
- EXPECT_EQ(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
- }
- TEST_F(DnsTransactionTestWithMockTime, CancelDohProbeOnDestruction) {
- ConfigureDohServers(/*use_post=*/true, /*num_doh_servers=*/1,
- /*make_available=*/false);
- AddQueryAndErrorResponse(/*id=*/0, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, /*opt_rdata=*/nullptr,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- /*enqueue_transaction_id=*/false);
- AddQueryAndErrorResponse(/*id=*/0, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, /*opt_rdata=*/nullptr,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- /* enqueue_transaction_id=*/false);
- std::unique_ptr<DnsProbeRunner> runner =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- runner->Start(/*network_change=*/false);
- // The first probe happens without any delay.
- RunUntilIdle();
- std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- // Expect the server to still be unavailable after the second probe.
- FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- base::TimeDelta next_delay = runner->GetDelayUntilNextProbeForTest(0);
- runner.reset();
- // Server stays unavailable because probe canceled before (non-existent)
- // success. No success result is added, so this FastForward will cause a
- // failure if probes attempt to run.
- FastForwardBy(next_delay);
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- }
- TEST_F(DnsTransactionTestWithMockTime, CancelDohProbeOnContextDestruction) {
- ConfigureDohServers(/*use_post=*/true, /*num_doh_servers=*/1,
- /*make_available=*/false);
- AddQueryAndErrorResponse(/*id=*/0, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, /*opt_rdata=*/nullptr,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- /*enqueue_transaction_id=*/false);
- AddQueryAndErrorResponse(/*id=*/0, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, /*opt_rdata=*/nullptr,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- /* enqueue_transaction_id=*/false);
- std::unique_ptr<DnsProbeRunner> runner =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- runner->Start(/*network_change=*/false);
- // The first probe happens without any delay.
- RunUntilIdle();
- std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- // Expect the server to still be unavailable after the second probe.
- FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- base::TimeDelta next_delay = runner->GetDelayUntilNextProbeForTest(0);
- resolve_context_.reset();
- // The probe detects that the context no longer exists and stops running.
- FastForwardBy(next_delay);
- // There are no more probes to run.
- EXPECT_EQ(base::TimeDelta(), runner->GetDelayUntilNextProbeForTest(0));
- }
- TEST_F(DnsTransactionTestWithMockTime, CancelOneOfMultipleProbeRunners) {
- ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
- false /* make_available */);
- AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- std::unique_ptr<DnsProbeRunner> runner1 =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- std::unique_ptr<DnsProbeRunner> runner2 =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- runner1->Start(true /* network_change */);
- runner2->Start(true /* network_change */);
- // The first two probes (one for each runner) happen without any delay.
- RunUntilIdle();
- std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- EXPECT_GT(runner1->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
- EXPECT_GT(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
- // Cancel only one probe runner.
- runner1.reset();
- // Expect the server to be available after the successful third probe.
- FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- FastForwardBy(runner2->GetDelayUntilNextProbeForTest(0));
- EXPECT_EQ(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
- }
- TEST_F(DnsTransactionTestWithMockTime, CancelAllOfMultipleProbeRunners) {
- ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
- false /* make_available */);
- AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- std::unique_ptr<DnsProbeRunner> runner1 =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- std::unique_ptr<DnsProbeRunner> runner2 =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- runner1->Start(false /* network_change */);
- runner2->Start(false /* network_change */);
- // The first two probes (one for each runner) happen without any delay.
- RunUntilIdle();
- std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- EXPECT_GT(runner1->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
- EXPECT_GT(runner2->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
- base::TimeDelta next_delay = runner1->GetDelayUntilNextProbeForTest(0);
- runner1.reset();
- runner2.reset();
- // Server stays unavailable because probe canceled before (non-existent)
- // success. No success result is added, so this FastForward will cause a
- // failure if probes attempt to run.
- FastForwardBy(next_delay);
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- }
- TEST_F(DnsTransactionTestWithMockTime, CancelDohProbe_AfterSuccess) {
- ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
- false /* make_available */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- std::unique_ptr<DnsProbeRunner> runner =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- runner->Start(true /* network_change */);
- // The first probe happens without any delay, and immediately succeeds.
- RunUntilIdle();
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- runner.reset();
- // No change expected after cancellation.
- RunUntilIdle();
- {
- std::unique_ptr<DnsServerIterator> doh_itr =
- resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- ASSERT_TRUE(doh_itr->AttemptAvailable());
- EXPECT_EQ(doh_itr->GetNextAttemptIndex(), 0u);
- }
- }
- TEST_F(DnsTransactionTestWithMockTime, DestroyFactoryAfterStartingDohProbe) {
- ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
- false /* make_available */);
- AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- std::unique_ptr<DnsProbeRunner> runner =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- runner->Start(false /* network_change */);
- // The first probe happens without any delay.
- RunUntilIdle();
- std::unique_ptr<DnsServerIterator> doh_itr = resolve_context_->GetDohIterator(
- session_->config(), SecureDnsMode::kAutomatic, session_.get());
- EXPECT_FALSE(doh_itr->AttemptAvailable());
- // Destroy factory and session.
- transaction_factory_.reset();
- ASSERT_TRUE(session_->HasOneRef());
- session_.reset();
- // Probe should not encounter issues and should stop running.
- FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
- EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0), base::TimeDelta());
- }
- TEST_F(DnsTransactionTestWithMockTime, StartWhileRunning) {
- ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
- false /* make_available */);
- AddQueryAndErrorResponse(0 /* id */, kT4HostName, kT4Qtype,
- ERR_CONNECTION_REFUSED, SYNCHRONOUS,
- Transport::HTTPS, nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- std::unique_ptr<DnsProbeRunner> runner =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- runner->Start(false /* network_change */);
- // The first probe happens without any delay.
- RunUntilIdle();
- EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- // Extra Start() call should have no effect because runner is already running.
- runner->Start(true /* network_change */);
- RunUntilIdle();
- EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- // Expect the server to be available after the successful second probe.
- FastForwardBy(runner->GetDelayUntilNextProbeForTest(0));
- EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- }
- TEST_F(DnsTransactionTestWithMockTime, RestartFinishedProbe) {
- ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
- false /* make_available */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- std::unique_ptr<DnsProbeRunner> runner =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- runner->Start(true /* network_change */);
- // The first probe happens without any delay and succeeds.
- RunUntilIdle();
- EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- // Expect runner to self-cancel on next cycle.
- FastForwardBy(runner->GetDelayUntilNextProbeForTest(0u));
- EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0u), base::TimeDelta());
- // Mark server unavailabe and restart runner.
- for (int i = 0; i < ResolveContext::kAutomaticModeFailureLimit; ++i) {
- resolve_context_->RecordServerFailure(0u /* server_index */,
- true /* is_doh_server */, ERR_FAILED,
- session_.get());
- }
- ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- runner->Start(false /* network_change */);
- // Expect the server to be available again after a successful immediately-run
- // probe.
- RunUntilIdle();
- EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- // Expect self-cancel again.
- FastForwardBy(runner->GetDelayUntilNextProbeForTest(0u));
- EXPECT_EQ(runner->GetDelayUntilNextProbeForTest(0u), base::TimeDelta());
- }
- // Test that a probe runner keeps running on the same schedule if it completes
- // but the server is marked unavailable again before the next scheduled probe.
- TEST_F(DnsTransactionTestWithMockTime, FastProbeRestart) {
- ConfigureDohServers(true /* use_post */, 1 /* num_doh_servers */,
- false /* make_available */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- AddQueryAndResponse(0 /* id */, kT4HostName, kT4Qtype, kT4ResponseDatagram,
- std::size(kT4ResponseDatagram), ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */,
- DnsQuery::PaddingStrategy::BLOCK_LENGTH_128,
- false /* enqueue_transaction_id */);
- std::unique_ptr<DnsProbeRunner> runner =
- transaction_factory_->CreateDohProbeRunner(resolve_context_.get());
- runner->Start(true /* network_change */);
- // The first probe happens without any delay and succeeds.
- RunUntilIdle();
- EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- base::TimeDelta scheduled_delay = runner->GetDelayUntilNextProbeForTest(0);
- EXPECT_GT(scheduled_delay, base::TimeDelta());
- // Mark server unavailabe and restart runner. Note that restarting the runner
- // is unnecessary, but a Start() call should always happen on a server
- // becoming unavailable and might as well replecate real behavior for the
- // test.
- for (int i = 0; i < ResolveContext::kAutomaticModeFailureLimit; ++i) {
- resolve_context_->RecordServerFailure(0u /* server_index */,
- true /* is_doh_server */, ERR_FAILED,
- session_.get());
- }
- ASSERT_FALSE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- runner->Start(false /* network_change */);
- // Probe should not run until scheduled delay.
- RunUntilIdle();
- EXPECT_FALSE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- // Expect the probe to run again and succeed after scheduled delay.
- FastForwardBy(scheduled_delay);
- EXPECT_TRUE(resolve_context_->GetDohServerAvailability(
- 0u /* doh_server_index */, session_.get()));
- }
- // Test that queries cannot be sent when they contain a too-long name.
- // Tests against incorrect name length validation, which is anti-pattern #3 from
- // the "NAME:WRECK" report:
- // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
- TEST_F(DnsTransactionTestWithMockTime, RejectsQueryingLongNames) {
- std::string long_dotted_name;
- while (long_dotted_name.size() <= dns_protocol::kMaxNameLength) {
- long_dotted_name.append("naaaaaamelabel.");
- }
- long_dotted_name.append("test");
- TransactionHelper helper0(ERR_INVALID_ARGUMENT);
- helper0.StartTransaction(transaction_factory_.get(), long_dotted_name.c_str(),
- dns_protocol::kTypeA, false /* secure */,
- resolve_context_.get());
- helper0.RunUntilComplete();
- }
- // Test that ERR_CONNECTION_REFUSED error after fallback of DnsTCPAttempt
- // should not cause DCHECK failure (https://crbug.com/1334250).
- TEST_F(DnsTransactionTestWithMockTime, TcpConnectionRefusedAfterFallback) {
- ConfigureNumServers(2);
- ConfigureFactory();
- socket_factory_->diverse_source_ports_ = false;
- // Data for UDP attempts to set `low_entropy` flag.
- for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
- AddQueryAndResponse(0 /* id */, kT0HostName, kT0Qtype, kT0ResponseDatagram,
- std::size(kT0ResponseDatagram), ASYNC, Transport::UDP);
- }
- // Data for TCP attempt.
- auto data1 = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName,
- kT0Qtype, ASYNC, Transport::TCP);
- data1->AddReadError(ERR_IO_PENDING, ASYNC);
- data1->AddReadError(ERR_CONNECTION_REFUSED, ASYNC);
- SequencedSocketData* sequenced_socket_data1 = data1->GetProvider();
- AddSocketData(std::move(data1));
- auto data2 = std::make_unique<DnsSocketData>(0 /* id */, kT0HostName,
- kT0Qtype, ASYNC, Transport::TCP);
- data2->AddReadError(ERR_IO_PENDING, ASYNC);
- data2->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
- ASYNC);
- SequencedSocketData* sequenced_socket_data2 = data2->GetProvider();
- AddSocketData(std::move(data2));
- // DNS transactions for UDP attempts to set `low_entropy` flag.
- for (int i = 0; i <= DnsUdpTracker::kPortReuseThreshold; ++i) {
- TransactionHelper udp_helper(kT0RecordCount);
- udp_helper.StartTransaction(transaction_factory_.get(), kT0HostName,
- kT0Qtype, false /* secure */,
- resolve_context_.get());
- udp_helper.RunUntilComplete();
- }
- ASSERT_TRUE(session_->udp_tracker()->low_entropy());
- // DNS transactions for TCP attempt.
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- false /* secure */, resolve_context_.get());
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(helper0.has_completed());
- base::TimeDelta timeout = resolve_context_->NextClassicFallbackPeriod(
- 0 /* classic_server_index */, 0 /* attempt */, session_.get());
- FastForwardBy(timeout);
- // Resume the first query.
- sequenced_socket_data1->Resume();
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(helper0.has_completed());
- // Resume the second query.
- sequenced_socket_data2->Resume();
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(helper0.has_completed());
- }
- // Test that ERR_CONNECTION_REFUSED error after fallback of DnsHTTPAttempt
- // should not cause DCHECK failure (https://crbug.com/1334250).
- TEST_F(DnsTransactionTestWithMockTime, HttpsConnectionRefusedAfterFallback) {
- ConfigureDohServers(false /* use_post */, 2 /* num_doh_servers */,
- true /* make_available */);
- auto data1 = std::make_unique<DnsSocketData>(
- 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data1->AddReadError(ERR_IO_PENDING, ASYNC);
- data1->AddReadError(ERR_CONNECTION_REFUSED, ASYNC);
- SequencedSocketData* sequenced_socket_data1 = data1->GetProvider();
- AddSocketData(std::move(data1), false /* enqueue_transaction_id */);
- auto data2 = std::make_unique<DnsSocketData>(
- 0 /* id */, kT0HostName, kT0Qtype, ASYNC, Transport::HTTPS,
- nullptr /* opt_rdata */, DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
- data2->AddReadError(ERR_IO_PENDING, ASYNC);
- data2->AddResponseData(kT0ResponseDatagram, std::size(kT0ResponseDatagram),
- ASYNC);
- SequencedSocketData* sequenced_socket_data2 = data2->GetProvider();
- AddSocketData(std::move(data2), false /* enqueue_transaction_id */);
- TransactionHelper helper0(kT0RecordCount);
- helper0.StartTransaction(transaction_factory_.get(), kT0HostName, kT0Qtype,
- true /* secure */, resolve_context_.get());
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(helper0.has_completed());
- base::TimeDelta timeout = resolve_context_->NextDohFallbackPeriod(
- 0 /* doh_server_index */, session_.get());
- FastForwardBy(timeout);
- // Resume the first query.
- sequenced_socket_data1->Resume();
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(helper0.has_completed());
- // Resume the second query.
- sequenced_socket_data2->Resume();
- EXPECT_TRUE(helper0.has_completed());
- }
- } // namespace
- } // namespace net
|