Discussion:
Query a DNS in C
(too old to reply)
Christian
2004-04-14 15:53:50 UTC
Permalink
Hello,

I want to query a DNS within a C program to get the mail server associated
to a domain name, ie, the equivalent of the command 'host -t mx
<domain_name>'.

I've had a look at the bind-utils sources, and also run 'host' under gdb but
giving that it runs multiple threads, i'm lost.

Can anyone point any explicit doc (that is, not the RFC 1035), or the
specific source files inside the bind-utils tree that manage the
request-response stuff ?

Thanks.

Christian.
J***@physik.fu-berlin.de
2004-04-14 16:22:53 UTC
Permalink
Post by Christian
I want to query a DNS within a C program to get the mail server associated
to a domain name, ie, the equivalent of the command 'host -t mx
<domain_name>'.
I've had a look at the bind-utils sources, and also run 'host' under gdb but
giving that it runs multiple threads, i'm lost.
Can anyone point any explicit doc (that is, not the RFC 1035), or the
specific source files inside the bind-utils tree that manage the
request-response stuff ?
While I can send you some (not very well tested) source code that does
that I guess it would be completely incomprehensible without understan-
ding RFC 1035 (and possibly a few related RFC, like 974 and 1123). I
would say that the RFCs are the _most_ explicit documentation you can
find. What else are you looking for exactly?

Regards, Jens
--
\ Jens Thoms Toerring ___ ***@physik.fu-berlin.de
\__________________________ http://www.toerring.de
p***@ipal.net
2004-04-14 20:17:05 UTC
Permalink
On 14 Apr 2004 16:22:53 GMT ***@physik.fu-berlin.de wrote:
| Christian <***@yahoo.com> wrote:
|> I want to query a DNS within a C program to get the mail server associated
|> to a domain name, ie, the equivalent of the command 'host -t mx
|> <domain_name>'.
|
|> I've had a look at the bind-utils sources, and also run 'host' under gdb but
|> giving that it runs multiple threads, i'm lost.
|
|> Can anyone point any explicit doc (that is, not the RFC 1035), or the
|> specific source files inside the bind-utils tree that manage the
|> request-response stuff ?
|
| While I can send you some (not very well tested) source code that does
| that I guess it would be completely incomprehensible without understan-
| ding RFC 1035 (and possibly a few related RFC, like 974 and 1123). I
| would say that the RFCs are the _most_ explicit documentation you can
| find. What else are you looking for exactly?

I think what the OP is really wanting is a simple set of tools (e.g. that
do this function and not much else) that encapsulates the details (what is
in RFC 1035) and lets the caller use a simple API to send queries and read
the results. Whether that API would simply be a "build and breakdown" API
for DNS datagrams, or a more sophisticated system that waits for multiple
events and does timesout, would be a design decision.

I have been thinking of writing just such a set of functions myself, but it
is still in the "surveying what others might need" phase for now (which this
thread might well contribute to).

I think BIND's tools are overkill for what the OP wants.
--
-----------------------------------------------------------------------------
| Phil Howard KA9WGN | http://linuxhomepage.com/ http://ham.org/ |
| (first name) at ipal.net | http://phil.ipal.org/ http://ka9wgn.ham.org/ |
-----------------------------------------------------------------------------
J***@physik.fu-berlin.de
2004-04-14 21:08:00 UTC
Permalink
Post by p***@ipal.net
|> I want to query a DNS within a C program to get the mail server associated
|> to a domain name, ie, the equivalent of the command 'host -t mx
|> <domain_name>'.
|
|> I've had a look at the bind-utils sources, and also run 'host' under gdb but
|> giving that it runs multiple threads, i'm lost.
|
|> Can anyone point any explicit doc (that is, not the RFC 1035), or the
|> specific source files inside the bind-utils tree that manage the
|> request-response stuff ?
|
| While I can send you some (not very well tested) source code that does
| that I guess it would be completely incomprehensible without understan-
| ding RFC 1035 (and possibly a few related RFC, like 974 and 1123). I
| would say that the RFCs are the _most_ explicit documentation you can
| find. What else are you looking for exactly?
I think what the OP is really wanting is a simple set of tools (e.g. that
do this function and not much else) that encapsulates the details (what is
in RFC 1035) and lets the caller use a simple API to send queries and read
the results. Whether that API would simply be a "build and breakdown" API
for DNS datagrams, or a more sophisticated system that waits for multiple
events and does timesout, would be a design decision.
I have been thinking of writing just such a set of functions myself, but it
is still in the "surveying what others might need" phase for now (which this
thread might well contribute to).
I think BIND's tools are overkill for what the OP wants.
If it's just that the OP can have my code for whatever it's worth - it's
supposed to take the name of the machine to send mail to (plus the name
of the local machine) as input arguments and then to return the names of
the machines prepared to accept mail for the remote machine successively
(in order of priority). It doesn't do the talking with the DNS server
directly, that's handled via the res_xxx() and dn_xxx() functions from
libresolv, it just tries to make sense out of the DNS servers reply. So
if the Christian is interested my email address isn't munged (just don't
send me HTML formated mails, they tend to go to /dev/null directly).

