<?xml version="1.0" encoding="utf-8" ?>

<rss version="2.0" 
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:admin="http://webns.net/mvcb/"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
   xmlns:wfw="http://wellformedweb.org/CommentAPI/"
   xmlns:content="http://purl.org/rss/1.0/modules/content/"
   >
<channel>
    
    <title>blueblog - by Christian J. Dietrich - PostgreSQL</title>
    <link>http://blog.cj2s.de/</link>
    <description>on malware, botnets and security by Christian J. Dietrich</description>
    <dc:language>en</dc:language>
    <generator>Serendipity 1.6.2 - http://www.s9y.org/</generator>
    <pubDate>Mon, 24 May 2010 08:49:40 GMT</pubDate>

    <image>
        <url>http://blog.cj2s.de/templates/bulletproof/img/s9y_banner_small.png</url>
        <title>RSS: blueblog - by Christian J. Dietrich - PostgreSQL - on malware, botnets and security by Christian J. Dietrich</title>
        <link>http://blog.cj2s.de/</link>
        <width>100</width>
        <height>21</height>
    </image>

<item>
    <title>DNS resolution functions for PostgreSQL</title>
    <link>http://blog.cj2s.de/archives/11-DNS-resolution-functions-for-PostgreSQL.html</link>
            <category>PostgreSQL</category>
    
    <comments>http://blog.cj2s.de/archives/11-DNS-resolution-functions-for-PostgreSQL.html#comments</comments>
    <wfw:comment>http://blog.cj2s.de/wfwcomment.php?cid=11</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://blog.cj2s.de/rss.php?version=2.0&amp;type=comments&amp;cid=11</wfw:commentRss>
    

    <author>nospam@example.com (Christian J. Dietrich)</author>
    <content:encoded>
    You are working with lots of IP addresses in a PostgreSQL database? Ever wanted to quickly find out the hostname for a given IP address? Issue something like &lt;pre style=&quot;line-height:0.6em;&quot;&gt;SELECT hostbyname(&#039;www.google.com&#039;);&lt;/pre&gt; in order to resolve that hostname? Then &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/pgfoundry.org/projects/pgdnsres/&#039;]);&quot;  href=&quot;http://pgfoundry.org/projects/pgdnsres/&quot;&gt;pg-dns-resolve&lt;/a&gt; is the right thing for you. pg-dns-resolve contains PL/Python functions for DNS resolution at the SQL prompt. Check out these examples:&lt;br /&gt;
&lt;br /&gt;
For all of the functions there is a variant ending in &quot;_n&quot; which means that on error, NULL is to be returned instead of an error string describing the cause of the error. Some functions have a &quot;_s&quot;-version which means they return the result as a set, i.e. multiple rows.&lt;br /&gt;
&lt;br /&gt;
Here we go. Resolve the hostname for a given IP address:&lt;br /&gt;
&lt;pre style=&quot;line-height:0.6em;&quot;&gt;&lt;br /&gt;
db=# select dst, hostbyaddr(dst) from dns_per_ip limit 2;&lt;br /&gt;
      dst      |        hostbyaddr&lt;br /&gt;
---------------+-----------------------------&lt;br /&gt;
 192.168.1.1   | (1, &#039;Unbekannter Rechner&#039;)&lt;br /&gt;
 193.232.128.6 | ns5.msk-ix.net&lt;br /&gt;
(2 rows)&lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
Forward resolve www.google.de to (one of) its IP address:&lt;br /&gt;
&lt;pre style=&quot;line-height:0.6em;&quot;&gt;&lt;br /&gt;
db=# select hostbyname(&#039;www.google.de&#039;);&lt;br /&gt;
 hostbyname&lt;br /&gt;
---------------&lt;br /&gt;
 74.125.43.105&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
Note that on error, NULL is returned by hostbyname_n, BUT hostbyname returns an error string instead. So if you want to know why the resolution failed, use hostbyname, otherwise use hostbyname_n.&lt;br /&gt;
&lt;pre style=&quot;line-height:0.6em;&quot;&gt;&lt;br /&gt;
db=# select hostbyname_n(&#039;nonexisting&#039;), hostbyname(&#039;nonexisting&#039;);&lt;br /&gt;
  hostbyname_n |                  hostbyname&lt;br /&gt;
---------------+----------------------------------------------------&lt;br /&gt;
               | (-2, &#039;Der Name oder der Dienst ist nicht bekannt&#039;)&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
db=# select hostbyname_n(&#039;nonexistinghost&#039;) is NULL;&lt;br /&gt;
 ?column?&lt;br /&gt;
----------&lt;br /&gt;
 true&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
If you need all IP addresses of a hostname, use addrsbyname. DNS usually returns a different order of multiple IP addresses due to round-robin. Note, that the list of IP addresses of addrsbyname is sorted, thus two executions with the same argument return the same list. This is very useful for comparisons.&lt;br /&gt;
&lt;pre style=&quot;line-height:0.6em;&quot;&gt;&lt;br /&gt;
db=# select addrsbyname(&#039;www.google.de&#039;);&lt;br /&gt;
 addrsbyname&lt;br /&gt;
-------------------&lt;br /&gt;
 74.125.43.103&lt;br /&gt;
 74.125.43.104&lt;br /&gt;
 74.125.43.105&lt;br /&gt;
 74.125.43.106&lt;br /&gt;
 74.125.43.147&lt;br /&gt;
 74.125.43.99&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
If you want e.g. a comma-separated list instead of newline-separated list, use your own separator string as the second argument to addrsbyname:&lt;br /&gt;
&lt;pre style=&quot;line-height:0.6em;&quot;&gt;&lt;br /&gt;
db=# select addrsbyname(&#039;www.google.de&#039;, &#039;, &#039;);&lt;br /&gt;
                                    addrsbyname&lt;br /&gt;
-----------------------------------------------------------------------------------------&lt;br /&gt;
 74.125.43.103, 74.125.43.104, 74.125.43.105, 74.125.43.106, 74.125.43.147, 74.125.43.99&lt;br /&gt;
(1 row) &lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
hostsbyname works similar to addrsbyname. hostsbyname returns a list of all hostnames associated with a given hostname, including aliases. As with addrsbyname there are 2 variants, one using the default newline delimiter to separate elements and one where you can specify the delimiter yourself. The list of resulting hostnames is sorted.&lt;br /&gt;
&lt;pre style=&quot;line-height:0.6em;&quot;&gt;&lt;br /&gt;
db=# select hostsbyname(&#039;www.google.de&#039;, &#039;, &#039;);&lt;br /&gt;
                  hostsbyname&lt;br /&gt;
-------------------------------------------------&lt;br /&gt;
 www.google.com, www.google.de, www.l.google.com&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
When working with sets, there are 4 interesting functions: addrsbyname_s and addrsbyname_ns as well as hostsbyname_s and hostsbyname_ns. Those return a set, i.e. multiple rows, instead of an aggregated string and they are useful when working with statements such as &lt;br /&gt;
&lt;pre style=&quot;line-height:0.6em;&quot;&gt;&lt;br /&gt;
  SELECT ... &lt;br /&gt;
  FROM ...&lt;br /&gt;
  WHERE xxx IN ( SELECT addrsbyname_ns(&#039;www.google.com&#039;) )&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
db=# SELECT addrsbyname_s(&#039;www.google.com&#039;);&lt;br /&gt;
 addrsbyname_s&lt;br /&gt;
---------------&lt;br /&gt;
 74.125.43.103&lt;br /&gt;
 74.125.43.104&lt;br /&gt;
 74.125.43.105&lt;br /&gt;
 74.125.43.106&lt;br /&gt;
 74.125.43.147&lt;br /&gt;
 74.125.43.99&lt;br /&gt;
(6 rows)&lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
Note the subtle difference: 6 rows instead of 1 row when comparing the output of addrsbyname_s to that of addrsbyname.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;line-height:0.6em;&quot;&gt;&lt;br /&gt;
db=# SELECT &#039;74.125.43.103&#039;::ip4 IN ( SELECT addrsbyname_s(&#039;www.google.com&#039;) );&lt;br /&gt;
 ?column?&lt;br /&gt;
----------&lt;br /&gt;
 t&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
db=# SELECT hostsbyname_ns(&#039;www.google.com&#039;);&lt;br /&gt;
  hostsbyname_ns&lt;br /&gt;
------------------&lt;br /&gt;
 www.google.com&lt;br /&gt;
 www.l.google.com&lt;br /&gt;
(2 rows)&lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
Query a non existing hostname with the &quot;_ns&quot;-variant and the result will be an empty set (0 rows):&lt;br /&gt;
&lt;pre style=&quot;line-height:0.6em;&quot;&gt;&lt;br /&gt;
db=# SELECT hostsbyname_ns(&#039;nonexistinghost&#039;);&lt;br /&gt;
 hostsbyname_ns&lt;br /&gt;
----------------&lt;br /&gt;
(0 rows)&lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
A special case is forward-confirmed reverse DNS resolution (http://en.wikipedia.org/wiki/Forward-confirmed_reverse_DNS):&lt;br /&gt;
&lt;pre style=&quot;line-height:0.6em;&quot;&gt;&lt;br /&gt;
db=# SELECT fcrdns(&#039;192.203.230.10&#039;);&lt;br /&gt;
 fcrdns&lt;br /&gt;
--------&lt;br /&gt;
 f&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;br /&gt;
db=# SELECT fcrdns(&#039;74.125.43.104&#039;);&lt;br /&gt;
 fcrdns&lt;br /&gt;
--------&lt;br /&gt;
 t&lt;br /&gt;
(1 row)&lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
Like it? It&#039;s free, download it here: &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/pgfoundry.org/projects/pgdnsres/&#039;]);&quot;  href=&quot;http://pgfoundry.org/projects/pgdnsres/&quot;&gt;http://pgfoundry.org/projects/pgdnsres/&lt;/a&gt;. Alternatively, grab a version from &lt;a onclick=&quot;_gaq.push([&#039;_trackPageview&#039;, &#039;/extlink/www.cj2s.de/plpython_dns-functions.sql&#039;]);&quot;  href=&quot;http://www.cj2s.de/plpython_dns-functions.sql&quot;&gt;http://www.cj2s.de/plpython_dns-functions.sql&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Installation is easy:&lt;br /&gt;
&lt;ul&gt;&lt;br /&gt;
&lt;li&gt;Make sure, you have ip4r installed. Get it from: http://pgfoundry.org/projects/ip4r/&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;Make sure, you have PL/Python installed and are allowed to add new functions&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;psql [YOUR OPTIONS] &lt; plpython_dns-functions.sql&lt;/li&gt;&lt;br /&gt;
&lt;/ul&gt; 
    </content:encoded>

    <pubDate>Fri, 14 May 2010 21:39:00 +0200</pubDate>
    <guid isPermaLink="false">http://blog.cj2s.de/archives/11-guid.html</guid>
    
</item>

</channel>
</rss>