.TH inet_res 3erl "kernel 8.5.4.2" "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 ERTS User\&'s Guide: Inet Configuration 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 \fIinet\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 But before all name servers are tried again, there is a (user configurable) timeout, \fIservfail_retry_timeout\fR\&\&. The point of this is to prevent the new query to be handled by a server\&'s servfail cache (a client that is too eager will actually only get what is in the servfail cache)\&. If there is too little time left of the resolver call\&'s timeout to do a retry, the resolver call may return before the call\&'s timeout has expired\&. .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, [nameserver()]} | .br {edns, 0 | false} | .br {inet6, boolean()} | .br {nameservers, [nameserver()]} | .br {recurse, boolean()} | .br {retry, integer()} | .br {timeout, integer()} | .br {udp_payload_size, integer()} | .br {usevc, boolean()} | .br {nxdomain_reply, boolean()} .br .fi .nf \fBnameserver()\fR\& = {inet:ip_address(), Port :: 1\&.\&.65535} .br .fi .nf \fBres_error()\fR\& = .br formerr | qfmterror | servfail | nxdomain | notimp | refused | .br badvers | 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 \fBdns_rr_type()\fR\& = .br a | aaaa | caa | cname | gid | hinfo | ns | mb | md | mg | .br mf | minfo | mx | naptr | null | ptr | soa | spf | srv | txt | .br uid | uinfo | unspec | uri | 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 hierarchy 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 | dns_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, dns_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 dns_name() | .br inet:ip4_address() | .br inet:ip6_address() | .br {MName :: dns_name(), .br RName :: dns_name(), .br Serial :: integer(), .br Refresh :: integer(), .br Retry :: integer(), .br Expiry :: integer(), .br Minimum :: integer()} | .br {inet:ip4_address(), Proto :: integer(), BitMap :: binary()} | .br {CpuString :: string(), OsString :: string()} | .br {RM :: dns_name(), EM :: dns_name()} | .br {Prio :: integer(), dns_name()} | .br {Prio :: integer(), .br Weight :: integer(), .br Port :: integer(), .br dns_name()} | .br {Order :: integer(), .br Preference :: integer(), .br Flags :: string(), .br Services :: string(), .br Regexp :: string(), .br dns_name()} | .br [string()] | .br binary() .br .fi .RS .LP \fIRegexp\fR\& is a string with characters encoded in the UTF-8 coding standard\&. .RE .nf \fBhostent()\fR\& = .br {hostent, .br H_name :: inet:hostname(), .br H_aliases :: [inet:hostname()], .br H_addrtype :: dns_rr_type(), .br H_length :: integer() >= 0, .br H_addr_list :: [dns_data()]} .br .fi .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 = dns_name() .br Type = dns_rr_type() .br Timeout = timeout() .br Hostent = inet:hostent() | hostent() .br Reason = inet:posix() | res_error() .br .RE .RE .RS .LP Resolves a DNS record of the specified \fIType\fR\& for the specified host, of class \fIin\fR\&\&. Returns, on success, when resolving a \fIType = a|aaaa\fR\& DNS record, a \fI#hostent{}\fR\& record with \fI#hostent\&.h_addrtype = inet|inet6\fR\&, respectively; see \fIinet:hostent()\fR\&\&. .LP When resolving other \fIType = dns_rr_type()\fR\&:s (of class \fIin\fR\&), also returns a \fI#hostent{}\fR\& record but with \fIdns_rr_type()\fR\& in \fI#hostent\&.h_addrtype\fR\&, and the resolved \fIdns_data()\fR\& in \fI#hostent\&.h_addr_list\fR\&; see \fIhostent()\fR\&\&. .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 = inet:ip_address() .br Timeout = timeout() .br Hostent = inet:hostent() .br Reason = inet:posix() | res_error() .br .RE .RE .RS .LP Backend functions used by \fIinet:gethostbyaddr/1\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 = dns_name() .br Hostent = inet:hostent() .br Timeout = timeout() .br Family = inet:address_family() .br Reason = inet:posix() | res_error() .br .RE .RE .RS .LP Backend functions used by \fIinet:gethostbyname/1,2\fR\&\&. .LP This function uses resolver option \fIsearch\fR\& just like \fIgetbyname/2,3\fR\&\&. .LP If resolver option \fIinet6\fR\& is \fItrue\fR\&, an IPv6 address is looked up\&. .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 = dns_name() | inet:ip_address() .br Class = dns_class() .br Type = dns_rr_type() .br Opts = [res_option() | 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 \fIresolve/*\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 = dns_name() | inet:ip_address() .br Class = dns_class() .br Type = dns_rr_type() .br Opts = [Opt] .br Opt = res_option() | verbose | atom() .br Timeout = timeout() .br Error = {error, Reason} | {error, {Reason, dns_msg()}} .br Reason = inet:posix() | res_error() .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 DNS Types\&. .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 \fIio:format/2\fR\& of queries, replies retransmissions, and so on, similar to from utilities, such as \fIdig\fR\& and \fInslookup\fR\&\&. .LP Option \fInxdomain_reply\fR\& (or rather \fI{nxdomain_reply,true}\fR\&) causes nxdomain errors from DNS servers to be returned as \fI{error, {nxdomain, dns_msg()}}\fR\&\&. \fIdns_msg()\fR\& contains the additional sections that where included by the answering server\&. This is mainly useful to inspect the SOA record to get the TTL for negative caching\&. .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 \fIlookup/3\fR\& can be implemented using \fIresolve/3\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 = dns_name() | inet:ip_address() .br Class = dns_class() .br Type = dns_rr_type() .br Timeout = timeout() .br Nameservers = [nameserver()] .br Reason = inet:posix() | res_error() .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 = dns_name() | inet:ip_address() .br Class = dns_class() .br Type = dns_rr_type() .br Timeout = timeout() .br Nameservers = [nameserver()] .br Reason = inet:posix() .br .RE .RE .RS .LP Resolves a DNS record of the specified type and class for the specified name\&. .RE