I do alot of programming in *nix using C gcc. I know how to do a basic gethostbyname(). BUt what if I wanted to pull down the entire DNS record. More to the point, is there a function that I'm missing that allows you to specify the specific record that you want to pull? Or will I need to do this manually through a UDP socket?
No, there is no such function in standard C or POSIX (and even the gethostbyname function, contrary to what you may think, is not a function for querying DNS - it can use any other way to get the address, like /etc/hosts or mDNS, whatever).
You might want to look at some DNS-specific libraries, like ldns, libbind or libdjbdns.
See also Code to do a direct DNS lookup.
Related
As a proof-of-concept, plus a handy paranoid tool, I'm writing an OpenBSD LKM that will connect to an IRC channel, and report when hooked syscalls are executed.
This is so I can essentially have a 'live' update of filesystem changes, user logons, etc., when I'm offsite but have internet access.
I've gotten as far as connecting the socket, but am stuck at trying to perform the equivalent of a getaddrinfo or even inet_addr call with a hardcoded address.
As these are userland functions, any attempts to use them will result in undefined references - fair enough. The trouble is, after a while of Googling and grep'ing the openbsd source, I cannot find any equivalent kernel functions to do this; the best recommendation has been to reimplement them in the module.
This means I need to also implement things like islower, isxdigit and isspace (and probably others as I progress), which gets a bit much to perform something so simple; is anyone aware of a workaround or alternative for this, or am I stuck c+p code from the net files?
This is definitely better done in userspace. Regardless, OpenBSD no longer supports kernel modules.
Not that you're working on this project anymore. I just wanted to answer so that this could be closed, and so that I could clarify how to use some stdlib functions in the kernel.
In response to this:
This means I need to also implement things like islower, isxdigit and isspace (and probably others as I progress), which gets a bit much to perform something so simple; is anyone aware of a workaround or alternative for this, or am I stuck c+p code from the net files?
Some C stdlib functions are available from libkern (see libkern(9)). Others, including many of the ctype functions like islower(), are available from libsa. To use these, you need something like:
#include <lib/libkern/libkern.h>
#include <lib/libsa/stand.h>
libsa contains a handful of headers (found in /usr/src/sys/lib/libsa/), so include each one you need.
I am trying to find out MAC address and I managed to create working solution using sysctl in Linux, problem is, that this solution is not working on FreeBSD version I am developing on. Is there any way I can find out mac address in C other than using sysctl?
Use the libpcap library. Its the most multi platform way you can find.
This library is used on network sniffers and intrusion detections, as well as dedicate measuring other network statistics. The nethogs utility to measure per process network usage, the iftop used to measure per machine/port bandwidth usage. Is very flexible in many roles.
Is written in C but there are some wrappers for other languages.
1: http://en.wikipedia.org/wiki/Pcap
[2]: http://www.tcpdump.org
[3]: http://sourceforge.net/projects/libpcap/
Edit:
here is a complete and exact and working example with the code and functions detailed:
http://coderrr.wordpress.com/2008/03/07/get-the-mac-address-of-a-local-ip/
There are plenty of tutorials and the source code is your best friend.
Edit 2: blaze pointed out getifaddrs(3) which seems to do the job, just a few caveats, its a non-posix function. Is a bsd function which glibc linux supports but do NOT documents. Is almost an undocumented featured :-)
All documentation are man pages and from the manual at kernel.org:
Not in POSIX.1-2001. This function first appeared in BSDi and is
present on
the BSD systems, but with slightly different semantics documented--returning
one entry per interface, not per address. This means ifa_addr and other
fields can actually be NULL if the interface has no address, and no link-level
address is returned if the interface has an IP address assigned. Also, the
way of choosing either ifa_broadaddr or ifa_dstaddr differs on various
systems.
and
The addresses returned on Linux will usually be the IPv4 and IPv6
addresses
assigned to the interface, but also one AF_PACKET address per interface
containing lower-level details about the interface and its physical layer. In
this case, the ifa_data field may contain a pointer to a struct
net_device_stats, defined in , which contains various
interface attributes and statistics.
So it may vary in behavior and you'll may have to #ifndef compile anyway.
The kernel.org man page at http://www.kernel.org/doc/man-pages/online/pages/man3/getifaddrs.3.html does provides example code in it, which may be helpful. My local linux man page is rather poor in comparison to the above linked.
I still think that libpcap is more portable if only because someone else had done all the portability work and all the extra features you gain by using it.
Hope this helps.
getifaddrs(3) returns IP addresses and MAC addresses on local interfaces. Portable between Linux and FreeBSD.
How do I get similar functionality to the host command using a c api (or any other language for that matter)? I need more information than just an IP address given by gethostbyname(); specifically, the SMTP-related data.
If a blocking (synchronous) query is ok, just use res_query(), and link your program with -lresolv.
len = res_query(host, C_IN, T_MX, &answer, sizeof(answer));
I'd suggest FireDNS. It's a very fast C library for all kinds of dns queries.
I know that the question is old, but I have long searched a dns library, and all answers here just stubs me. I think libraries like adns/udns have written not for human beings. And FireDNS for a long time have not working download links.
I have found poslib as the best dns library with very easy interface.
I like adns because it allows for asynchronous requests
I don't think there is a function in the C standard library for this, but many scripting languages do have this functionality 'built in'. For example, Perl has the Net::DNS package:
use Net::DNS;
my #mx = mx("example.com");
foreach $host (#mx) {
print $host;
}
If you need to do this in C, a quick google shows up a few C libraries out there which you can use:
adns
udns
dns.c
FireDNS (as mentioned by ko-dos)
And I would add, unless you're writing a mail relay you almost certainly shouldn't be looking up MX records - you should be passing the mail on to a user-configured mail relay instead.
You can also try c-ares library https://c-ares.haxx.se/, which allows to send asynchronous DNS queries. It also comes with adig - its own version of dig utility for querying DNS. You can check it to see how to parse DNS reply: adig.c source
Is is it possible to have Minix 3 as a dns-server and if one would dare to code the service self how would that code look like (roughly)?
Minix actually has a nameserver in it already. Since Minix is open source, you can use it as a starting point. The program is called "nonamed". The man page says it isn't a name daemon, but actually it is.
It's just that it's very simple, which is probably what you want. Either you can use it as is, just put all hostnames you want to resolve in /etc/hosts, and "nonamed" will export those... or use nonamed as something to extend upon. At least the protocol is there already.
Man page for nonamed(8) and source code.
That's kind of a big question for little, ol' StackOverflow. I'd suggest looking around for some code that you could use or port.
I write or modify programs which perform name resolution and need a
good control of the process. So I do not use getaddrinfo(), I go
deeper and use res_query() / res_send() / etc in resolv.h, documented
in resolver(3).
Although not documented, the common way to set the resolver used is to
update _res.nsaddr_list. But this array, defined in resolv.h, stores
struct sockaddr_in, that is IPv4 addresses only. (IPv6 addresses
are struct sockaddr_in6, a family-independant system would use struct sockaddr.)
I'm looking for a way (preferrably portable, at least among the
various Unix) to tell _res that I want also IPv6 addresses.
Apparently, a long time ago, there was in FreeBSD a _res_ext with this
ability but I cannot find it anymore in a recent FreeBSD 7 (grep
_res_ext /usr/include/resolv.h finds nothing). You can still find
code which uses it (try yourself with Google Codesearch).
Thanks to Alnitak, I noticed it is apparently now _res._ext and not .res_ext. I wonder where these sort of things are documented or announced... I have no idea how portable _res._ext is. I can find it on Debian and FreeBSD. It seems there are few programs which use it.
Stéphane - if your resolv.h doesn't include any support for sockaddr_in6 then that suggests that on your particular O/S the resolver does not itself support IPv6 transport.
I've checked some of my systems here:
MacOS X 10.5.6 - supports the BIND 9 library, which has a res_setservers() function which can take IPv6 addresses, no _res._ext extension.
CentOS 5.2 - has the _res._ext extension, although there's no mention of IPv6 in the man page for resolv.conf except that there's a setting to tell the resolver to return AAAA records before looking for A records for gethostbyname().
EDIT - also, the CVS repository for FreeBSD suggests that FreeBSD 7.0 (see tag FREEBSD_7_0_0_RELEASE) does also support res_setservers() from Bind 9.
glibc:
res_setservers: no
__res_state._u._ext.nsaddrs
__res_state._u._ext.nsmap
set the latter to MAXNS+1 according to:
http://sourceware.org/ml/libc-hacker/2002-05/msg00035.html
BSD-libc:
res_setservers: yes
__res_state._u._ext.__res_state_ext
Seems messy to me and you'll probably need autoconf.