Regards, Jens
--
\ Jens Thoms Toerring ___ ***@physik.fu-berlin.de
\__________________________ http://www.toerring.de
J***@physik.fu-berlin.de
2004-04-14 22:41:40 UTC
Permalink
Post by J***@physik.fu-berlin.de
If it's just that the OP can have my code for whatever it's worth - it's
supposed to take the name of the machine to send mail to (plus the name
of the local machine) as input arguments and then to return the names of
the machines prepared to accept mail for the remote machine successively
(in order of priority). It doesn't do the talking with the DNS server
directly, that's handled via the res_xxx() and dn_xxx() functions from
libresolv, it just tries to make sense out of the DNS servers reply. So
if the Christian is interested my email address isn't munged (just don't
send me HTML formated mails, they tend to go to /dev/null directly).
Or just download it from:

http://www.physik.fu-berlin.de/~toerring/mx.c

See the instructions at the start of the file on how to compile and
link it, hopefully everything else is either self-explaining or well
enough documented.
Regards, Jens
--
\ Jens Thoms Toerring ___ ***@physik.fu-berlin.de
\__________________________ http://www.toerring.de
p***@ipal.net
2004-04-17 15:36:29 UTC
Permalink
On 14 Apr 2004 21:08:00 GMT ***@physik.fu-berlin.de wrote:

| If it's just that the OP can have my code for whatever it's worth - it's
| supposed to take the name of the machine to send mail to (plus the name
| of the local machine) as input arguments and then to return the names of
| the machines prepared to accept mail for the remote machine successively
| (in order of priority). It doesn't do the talking with the DNS server
| directly, that's handled via the res_xxx() and dn_xxx() functions from
| libresolv, it just tries to make sense out of the DNS servers reply. So
| if the Christian is interested my email address isn't munged (just don't
| send me HTML formated mails, they tend to go to /dev/null directly).

Do you know of a library which can assist in doing the DNS queries in a
non-blocking way? It would be such that during any number of outstanding
queries, the process can continue to do other things, or wait in parallel
for these answers and other things it is waiting for. I would envision
(since I am thinking of writing my own if no good one can be found) that
such a library would have functions to set up a proper socket on which to
do waits (select or poll), functions to construct queries, a function to
do a non-blocking read/receive for any waiting answers, and functions to
take apart the answers.
--
-----------------------------------------------------------------------------
| Phil Howard KA9WGN | http://linuxhomepage.com/ http://ham.org/ |
| (first name) at ipal.net | http://phil.ipal.org/ http://ka9wgn.ham.org/ |
-----------------------------------------------------------------------------
j***@invalid.address
2004-04-17 17:39:23 UTC
Permalink
Post by p***@ipal.net
Do you know of a library which can assist in doing the DNS queries
in a non-blocking way? It would be such that during any number of
outstanding queries, the process can continue to do other things, or
wait in parallel for these answers and other things it is waiting
for. I would envision (since I am thinking of writing my own if no
good one can be found) that such a library would have functions to
set up a proper socket on which to do waits (select or poll),
functions to construct queries, a function to do a non-blocking
read/receive for any waiting answers, and functions to take apart
the answers.
I've never used this, but it sounds like what you're describing.

http://daniel.haxx.se/projects/c-ares/

Joe
--
If people don't want to come out to the ballpark, nobody's going
to stop them.
- Yogi Berra
Konstantin Sorokin
2004-04-18 05:43:43 UTC
Permalink
Post by p***@ipal.net
Do you know of a library which can assist in doing the DNS queries in a
non-blocking way? It would be such that during any number of outstanding
queries, the process can continue to do other things, or wait in parallel
for these answers and other things it is waiting for. I would envision
(since I am thinking of writing my own if no good one can be found) that
such a library would have functions to set up a proper socket on which to
do waits (select or poll), functions to construct queries, a function to
do a non-blocking read/receive for any waiting answers, and functions to
take apart the answers.
ADNS

http://www.chiark.greenend.org.uk/~ian/adns/
--
Konstantin Sorokin
Jem Berkes
2004-04-14 17:35:18 UTC
Permalink
Post by Christian
I want to query a DNS within a C program to get the mail server
associated to a domain name, ie, the equivalent of the command 'host
-t mx <domain_name>'.
I've had a look at the bind-utils sources, and also run 'host' under
gdb but giving that it runs multiple threads, i'm lost.
DNS queries are just UDP packets sent to nameservers. While gethostbyname
returns the DNS A record for a host, I am not aware of any standard C or
POSIX function that can get you the MX host.

