.TH inet_res 3erl "kernel 5.1.1" "Ericsson AB" "Erlang Module Definition" .SH NAME inet_res \- A rudimentary DNS client. .SH DESCRIPTION .LP This module performs DNS name resolving to recursive name servers\&. .LP See also \fBERTS User\&'s Guide: Inet Configuration\fR\& for more information about how to configure an Erlang runtime system for IP communication, and how to enable this DNS client by defining \fI\&'dns\&'\fR\& as a lookup method\&. The DNS client then acts as a backend for the resolving functions in \fB\fIinet\fR\&\fR\&\&. .LP This DNS client can resolve DNS records even if it is not used for normal name resolving in the node\&. .LP This is not a full-fledged resolver, only a DNS client that relies on asking trusted recursive name servers\&. .SH "NAME RESOLVING" .LP UDP queries are used unless resolver option \fIusevc\fR\& is \fItrue\fR\&, which forces TCP queries\&. If the query is too large for UDP, TCP is used instead\&. For regular DNS queries, 512 bytes is the size limit\&. .LP When EDNS is enabled (resolver option \fIedns\fR\& is set to the EDNS version (that is, \fI0\fR\& instead of \fIfalse\fR\&), resolver option \fIudp_payload_size\fR\& sets the limit\&. If a name server replies with the TC bit set (truncation), indicating that the answer is incomplete, the query is retried to that name server using TCP\&. Resolver option \fIudp_payload_size\fR\& also sets the advertised size for the maximum allowed reply size, if EDNS is enabled, otherwise the name server uses the limit 512 bytes\&. If the reply is larger, it gets truncated, forcing a TCP requery\&. .LP For UDP queries, resolver options \fItimeout\fR\& and \fIretry\fR\& control retransmission\&. Each name server in the \fInameservers\fR\& list is tried with a time-out of \fItimeout\fR\&/\fIretry\fR\&\&. Then all name servers are tried again, doubling the time-out, for a total of \fIretry\fR\& times\&. .LP For queries not using the \fIsearch\fR\& list, if the query to all \fInameservers\fR\& results in \fI{error,nxdomain}\fR\& or an empty answer, the same query is tried for \fIalt_nameservers\fR\&\&. .SH "RESOLVER TYPES" .LP The following data types concern the resolver: .SH DATA TYPES .nf \fBres_option()\fR\& = .br {alt_nameservers, [\fBnameserver()\fR\&]} | .br {edns, 0 | false} | .br {inet6, boolean()} | .br {nameservers, [\fBnameserver()\fR\&]} | .br {recurse, boolean()} | .br {retry, integer()} | .br {timeout, integer()} | .br {udp_payload_size, integer()} | .br {usevc, boolean()} .br .fi .nf \fBnameserver()\fR\& = {\fBinet:ip_address()\fR\&, Port :: 1\&.\&.65535} .br .fi .nf \fBres_error()\fR\& = .br formerr | .br qfmterror | .br servfail | .br nxdomain | .br notimp | .br refused | .br badvers | .br timeout .br .fi .SH "DNS TYPES" .LP The following data types concern the DNS client: .SH DATA TYPES .nf \fBdns_name()\fR\& = string() .br .fi .RS .LP A string with no adjacent dots\&. .RE .nf \fBrr_type()\fR\& = .br a | .br aaaa | .br cname | .br gid | .br hinfo | .br ns | .br mb | .br md | .br mg | .br mf | .br minfo | .br mx | .br naptr | .br null | .br ptr | .br soa | .br spf | .br srv | .br txt | .br uid | .br uinfo | .br unspec | .br wks .br .fi .nf \fBdns_class()\fR\& = in | chaos | hs | any .br .fi .nf \fBdns_msg()\fR\& = term() .br .fi .RS .LP This is the start of a hiearchy of opaque data structures that can be examined with access functions in \fIinet_dns\fR\&, which return lists of \fI{Field,Value}\fR\& tuples\&. The arity 2 functions only return the value for a specified field\&. .LP .nf dns_msg() = DnsMsg inet_dns:msg(DnsMsg) -> [ {header, dns_header()} | {qdlist, dns_query()} | {anlist, dns_rr()} | {nslist, dns_rr()} | {arlist, dns_rr()} ] inet_dns:msg(DnsMsg, header) -> dns_header() % for example inet_dns:msg(DnsMsg, Field) -> Value dns_header() = DnsHeader inet_dns:header(DnsHeader) -> [ {id, integer()} | {qr, boolean()} | {opcode, 'query' | iquery | status | integer()} | {aa, boolean()} | {tc, boolean()} | {rd, boolean()} | {ra, boolean()} | {pr, boolean()} | {rcode, integer(0..16)} ] inet_dns:header(DnsHeader, Field) -> Value query_type() = axfr | mailb | maila | any | rr_type() dns_query() = DnsQuery inet_dns:dns_query(DnsQuery) -> [ {domain, dns_name()} | {type, query_type()} | {class, dns_class()} ] inet_dns:dns_query(DnsQuery, Field) -> Value dns_rr() = DnsRr inet_dns:rr(DnsRr) -> DnsRrFields | DnsRrOptFields DnsRrFields = [ {domain, dns_name()} | {type, rr_type()} | {class, dns_class()} | {ttl, integer()} | {data, dns_data()} ] DnsRrOptFields = [ {domain, dns_name()} | {type, opt} | {udp_payload_size, integer()} | {ext_rcode, integer()} | {version, integer()} | {z, integer()} | {data, dns_data()} ] inet_dns:rr(DnsRr, Field) -> Value .fi .LP There is an information function for the types above: .LP .nf inet_dns:record_type(dns_msg()) -> msg; inet_dns:record_type(dns_header()) -> header; inet_dns:record_type(dns_query()) -> dns_query; inet_dns:record_type(dns_rr()) -> rr; inet_dns:record_type(_) -> undefined. .fi .LP So, \fIinet_dns:(inet_dns:record_type(X))(X)\fR\& converts any of these data structures into a \fI{Field,Value}\fR\& list\&. .RE .nf \fBdns_data()\fR\& = .br \fBdns_name()\fR\& | .br \fBinet:ip4_address()\fR\& | .br \fBinet:ip6_address()\fR\& | .br {MName :: \fBdns_name()\fR\&, .br RName :: \fBdns_name()\fR\&, .br Serial :: integer(), .br Refresh :: integer(), .br Retry :: integer(), .br Expiry :: integer(), .br Minimum :: integer()} | .br {\fBinet:ip4_address()\fR\&, Proto :: integer(), BitMap :: binary()} | .br {CpuString :: string(), OsString :: string()} | .br {RM :: \fBdns_name()\fR\&, EM :: \fBdns_name()\fR\&} | .br {Prio :: integer(), \fBdns_name()\fR\&} | .br {Prio :: integer(), .br Weight :: integer(), .br Port :: integer(), .br \fBdns_name()\fR\&} | .br {Order :: integer(), .br Preference :: integer(), .br Flags :: string(), .br Services :: string(), .br Regexp :: string(), .br \fBdns_name()\fR\&} | .br [string()] | .br binary() .br .fi .RS .LP \fIRegexp\fR\& is a string with characters encoded in the UTF-8 coding standard\&. .RE .SH EXPORTS .LP .nf .B getbyname(Name, Type) -> {ok, Hostent} | {error, Reason} .br .fi .br .nf .B getbyname(Name, Type, Timeout) -> {ok, Hostent} | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Name = \fBdns_name()\fR\& .br Type = \fBrr_type()\fR\& .br Timeout = timeout() .br Hostent = \fBinet:hostent()\fR\& .br Reason = \fBinet:posix()\fR\& | \fBres_error()\fR\& .br .RE .RE .RS .LP Resolves a DNS record of the specified type for the specified host, of class \fIin\fR\&\&. Returns, on success, a \fIhostent()\fR\& record with \fIdns_data()\fR\& elements in the address list field\&. .LP This function uses resolver option \fIsearch\fR\& that is a list of domain names\&. If the name to resolve contains no dots, it is prepended to each domain name in the search list, and they are tried in order\&. If the name contains dots, it is first tried as an absolute name and if that fails, the search list is used\&. If the name has a trailing dot, it is supposed to be an absolute name and the search list is not used\&. .RE .LP .nf .B gethostbyaddr(Address) -> {ok, Hostent} | {error, Reason} .br .fi .br .nf .B gethostbyaddr(Address, Timeout) -> {ok, Hostent} | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Address = \fBinet:ip_address()\fR\& .br Timeout = timeout() .br Hostent = \fBinet:hostent()\fR\& .br Reason = \fBinet:posix()\fR\& | \fBres_error()\fR\& .br .RE .RE .RS .LP Backend functions used by \fB\fIinet:gethostbyaddr/1\fR\&\fR\&\&. .RE .LP .nf .B gethostbyname(Name) -> {ok, Hostent} | {error, Reason} .br .fi .br .nf .B gethostbyname(Name, Family) -> {ok, Hostent} | {error, Reason} .br .fi .br .nf .B gethostbyname(Name, Family, Timeout) -> .B {ok, Hostent} | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Name = \fBdns_name()\fR\& .br Hostent = \fBinet:hostent()\fR\& .br Timeout = timeout() .br Family = \fBinet:address_family()\fR\& .br Reason = \fBinet:posix()\fR\& | \fBres_error()\fR\& .br .RE .RE .RS .LP Backend functions used by \fB\fIinet:gethostbyname/1,2\fR\&\fR\&\&. .LP This function uses resolver option \fIsearch\fR\& just like \fB\fIgetbyname/2,3\fR\&\fR\&\&. .LP If resolver option \fIinet6\fR\& is \fItrue\fR\&, an IPv6 address is looked up\&. If that fails, the IPv4 address is looked up and returned on IPv6-mapped IPv4 format\&. .RE .LP .nf .B lookup(Name, Class, Type) -> [dns_data()] .br .fi .br .nf .B lookup(Name, Class, Type, Opts) -> [dns_data()] .br .fi .br .nf .B lookup(Name, Class, Type, Opts, Timeout) -> [dns_data()] .br .fi .br .RS .LP Types: .RS 3 Name = \fBdns_name()\fR\& | \fBinet:ip_address()\fR\& .br Class = \fBdns_class()\fR\& .br Type = \fBrr_type()\fR\& .br Opts = [\fBres_option()\fR\& | verbose] .br Timeout = timeout() .br .RE .RE .RS .LP Resolves the DNS data for the record of the specified type and class for the specified name\&. On success, filters out the answer records with the correct \fIClass\fR\& and \fIType\fR\&, and returns a list of their data fields\&. So, a lookup for type \fIany\fR\& gives an empty answer, as the answer records have specific types that are not \fIany\fR\&\&. An empty answer or a failed lookup returns an empty list\&. .LP Calls \fB\fIresolve/*\fR\&\fR\& with the same arguments and filters the result, so \fIOpts\fR\& is described for those functions\&. .RE .LP .nf .B resolve(Name, Class, Type) -> {ok, dns_msg()} | Error .br .fi .br .nf .B resolve(Name, Class, Type, Opts) -> {ok, dns_msg()} | Error .br .fi .br .nf .B resolve(Name, Class, Type, Opts, Timeout) -> .B {ok, dns_msg()} | Error .br .fi .br .RS .LP Types: .RS 3 Name = \fBdns_name()\fR\& | \fBinet:ip_address()\fR\& .br Class = \fBdns_class()\fR\& .br Type = \fBrr_type()\fR\& .br Opts = [Opt] .br Opt = \fBres_option()\fR\& | verbose | atom() .br Timeout = timeout() .br Error = {error, Reason} | {error, {Reason, \fBdns_msg()\fR\&}} .br Reason = \fBinet:posix()\fR\& | \fBres_error()\fR\& .br .RE .RE .RS .LP Resolves a DNS record of the specified type and class for the specified name\&. The returned \fIdns_msg()\fR\& can be examined using access functions in \fIinet_db\fR\&, as described in section in \fBDNS Types\fR\&\&. .LP If \fIName\fR\& is an \fIip_address()\fR\&, the domain name to query for is generated as the standard reverse \fI"\&.IN-ADDR\&.ARPA\&."\fR\& name for an IPv4 address, or the \fI"\&.IP6\&.ARPA\&."\fR\& name for an IPv6 address\&. In this case, you most probably want to use \fIClass = in\fR\& and \fIType = ptr\fR\&, but it is not done automatically\&. .LP \fIOpts\fR\& overrides the corresponding resolver options\&. If option \fInameservers\fR\& is specified, it is assumed that it is the complete list of name serves, so resolver option \fIalt_nameserves\fR\& is ignored\&. However, if option \fIalt_nameserves\fR\& is also specified to this function, it is used\&. .LP Option \fIverbose\fR\& (or rather \fI{verbose,true}\fR\&) causes diagnostics printout through \fB\fIio:format/2\fR\&\fR\& of queries, replies retransmissions, and so on, similar to from utilities, such as \fIdig\fR\& and \fInslookup\fR\&\&. .LP If \fIOpt\fR\& is any atom, it is interpreted as \fI{Opt,true}\fR\& unless the atom string starts with \fI"no"\fR\&, making the interpretation \fI{Opt,false}\fR\&\&. For example, \fIusevc\fR\& is an alias for \fI{usevc,true}\fR\& and \fInousevc\fR\& is an alias for \fI{usevc,false}\fR\&\&. .LP Option \fIinet6\fR\& has no effect on this function\&. You probably want to use \fIType = a | aaaa\fR\& instead\&. .RE .SH "EXAMPLE" .LP This access functions example shows how \fB\fIlookup/3\fR\&\fR\& can be implemented using \fB\fIresolve/3\fR\&\fR\& from outside the module: .LP .nf example_lookup(Name, Class, Type) -> case inet_res:resolve(Name, Class, Type) of {ok,Msg} -> [inet_dns:rr(RR, data) || RR <- inet_dns:msg(Msg, anlist), inet_dns:rr(RR, type) =:= Type, inet_dns:rr(RR, class) =:= Class]; {error,_} -> [] end. .fi .SH "LEGACY FUNCTIONS" .LP These are deprecated because the annoying double meaning of the name servers/time-out argument, and because they have no decent place for a resolver options list\&. .SH EXPORTS .LP .nf .B nslookup(Name, Class, Type) -> {ok, dns_msg()} | {error, Reason} .br .fi .br .nf .B nslookup(Name, Class, Type, Timeout) -> .B {ok, dns_msg()} | {error, Reason} .br .fi .br .nf .B nslookup(Name, Class, Type, Nameservers) -> .B {ok, dns_msg()} | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Name = \fBdns_name()\fR\& | \fBinet:ip_address()\fR\& .br Class = \fBdns_class()\fR\& .br Type = \fBrr_type()\fR\& .br Timeout = timeout() .br Nameservers = [\fBnameserver()\fR\&] .br Reason = \fBinet:posix()\fR\& | \fBres_error()\fR\& .br .RE .RE .RS .LP Resolves a DNS record of the specified type and class for the specified name\&. .RE .LP .nf .B nnslookup(Name, Class, Type, Nameservers) -> .B {ok, dns_msg()} | {error, Reason} .br .fi .br .nf .B nnslookup(Name, Class, Type, Nameservers, Timeout) -> .B {ok, dns_msg()} | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Name = \fBdns_name()\fR\& | \fBinet:ip_address()\fR\& .br Class = \fBdns_class()\fR\& .br Type = \fBrr_type()\fR\& .br Timeout = timeout() .br Nameservers = [\fBnameserver()\fR\&] .br Reason = \fBinet:posix()\fR\& .br .RE .RE .RS .LP Resolves a DNS record of the specified type and class for the specified name\&. .RE