<p>Let's learn today how to get the details of a DNS <a href="https://en.wikipedia.org/wiki/CNAME_record">CNAME</a> record using Go. Go provides us with the <a href="https://golang.org/pkg/net/"><code>net</code></a> package to do exactly this. The function we need is called <a href="https://golang.org/pkg/net/#LookupCNAME"><code>LookupCNAME</code></a>.</p>
<div class="highlight"><pre><span></span><span class="kn">package</span> <span class="nx">main</span>
<span class="kn">import</span> <span class="p">(</span>
<span class="s">"errors"</span>
<span class="s">"log"</span>
<span class="s">"net"</span>
<span class="s">"strings"</span>
<span class="p">)</span>
<span class="kd">func</span> <span class="nx">lookupCNAME</span><span class="p">(</span><span class="nx">host</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="kt">string</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="nx">host</span> <span class="o">==</span> <span class="s">""</span> <span class="p">{</span>
<span class="k">return</span> <span class="s">""</span><span class="p">,</span> <span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"Empty host name"</span><span class="p">)</span>
<span class="p">}</span>
<span class="nx">cname</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">net</span><span class="p">.</span><span class="nx">LookupCNAME</span><span class="p">(</span><span class="nx">host</span><span class="p">)</span>
<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
<span class="k">return</span> <span class="s">""</span><span class="p">,</span> <span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"Domain name doesn't exist"</span><span class="p">)</span>
<span class="p">}</span>
<span class="nx">cname</span> <span class="p">=</span> <span class="nx">strings</span><span class="p">.</span><span class="nx">TrimSuffix</span><span class="p">(</span><span class="nx">cname</span><span class="p">,</span> <span class="s">"."</span><span class="p">)</span>
<span class="nx">host</span> <span class="p">=</span> <span class="nx">strings</span><span class="p">.</span><span class="nx">TrimSuffix</span><span class="p">(</span><span class="nx">host</span><span class="p">,</span> <span class="s">"."</span><span class="p">)</span>
<span class="k">if</span> <span class="nx">cname</span> <span class="o">==</span> <span class="s">""</span> <span class="o">||</span> <span class="nx">cname</span> <span class="o">==</span> <span class="nx">host</span> <span class="p">{</span>
<span class="k">return</span> <span class="s">""</span><span class="p">,</span> <span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"Domain name is not a CNAME"</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">cname</span><span class="p">,</span> <span class="kc">nil</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">result</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">lookupCNAME</span><span class="p">(</span><span class="s">"api.yellowduck.be"</span><span class="p">)</span>
<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
<span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
<span class="p">}</span>
<span class="nx">log</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">result</span><span class="p">)</span>
<span class="p">}</span>
</pre></div>
<p>The <code>LookupCNAME</code> function is described as follows:</p>
<div class="highlight"><pre><span></span><span class="kd">func</span> <span class="nx">LookupCNAME</span><span class="p">(</span><span class="nx">host</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="nx">cname</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">err</span> <span class="kt">error</span><span class="p">)</span>
</pre></div>
<blockquote><p><code>LookupCNAME</code> returns the canonical name for the given <code>host</code>. Callers that do not care about the canonical name can call <a href="https://golang.org/pkg/net/#LookupHost"><code>LookupHost</code></a> or <a href="https://golang.org/pkg/net/#LookupIP"><code>LookupIP</code></a> directly; both take care of resolving the canonical name as part of the lookup.</p>
<p>A canonical name is the final name after following zero or more <code>CNAME</code> records. <code>LookupCNAME</code> does not return an error if host does not contain DNS "CNAME" records, as long as host resolves to address records.</p>
</blockquote>