BIND (note: not bind()) provides all kinds of utilities that make these
kind of lookups easy but you're talking about a lot of extra software just
to do a simple MX lookup.

If you can craft your own UDP packet (for an MX lookup) you can just send
the single query packet to your nameserver and wait for the reply. The
format for the packet is straightforward in the RFC for DNS. You can also
do a packet dump on a typical host -t MX lookup to see what the packet
looks like.
--
Jem Berkes
http://www.sysdesign.ca/
Barry Margolin
2004-04-15 01:18:24 UTC
Permalink
Post by Jem Berkes
Post by Christian
I want to query a DNS within a C program to get the mail server
associated to a domain name, ie, the equivalent of the command 'host
-t mx <domain_name>'.
I've had a look at the bind-utils sources, and also run 'host' under
gdb but giving that it runs multiple threads, i'm lost.
DNS queries are just UDP packets sent to nameservers. While gethostbyname
returns the DNS A record for a host, I am not aware of any standard C or
POSIX function that can get you the MX host.
While not POSIX, just about every Unix system includes the de facto
standard BIND resolver library. Documentation of this is in a chapter
of the "DNS & BIND" book.
--
Barry Margolin, ***@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
Hovik Melikyan
2004-04-15 12:06:08 UTC
Permalink
Post by Barry Margolin
Post by Jem Berkes
DNS queries are just UDP packets sent to nameservers. While
gethostbyname
Post by Barry Margolin
Post by Jem Berkes
returns the DNS A record for a host, I am not aware of any standard C or
POSIX function that can get you the MX host.
While not POSIX, just about every Unix system includes the de facto
standard BIND resolver library.
Yes, that's <resolv.h>. Some systems contain the library in the CRTL, some
ship it separately as libresolv.

Note that on Linux this library lacks some of the functions declared in the
header, namely the query parsing methods. To my understanding, it's a
historical flaw that can't be fixed now for compatibility reasons. The
missing functions can be found in BIND sources in modules ns_name.c and
ns_parse.c. You can 'borrow' these 2 files and link them to your project
directly (if the licensing model of your code allows it, of course).

SunOS, *BSD*, Darwin and others seem to fine though. Windows has its own
resolver interface, dnsapi.dll.
--
Hovik Melikyan
Jem Berkes
2004-04-16 01:34:01 UTC
Permalink
Post by Christian
I want to query a DNS within a C program to get the mail server
associated to a domain name, ie, the equivalent of the command 'host
-t mx <domain_name>'.
I've had a look at the bind-utils sources, and also run 'host' under
gdb but giving that it runs multiple threads, i'm lost.
Can anyone point any explicit doc (that is, not the RFC 1035), or the
specific source files inside the bind-utils tree that manage the
request-response stuff ?
I've been meaning to figure out how to do the same thing for a while. I
finally cooked up this little program that shows how to do the query
(that part is simple) and then parses the response in a way that should
be extensible. Compared to the massive 'host' program from BIND this
thing does the job in about 6 KBytes.

You can find the source here. This is NOT released under the GPL, please
don't re-use without permission.

http://www.pc-tools.net/beta/resolv/hostmx.c


/*
hostmx.c 2004-04-14
Copyright (C) 2004 Jem Berkes <***@pc9.org>
http://www.sysdesign.ca/

Does an MX lookup using res_query and parses the response datagram
Extensible RR parser (currently shows MX and A records in response)

Compile: gcc -o hostmx -s -Wall -pedantic -lresolv hostmx.c
Syntax: hostmx domain
*/
--
Jem Berkes
http://www.sysdesign.ca/
SM Ryan
2004-04-16 04:00:04 UTC
Permalink
# > I want to query a DNS within a C program to get the mail server
# > associated to a domain name, ie, the equivalent of the command 'host
# > -t mx <domain_name>'.

If you're interested in mixed C and Tcl code, I do a MX lookup for mailto
url processing.

http://www.rawbw.com/~wyrmwif/html/wyrm-uri.html#148
http://www.rawbw.com/~wyrmwif/html/wyrm-uri.html#101

Some day I'll go back and document it better.

--
SM Ryan http://www.rawbw.com/~wyrmwif/
If your job was as meaningless as theirs, wouldn't you go crazy too?
Jem Berkes
2004-04-16 18:12:12 UTC
Permalink
Post by Jem Berkes
http://www.pc-tools.net/beta/resolv/hostmx.c
Please be aware, this is just experimental code (i.e. written in an hour
and not tested) just meant to illustrate an approach. Use at your own risk.
--
Jem Berkes
http://www.sysdesign.ca/
William Ahern
2004-04-16 17:13:46 UTC
Permalink
Post by Christian
Hello,
I want to query a DNS within a C program to get the mail server associated
to a domain name, ie, the equivalent of the command 'host -t mx
<domain_name>'.
I've had a look at the bind-utils sources, and also run 'host' under gdb but
giving that it runs multiple threads, i'm lost.
Can anyone point any explicit doc (that is, not the RFC 1035), or the
specific source files inside the bind-utils tree that manage the
request-response stuff ?
Here are two great DNS client libraries:

