ZealOS/docs/Home/Net/Protocols/DNS.ZC.html
2021-12-11 06:10:58 -05:00

747 lines
62 KiB
HTML
Executable file

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=US-ASCII">
<meta name="generator" content="ZealOS V1.07">
<style type="text/css">
body {background-color:#1f1f1f;}
.cF0{color:#e3e3e3;background-color:#1f1f1f;}
.cF1{color:#4f84a6;background-color:#1f1f1f;}
.cF2{color:#73a255;background-color:#1f1f1f;}
.cF3{color:#297582;background-color:#1f1f1f;}
.cF4{color:#b34f4b;background-color:#1f1f1f;}
.cF5{color:#8a52c3;background-color:#1f1f1f;}
.cF6{color:#b7822f;background-color:#1f1f1f;}
.cF7{color:#444444;background-color:#1f1f1f;}
.cF8{color:#6d6d6d;background-color:#1f1f1f;}
.cF9{color:#94bfde;background-color:#1f1f1f;}
.cFA{color:#a1ce97;background-color:#1f1f1f;}
.cFB{color:#6db4be;background-color:#1f1f1f;}
.cFC{color:#e88e88;background-color:#1f1f1f;}
.cFD{color:#ca94e8;background-color:#1f1f1f;}
.cFE{color:#d4b475;background-color:#1f1f1f;}
.cFF{color:#1f1f1f;background-color:#1f1f1f;}
</style>
</head>
<body>
<pre style="font-family:monospace;font-size:12pt">
<a name="l1"></a><span class=cF2>// https://www2.cs.duke.edu/courses/fall16/compsci356/DNS/DNS-primer.pdf</span><span class=cF0>
<a name="l2"></a></span><span class=cF2>// https://en.wikipedia.org/wiki/Domain_Name_System</span><span class=cF0>
<a name="l3"></a>
<a name="l4"></a></span><span class=cF2>// DNS Cache is a HashTable, similar to ARP Cache</span><span class=cF0>
<a name="l5"></a>
<a name="l6"></a>#</span><span class=cF1>define</span><span class=cF0> DNS_HASHTABLE_SIZE </span><span class=cFE>2048</span><span class=cF0> </span><span class=cF2>// 1024 might be fine, test it</span><span class=cF0>
<a name="l7"></a>#</span><span class=cF1>define</span><span class=cF0> HTT_DNS </span><span class=cFE>0x00100</span><span class=cF0> </span><span class=cF2>// identical to HTT_DICT_WORD</span><span class=cF0>
<a name="l8"></a>
<a name="l9"></a>#</span><span class=cF1>define</span><span class=cF0> DNS_FLAG_RD </span><span class=cFE>0x0100</span><span class=cF0>
<a name="l10"></a>
<a name="l11"></a>#</span><span class=cF1>define</span><span class=cF0> DNS_OP_QUERY </span><span class=cFE>0</span><span class=cF0>
<a name="l12"></a>
<a name="l13"></a>#</span><span class=cF1>define</span><span class=cF0> DNS_TYPE_A </span><span class=cFE>1</span><span class=cF0>
<a name="l14"></a>
<a name="l15"></a>#</span><span class=cF1>define</span><span class=cF0> DNS_CLASS_IN </span><span class=cFE>1</span><span class=cF0>
<a name="l16"></a>
<a name="l17"></a>#</span><span class=cF1>define</span><span class=cF0> DNS_TIMEOUT </span><span class=cFE>5000</span><span class=cF0>
<a name="l18"></a>
<a name="l19"></a>#</span><span class=cF1>define</span><span class=cF0> DNS_MAX_RETRIES </span><span class=cFE>5</span><span class=cF0>
<a name="l20"></a>
<a name="l21"></a></span><span class=cF1>class</span><span class=cF0> CDNSHash:</span><span class=cF9>CHash</span><span class=cF0>
<a name="l22"></a>{ </span><span class=cF2>// store U8 *hostname as CHash-&gt;str U8 *</span><span class=cF0>
<a name="l23"></a> CAddressInfo info;
<a name="l24"></a> </span><span class=cF2>// Shrine has 'TODO: honor TTL' ...</span><span class=cF0>
<a name="l25"></a> </span><span class=cF2>// Duke: 'TTL: the number of seconds the results can be cached'</span><span class=cF0>
<a name="l26"></a> </span><span class=cF2>// perhaps have a separate task for removing cached results ?</span><span class=cF0>
<a name="l27"></a>};
<a name="l28"></a>
<a name="l29"></a></span><span class=cF1>class</span><span class=cF0> CDNSDomainName
<a name="l30"></a>{
<a name="l31"></a> </span><span class=cF1>U8</span><span class=cF0> **labels;
<a name="l32"></a> </span><span class=cF9>I64</span><span class=cF0> num_labels;
<a name="l33"></a>};
<a name="l34"></a>
<a name="l35"></a></span><span class=cF1>class</span><span class=cF0> CDNSQuestion
<a name="l36"></a>{
<a name="l37"></a> CDNSQuestion *next;
<a name="l38"></a> CDNSDomainName q_name;
<a name="l39"></a> </span><span class=cF9>U16</span><span class=cF0> q_type;
<a name="l40"></a> </span><span class=cF9>U16</span><span class=cF0> q_class;
<a name="l41"></a>};
<a name="l42"></a>
<a name="l43"></a></span><span class=cF1>class</span><span class=cF0> CDNSHeader
<a name="l44"></a>{
<a name="l45"></a> </span><span class=cF9>U16</span><span class=cF0> id;
<a name="l46"></a> </span><span class=cF9>U16</span><span class=cF0> flags;
<a name="l47"></a> </span><span class=cF9>U16</span><span class=cF0> q_count; </span><span class=cF2>// number of entries in question section</span><span class=cF0>
<a name="l48"></a> </span><span class=cF9>U16</span><span class=cF0> a_count; </span><span class=cF2>// number of resource records in answer section</span><span class=cF0>
<a name="l49"></a> </span><span class=cF9>U16</span><span class=cF0> ns_count; </span><span class=cF2>// number of name server resource records in authority records section</span><span class=cF0>
<a name="l50"></a> </span><span class=cF9>U16</span><span class=cF0> ar_count; </span><span class=cF2>// number of resource records in additional records section</span><span class=cF0>
<a name="l51"></a>};
<a name="l52"></a>
<a name="l53"></a></span><span class=cF1>class</span><span class=cF0> CDNSRR
<a name="l54"></a>{ </span><span class=cF2>// RR: Resource Record</span><span class=cF0>
<a name="l55"></a> CDNSRR *next;
<a name="l56"></a> CDNSDomainName name; </span><span class=cF2>// name of the node this record is for</span><span class=cF0>
<a name="l57"></a> </span><span class=cF9>U16</span><span class=cF0> type; </span><span class=cF2>// RR type, e.g. 44=SSHFP, 15=MX, 49=DHCID ...</span><span class=cF0>
<a name="l58"></a> </span><span class=cF9>U16</span><span class=cF0> rr_class; </span><span class=cF2>// class code</span><span class=cF0>
<a name="l59"></a> </span><span class=cF9>U32</span><span class=cF0> ttl; </span><span class=cF2>// count in seconds that RR stays valid (max = 2^31 - 1)</span><span class=cF0>
<a name="l60"></a> </span><span class=cF9>U16</span><span class=cF0> rd_length; </span><span class=cF2>// length of r_data member</span><span class=cF0>
<a name="l61"></a> </span><span class=cF1>U8</span><span class=cF0> *r_data; </span><span class=cF2>// additional RR-specific data</span><span class=cF0>
<a name="l62"></a>};
<a name="l63"></a>
<a name="l64"></a></span><span class=cF1>class</span><span class=cF0> CDNSGlobals
<a name="l65"></a>{
<a name="l66"></a> </span><span class=cF9>U16</span><span class=cF0> addr_family;
<a name="l67"></a> CIPAddressStorage dns_ip;
<a name="l68"></a>
<a name="l69"></a>} dns_globals;
<a name="l70"></a>
<a name="l71"></a></span><span class=cF9>CHashTable</span><span class=cF0> *dns_cache = </span><span class=cF3>NULL</span><span class=cF0>;
<a name="l72"></a>
<a name="l73"></a></span><span class=cF1>U0</span><span class=cF0> DNSCacheInit()
<a name="l74"></a>{
<a name="l75"></a> dns_cache = </span><span class=cF5>HashTableNew</span><span class=cF0>(DNS_HASHTABLE_SIZE);
<a name="l76"></a>
<a name="l77"></a> </span><span class=cF5>MemSet</span><span class=cF0>(&amp;dns_globals.dns_ip, </span><span class=cFE>0</span><span class=cF0>, </span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CIPAddressStorage</span><span class=cF7>)</span><span class=cF0>);
<a name="l78"></a> dns_globals.addr_family = </span><span class=cFE>0</span><span class=cF0>;
<a name="l79"></a>}
<a name="l80"></a>
<a name="l81"></a>CDNSHash *DNSCacheFind(</span><span class=cF1>U8</span><span class=cF0> *hostname)
<a name="l82"></a>{
<a name="l83"></a> CDNSHash *entry = </span><span class=cF5>HashFind</span><span class=cF0>(hostname, dns_cache, HTT_DNS);
<a name="l84"></a>
<a name="l85"></a> </span><span class=cF1>if</span><span class=cF0> (entry == </span><span class=cF3>NULL</span><span class=cF0>)
<a name="l86"></a> NetWarn(</span><span class=cF6>&quot;DNS CACHE FIND: Could not find a hostname in the DNS Cache.&quot;</span><span class=cF0>);
<a name="l87"></a>
<a name="l88"></a> </span><span class=cF1>return</span><span class=cF0> entry;
<a name="l89"></a>}
<a name="l90"></a>
<a name="l91"></a>CDNSHash *DNSCachePut(</span><span class=cF1>U8</span><span class=cF0> *hostname, CAddressInfo *info)
<a name="l92"></a>{
<a name="l93"></a> NetLog(</span><span class=cF6>&quot;DNS CACHE PUT: Attempting Find DNS Entry in Cache: hostname: %s&quot;</span><span class=cF0>, hostname);
<a name="l94"></a> CDNSHash *entry = DNSCacheFind(hostname);
<a name="l95"></a>
<a name="l96"></a> </span><span class=cF1>if</span><span class=cF0> (!entry)
<a name="l97"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l98"></a> entry = </span><span class=cF5>CAlloc</span><span class=cF0>(</span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CDNSHash</span><span class=cF7>)</span><span class=cF0>);
<a name="l99"></a> entry-&gt;str = </span><span class=cF5>StrNew</span><span class=cF0>(hostname);
<a name="l100"></a> entry-&gt;type = HTT_DNS;
<a name="l101"></a>
<a name="l102"></a> AddressInfoCopy(&amp;entry-&gt;info, info);
<a name="l103"></a>
<a name="l104"></a> </span><span class=cF5>HashAdd</span><span class=cF0>(entry, dns_cache);
<a name="l105"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l106"></a> </span><span class=cF1>else</span><span class=cF0>
<a name="l107"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l108"></a> NetWarn(</span><span class=cF6>&quot;DNS CACHE PUT: Entry was already found in Cache. Overwriting.&quot;</span><span class=cF0>);
<a name="l109"></a> </span><span class=cF5>Free</span><span class=cF0>(entry-&gt;info.address);
<a name="l110"></a> AddressInfoCopy(&amp;entry-&gt;info, info);
<a name="l111"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l112"></a>
<a name="l113"></a> </span><span class=cF1>return</span><span class=cF0> entry;
<a name="l114"></a>}
<a name="l115"></a>
<a name="l116"></a></span><span class=cF9>I64</span><span class=cF0> DNSQuestionSizeCalculate(CDNSQuestion *q)
<a name="l117"></a>{ </span><span class=cF2>// ??</span><span class=cF0>
<a name="l118"></a> </span><span class=cF9>I64</span><span class=cF0> i, size = </span><span class=cFE>0</span><span class=cF0>;
<a name="l119"></a>
<a name="l120"></a> </span><span class=cF1>for</span><span class=cF0> (i = </span><span class=cFE>0</span><span class=cF0>; i &lt; q-&gt;q_name.num_labels; i++)
<a name="l121"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l122"></a> size += </span><span class=cFE>1</span><span class=cF0> + </span><span class=cF5>StrLen</span><span class=cF0>(q-&gt;q_name.labels[i]);
<a name="l123"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l124"></a>
<a name="l125"></a> </span><span class=cF1>return</span><span class=cF0> size + </span><span class=cFE>1</span><span class=cF0> + </span><span class=cFE>4</span><span class=cF0>;
<a name="l126"></a>}
<a name="l127"></a>
<a name="l128"></a></span><span class=cF1>U0</span><span class=cF0> DNSQuestionSerialize(</span><span class=cF1>U8</span><span class=cF0> *buffer, CDNSQuestion *q)
<a name="l129"></a>{ </span><span class=cF2>// ??</span><span class=cF0>
<a name="l130"></a> </span><span class=cF9>I64</span><span class=cF0> i;
<a name="l131"></a> </span><span class=cF1>U8</span><span class=cF0> *label;
<a name="l132"></a>
<a name="l133"></a> </span><span class=cF1>for</span><span class=cF0> (i = </span><span class=cFE>0</span><span class=cF0>; i &lt; q-&gt;q_name.num_labels; i++)
<a name="l134"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l135"></a> label = q-&gt;q_name.labels[i];
<a name="l136"></a>
<a name="l137"></a> *buffer++ = </span><span class=cF5>StrLen</span><span class=cF0>(label);
<a name="l138"></a>
<a name="l139"></a> </span><span class=cF1>while</span><span class=cF0> (*label)
<a name="l140"></a> *buffer++ = *label++;
<a name="l141"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l142"></a>
<a name="l143"></a> *buffer++ = </span><span class=cFE>0</span><span class=cF0>;
<a name="l144"></a> *buffer++ = q-&gt;q_type &gt;&gt; </span><span class=cFE>8</span><span class=cF0>;
<a name="l145"></a> *buffer++ = q-&gt;q_type &amp; </span><span class=cFE>0xFF</span><span class=cF0>;
<a name="l146"></a> *buffer++ = q-&gt;q_class &gt;&gt; </span><span class=cFE>8</span><span class=cF0>;
<a name="l147"></a> *buffer++ = q-&gt;q_class &amp; </span><span class=cFE>0xFF</span><span class=cF0>;
<a name="l148"></a>}
<a name="l149"></a>
<a name="l150"></a></span><span class=cF9>I64</span><span class=cF0> DNSQuestionSend(</span><span class=cF9>U16</span><span class=cF0> id, </span><span class=cF9>U16</span><span class=cF0> local_port, CDNSQuestion *q)
<a name="l151"></a>{
<a name="l152"></a> CIPV4Address *ipv4_addr;
<a name="l153"></a> </span><span class=cF1>U8</span><span class=cF0> *dns_frame;
<a name="l154"></a> </span><span class=cF9>U16</span><span class=cF0> flags;
<a name="l155"></a> CDNSHeader *header;
<a name="l156"></a> </span><span class=cF9>I64</span><span class=cF0> de_index;
<a name="l157"></a>
<a name="l158"></a> </span><span class=cF1>switch</span><span class=cF0> (dns_globals.addr_family)
<a name="l159"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l160"></a> </span><span class=cF1>case</span><span class=cF0> AF_UNSPEC: </span><span class=cF2>// 0, global dns ip not set</span><span class=cF0>
<a name="l161"></a> NetErr(</span><span class=cF6>&quot;DNS SEND QUESTION: Failed, global dns addr family was AF_UNSPEC.&quot;</span><span class=cF0>);
<a name="l162"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>;
<a name="l163"></a>
<a name="l164"></a> </span><span class=cF1>case</span><span class=cF0> AF_INET6:
<a name="l165"></a> NetErr(</span><span class=cF6>&quot;DNS SEND QUESTION: Failed, IPV6 not supported yet in DNS.&quot;</span><span class=cF0>);
<a name="l166"></a> </span><span class=cF5>throw</span><span class=cF0>(</span><span class=cF6>'DNS'</span><span class=cF0>);
<a name="l167"></a>
<a name="l168"></a> </span><span class=cF1>case</span><span class=cF0> AF_INET:
<a name="l169"></a> ipv4_addr = &amp;dns_globals.dns_ip;
<a name="l170"></a>
<a name="l171"></a> </span><span class=cF1>if</span><span class=cF0> (!*ipv4_addr)
<a name="l172"></a> {
<a name="l173"></a> NetErr(</span><span class=cF6>&quot;DNS SEND QUESTION: Failed, ipv4_addr had no value set.&quot;</span><span class=cF0>);
<a name="l174"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>;
<a name="l175"></a> }
<a name="l176"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l177"></a>
<a name="l178"></a> </span><span class=cF2>// UDPPacketAllocate currently only accepts IPV4 ...</span><span class=cF0>
<a name="l179"></a> de_index = UDPPacketAllocate(&amp;dns_frame,
<a name="l180"></a> IPV4AddressGet,
<a name="l181"></a> local_port,
<a name="l182"></a> *ipv4_addr,
<a name="l183"></a> </span><span class=cFE>53</span><span class=cF0>,
<a name="l184"></a> </span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CDNSHeader</span><span class=cF7>)</span><span class=cF0> + DNSQuestionSizeCalculate</span><span class=cF7>(</span><span class=cF0>q</span><span class=cF7>)</span><span class=cF0>);
<a name="l185"></a> </span><span class=cF1>if</span><span class=cF0> (de_index &lt; </span><span class=cFE>0</span><span class=cF0>)
<a name="l186"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l187"></a> NetErr(</span><span class=cF6>&quot;DNS SEND QUESTION: Failed, UDPPacketAllocate returned error.&quot;</span><span class=cF0>);
<a name="l188"></a> </span><span class=cF1>return</span><span class=cF0> de_index;
<a name="l189"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l190"></a>
<a name="l191"></a> flags = DNS_OP_QUERY &lt;&lt; </span><span class=cFE>11</span><span class=cF0> | DNS_FLAG_RD;
<a name="l192"></a>
<a name="l193"></a> header = dns_frame;
<a name="l194"></a>
<a name="l195"></a> header-&gt;id = </span><span class=cF5>EndianU16</span><span class=cF0>(id);
<a name="l196"></a> header-&gt;flags = </span><span class=cF5>EndianU16</span><span class=cF0>(flags);
<a name="l197"></a> header-&gt;q_count = </span><span class=cF5>EndianU16</span><span class=cF0>(</span><span class=cFE>1</span><span class=cF0>);
<a name="l198"></a> header-&gt;a_count = </span><span class=cFE>0</span><span class=cF0>;
<a name="l199"></a> header-&gt;ns_count = </span><span class=cFE>0</span><span class=cF0>;
<a name="l200"></a> header-&gt;ar_count = </span><span class=cFE>0</span><span class=cF0>;
<a name="l201"></a>
<a name="l202"></a> DNSQuestionSerialize(dns_frame + </span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CDNSHeader</span><span class=cF7>)</span><span class=cF0>, q);
<a name="l203"></a>
<a name="l204"></a> UDPPacketFinish(de_index);
<a name="l205"></a> </span><span class=cF1>return</span><span class=cF0> </span><span class=cFE>0</span><span class=cF0>;
<a name="l206"></a>
<a name="l207"></a>}
<a name="l208"></a>
<a name="l209"></a>
<a name="l210"></a></span><span class=cF9>I64</span><span class=cF0> DNSDomainNameParse(</span><span class=cF1>U8</span><span class=cF0> *packet_data, </span><span class=cF9>I64</span><span class=cF0> packet_length, </span><span class=cF1>U8</span><span class=cF0> **data_inout, </span><span class=cF9>I64</span><span class=cF0> *length_inout, CDNSDomainName *name_out)
<a name="l211"></a>{ </span><span class=cF2>// these methods look not-so-good, ngl.</span><span class=cF0>
<a name="l212"></a> </span><span class=cF1>U8</span><span class=cF0> *data = *data_inout;
<a name="l213"></a> </span><span class=cF1>U8</span><span class=cF0> *name_buf;
<a name="l214"></a> </span><span class=cF9>I64</span><span class=cF0> length = *length_inout;
<a name="l215"></a> </span><span class=cF9>I64</span><span class=cF0> label_len;
<a name="l216"></a> </span><span class=cF1>Bool</span><span class=cF0> jump_taken = </span><span class=cF3>FALSE</span><span class=cF0>;
<a name="l217"></a>
<a name="l218"></a> </span><span class=cF1>if</span><span class=cF0> (length &lt; </span><span class=cFE>1</span><span class=cF0>)
<a name="l219"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l220"></a> NetErr(</span><span class=cF6>&quot;DNS PARSE DOMAIN NAME: Length less than one.&quot;</span><span class=cF0>);
<a name="l221"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>;
<a name="l222"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l223"></a>
<a name="l224"></a> name_out-&gt;labels = </span><span class=cF5>CAlloc</span><span class=cF0>(</span><span class=cFE>16</span><span class=cF0> * </span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF1>U8</span><span class=cF0> *</span><span class=cF7>)</span><span class=cF0>);
<a name="l225"></a> name_out-&gt;num_labels = </span><span class=cFE>0</span><span class=cF0>;
<a name="l226"></a>
<a name="l227"></a> name_buf = </span><span class=cF5>CAlloc</span><span class=cF0>(</span><span class=cFE>256</span><span class=cF0>); </span><span class=cF2>// ?..</span><span class=cF0>
<a name="l228"></a> name_out-&gt;labels[</span><span class=cFE>0</span><span class=cF0>] = name_buf;
<a name="l229"></a>
<a name="l230"></a> </span><span class=cF1>while</span><span class=cF0> (length)
<a name="l231"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l232"></a> label_len = *data++;
<a name="l233"></a> length--;
<a name="l234"></a>
<a name="l235"></a> </span><span class=cF1>if</span><span class=cF0> (label_len == </span><span class=cFE>0</span><span class=cF0>)
<a name="l236"></a> </span><span class=cF1>break</span><span class=cF0>;
<a name="l237"></a> </span><span class=cF1>else</span><span class=cF0> </span><span class=cF1>if</span><span class=cF0> (label_len &gt;= </span><span class=cFE>192</span><span class=cF0>)
<a name="l238"></a> {
<a name="l239"></a> label_len &amp;= </span><span class=cFE>0x3F</span><span class=cF0>; </span><span class=cF2>// ...</span><span class=cF0>
<a name="l240"></a>
<a name="l241"></a> </span><span class=cF1>if</span><span class=cF0> (!jump_taken)
<a name="l242"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l243"></a> *data_inout = data + </span><span class=cFE>1</span><span class=cF0>;
<a name="l244"></a> *length_inout = length - </span><span class=cFE>1</span><span class=cF0>;
<a name="l245"></a> jump_taken = </span><span class=cF3>TRUE</span><span class=cF0>;
<a name="l246"></a> NetLog(</span><span class=cF6>&quot;DNS PARSE DOMAIN NAME: Jump taken&quot;</span><span class=cF0>);
<a name="l247"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l248"></a>
<a name="l249"></a> data = packet_data + (label_len &lt;&lt; </span><span class=cFE>8</span><span class=cF0> | *data);
<a name="l250"></a> length = packet_data + packet_length - data;
<a name="l251"></a> }
<a name="l252"></a> </span><span class=cF1>else</span><span class=cF0>
<a name="l253"></a> {
<a name="l254"></a> </span><span class=cF1>if</span><span class=cF0> (length &lt; label_len)
<a name="l255"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>; </span><span class=cF2>// ?</span><span class=cF0>
<a name="l256"></a>
<a name="l257"></a> </span><span class=cF5>MemCopy</span><span class=cF0>(name_buf, data, label_len);
<a name="l258"></a> data += label_len;
<a name="l259"></a> length -= label_len;
<a name="l260"></a>
<a name="l261"></a> name_buf[label_len] = </span><span class=cFE>0</span><span class=cF0>;
<a name="l262"></a> name_out-&gt;labels[name_out-&gt;num_labels++] = name_buf;
<a name="l263"></a>
<a name="l264"></a> name_buf += label_len + </span><span class=cFE>1</span><span class=cF0>;
<a name="l265"></a> }
<a name="l266"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l267"></a>
<a name="l268"></a> </span><span class=cF1>if</span><span class=cF0> (!jump_taken)
<a name="l269"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l270"></a> *data_inout = data;
<a name="l271"></a> *length_inout = length;
<a name="l272"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l273"></a>
<a name="l274"></a> </span><span class=cF1>return</span><span class=cF0> </span><span class=cFE>0</span><span class=cF0>;
<a name="l275"></a>}
<a name="l276"></a>
<a name="l277"></a>
<a name="l278"></a></span><span class=cF9>I64</span><span class=cF0> DNSQuestionParse(</span><span class=cF1>U8</span><span class=cF0> *packet_data, </span><span class=cF9>I64</span><span class=cF0> packet_length, </span><span class=cF1>U8</span><span class=cF0> **data_inout, </span><span class=cF9>I64</span><span class=cF0> *length_inout, CDNSQuestion *q_out)
<a name="l279"></a>{
<a name="l280"></a> </span><span class=cF1>U8</span><span class=cF0> *data;
<a name="l281"></a> </span><span class=cF9>I64</span><span class=cF0> length;
<a name="l282"></a> </span><span class=cF9>I64</span><span class=cF0> error = DNSDomainNameParse(packet_data, packet_length, data_inout, length_inout, &amp;q_out-&gt;q_name);
<a name="l283"></a>
<a name="l284"></a> </span><span class=cF1>if</span><span class=cF0> (error &lt; </span><span class=cFE>0</span><span class=cF0>)
<a name="l285"></a> </span><span class=cF1>return</span><span class=cF0> error;
<a name="l286"></a>
<a name="l287"></a> data = *data_inout;
<a name="l288"></a> length = *length_inout;
<a name="l289"></a>
<a name="l290"></a> </span><span class=cF1>if</span><span class=cF0> (length &lt; </span><span class=cFE>4</span><span class=cF0>)
<a name="l291"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>;
<a name="l292"></a>
<a name="l293"></a> q_out-&gt;next = </span><span class=cF3>NULL</span><span class=cF0>;
<a name="l294"></a> q_out-&gt;q_type = data[</span><span class=cFE>1</span><span class=cF0>] &lt;&lt; </span><span class=cFE>8</span><span class=cF0> | data[</span><span class=cFE>0</span><span class=cF0>];
<a name="l295"></a> q_out-&gt;q_class = data[</span><span class=cFE>3</span><span class=cF0>] &lt;&lt; </span><span class=cFE>8</span><span class=cF0> | data[</span><span class=cFE>2</span><span class=cF0>];
<a name="l296"></a>
<a name="l297"></a> *data_inout = data + </span><span class=cFE>4</span><span class=cF0>;
<a name="l298"></a> *length_inout = length - </span><span class=cFE>4</span><span class=cF0>;
<a name="l299"></a>
<a name="l300"></a> </span><span class=cF1>return</span><span class=cF0> </span><span class=cFE>0</span><span class=cF0>;
<a name="l301"></a>}
<a name="l302"></a>
<a name="l303"></a></span><span class=cF9>I64</span><span class=cF0> DNSRRParse(</span><span class=cF1>U8</span><span class=cF0> *packet_data, </span><span class=cF9>I64</span><span class=cF0> packet_length, </span><span class=cF1>U8</span><span class=cF0> **data_inout, </span><span class=cF9>I64</span><span class=cF0> *length_inout, CDNSRR *rr_out)
<a name="l304"></a>{
<a name="l305"></a> </span><span class=cF1>U8</span><span class=cF0> *data;
<a name="l306"></a> </span><span class=cF9>I64</span><span class=cF0> length;
<a name="l307"></a> </span><span class=cF9>I64</span><span class=cF0> record_length;
<a name="l308"></a> </span><span class=cF9>I64</span><span class=cF0> error = DNSDomainNameParse(packet_data, packet_length, data_inout, length_inout, &amp;rr_out-&gt;name);
<a name="l309"></a>
<a name="l310"></a> </span><span class=cF1>if</span><span class=cF0> (error &lt; </span><span class=cFE>0</span><span class=cF0>)
<a name="l311"></a> </span><span class=cF1>return</span><span class=cF0> error;
<a name="l312"></a>
<a name="l313"></a> data = *data_inout;
<a name="l314"></a> length = *length_inout;
<a name="l315"></a>
<a name="l316"></a> </span><span class=cF1>if</span><span class=cF0> (length &lt; </span><span class=cFE>10</span><span class=cF0>)
<a name="l317"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>;
<a name="l318"></a>
<a name="l319"></a> rr_out-&gt;next = </span><span class=cF3>NULL</span><span class=cF0>;
<a name="l320"></a> </span><span class=cF5>MemCopy</span><span class=cF0>(&amp;rr_out-&gt;type, data, </span><span class=cFE>10</span><span class=cF0>); </span><span class=cF2>// ???</span><span class=cF0>
<a name="l321"></a>
<a name="l322"></a> record_length = </span><span class=cFE>10</span><span class=cF0> + </span><span class=cF5>EndianU16</span><span class=cF0>(rr_out-&gt;rd_length);
<a name="l323"></a>
<a name="l324"></a> </span><span class=cF1>if</span><span class=cF0> (length &lt; record_length)
<a name="l325"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>;
<a name="l326"></a>
<a name="l327"></a> rr_out-&gt;r_data = data + </span><span class=cFE>10</span><span class=cF0>; </span><span class=cF2>// ??</span><span class=cF0>
<a name="l328"></a>
<a name="l329"></a> *data_inout = data + record_length;
<a name="l330"></a> *length_inout = length - record_length;
<a name="l331"></a>
<a name="l332"></a> </span><span class=cF1>return</span><span class=cF0> </span><span class=cFE>0</span><span class=cF0>;
<a name="l333"></a>}
<a name="l334"></a>
<a name="l335"></a></span><span class=cF9>I64</span><span class=cF0> DNSResponseParse(</span><span class=cF9>U16</span><span class=cF0> id, </span><span class=cF1>U8</span><span class=cF0> *data, </span><span class=cF9>I64</span><span class=cF0> length, CDNSHeader **header_out, CDNSQuestion **questions_out, CDNSRR **answers_out)
<a name="l336"></a>{
<a name="l337"></a> CDNSHeader *header;
<a name="l338"></a> CDNSQuestion *question;
<a name="l339"></a> CDNSRR *answer;
<a name="l340"></a> </span><span class=cF9>I64</span><span class=cF0> i;
<a name="l341"></a> </span><span class=cF1>U8</span><span class=cF0> *packet_data = data;
<a name="l342"></a> </span><span class=cF9>I64</span><span class=cF0> packet_length = length;
<a name="l343"></a>
<a name="l344"></a> </span><span class=cF1>if</span><span class=cF0> (length &lt; </span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CDNSHeader</span><span class=cF7>)</span><span class=cF0>)
<a name="l345"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l346"></a> NetErr(</span><span class=cF6>&quot;DNS PARSE RESPONSE: Length too short.&quot;</span><span class=cF0>);
<a name="l347"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>;
<a name="l348"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l349"></a>
<a name="l350"></a> header = data;
<a name="l351"></a> data += </span><span class=cF1>sizeof</span><span class=cF0>(CDNSHeader);
<a name="l352"></a>
<a name="l353"></a> </span><span class=cF1>if</span><span class=cF0> (id != </span><span class=cFE>0</span><span class=cF0> &amp;&amp; </span><span class=cF5>EndianU16</span><span class=cF7>(</span><span class=cF0>header-&gt;id</span><span class=cF7>)</span><span class=cF0> != id)
<a name="l354"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l355"></a> NetErr(</span><span class=cF6>&quot;DNS PARSE RESPONSE: Header ID mismatch.&quot;</span><span class=cF0>);
<a name="l356"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>;
<a name="l357"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l358"></a>
<a name="l359"></a> </span><span class=cF1>for</span><span class=cF0> (i = </span><span class=cFE>0</span><span class=cF0>; i &lt; </span><span class=cF5>EndianU16</span><span class=cF7>(</span><span class=cF0>header-&gt;q_count</span><span class=cF7>)</span><span class=cF0>; i++)
<a name="l360"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l361"></a> question = </span><span class=cF5>CAlloc</span><span class=cF0>(</span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CDNSQuestion</span><span class=cF7>)</span><span class=cF0>);
<a name="l362"></a> </span><span class=cF1>if</span><span class=cF0> (DNSQuestionParse</span><span class=cF7>(</span><span class=cF0>packet_data, packet_length, &amp;data, &amp;length, question</span><span class=cF7>)</span><span class=cF0> &lt; </span><span class=cFE>0</span><span class=cF0>)
<a name="l363"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>;
<a name="l364"></a>
<a name="l365"></a> question-&gt;next = *questions_out;
<a name="l366"></a> *questions_out = question;
<a name="l367"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l368"></a>
<a name="l369"></a> </span><span class=cF1>for</span><span class=cF0> (i = </span><span class=cFE>0</span><span class=cF0>; i &lt; </span><span class=cF5>EndianU16</span><span class=cF7>(</span><span class=cF0>header-&gt;a_count</span><span class=cF7>)</span><span class=cF0>; i++)
<a name="l370"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l371"></a> answer = </span><span class=cF5>CAlloc</span><span class=cF0>(</span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CDNSRR</span><span class=cF7>)</span><span class=cF0>);
<a name="l372"></a> </span><span class=cF1>if</span><span class=cF0> (DNSRRParse</span><span class=cF7>(</span><span class=cF0>packet_data, packet_length, &amp;data, &amp;length, answer</span><span class=cF7>)</span><span class=cF0> &lt; </span><span class=cFE>0</span><span class=cF0>)
<a name="l373"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>;
<a name="l374"></a>
<a name="l375"></a> answer-&gt;next = *answers_out;
<a name="l376"></a> *answers_out = answer;
<a name="l377"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l378"></a>
<a name="l379"></a> *header_out = header;
<a name="l380"></a> </span><span class=cF1>return</span><span class=cF0> </span><span class=cFE>0</span><span class=cF0>;
<a name="l381"></a>
<a name="l382"></a>}
<a name="l383"></a>
<a name="l384"></a></span><span class=cF1>U0</span><span class=cF0> DNSQuestionBuild(CDNSQuestion *q, </span><span class=cF1>U8</span><span class=cF0> *name)
<a name="l385"></a>{
<a name="l386"></a> </span><span class=cF1>U8</span><span class=cF0> *copy = </span><span class=cF5>StrNew</span><span class=cF0>(name);
<a name="l387"></a> </span><span class=cF1>U8</span><span class=cF0> *dot;
<a name="l388"></a>
<a name="l389"></a> q-&gt;next = </span><span class=cF3>NULL</span><span class=cF0>;
<a name="l390"></a> q-&gt;q_name.labels = </span><span class=cF5>CAlloc</span><span class=cF0>(</span><span class=cFE>16</span><span class=cF0> * </span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF1>U8</span><span class=cF0> *</span><span class=cF7>)</span><span class=cF0>);
<a name="l391"></a> q-&gt;q_name.labels[</span><span class=cFE>0</span><span class=cF0>] = </span><span class=cFE>0</span><span class=cF0>;
<a name="l392"></a> q-&gt;q_name.num_labels = </span><span class=cFE>0</span><span class=cF0>;
<a name="l393"></a> q-&gt;q_type = DNS_TYPE_A;
<a name="l394"></a> q-&gt;q_class = DNS_CLASS_IN;
<a name="l395"></a>
<a name="l396"></a> </span><span class=cF1>while</span><span class=cF0> (*copy)
<a name="l397"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l398"></a> q-&gt;q_name.labels[q-&gt;q_name.num_labels++] = copy;
<a name="l399"></a> dot = </span><span class=cF5>StrFirstOcc</span><span class=cF0>(copy, </span><span class=cF6>&quot;.&quot;</span><span class=cF0>);
<a name="l400"></a>
<a name="l401"></a> </span><span class=cF1>if</span><span class=cF0> (dot)
<a name="l402"></a> {
<a name="l403"></a> *dot = </span><span class=cFE>0</span><span class=cF0>;
<a name="l404"></a> copy = dot + </span><span class=cFE>1</span><span class=cF0>;
<a name="l405"></a> }
<a name="l406"></a> </span><span class=cF1>else</span><span class=cF0>
<a name="l407"></a> </span><span class=cF1>break</span><span class=cF0>;
<a name="l408"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l409"></a>}
<a name="l410"></a>
<a name="l411"></a></span><span class=cF2>// these Free methods bother me a bit...</span><span class=cF0>
<a name="l412"></a></span><span class=cF1>U0</span><span class=cF0> DNSQuestionFree(CDNSQuestion *q)
<a name="l413"></a>{
<a name="l414"></a> </span><span class=cF5>Free</span><span class=cF0>(q-&gt;q_name.labels[</span><span class=cFE>0</span><span class=cF0>]);
<a name="l415"></a>}
<a name="l416"></a>
<a name="l417"></a></span><span class=cF1>U0</span><span class=cF0> DNSRRFree(CDNSRR *rr)
<a name="l418"></a>{
<a name="l419"></a> </span><span class=cF5>Free</span><span class=cF0>(rr-&gt;name.labels[</span><span class=cFE>0</span><span class=cF0>]);
<a name="l420"></a>}
<a name="l421"></a>
<a name="l422"></a></span><span class=cF1>U0</span><span class=cF0> DNSQuestionChainFree(CDNSQuestion *questions)
<a name="l423"></a>{
<a name="l424"></a> CDNSQuestion *next;
<a name="l425"></a>
<a name="l426"></a> </span><span class=cF1>while</span><span class=cF0> (questions)
<a name="l427"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l428"></a> next = questions-&gt;next;
<a name="l429"></a> DNSQuestionFree(questions);
<a name="l430"></a> </span><span class=cF5>Free</span><span class=cF0>(questions);
<a name="l431"></a> questions = next;
<a name="l432"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l433"></a>}
<a name="l434"></a>
<a name="l435"></a></span><span class=cF1>U0</span><span class=cF0> DNSRRChainFree(CDNSRR *rrs)
<a name="l436"></a>{ </span><span class=cF2>// Shrine sets rrs-&gt;next to a CDNSQuestion when it would be a CDNSRR ... assuming it's wrong and fixing it here..</span><span class=cF0>
<a name="l437"></a> CDNSRR *next;
<a name="l438"></a>
<a name="l439"></a> </span><span class=cF1>while</span><span class=cF0> (rrs)
<a name="l440"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l441"></a> next = rrs-&gt;next;
<a name="l442"></a> DNSRRFree(rrs);
<a name="l443"></a> </span><span class=cF5>Free</span><span class=cF0>(rrs);
<a name="l444"></a> rrs = next;
<a name="l445"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l446"></a>}
<a name="l447"></a>
<a name="l448"></a>
<a name="l449"></a></span><span class=cF9>I64</span><span class=cF0> DNSQueryRun(CUDPSocket *udp_socket, </span><span class=cF1>U8</span><span class=cF0> *name, </span><span class=cF9>U16</span><span class=cF0> port, CAddressInfo **result_out)
<a name="l450"></a>{ </span><span class=cF2>// IPV4-UDP-based, TODO: take good look at this method to ensure no floating pointers after.</span><span class=cF0>
<a name="l451"></a> </span><span class=cF2>// note: UDP Socket created in this method is not closed in this method, gets closed e.g. in DNSAddressInfoGet</span><span class=cF0>
<a name="l452"></a> </span><span class=cF9>I64</span><span class=cF0> retries = </span><span class=cFE>0</span><span class=cF0>;
<a name="l453"></a> </span><span class=cF9>I64</span><span class=cF0> timeout = DNS_TIMEOUT;
<a name="l454"></a> </span><span class=cF9>U16</span><span class=cF0> local_port = </span><span class=cF5>MaxI64</span><span class=cF0>(</span><span class=cFE>1024</span><span class=cF0>, </span><span class=cF5>RandU16</span><span class=cF0>); </span><span class=cF2>// Pick a random port above 1023. (within standard application port range)</span><span class=cF0>
<a name="l455"></a> </span><span class=cF9>U16</span><span class=cF0> id = </span><span class=cF5>RandU16</span><span class=cF0>;
<a name="l456"></a> </span><span class=cF9>I64</span><span class=cF0> error = </span><span class=cFE>0</span><span class=cF0>;
<a name="l457"></a> </span><span class=cF1>U8</span><span class=cF0> buffer[</span><span class=cFE>2048</span><span class=cF0>];
<a name="l458"></a> </span><span class=cF9>I64</span><span class=cF0> count;
<a name="l459"></a> </span><span class=cF1>Bool</span><span class=cF0> have; </span><span class=cF2>// ??</span><span class=cF0>
<a name="l460"></a>
<a name="l461"></a> CDNSQuestion q;
<a name="l462"></a> CDNSHeader *header;
<a name="l463"></a> CDNSQuestion *questions;
<a name="l464"></a> CDNSRR *answers;
<a name="l465"></a> CDNSRR *a;
<a name="l466"></a>
<a name="l467"></a> CSocketAddressIPV4 ipv4_addr;
<a name="l468"></a> CSocketAddressIPV4 ipv4_addr_in; </span><span class=cF2>// ?</span><span class=cF0>
<a name="l469"></a> CSocketAddressIPV4 *ipv4_addr_temp;
<a name="l470"></a> CAddressInfo *res;
<a name="l471"></a>
<a name="l472"></a> </span><span class=cF2>//setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO_MS, &amp;timeout, sizeof(timeout))</span><span class=cF0>
<a name="l473"></a> udp_socket-&gt;receive_timeout_ms = timeout;
<a name="l474"></a>
<a name="l475"></a> ipv4_addr.family = AF_INET;
<a name="l476"></a> ipv4_addr.port = </span><span class=cF5>EndianU16</span><span class=cF0>(local_port);
<a name="l477"></a> ipv4_addr.address.address = INADDR_ANY;
<a name="l478"></a>
<a name="l479"></a> </span><span class=cF2>// UDPSocketBind will be attempted on the udp_socket param, method expects a UDPSocket() result to be made already</span><span class=cF0>
<a name="l480"></a> </span><span class=cF1>if</span><span class=cF0> (UDPSocketBind</span><span class=cF7>(</span><span class=cF0>udp_socket, &amp;ipv4_addr</span><span class=cF7>)</span><span class=cF0>) </span><span class=cF2>// expected return value is 0</span><span class=cF0>
<a name="l481"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l482"></a> NetErr(</span><span class=cF6>&quot;DNS RUN QUERY: Failed to bind UDP socket.&quot;</span><span class=cF0>);
<a name="l483"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>;
<a name="l484"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l485"></a>
<a name="l486"></a> DNSQuestionBuild(&amp;q, name);
<a name="l487"></a>
<a name="l488"></a> </span><span class=cF1>while</span><span class=cF0> (</span><span class=cF3>TRUE</span><span class=cF0>) </span><span class=cF2>// Shrine uses while (1) infinite loop, need to be careful not to lock</span><span class=cF0>
<a name="l489"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l490"></a> error = DNSQuestionSend(id, local_port, &amp;q);
<a name="l491"></a> </span><span class=cF1>if</span><span class=cF0> (error &lt; </span><span class=cFE>0</span><span class=cF0>)
<a name="l492"></a> {
<a name="l493"></a> NetErr(</span><span class=cF6>&quot;DNS RUN QUERY: Failed to Send Question.&quot;</span><span class=cF0>);
<a name="l494"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>;
<a name="l495"></a> }
<a name="l496"></a>
<a name="l497"></a> count = UDPSocketReceiveFrom(udp_socket, buffer, </span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>buffer</span><span class=cF7>)</span><span class=cF0>, &amp;ipv4_addr_in);
<a name="l498"></a>
<a name="l499"></a> </span><span class=cF1>if</span><span class=cF0> (count &gt; </span><span class=cFE>0</span><span class=cF0>)
<a name="l500"></a> {
<a name="l501"></a> NetLog(</span><span class=cF6>&quot;DNS RUN QUERY: Trying Parse Response.&quot;</span><span class=cF0>);
<a name="l502"></a>
<a name="l503"></a> header = </span><span class=cF3>NULL</span><span class=cF0>;
<a name="l504"></a> questions = </span><span class=cF3>NULL</span><span class=cF0>;
<a name="l505"></a> answers = </span><span class=cF3>NULL</span><span class=cF0>;
<a name="l506"></a>
<a name="l507"></a> error = DNSResponseParse(id, buffer, count, &amp;header, &amp;questions, &amp;answers);
<a name="l508"></a>
<a name="l509"></a> </span><span class=cF1>if</span><span class=cF0> (error == </span><span class=cFE>0</span><span class=cF0>) </span><span class=cF2>// Shrine has (error &gt;= 0), but DNSResponseParse can only return 0 or 1 ..</span><span class=cF0>
<a name="l510"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l511"></a> have = </span><span class=cF3>FALSE</span><span class=cF0>;
<a name="l512"></a>
<a name="l513"></a> a = answers;
<a name="l514"></a> </span><span class=cF1>while</span><span class=cF0> (a)
<a name="l515"></a> {
<a name="l516"></a> </span><span class=cF2>// Shrine has TODO: if multiple acceptable answers, pick one at random, not just first one.</span><span class=cF0>
<a name="l517"></a> </span><span class=cF2>// perhaps we could use r_count in header for that ?</span><span class=cF0>
<a name="l518"></a>
<a name="l519"></a> </span><span class=cF1>if</span><span class=cF0> (</span><span class=cF5>EndianU16</span><span class=cF7>(</span><span class=cF0>a-&gt;type</span><span class=cF7>)</span><span class=cF0> == DNS_TYPE_A &amp;&amp;
<a name="l520"></a> </span><span class=cF5>EndianU16</span><span class=cF7>(</span><span class=cF0>a-&gt;rr_class</span><span class=cF7>)</span><span class=cF0> == DNS_CLASS_IN &amp;&amp;
<a name="l521"></a> </span><span class=cF5>EndianU16</span><span class=cF7>(</span><span class=cF0>a-&gt;rd_length</span><span class=cF7>)</span><span class=cF0> == </span><span class=cFE>4</span><span class=cF0>)
<a name="l522"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l523"></a> res = </span><span class=cF5>CAlloc</span><span class=cF0>(</span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CAddressInfo</span><span class=cF7>)</span><span class=cF0>);
<a name="l524"></a>
<a name="l525"></a> res-&gt;flags = </span><span class=cFE>0</span><span class=cF0>;
<a name="l526"></a> res-&gt;family = AF_INET;
<a name="l527"></a> res-&gt;socket_type = </span><span class=cFE>0</span><span class=cF0>; </span><span class=cF2>// ??</span><span class=cF0>
<a name="l528"></a> res-&gt;protocol = </span><span class=cFE>0</span><span class=cF0>; </span><span class=cF2>// ??</span><span class=cF0>
<a name="l529"></a> res-&gt;address_length = </span><span class=cF1>sizeof</span><span class=cF0>(CSocketAddressIPV4);
<a name="l530"></a> res-&gt;address = </span><span class=cF5>CAlloc</span><span class=cF0>(</span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CSocketAddressIPV4</span><span class=cF7>)</span><span class=cF0>);
<a name="l531"></a> res-&gt;canonical_name = </span><span class=cFE>0</span><span class=cF0>;
<a name="l532"></a> res-&gt;next = </span><span class=cF3>NULL</span><span class=cF0>;
<a name="l533"></a>
<a name="l534"></a> ipv4_addr_temp = res-&gt;address;
<a name="l535"></a>
<a name="l536"></a> ipv4_addr_temp-&gt;family = AF_INET;
<a name="l537"></a> ipv4_addr_temp-&gt;port = port;
<a name="l538"></a> </span><span class=cF5>MemCopy</span><span class=cF0>(&amp;ipv4_addr_temp-&gt;address.address, answers-&gt;r_data, </span><span class=cFE>4</span><span class=cF0>);
<a name="l539"></a>
<a name="l540"></a> DNSCachePut(name, res);
<a name="l541"></a> *result_out = res;
<a name="l542"></a> have = </span><span class=cF3>TRUE</span><span class=cF0>;
<a name="l543"></a>
<a name="l544"></a> </span><span class=cF1>break</span><span class=cF0>;
<a name="l545"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l546"></a>
<a name="l547"></a> a = a-&gt;next;
<a name="l548"></a> }
<a name="l549"></a>
<a name="l550"></a> DNSQuestionChainFree(questions);
<a name="l551"></a> DNSRRChainFree(answers);
<a name="l552"></a>
<a name="l553"></a> </span><span class=cF1>if</span><span class=cF0> (have)
<a name="l554"></a> </span><span class=cF1>break</span><span class=cF0>;
<a name="l555"></a>
<a name="l556"></a> </span><span class=cF2>// Shrine comment: 'at this point, we could try iterative resolution,</span><span class=cF0>
<a name="l557"></a> </span><span class=cF2>// but all end-user DNS servers would have tried that already'</span><span class=cF0>
<a name="l558"></a>
<a name="l559"></a> NetErr(</span><span class=cF6>&quot;DNS RUN QUERY: Failed to find suitable answer in reply.&quot;</span><span class=cF0>);
<a name="l560"></a> error = -</span><span class=cFE>1</span><span class=cF0>;
<a name="l561"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l562"></a> </span><span class=cF1>else</span><span class=cF0>
<a name="l563"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l564"></a> NetErr(</span><span class=cF6>&quot;DNS RUN QUERY: Failed a DNS Parse Response.&quot;</span><span class=cF0>);
<a name="l565"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l566"></a> }
<a name="l567"></a>
<a name="l568"></a> </span><span class=cF1>if</span><span class=cF0> (++retries == DNS_MAX_RETRIES)
<a name="l569"></a> {
<a name="l570"></a> NetErr(</span><span class=cF6>&quot;DNS RUN QUERY: Failed, max retries reached.&quot;</span><span class=cF0>);
<a name="l571"></a> error = -</span><span class=cFE>1</span><span class=cF0>;
<a name="l572"></a> </span><span class=cF1>break</span><span class=cF0>;
<a name="l573"></a> }
<a name="l574"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l575"></a>
<a name="l576"></a> DNSQuestionFree(&amp;q);
<a name="l577"></a> </span><span class=cF1>return</span><span class=cF0> error;
<a name="l578"></a>}
<a name="l579"></a>
<a name="l580"></a></span><span class=cF2>// Shrine has port arg as U8 *service with a no_warn and says it should be parsed as port, allowing that here</span><span class=cF0>
<a name="l581"></a></span><span class=cF2>// Also has CAddressInfo *hints with a no_warn, omitting that for now</span><span class=cF0>
<a name="l582"></a></span><span class=cF9>I64</span><span class=cF0> DNSAddressInfoGet(</span><span class=cF1>U8</span><span class=cF0> *node_name, </span><span class=cF9>U16</span><span class=cF0> port, CAddressInfo **result)
<a name="l583"></a>{
<a name="l584"></a> </span><span class=cF9>I64</span><span class=cF0> error;
<a name="l585"></a> CUDPSocket *udp_socket;
<a name="l586"></a> CDNSHash *cached_entry = DNSCacheFind(node_name);
<a name="l587"></a>
<a name="l588"></a> </span><span class=cF1>if</span><span class=cF0> (cached_entry)
<a name="l589"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l590"></a> *result = </span><span class=cF5>CAlloc</span><span class=cF0>(</span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CAddressInfo</span><span class=cF7>)</span><span class=cF0>);
<a name="l591"></a> AddressInfoCopy(*result, &amp;cached_entry-&gt;info);
<a name="l592"></a> </span><span class=cF2>//(*res)-&gt;flags |= AI_CACHED; // TODO: add AI_CACHED define (maybe a better name?) not used anywhere i don't think..</span><span class=cF0>
<a name="l593"></a> </span><span class=cF1>return</span><span class=cF0> </span><span class=cFE>0</span><span class=cF0>;
<a name="l594"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l595"></a>
<a name="l596"></a> udp_socket = UDPSocket(AF_INET);
<a name="l597"></a> error = </span><span class=cFE>0</span><span class=cF0>;
<a name="l598"></a>
<a name="l599"></a> </span><span class=cF1>if</span><span class=cF0> (udp_socket)
<a name="l600"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l601"></a> error = DNSQueryRun(udp_socket, node_name, port, result);
<a name="l602"></a>
<a name="l603"></a> UDPSocketClose(udp_socket);
<a name="l604"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l605"></a> </span><span class=cF1>else</span><span class=cF0>
<a name="l606"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l607"></a> NetErr(</span><span class=cF6>&quot;DNS GET ADDRESS INFO: Failed to make UDP Socket.&quot;</span><span class=cF0>);
<a name="l608"></a> error = -</span><span class=cFE>1</span><span class=cF0>;
<a name="l609"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l610"></a>
<a name="l611"></a> </span><span class=cF1>return</span><span class=cF0> error;
<a name="l612"></a>}
<a name="l613"></a>
<a name="l614"></a></span><span class=cF1>U0</span><span class=cF0> DNSResolverIPV4Set(</span><span class=cF9>U32</span><span class=cF0> ip)
<a name="l615"></a>{
<a name="l616"></a> CIPV4Address *address = &amp;dns_globals.dns_ip;
<a name="l617"></a>
<a name="l618"></a> dns_globals.addr_family = AF_INET;
<a name="l619"></a> address-&gt;address = ip;
<a name="l620"></a>}
<a name="l621"></a>
<a name="l622"></a></span><span class=cF1>U0</span><span class=cF0> Host(</span><span class=cF1>U8</span><span class=cF0> *hostname)
<a name="l623"></a>{ </span><span class=cF2>// getaddrinfo() for whole system in Shrine ends up as pointer to DNSAddressInfoGet.. should we do something similar?</span><span class=cF0>
<a name="l624"></a> CAddressInfo *current;
<a name="l625"></a> CAddressInfo *result = </span><span class=cF3>NULL</span><span class=cF0>;
<a name="l626"></a> </span><span class=cF9>I64</span><span class=cF0> error = DNSAddressInfoGet(hostname, </span><span class=cF3>NULL</span><span class=cF0>, &amp;result);
<a name="l627"></a> </span><span class=cF9>I64</span><span class=cF0> i = </span><span class=cFE>0</span><span class=cF0>;
<a name="l628"></a> CSocketAddressIPV4 *ipv4_address;
<a name="l629"></a>
<a name="l630"></a> </span><span class=cF1>if</span><span class=cF0> (error &lt; </span><span class=cFE>0</span><span class=cF0>)
<a name="l631"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l632"></a> NetErr(</span><span class=cF6>&quot;HOST(): Failed at DNS Get Address Info.&quot;</span><span class=cF0>);
<a name="l633"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l634"></a> </span><span class=cF1>else</span><span class=cF0>
<a name="l635"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l636"></a> </span><span class=cF6>&quot;Results:\n\n&quot;</span><span class=cF0>;
<a name="l637"></a> current = result;
<a name="l638"></a> </span><span class=cF1>while</span><span class=cF0> (current)
<a name="l639"></a> {
<a name="l640"></a> </span><span class=cF6>&quot;Result %d:\n&quot;</span><span class=cF0>, ++i;
<a name="l641"></a>
<a name="l642"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>flags:</span><span class=cF0> </span><span class=cF6>0x%04X \n&quot;</span><span class=cF0>, current-&gt;flags;
<a name="l643"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>family:</span><span class=cF0> </span><span class=cF6>%d \n&quot;</span><span class=cF0>, current-&gt;family;
<a name="l644"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>socket type:</span><span class=cF0> </span><span class=cF6>%d \n&quot;</span><span class=cF0>, current-&gt;socket_type;
<a name="l645"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>protocol:</span><span class=cF0> </span><span class=cF6>%d \n&quot;</span><span class=cF0>, current-&gt;protocol;
<a name="l646"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>address length:</span><span class=cF0> </span><span class=cF6>%d \n&quot;</span><span class=cF0>, current-&gt;address_length;
<a name="l647"></a> </span><span class=cF1>switch</span><span class=cF0> (current-&gt;family)
<a name="l648"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l649"></a> </span><span class=cF1>case</span><span class=cF0> AF_INET:
<a name="l650"></a> ipv4_address = current-&gt;address;
<a name="l651"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>address:</span><span class=cF0> </span><span class=cF6>%s \n&quot;</span><span class=cF0>, NetworkToPresentation(AF_INET, &amp;ipv4_address-&gt;address);
<a name="l652"></a> </span><span class=cF1>break</span><span class=cF0>;
<a name="l653"></a>
<a name="l654"></a> </span><span class=cF1>case</span><span class=cF0> AF_INET6:
<a name="l655"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>address:</span><span class=cF0> </span><span class=cF6>IPV6 \n&quot;</span><span class=cF0>; </span><span class=cF2>// FIXME</span><span class=cF0>
<a name="l656"></a> </span><span class=cF1>break</span><span class=cF0>;
<a name="l657"></a>
<a name="l658"></a> </span><span class=cF1>case</span><span class=cF0> AF_UNSPEC:
<a name="l659"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>address:</span><span class=cF0> </span><span class=cF6>AF_UNSPEC \n&quot;</span><span class=cF0>;
<a name="l660"></a> </span><span class=cF1>break</span><span class=cF0>;
<a name="l661"></a>
<a name="l662"></a> </span><span class=cF1>default</span><span class=cF0>:
<a name="l663"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>address:</span><span class=cF0> </span><span class=cF6>INVALID \n&quot;</span><span class=cF0>;
<a name="l664"></a> </span><span class=cF1>break</span><span class=cF0>;
<a name="l665"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l666"></a>
<a name="l667"></a> current = current-&gt;next;
<a name="l668"></a> }
<a name="l669"></a> </span><span class=cF6>&quot;\n&quot;</span><span class=cF0>;
<a name="l670"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l671"></a>
<a name="l672"></a> AddressInfoFree(result);
<a name="l673"></a>}
<a name="l674"></a>
<a name="l675"></a></span><span class=cF1>U0</span><span class=cF0> DNSRep()
<a name="l676"></a>{
<a name="l677"></a> </span><span class=cF9>I64</span><span class=cF0> i;
<a name="l678"></a> CDNSHash *temp_hash;
<a name="l679"></a> CSocketAddressIPV4 *ipv4_address;
<a name="l680"></a>
<a name="l681"></a> </span><span class=cF6>&quot;$LTBLUE$DNS Report:$FG$\n\n&quot;</span><span class=cF0>;
<a name="l682"></a> </span><span class=cF1>for</span><span class=cF0> (i = </span><span class=cFE>0</span><span class=cF0>; i &lt;= dns_cache-&gt;mask; i++)
<a name="l683"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l684"></a> temp_hash = dns_cache-&gt;body[i];
<a name="l685"></a>
<a name="l686"></a> </span><span class=cF1>while</span><span class=cF0> (temp_hash)
<a name="l687"></a> {
<a name="l688"></a> </span><span class=cF6>&quot;DNS Hash @ 0x%X:\n&quot;</span><span class=cF0>, temp_hash;
<a name="l689"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>Hostname:</span><span class=cF0> </span><span class=cF6>%s\n&quot;</span><span class=cF0>, temp_hash-&gt;str;
<a name="l690"></a>
<a name="l691"></a> </span><span class=cF1>switch</span><span class=cF0> (temp_hash-&gt;info.family)
<a name="l692"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l693"></a> </span><span class=cF1>case</span><span class=cF0> AF_INET:
<a name="l694"></a> ipv4_address = temp_hash-&gt;info.address;
<a name="l695"></a>
<a name="l696"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>IP Address:</span><span class=cF0> </span><span class=cF6>%s\n&quot;</span><span class=cF0>,
<a name="l697"></a> NetworkToPresentation(temp_hash-&gt;info.family,
<a name="l698"></a> &amp;ipv4_address-&gt;address);
<a name="l699"></a> </span><span class=cF1>break</span><span class=cF0>;
<a name="l700"></a> </span><span class=cF1>case</span><span class=cF0> AF_INET6:
<a name="l701"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>IP Address:</span><span class=cF0> </span><span class=cF6>IPV6\n&quot;</span><span class=cF0>; </span><span class=cF2>// FIXME</span><span class=cF0>
<a name="l702"></a> </span><span class=cF1>break</span><span class=cF0>;
<a name="l703"></a>
<a name="l704"></a> </span><span class=cF1>case</span><span class=cF0> AF_UNSPEC:
<a name="l705"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>IP Address:</span><span class=cF0> </span><span class=cF6>AF_UNSPEC&quot;</span><span class=cF0>;
<a name="l706"></a> </span><span class=cF1>break</span><span class=cF0>;
<a name="l707"></a>
<a name="l708"></a> </span><span class=cF1>default</span><span class=cF0>:
<a name="l709"></a> </span><span class=cF6>&quot;</span><span class=cF0> </span><span class=cF6>IP Address:</span><span class=cF0> </span><span class=cF6>INVALID&quot;</span><span class=cF0>;
<a name="l710"></a> </span><span class=cF1>break</span><span class=cF0>;
<a name="l711"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l712"></a>
<a name="l713"></a> </span><span class=cF6>&quot;\n&quot;</span><span class=cF0>;
<a name="l714"></a> temp_hash = temp_hash-&gt;next;
<a name="l715"></a> }
<a name="l716"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l717"></a>}
<a name="l718"></a>
<a name="l719"></a>DNSCacheInit;</span></pre></body>
</html>