blob: eb66a6c89be4d390be782bdfcebe1c83c227cd54 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#ifndef __PJLIB_UTIL_DNS_H__
21#define __PJLIB_UTIL_DNS_H__
22
23
24/**
25 * @file dns.h
26 * @brief Low level DNS message parsing and packetization.
27 */
28#include <pjlib-util/types.h>
29#include <pj/sock.h>
30
31PJ_BEGIN_DECL
32
33/**
34 * @defgroup PJ_DNS DNS and Asynchronous DNS Resolver
35 * @ingroup PJ_PROTOCOLS
36 */
37
38/**
39 * @defgroup PJ_DNS_PARSING Low-level DNS Message Parsing and Packetization
40 * @ingroup PJ_DNS
41 * @{
42 *
43 * This module provides low-level services to parse and packetize DNS queries
44 * and responses. The functions support building a DNS query packet and parse
45 * the data in the DNS response. This implementation conforms to the
46 * following specifications:
47 * - RFC 1035: DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION
48 * - RFC 1886: DNS Extensions to support IP version 6
49 *
50 * To create a DNS query packet, application should call #pj_dns_make_query()
51 * function, specifying the desired DNS query type, the name to be resolved,
52 * and the buffer where the DNS packet will be built into.
53 *
54 * When incoming DNS query or response packet arrives, application can use
55 * #pj_dns_parse_packet() to parse the TCP/UDP payload into parsed DNS packet
56 * structure.
57 *
58 * This module does not provide any networking functionalities to send or
59 * receive DNS packets. This functionality should be provided by higher layer
60 * modules such as @ref PJ_DNS_RESOLVER.
61 */
62
63enum
64{
65 PJ_DNS_CLASS_IN = 1 /**< DNS class IN. */
66};
67
68/**
69 * This enumeration describes standard DNS record types as described by
70 * RFC 1035, RFC 2782, and others.
71 */
72typedef enum pj_dns_type
73{
74 PJ_DNS_TYPE_A = 1, /**< Host address (A) record. */
75 PJ_DNS_TYPE_NS = 2, /**< Authoritative name server (NS) */
76 PJ_DNS_TYPE_MD = 3, /**< Mail destination (MD) record. */
77 PJ_DNS_TYPE_MF = 4, /**< Mail forwarder (MF) record. */
78 PJ_DNS_TYPE_CNAME = 5, /**< Canonical name (CNAME) record. */
79 PJ_DNS_TYPE_SOA = 6, /**< Marks start of zone authority. */
80 PJ_DNS_TYPE_MB = 7, /**< Mailbox domain name (MB). */
81 PJ_DNS_TYPE_MG = 8, /**< Mail group member (MG). */
82 PJ_DNS_TYPE_MR = 9, /**< Mail rename domain name. */
83 PJ_DNS_TYPE_NULL = 10, /**< NULL RR. */
84 PJ_DNS_TYPE_WKS = 11, /**< Well known service description */
85 PJ_DNS_TYPE_PTR = 12, /**< Domain name pointer. */
86 PJ_DNS_TYPE_HINFO = 13, /**< Host information. */
87 PJ_DNS_TYPE_MINFO = 14, /**< Mailbox or mail list information. */
88 PJ_DNS_TYPE_MX = 15, /**< Mail exchange record. */
89 PJ_DNS_TYPE_TXT = 16, /**< Text string. */
90 PJ_DNS_TYPE_RP = 17, /**< Responsible person. */
91 PJ_DNS_TYPE_AFSB = 18, /**< AFS cell database. */
92 PJ_DNS_TYPE_X25 = 19, /**< X.25 calling address. */
93 PJ_DNS_TYPE_ISDN = 20, /**< ISDN calling address. */
94 PJ_DNS_TYPE_RT = 21, /**< Router. */
95 PJ_DNS_TYPE_NSAP = 22, /**< NSAP address. */
96 PJ_DNS_TYPE_NSAP_PTR= 23, /**< NSAP reverse address. */
97 PJ_DNS_TYPE_SIG = 24, /**< Signature. */
98 PJ_DNS_TYPE_KEY = 25, /**< Key. */
99 PJ_DNS_TYPE_PX = 26, /**< X.400 mail mapping. */
100 PJ_DNS_TYPE_GPOS = 27, /**< Geographical position (withdrawn) */
101 PJ_DNS_TYPE_AAAA = 28, /**< IPv6 address. */
102 PJ_DNS_TYPE_LOC = 29, /**< Location. */
103 PJ_DNS_TYPE_NXT = 30, /**< Next valid name in the zone. */
104 PJ_DNS_TYPE_EID = 31, /**< Endpoint idenfitier. */
105 PJ_DNS_TYPE_NIMLOC = 32, /**< Nimrod locator. */
106 PJ_DNS_TYPE_SRV = 33, /**< Server selection (SRV) record. */
107 PJ_DNS_TYPE_ATMA = 34, /**< DNS ATM address record. */
108 PJ_DNS_TYPE_NAPTR = 35, /**< DNS Naming authority pointer record. */
109 PJ_DNS_TYPE_KX = 36, /**< DNS key exchange record. */
110 PJ_DNS_TYPE_CERT = 37, /**< DNS certificate record. */
111 PJ_DNS_TYPE_A6 = 38, /**< DNS IPv6 address (experimental) */
112 PJ_DNS_TYPE_DNAME = 39, /**< DNS non-terminal name redirection rec. */
113
114 PJ_DNS_TYPE_OPT = 41, /**< DNS options - contains EDNS metadata. */
115 PJ_DNS_TYPE_APL = 42, /**< DNS Address Prefix List (APL) record. */
116 PJ_DNS_TYPE_DS = 43, /**< DNS Delegation Signer (DS) */
117 PJ_DNS_TYPE_SSHFP = 44, /**< DNS SSH Key Fingerprint */
118 PJ_DNS_TYPE_IPSECKEY= 45, /**< DNS IPSEC Key. */
119 PJ_DNS_TYPE_RRSIG = 46, /**< DNS Resource Record signature. */
120 PJ_DNS_TYPE_NSEC = 47, /**< DNS Next Secure Name. */
121 PJ_DNS_TYPE_DNSKEY = 48 /**< DNSSEC Key. */
122} pj_dns_type;
123
124
125
126/**
127 * Standard DNS header, according to RFC 1035, which will be present in
128 * both DNS query and DNS response.
129 *
130 * Note that all values seen by application would be in
131 * host by order. The library would convert them to network
132 * byte order as necessary.
133 */
134typedef struct pj_dns_hdr
135{
136 pj_uint16_t id; /**< Transaction ID. */
137 pj_uint16_t flags; /**< Flags. */
138 pj_uint16_t qdcount; /**< Nb. of queries. */
139 pj_uint16_t anscount; /**< Nb. of res records */
140 pj_uint16_t nscount; /**< Nb. of NS records. */
141 pj_uint16_t arcount; /**< Nb. of additional records */
142} pj_dns_hdr;
143
144/** Create RCODE flag */
145#define PJ_DNS_SET_RCODE(c) ((pj_uint16_t)((c) & 0x0F))
146
147/** Create RA (Recursion Available) bit */
148#define PJ_DNS_SET_RA(on) ((pj_uint16_t)((on) << 7))
149
150/** Create RD (Recursion Desired) bit */
151#define PJ_DNS_SET_RD(on) ((pj_uint16_t)((on) << 8))
152
153/** Create TC (Truncated) bit */
154#define PJ_DNS_SET_TC(on) ((pj_uint16_t)((on) << 9))
155
156/** Create AA (Authoritative Answer) bit */
157#define PJ_DNS_SET_AA(on) ((pj_uint16_t)((on) << 10))
158
159/** Create four bits opcode */
160#define PJ_DNS_SET_OPCODE(o) ((pj_uint16_t)((o) << 11))
161
162/** Create query/response bit */
163#define PJ_DNS_SET_QR(on) ((pj_uint16_t)((on) << 15))
164
165
166/** Get RCODE value */
167#define PJ_DNS_GET_RCODE(val) (((val) & PJ_DNS_SET_RCODE(0x0F)) >> 0)
168
169/** Get RA bit */
170#define PJ_DNS_GET_RA(val) (((val) & PJ_DNS_SET_RA(1)) >> 7)
171
172/** Get RD bit */
173#define PJ_DNS_GET_RD(val) (((val) & PJ_DNS_SET_RD(1)) >> 8)
174
175/** Get TC bit */
176#define PJ_DNS_GET_TC(val) (((val) & PJ_DNS_SET_TC(1)) >> 9)
177
178/** Get AA bit */
179#define PJ_DNS_GET_AA(val) (((val) & PJ_DNS_SET_AA(1)) >> 10)
180
181/** Get OPCODE value */
182#define PJ_DNS_GET_OPCODE(val) (((val) & PJ_DNS_SET_OPCODE(0x0F)) >> 11)
183
184/** Get QR bit */
185#define PJ_DNS_GET_QR(val) (((val) & PJ_DNS_SET_QR(1)) >> 15)
186
187
188/**
189 * These constants describe DNS RCODEs. Application can fold these constants
190 * into PJLIB pj_status_t namespace by calling #PJ_STATUS_FROM_DNS_RCODE()
191 * macro.
192 */
193typedef enum pj_dns_rcode
194{
195 PJ_DNS_RCODE_FORMERR = 1, /**< Format error. */
196 PJ_DNS_RCODE_SERVFAIL = 2, /**< Server failure. */
197 PJ_DNS_RCODE_NXDOMAIN = 3, /**< Name Error. */
198 PJ_DNS_RCODE_NOTIMPL = 4, /**< Not Implemented. */
199 PJ_DNS_RCODE_REFUSED = 5, /**< Refused. */
200 PJ_DNS_RCODE_YXDOMAIN = 6, /**< The name exists. */
201 PJ_DNS_RCODE_YXRRSET = 7, /**< The RRset (name, type) exists. */
202 PJ_DNS_RCODE_NXRRSET = 8, /**< The RRset (name, type) doesn't exist*/
203 PJ_DNS_RCODE_NOTAUTH = 9, /**< Not authorized. */
204 PJ_DNS_RCODE_NOTZONE = 10 /**< The zone specified is not a zone. */
205
206} pj_dns_rcode;
207
208
209/**
210 * This structure describes a DNS query record.
211 */
212typedef struct pj_dns_parsed_query
213{
214 pj_str_t name; /**< The domain in the query. */
215 pj_uint16_t type; /**< Type of the query (pj_dns_type) */
216 pj_uint16_t dnsclass; /**< Network class (PJ_DNS_CLASS_IN=1) */
217} pj_dns_parsed_query;
218
219
220/**
221 * This structure describes a Resource Record parsed from the DNS packet.
222 * All integral values are in host byte order.
223 */
224typedef struct pj_dns_parsed_rr
225{
226 pj_str_t name; /**< The domain name which this rec pertains. */
227 pj_uint16_t type; /**< RR type code. */
228 pj_uint16_t dnsclass; /**< Class of data (PJ_DNS_CLASS_IN=1). */
229 pj_uint32_t ttl; /**< Time to live. */
230 pj_uint16_t rdlength; /**< Resource data length. */
231 void *data; /**< Pointer to the raw resource data, only
232 when the type is not known. If it is known,
233 the data will be put in rdata below. */
234
235 /** For resource types that are recognized/supported by this library,
236 * the parsed resource data will be placed in this rdata union.
237 */
238 union rdata
239 {
240 /** SRV Resource Data (PJ_DNS_TYPE_SRV, 33) */
241 struct srv {
242 pj_uint16_t prio; /**< Target priority (lower is higher). */
243 pj_uint16_t weight; /**< Weight/proportion */
244 pj_uint16_t port; /**< Port number of the service */
245 pj_str_t target; /**< Target name. */
246 } srv;
247
248 /** CNAME Resource Data (PJ_DNS_TYPE_CNAME, 5) */
249 struct cname {
250 pj_str_t name; /**< Primary canonical name for an alias. */
251 } cname;
252
253 /** NS Resource Data (PJ_DNS_TYPE_NS, 2) */
254 struct ns {
255 pj_str_t name; /**< Primary name server. */
256 } ns;
257
258 /** PTR Resource Data (PJ_DNS_TYPE_PTR, 12) */
259 struct ptr {
260 pj_str_t name; /**< PTR name. */
261 } ptr;
262
263 /** A Resource Data (PJ_DNS_TYPE_A, 1) */
264 struct a {
265 pj_in_addr ip_addr;/**< IPv4 address in network byte order. */
266 } a;
267
268 /** AAAA Resource Data (PJ_DNS_TYPE_AAAA, 28) */
269 struct aaaa {
270 pj_in6_addr ip_addr;/**< IPv6 address in network byte order. */
271 } aaaa;
272
273 } rdata;
274
275} pj_dns_parsed_rr;
276
277
278/**
279 * This structure describes the parsed repersentation of the raw DNS packet.
280 * Note that all integral values in the parsed packet are represented in
281 * host byte order.
282 */
283typedef struct pj_dns_parsed_packet
284{
285 pj_dns_hdr hdr; /**< Pointer to DNS hdr, in host byte order */
286 pj_dns_parsed_query *q; /**< Array of DNS queries. */
287 pj_dns_parsed_rr *ans; /**< Array of DNS RR answer. */
288 pj_dns_parsed_rr *ns; /**< Array of NS record in the answer. */
289 pj_dns_parsed_rr *arr; /**< Array of additional RR answer. */
290} pj_dns_parsed_packet;
291
292
293/**
294 * Option flags to be specified when calling #pj_dns_packet_dup() function.
295 * These flags can be combined with bitwise OR operation.
296 */
297enum pj_dns_dup_options
298{
299 PJ_DNS_NO_QD = 1, /**< Do not duplicate the query section. */
300 PJ_DNS_NO_ANS = 2, /**< Do not duplicate the answer section. */
301 PJ_DNS_NO_NS = 4, /**< Do not duplicate the NS section. */
302 PJ_DNS_NO_AR = 8 /**< Do not duplicate the additional rec section */
303};
304
305
306/**
307 * Create DNS query packet to resolve the specified names. This function
308 * can be used to build any types of DNS query, such as A record or DNS SRV
309 * record.
310 *
311 * Application specifies the type of record and the name to be queried,
312 * and the function will build the DNS query packet into the buffer
313 * specified. Once the packet is successfully built, application can send
314 * the packet via TCP or UDP connection.
315 *
316 * @param packet The buffer to put the DNS query packet.
317 * @param size On input, it specifies the size of the buffer.
318 * On output, it will be filled with the actual size of
319 * the DNS query packet.
320 * @param id DNS query ID to associate DNS response with the
321 * query.
322 * @param qtype DNS type of record to be queried (see #pj_dns_type).
323 * @param name Name to be queried from the DNS server.
324 *
325 * @return PJ_SUCCESS on success, or the appropriate error code.
326 */
327PJ_DECL(pj_status_t) pj_dns_make_query(void *packet,
328 unsigned *size,
329 pj_uint16_t id,
330 int qtype,
331 const pj_str_t *name);
332
333/**
334 * Parse raw DNS packet into parsed DNS packet structure. This function is
335 * able to parse few DNS resource records such as A record, PTR record,
336 * CNAME record, NS record, and SRV record.
337 *
338 * @param pool Pool to allocate memory for the parsed packet.
339 * @param packet Pointer to the DNS packet (the TCP/UDP payload of
340 * the raw packet).
341 * @param size The size of the DNS packet.
342 * @param p_res Pointer to store the resulting parsed packet.
343 *
344 * @return PJ_SUCCESS on success, or the appropriate error code.
345 */
346PJ_DECL(pj_status_t) pj_dns_parse_packet(pj_pool_t *pool,
347 const void *packet,
348 unsigned size,
349 pj_dns_parsed_packet **p_res);
350
351/**
352 * Duplicate DNS packet.
353 *
354 * @param pool The pool to allocate memory for the duplicated packet.
355 * @param p The DNS packet to be cloned.
356 * @param options Option flags, from pj_dns_dup_options.
357 * @param p_dst Pointer to store the cloned DNS packet.
358 */
359PJ_DECL(void) pj_dns_packet_dup(pj_pool_t *pool,
360 const pj_dns_parsed_packet*p,
361 unsigned options,
362 pj_dns_parsed_packet **p_dst);
363
364
365/**
366 * Utility function to get the type name string of the specified DNS type.
367 *
368 * @param type DNS type (see #pj_dns_type).
369 *
370 * @return String name of the type (e.g. "A", "SRV", etc.).
371 */
372PJ_DECL(const char *) pj_dns_get_type_name(int type);
373
374
375/**
376 * Initialize DNS record as DNS SRV record.
377 *
378 * @param rec The DNS resource record to be initialized as DNS
379 * SRV record.
380 * @param res_name Resource name.
381 * @param dnsclass DNS class.
382 * @param ttl Resource TTL value.
383 * @param prio DNS SRV priority.
384 * @param weight DNS SRV weight.
385 * @param port Target port.
386 * @param target Target name.
387 */
388PJ_DECL(void) pj_dns_init_srv_rr(pj_dns_parsed_rr *rec,
389 const pj_str_t *res_name,
390 unsigned dnsclass,
391 unsigned ttl,
392 unsigned prio,
393 unsigned weight,
394 unsigned port,
395 const pj_str_t *target);
396
397/**
398 * Initialize DNS record as DNS CNAME record.
399 *
400 * @param rec The DNS resource record to be initialized as DNS
401 * CNAME record.
402 * @param res_name Resource name.
403 * @param dnsclass DNS class.
404 * @param ttl Resource TTL value.
405 * @param name Host name.
406 */
407PJ_DECL(void) pj_dns_init_cname_rr(pj_dns_parsed_rr *rec,
408 const pj_str_t *res_name,
409 unsigned dnsclass,
410 unsigned ttl,
411 const pj_str_t *name);
412
413/**
414 * Initialize DNS record as DNS A record.
415 *
416 * @param rec The DNS resource record to be initialized as DNS
417 * A record.
418 * @param res_name Resource name.
419 * @param dnsclass DNS class.
420 * @param ttl Resource TTL value.
421 * @param ip_addr Host address.
422 */
423PJ_DECL(void) pj_dns_init_a_rr(pj_dns_parsed_rr *rec,
424 const pj_str_t *res_name,
425 unsigned dnsclass,
426 unsigned ttl,
427 const pj_in_addr *ip_addr);
428
429/**
430 * Dump DNS packet to standard log.
431 *
432 * @param res The DNS packet.
433 */
434PJ_DECL(void) pj_dns_dump_packet(const pj_dns_parsed_packet *res);
435
436
437/**
438 * @}
439 */
440
441PJ_END_DECL
442
443
444#endif /* __PJLIB_UTIL_DNS_H__ */
445