ADNS: http://www.chiark.greenend.org.uk/~ian/adns/

Ares: ftp://athena-dist.mit.edu/pub/ATHENA/ares/
C-Ares: http://daniel.haxx.se/projects/c-ares/

With Ares especially (or the fork C-Ares, which has the man pages on the
web) you can learn a great deal about the DNS message structure. Read
adig.c--callback(), display_question() and display_rr()--for a great tuorial
on how to parse a DNS response. For the most part it's quite
straightforward, except DNS has a "compression" feature which allows for
references (e.g. www3.yahoo.com might have several entries in the response,
but all but one actually has the full string, the rest are pointers back to
the original somewhere else in the message).

One gotcha concerning MX records, however, is handling CNAME chains.
Technically they're not allowed, but there are many perpetrators out there.
Neither of the libraries follow them by default (though I think ADNS might
if you disable strict compliance mode).

- Bill
Jem Berkes
2004-04-19 01:15:10 UTC
Permalink
Post by William Ahern
With Ares especially (or the fork C-Ares, which has the man pages on
the web) you can learn a great deal about the DNS message structure.
Read adig.c--callback(), display_question() and display_rr()--for a
great tuorial on how to parse a DNS response. For the most part it's
quite straightforward, except DNS has a "compression" feature which
allows for references (e.g. www3.yahoo.com might have several entries
in the response, but all but one actually has the full string, the
rest are pointers back to the original somewhere else in the message).
There's a function in resolv that automatically expands out these
references, dn_expand()
Post by William Ahern
One gotcha concerning MX records, however, is handling CNAME chains.
Technically they're not allowed, but there are many perpetrators out
there. Neither of the libraries follow them by default (though I think
ADNS might if you disable strict compliance mode).
I think it may be wiser to consider that the libraries are just providing
convenient decoding of DNS respones. So if you ask for an MX record, you
get the 'name' for the MX record but you shouldn't really stop until you
have the A record. One of the MXers might be down too, so you should move
on to get another A record for that host, or even down to a lower priority
MX. Read up on the RFCs to understand the recommended strategy.
--
Jem Berkes
http://www.sysdesign.ca/
Ian Zimmerman
2004-04-28 03:37:08 UTC
Permalink
Bill> Here are two great DNS client libraries:

Bill> ADNS: http://www.chiark.greenend.org.uk/~ian/adns/

Bill> Ares: ftp://athena-dist.mit.edu/pub/ATHENA/ares/ C-Ares:
Bill> http://daniel.haxx.se/projects/c-ares/

BTW, I remember that you couldn't do AXFR queries with ADNS when I
looked at it. Can you do that now, or can you do that with (c-)?ares ?
--
Nothing can be explained to a stone.
Or to a stoned person, either.
William Ahern
2004-04-28 16:21:50 UTC
Permalink
Bill> ADNS: http://www.chiark.greenend.org.uk/~ian/adns/
Bill> http://daniel.haxx.se/projects/c-ares/
BTW, I remember that you couldn't do AXFR queries with ADNS when I
looked at it. Can you do that now, or can you do that with (c-)?ares ?
Hmmmm. I never tried. Though, if you couldn't do it w/ ADNS before I doubt
you could today. There was a flurry of patches for IPv6 and that still
hasn't made it into a release. (Granted, there was still some finishing work
to be done.)

It doesn't seem Ares supports it either. Ares can see lots of query and
record types but can't build or parse them, AXFR being one of them. C-Ares
hasn't changed much except for a few tweaks to better integrate into the
cURL project, such as Win32/VC++ support.
Daniel Stenberg
2004-04-29 06:20:07 UTC
Permalink
Post by William Ahern
Post by Ian Zimmerman
BTW, I remember that you couldn't do AXFR queries with ADNS when I
looked at it. Can you do that now, or can you do that with (c-)?ares ?
...
Post by William Ahern
It doesn't seem Ares supports it either. Ares can see lots of query and
record types but can't build or parse them, AXFR being one of them. C-Ares
hasn't changed much except for a few tweaks to better integrate into the
cURL project, such as Win32/VC++ support.
Let me just point out that c-ares is now a project in development. It
means you can join in and improve things, file bug reports and similar
things. c-ares has done more changes to ares than what is mentioned
here, but that's beside the point.

/ Daniel - captain of the c-ares boat

Loading...