Tristan Matthews | 0a329cc | 2013-07-17 13:20:14 -0400 | [diff] [blame] | 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 | * Dump DNS packet to standard log. |
| 431 | * |
| 432 | * @param res The DNS packet. |
| 433 | */ |
| 434 | PJ_DECL(void) pj_dns_dump_packet(const pj_dns_parsed_packet *res); |
| 435 | |
| 436 | |
| 437 | /** |
| 438 | * @} |
| 439 | */ |
| 440 | |
| 441 | PJ_END_DECL |
| 442 | |
| 443 | |
| 444 | #endif /* __PJLIB_UTIL_DNS_H__ */ |
| 445 | |