--- /dev/null
+digraph {
+ graph [fontname = "monospace"];
+ node [fontname = "monospace"];
+ edge [fontname = "monospace"];
+
+ subgraph cluster_beginResolve {
+ label="SyncRes::beginResolve(const DNSName &qname, const QType &qtype, uint16_t qclass, vector<DNSRecord>&ret)\nreturns the RCODE\nret is filled with all relevant records";
+
+ beginResolve_doResolve [label="SyncRes::doResolve()", color=red];
+
+ "Is this an AXFR request?";
+ "Is this an AXFR request?" -> beginResolve_return_minus_1 [label=yes];
+ "Is this an AXFR request?" -> "Is qname+qclass+qtype 'special'?" [label=no];
+ "Is qname+qclass+qtype 'special'?" -> "Handle special names (version.bind, localhost)" [label=yes];
+ "Handle special names (version.bind, localhost)" -> beginResolve_return_0;
+
+ "Is qname+qclass+qtype 'special'?" -> "Is the qlass IN?" [label=no];
+ "Is the qlass IN?" -> beginResolve_return_minus_1 [label=no];
+ "Is the qlass IN?" -> beginResolve_doResolve [label=yes];
+ beginResolve_doResolve -> beginResolve_return_doResolve;
+ beginResolve_return_doResolve [label="return result from doResolve", color=green];
+ beginResolve_return_0 [label="return 0", color=green];
+ beginResolve_return_minus_1 [label="return -1", color=green];
+ }
+
+ subgraph cluster_doResolve {
+ label="SyncRes::doResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, set<GetBestNSAnswer>& beenthere)";
+
+ doResolve_doOOBResolve [label="SyncRes::doOOBResolve()", color=red];
+ doResolve_doCNAMECacheCheck [label="SyncRes::doCNAMECacheCheck()", color=red];
+ doResolve_asyncResolveWrapper [label="SyncRes::asyncResolveWrapper()", color=red];
+ doResolve_doCacheCheck [label="SyncRes::doCacheCheck()", color=red];
+ doResolve_getBestNSNamesFromCache [label="SyncRes::getBestNSNamesFromCache()", color=red];
+ doResolve_doResolveAt [label="SyncRes::doResolveAt()", color=red];
+
+ doResolve_return_res [label="return res", color=green];
+ doResolve_return_servfail [label="return SERVFAIL", color=green];
+
+ "SERVFAIL if too deep" -> "Check if called from getRootNS()";
+ "Check if called from getRootNS()" -> "Check if RD-bit was not set (d_cacheonly)" [label=yes];
+ "Check if called from getRootNS()" -> doResolve_getBestNSNamesFromCache [label=no];
+ "Check if RD-bit was not set (d_cacheonly)" -> doResolve_doCNAMECacheCheck [label=no];
+ "Check if RD-bit was not set (d_cacheonly)" -> "Check if there is a forward or auth-zone" [label=yes];
+ "Check if there is a forward or auth-zone" -> doResolve_doCNAMECacheCheck [label=no];
+ "Check if there is a forward or auth-zone" -> "Check if we are auth" [label=yes];
+ "Check if we are auth" -> doResolve_asyncResolveWrapper [label="no, so forward"];
+ "Check if we are auth" -> doResolve_doOOBResolve [label=yes];
+ doResolve_doOOBResolve -> "return res from doOOBResolve()";
+ "return res from doOOBResolve()" [color=green];
+ doResolve_asyncResolveWrapper -> "return result from asyncResolveWrapper()";
+ "return result from asyncResolveWrapper()" [color=green];
+ doResolve_doCNAMECacheCheck -> "Did doCNAMECacheCheck() return a true-ish value?";
+ "Did doCNAMECacheCheck() return a true-ish value?" -> doResolve_return_res [label=yes];
+ "Did doCNAMECacheCheck() return a true-ish value?" -> doResolve_doCacheCheck [label=no];
+ doResolve_doCacheCheck -> "did doCacheCheck() return a true-ish value?";
+ "did doCacheCheck() return a true-ish value?" -> doResolve_return_res [label=yes];
+ "did doCacheCheck() return a true-ish value?" -> doResolve_getBestNSNamesFromCache [label=no];
+
+ doResolve_getBestNSNamesFromCache -> doResolve_doResolveAt;
+ doResolve_doResolveAt -> doResolve_return_res [label="res == -2"];
+ doResolve_doResolveAt -> doResolve_return_servfail [label="res < 0 &&\nres != -2"];
+ doResolve_doResolveAt -> doResolve_return_res [label="res >= 0"];
+ }
+
+ subgraph cluster_doOOBResolve {
+ label="SyncRes::doOOBResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int& res)\nReturns true if data came from local auth-store.\nvector<DNSRecord> ret is filled with answers";
+
+ doOOBResolve_getBestAuthZone [label="SyncRes::getBestAuthZone()", color=red];
+ doOOBResolve_return_false [label="return false", color=green];
+ doOOBResolve_return_true [label="return true", color=green];
+
+ doOOBResolve_getBestAuthZone -> doOOBResolve_return_false [label="returned iterator to end of authstorage"];
+ doOOBResolve_getBestAuthZone -> "Add auth-records matching qname+qtype || CNAME || NS to ret" [label="returned iterator in the authstorage"];
+ "Add auth-records matching qname+qtype || CNAME || NS to ret" -> doOOBResolve_return_true [label="records were added to ret"]
+ "Add auth-records matching qname+qtype || CNAME || NS to ret" -> "Did we have any data for the qname?" [label="no records were added to ret"];
+
+ "Did we have any data for the qname?" -> "Add SOA to AUTHORITY in ret" [label="yes (empty NOERROR)"];
+ "Add SOA to AUTHORITY in ret" -> "Set res to NOERROR" -> doOOBResolve_return_true;
+
+ "Did we have any data for the qname?" -> "Is there a wildcard match?" [label=no];
+ "Is there a wildcard match?" -> "Add auth-records from wildcard to ret" [label=yes];
+ "Add auth-records from wildcard to ret" -> "Set res to NOERROR";
+
+ "Is there a wildcard match?" -> "Add NS-records from auth-zone" [label=no];
+
+ "Add NS-records from auth-zone" -> "Set res to NOERROR" [label="NS record were added"];
+ "Add NS-records from auth-zone" -> "Try to add SOA" [label="No NS record were added"];
+
+ "Try to add SOA" -> "Set res to NXDOMAIN" -> doOOBResolve_return_true;
+ }
+
+ subgraph cluster_asyncResolveWrapper {
+ label="SyncRes::asyncResolveWrapper()";
+ }
+
+ subgraph cluster_doResolveAt {
+ label="SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, set<GetBestNSAnswer>&beenthere)\nreturns -1 in case of no results, -2 when a FilterEngine Policy was hit, rcode otherwise";
+
+ doResolveAt_nameServersBlockedByRPZ [label="SyncRes::nameserversBlockedByRPZ()", color=red];
+ doResolveAt_doOOBResolve_for_NS [label="SyncRes::doOOBResolve()", color=red];
+ doResolveAt_retrieveAddressesForNS [label="SyncRes::retrieveAddressesForNS()", color=red];
+ doResolveAt_nameserverIPBlockedByRPZ [label="SyncRes::nameserverIPBlockedByRPZ()", color=red];
+ doResolveAt_Lua_preoutquery [label="Lua preoutquery", color=red];
+ doResolveAt_asyncresolveWrapper [label="SyncRes::asyncresolveWrapper()", color=red];
+ doResolveAt_processRecords [label="SyncRes::processRecords()", color=red];
+ doResolveAt_doResolve [label="SyncRes::doResolve()", color=red];
+
+ doResolveAt_return_minus_2 [label="return -2", color=green];
+ doResolveAt_return_minus_1 [label="return -1", color=green];
+ doResolveAt_return_0 [label="return 0", color=green];
+ doResolveAt_return_rcode [label="return rcode", color=green];
+ doResolveAt_return_servfail [label="return SERVFAIL", color=green];
+ doResolveAt_return_nxdomain [label="return NXDOMAIN", color=green];
+
+ doResolveAt_mainloop_continue [label="continue"];
+ doResolveAt_mainloop_continue -> "Get nameserver from nameservers";
+
+ doResolveAt_nsiploop_continue [label="continue"];
+ doResolveAt_nsiploop_continue -> "Get IP from IPs";
+
+ doResolveAt_nameServersBlockedByRPZ -> doResolveAt_return_minus_2 [label="RPZ NSDNAME hit"];
+ doResolveAt_nameServersBlockedByRPZ -> "Get nameserver from nameservers" [lhead=cluster_doResolveAt_mainloop, label="RPZ NSDNAME not hit"];
+
+ doResolveAt_ImmediateServFailException [label="throw ImmediateServFailException", color=green];
+
+ "Get nameserver from nameservers" -> doResolveAt_mainloop_continue [label="qname == nsname"];
+ "Get nameserver from nameservers" -> doResolveAt_return_minus_1 [label="All nameservers tried"];
+ "Get nameserver from nameservers" -> "Is the nameserver out of band?";
+ "Is the nameserver out of band?" -> doResolveAt_doOOBResolve_for_NS [label=yes];
+ doResolveAt_doOOBResolve_for_NS -> "updateCacheFromRecords()";
+ "Is the nameserver out of band?" -> doResolveAt_retrieveAddressesForNS [label=no];
+ doResolveAt_retrieveAddressesForNS -> doResolveAt_mainloop_continue [label="No IPs returned"];
+ doResolveAt_retrieveAddressesForNS -> doResolveAt_nameserverIPBlockedByRPZ [label="IPs returned"];
+ doResolveAt_nameserverIPBlockedByRPZ -> doResolveAt_return_minus_2 [label="RPZ NSIP hit"];
+ doResolveAt_nameserverIPBlockedByRPZ -> "Get IP from IPs" [label="RPZ NSIP not hit"];
+
+ "Get IP from IPs" -> doResolveAt_nsiploop_continue [label="IP is throttled"];
+ "Get IP from IPs" -> doResolveAt_ImmediateServFailException [label="Too many queries sent while resolving"];
+ "Get IP from IPs" -> doResolveAt_ImmediateServFailException [label="Resolving took too long"];
+ "Get IP from IPs" -> doResolveAt_mainloop_continue [label="No IP address worked"];
+ "Get IP from IPs" -> doResolveAt_Lua_preoutquery;
+
+ doResolveAt_Lua_preoutquery -> "Check resolveret" [label="true"];
+ doResolveAt_Lua_preoutquery -> doResolveAt_getEDNSSubnetMask [label="false"];
+ doResolveAt_getEDNSSubnetMask -> doResolveAt_asyncresolveWrapper;
+ doResolveAt_asyncresolveWrapper -> "Check resolveret";
+ "Check resolveret" -> doResolveAt_ImmediateServFailException [label="resolveret == -3\n(kill query)"];
+ "Check resolveret" -> "resolveret == 1";
+ "resolveret == 1" -> doResolveAt_nsiploop_continue [label="nameserver returned\nSERVFAIL || REFUSED"];
+ "resolveret == 1" -> "updateCacheFromRecords()";
+ "updateCacheFromRecords()" -> doResolveAt_return_rcode [label="rcode != NOERROR"]; // line 1473
+ "updateCacheFromRecords()" -> doResolveAt_processRecords; // line 1484
+ doResolveAt_processRecords -> doResolveAt_return_0 [label="done == true"];
+ doResolveAt_processRecords -> "Have newtarget?";
+
+ "Have newtarget?" -> "qname == newtarget || depth > 10?" [label=yes];
+ "qname == newtarget || depth > 10?" -> doResolveAt_return_servfail [label=yes];
+ "qname == newtarget || depth > 10?" -> doResolveAt_doResolve [label=no];
+ doResolveAt_doResolve -> doResolveAt_return_rcode;
+
+ "Have newtarget?" -> "Have NXDOMAIN from upstream?" [label=no];
+ "Have NXDOMAIN from upstream?" -> "Add NSECs if needed" [label=yes];
+ "Add NSECs if needed" -> doResolveAt_return_nxdomain;
+
+ "Have NXDOMAIN from upstream?" -> "Have empty NOERROR?" [label=no];
+ "Have empty NOERROR?" -> "Add NSEC records if needed" [label=yes];
+ "Add NSEC records if needed" -> doResolveAt_return_0;
+
+ "Have empty NOERROR?" -> "Have realreferral?" [label=no];
+ "Have realreferral?" -> "Was a server in nsset blocker by RPZNSDNAME?" [label=yes];
+ "Was a server in nsset blocker by RPZNSDNAME?" -> doResolveAt_return_minus_2 [label=yes];
+ "Was a server in nsset blocker by RPZNSDNAME?" -> "Get nameserver from nameservers" [label=no];
+
+ "Have realreferral?" -> "Was this an OOB nameserver?" [label=no];
+ "Was this an OOB nameserver?" -> "Get nameserver from nameservers" [label="no, nameserver was lame"];
+ "Was this an OOB nameserver?" -> "Get nameserver from nameservers" [label=yes];
+ }
+
+ subgraph cluster_processRecords {
+ label="SyncRes::processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, bool& sawDS)\nreturns true is this level of recursion is done";
+
+// { rank=same; "Get record from lwr.d_records" processRecords_return_done}
+
+// { rank=same; "Is this a proper CNAME referral?" "Is this a DNSSEC record in the ANSWER section?" "Is this the actual answer?" "Is this an NS record in the AUTHORITY?" "Is this a DS in the AUTHORITY?" "Is this a proper NXDOMAIN?" "Are we not done && is this a NOERROR && is this a SOA in the AUTHORITY?"}
+
+ "Get record from lwr.d_records";
+ "Get record from lwr.d_records" -> "Is this a proper NXDOMAIN?"; // line 1177
+ "Get record from lwr.d_records" -> processRecords_return_done [label="All records checked"];
+ "Get record from lwr.d_records" -> "Get record from lwr.d_records" [label="type != OPT &&\nclass != IN"];
+
+ "Is this a proper NXDOMAIN?" -> "is newtarget empty?" [label=yes]; // note, we have a CNAME chasing bug here issue #679
+ "is newtarget empty?" -> processRecords_wasVariable [label=no];
+ "is newtarget empty?" -> "Add this SOA to ret" [label=yes];
+ processRecords_wasVariable [label="SyncRes::wasVariable", color=red]
+ "Add this SOA to ret" -> processRecords_wasVariable;
+ processRecords_wasVariable -> "Set negindic to true" [label="was indeed variable"];
+ processRecords_wasVariable -> "Add to negative cache" [label="was not variable"];
+ "Add to negative cache" -> "If s_rootNXTrust && auth.isRoot()";
+ "If s_rootNXTrust && auth.isRoot()" -> "Set negindic to true" [label=no];
+ "If s_rootNXTrust && auth.isRoot()" -> "Add tld label to negative cache" [label=yes];
+ "Add tld label to negative cache" -> "Set negindic to true";
+ "Set negindic to true" -> "Get record from lwr.d_records";
+
+ "Is this a proper NXDOMAIN?" -> "Is this a proper CNAME referral?" [label=no];
+ "Is this a proper CNAME referral?" -> "Add CNAME record to ret" [label=yes];
+ "Add CNAME record to ret" -> "Set newtarget to this CNAME" -> "Get record from lwr.d_records";
+
+ "Is this a proper CNAME referral?" -> "Is this a DNSSEC record in the ANSWER section?" [label=no];
+ "Is this a DNSSEC record in the ANSWER section?" -> "Is the record.qtype not RRSIG and is the record's qname the qname we want?"[label=yes];
+ "Is the record.qtype not RRSIG and is the record's qname the qname we want?" -> "Add this record to ret" [label=yes];
+ "Add this record to ret" -> "Get record from lwr.d_records";
+ "Is the record.qtype not RRSIG and is the record's qname the qname we want?" -> "Get record from lwr.d_records" [label=no];
+
+ "Is this a DNSSEC record in the ANSWER section?" -> "Is this the actual answer?" [label=no];
+ "Is this the actual answer?" -> "Set done=true" [label=yes];
+ "Set done=true" -> "Add answer record to ret" -> "Get record from lwr.d_records";
+
+ "Is this the actual answer?" -> "Is this an NS record in the AUTHORITY?" [label=no];
+ "Is this an NS record in the AUTHORITY?" -> "Is record.d_name more specific than the our current auth?" [label=yes];
+ "Is record.d_name more specific than the our current auth?" -> "set newauth to record.d_name" [label=yes];
+ "set newauth to record.d_name" -> "set realreferral=true" -> "add NS record to ret";
+ "Is record.d_name more specific than the our current auth?" -> "add NS record to ret" [label=no];
+ "add NS record to ret" -> "Get record from lwr.d_records";
+
+ "Is this an NS record in the AUTHORITY?" -> "Is this a DS in the AUTHORITY?" [label=no];
+ "Is this a DS in the AUTHORITY?" -> "set sawDS=true" [label=yes];
+ "set sawDS=true" -> "Get record from lwr.d_records";
+
+ "Is this a DS in the AUTHORITY?" -> "Are we not done && is this a NOERROR && is this a SOA in the AUTHORITY?" [label=no];
+ "Are we not done && is this a NOERROR && is this a SOA in the AUTHORITY?" -> "is newtarget empty?" [label=yes];
+ "is newtarget empty?" -> "Harvest DNSSEC data and add to negative cache" [label=yes];
+ "is newtarget empty?" -> "Get record from lwr.d_records";
+ "Harvest DNSSEC data and add to negative cache" -> "Set negindic to true" -> "Get record from lwr.d_records";
+
+ "Are we not done && is this a NOERROR && is this a SOA in the AUTHORITY?" -> "Get record from lwr.d_records" [label=no];
+
+ processRecords_return_done [label="return done", color=green];
+ }
+
+ subgraph cluster_doCNAMECacheCheck {
+ label="SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>& ret, unsigned int depth, int &res)\nreturns true if this function handled the query";
+
+ doCNAMECacheCheck_return_true [label="return true", color=green];
+ doCNAMECacheCheck_return_false [label="return false", color=green];
+
+ doCNAMECacheCheck_servfail [label="Set res to SERVFAIL"];
+ doCNAMECacheCheck_servfail -> doCNAMECacheCheck_return_true;
+
+ doCNAMECacheCheck_doResolve [label="SyncRes::doResolve", color=red];
+
+ "Too deep recursion or CNAMEs?" -> doCNAMECacheCheck_servfail [label=yes];
+ "Too deep recursion or CNAMEs?" -> "Get cache entries for qname|CNAME" [label=no];
+ "Get cache entries for qname|CNAME" -> "get a record from the cache entries" -> "Is the TTL not expired?";
+ "Is the TTL not expired?" -> "get a record from the cache entries" [label=yes];
+ "Is the TTL not expired?" -> "Add record and RRSIGS to ret" [label=no];
+ "Add record and RRSIGS to ret" -> "is qtype CNAME?";
+ "is qtype CNAME?" -> doCNAMECacheCheck_doResolve [label=no];
+ doCNAMECacheCheck_doResolve -> "Set res to the result of doResolve" -> doCNAMECacheCheck_return_true;
+ "is qtype CNAME?" -> "Set res=0" [label=yes];
+ "Set res=0" -> doCNAMECacheCheck_return_true;
+ "Get cache entries for qname|CNAME" -> doCNAMECacheCheck_return_false [label="No cache entries"];
+ }
+}