1 /* $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 31 PJ_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 63 enum 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 */ 72 typedef 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 */ 134 typedef 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 */ 193 typedef 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 */ 212 typedef 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 */ 224 typedef 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 */ 283 typedef 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 */ 297 enum 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 */ 327 PJ_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 */ 346 PJ_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 */ 359 PJ_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 */ 372 PJ_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 */ 388 PJ_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 */ 407 PJ_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 */ 423 PJ_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 * Initialize DNS record as DNS AAAA record. 431 * 432 * @param rec The DNS resource record to be initialized as DNS 433 * AAAA record. 434 * @param res_name Resource name. 435 * @param dnsclass DNS class. 436 * @param ttl Resource TTL value. 437 * @param ip_addr Host address. 438 */ 439 PJ_DECL(void) pj_dns_init_aaaa_rr(pj_dns_parsed_rr *rec, 440 const pj_str_t *res_name, 441 unsigned dnsclass, 442 unsigned ttl, 443 const pj_in6_addr *ip_addr); 444 445 /** 446 * Dump DNS packet to standard log. 447 * 448 * @param res The DNS packet. 449 */ 450 PJ_DECL(void) pj_dns_dump_packet(const pj_dns_parsed_packet *res); 451 452 453 /** 454 * @} 455 */ 456 457 PJ_END_DECL 458 459 460 #endif /* __PJLIB_UTIL_DNS_H__ */ 461 462