Lookup MX Records In DNS
From Erlang Community
| Revision as of 09:28, 21 July 2006 (edit) JuNC (Talk | contribs) ← Previous diff |
Current revision (13:23, 15 June 2007) (edit) (undo) Dizzyd (Talk | contribs) (Stupid spammers) |
||
| (5 intermediate revisions not shown.) | |||
| Line 10: | Line 10: | ||
| out how it works properly so I have to start by adding a nameserver to query from: | out how it works properly so I have to start by adding a nameserver to query from: | ||
| - | < | + | <code caption="Code snippet 1"> |
| - | + | ||
| - | + | ||
| - | + | ||
| ok = inet_db:add_ns({192,168,0,10}). | ok = inet_db:add_ns({192,168,0,10}). | ||
| - | </ | + | </code> |
| - | + | ||
| This adds the given IP to the internal database of nameservers. (Note the Erlang convention | This adds the given IP to the internal database of nameservers. (Note the Erlang convention | ||
| Line 29: | Line 25: | ||
| Use include_lib to add this: | Use include_lib to add this: | ||
| - | < | + | <code caption="Code snippet 2"> |
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | ||
| -include_lib("kernel/src/inet_dns.hrl"). | -include_lib("kernel/src/inet_dns.hrl"). | ||
| - | </ | + | </code> |
| - | + | ||
| The query is extremely simple to achieve, just pass the domain and record type | The query is extremely simple to achieve, just pass the domain and record type | ||
| Line 50: | Line 41: | ||
| I simply match on the record and list: | I simply match on the record and list: | ||
| - | < | + | <code caption="Code snippet 3"> |
| - | + | ||
| - | + | ||
| - | + | ||
| mxlookup(Domain) -> | mxlookup(Domain) -> | ||
| - | case inet_res:nslookup(Domain,1, | + | case inet_res:nslookup(Domain,1,?S_MX) of |
| { error, Reply } -> Reply; | { error, Reply } -> Reply; | ||
| { ok, #dns_rec{ arlist = Ans } } -> findmx( Ans ) | { ok, #dns_rec{ arlist = Ans } } -> findmx( Ans ) | ||
| end. | end. | ||
| - | </ | + | </code> |
| - | + | ||
| Each entry in this list is a record of #dns_rr (DNS Resource Record). | Each entry in this list is a record of #dns_rr (DNS Resource Record). | ||
| Line 71: | Line 58: | ||
| for this HowTo I'll simply return the first host found: | for this HowTo I'll simply return the first host found: | ||
| - | < | + | <code caption="Code snippet 4"> |
| - | + | ||
| - | + | ||
| - | + | ||
| findmx( [#dns_rr{ type=?S_A, data = Addr } | T] ) -> Addr; | findmx( [#dns_rr{ type=?S_A, data = Addr } | T] ) -> Addr; | ||
| Line 80: | Line 64: | ||
| findmx( _Other ) -> none. | findmx( _Other ) -> none. | ||
| - | </ | + | </code> |
| - | + | ||
| ==Conclusion== | ==Conclusion== | ||
| Line 91: | Line 74: | ||
| ==Listing== | ==Listing== | ||
| - | < | + | <code caption="Code listing 1 (mxlookup.erl)"> |
| - | + | ||
| - | + | ||
| - | + | ||
| -module(mxlookup). | -module(mxlookup). | ||
| Line 119: | Line 99: | ||
| end. | end. | ||
| - | </ | + | </code> |
| - | + | ||
| - | < | + | <code caption="Code listing 2 (testmx.erl)"> |
| - | + | ||
| - | + | ||
| - | + | ||
| -module(testmx). | -module(testmx). | ||
| Line 137: | Line 113: | ||
| io:format("Atomic Tiger: ~p~nTrapexit: ~p~n",[Addr1,Addr2]). | io:format("Atomic Tiger: ~p~nTrapexit: ~p~n",[Addr1,Addr2]). | ||
| - | </ | + | </code> |
| - | + | ||
| [[Category:HowTo]] | [[Category:HowTo]] | ||
Current revision
Contents |
[edit] Introduction
For the E-mail server I'm writing I had the simple requirement to lookup MX records from the DNS. Erlang provides a small interface for performing DNS queries. The modules you'll need to use are inet_db, inet_dns and inet_res.
[edit] Using The DNS Lookup Interface
Although it looks like there is a mechanism for querying the system nameservers, I couldn't figure out how it works properly so I have to start by adding a nameserver to query from:
Code snippet 1 |
ok = inet_db:add_ns({192,168,0,10}).
|
This adds the given IP to the internal database of nameservers. (Note the Erlang convention of IP addresses given as quadruples).
The next stage is to construct an appropriate query. Handily enough Erlang provides a very simple interface. The header file is "kernel/src/inet_dns.hrl" and this provides all of the macros and details required to do the lookup.
Use include_lib to add this:
Code snippet 2 |
-include_lib("kernel/src/inet_dns.hrl").
|
The query is extremely simple to achieve, just pass the domain and record type to inet_res:nslookup/3.
This returns { ok, Result } on success or {error, Reason} on failure.
Result is actually a record, named #dns_rec in inet_dns.hrl. This record has five fields, but for the purposes of this HowTo we are only interested in one, the arlist field. This field is a list of resource entries. To do the MX lookup I simply match on the record and list:
Code snippet 3 |
mxlookup(Domain) ->
case inet_res:nslookup(Domain,1,?S_MX) of
{ error, Reply } -> Reply;
{ ok, #dns_rec{ arlist = Ans } } -> findmx( Ans )
end.
|
Each entry in this list is a record of #dns_rr (DNS Resource Record).
findmx/1 is a function which searches through the list of resources and filters out the MX servers. We're basically interested in the host addresses (for sending email to) so findmx/1 is very simple (and naive), for this HowTo I'll simply return the first host found:
Code snippet 4 |
findmx( [#dns_rr{ type=?S_A, data = Addr } | T] ) -> Addr;
findmx( [H | T ]) -> findmx(T);
findmx( _Other ) -> none.
|
[edit] Conclusion
Extensions like handling timeouts, sorting and verifying results and so forth should be straightforward, the comments in inet_dns.hrl outline what each member of each record means.
[edit] Listing
Code listing 1 (mxlookup.erl) |
-module(mxlookup).
-export([lookup/1, init/1]).
-include_lib("kernel/src/inet_dns.hrl").
init([NS | T]) ->
ok = inet_db:add_ns(NS),
init(T);
init([]) -> ok;
init(Nameserver) ->
ok = inet_db:add_ns(Nameserver).
findmx( [#dns_rr{ type=?S_A, data = Addr } | _] ) -> Addr;
findmx( [_ | T ]) -> findmx(T);
findmx( _Other ) -> none.
lookup(Domain) ->
case inet_res:nslookup(Domain,1,mx) of
{ error, Reply } -> Reply;
{ ok, #dns_rec{ arlist = Ans } } -> findmx( Ans )
end.
|
Code listing 2 (testmx.erl) |
-module(testmx).
-export([test/0]).
test() ->
mxlookup:init( [{192,168,0,10}] ),
Addr1 = mxlookup:lookup( "atomictiger.net" ),
Addr2 = mxlookup:lookup( "trapexit.org" ),
io:format("Atomic Tiger: ~p~nTrapexit: ~p~n",[Addr1,Addr2]).
|

Digg It
Del.icio.us
Reddit
Facebook
Stumble Upon
Technorati

