summaryrefslogtreecommitdiffstats
path: root/branches/1.0/tinyNET/src/dns/tnet_dns.c
diff options
context:
space:
mode:
Diffstat (limited to 'branches/1.0/tinyNET/src/dns/tnet_dns.c')
-rw-r--r--branches/1.0/tinyNET/src/dns/tnet_dns.c973
1 files changed, 0 insertions, 973 deletions
diff --git a/branches/1.0/tinyNET/src/dns/tnet_dns.c b/branches/1.0/tinyNET/src/dns/tnet_dns.c
deleted file mode 100644
index 0683cbb..0000000
--- a/branches/1.0/tinyNET/src/dns/tnet_dns.c
+++ /dev/null
@@ -1,973 +0,0 @@
-/*
-* Copyright (C) 2009-2010 Mamadou Diop.
-*
-* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
-*
-* This file is part of Open Source Doubango Framework.
-*
-* DOUBANGO is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation, either version 3 of the License, or
-* (at your option) any later version.
-*
-* DOUBANGO is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with DOUBANGO.
-*
-*/
-/**@file tnet_dns.c
- * @brief DNS utility functions (RFCS [1034 1035] [3401 3402 3403 3404] [3761]).
- *
- * @author Mamadou Diop <diopmamadou(at)doubango.org>
- *
- * @date Created: Sat Nov 8 16:54:58 2009 mdiop
- */
-#include "tnet_dns.h"
-
-#include "tnet_dns_regexp.h"
-#include "tnet_dns_message.h"
-#include "tnet_dns_opt.h"
-#include "tnet_dns_srv.h"
-#include "tnet_dns_naptr.h"
-
-#include "tnet_types.h"
-
-#include "tsk_memory.h"
-#include "tsk_time.h"
-#include "tsk_debug.h"
-#include "tsk_string.h"
-
-#include <string.h> /* tsk_strlen, memser, .... */
-#include <ctype.h> /* isdigist */
-
-/* DNS cache functions */
-int tnet_dns_cache_maintenance(tnet_dns_ctx_t *ctx);
-int tnet_dns_cache_entry_add(tnet_dns_ctx_t *ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tnet_dns_response_t* response);
-const tnet_dns_cache_entry_t* tnet_dns_cache_entry_get(tnet_dns_ctx_t *ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype);
-
-/**@defgroup tnet_dns_group DNS utility functions (RFCS [1034 1035] [3401 3402 3403 3404]).
-*
-* <h1>11 DNS</h1>
-* <p>
-* The DNS Stack (RFC 1034 and RFC 1035) contains all network functions to send queries (both IPv4 and IPv6) and parse responses. <br>
-* The core framework implements RFC 3401, 3402, 3403 and 3404, also known as Dynamic Delegation Discovery System (DDDS).
-* </p>
-* <p>
-* The DNS servers are automatically loaded by the stack when you create a context (@ref tnet_dns_ctx_create()). <br>
-* On Windows systems (XP, VISTA, 7 and CE) the servers are retrieved using WIN32 APIs. On Unix-like systems (both desktop and embedded) such as Debian, Ubuntu, Nokia’s N900… the list of DNS servers comes from “/etc/resolv.conf” file. <br>
-* On Google Android operating system, this file is missing and the DNS settings are stored in the shared memory. You can access this shared memory by using @a property_get() and @a property_set() function which are part of Bionic. <br>
-* In all cases, you can retrieve the DNS servers yourself (e.g. using java/C# Frameworks) and add them to the context using @ref tnet_dns_add_server().
-* </p>
-* <p>
-* DNS resolution is always performed in a synchronous manner and is thread-safe. For all DNS requests the default timeout value is 5 seconds (@ref TNET_DNS_TIMEOUT_DEFAULT).
-* The stack also implements the ENUM protocol (RFC 3761).
-* </p>
-*
-* <h2>11.1 Resource Records</h2>
-* The table below lists all DNS Resource Records (RR) for which we provide a parser.
-*
-* <table>
-* <tr><td>Code</td> <td>RFC</td> <td>Description</td> <td>Well-defined type</td></tr>
-* <tr><td>A</td> <td>RFC 1035</td> <td>IPv4 address</td> <td>tnet_dns_a_t</td></tr>
-* <tr><td>AAAA</td> <td>RFC 3596</td> <td>IPv6 address</td> <td>tnet_dns_aaaa_t</td></tr>
-* <tr><td>CNAME</td> <td>RFC 1035</td> <td>Canonical name</td> <td>tnet_dns_cname_t</td></tr>
-* <tr><td>MX</td> <td>RFC 2035</td> <td>Mail exchange</td> <td>tnet_dns_mx_t</td></tr>
-* <tr><td>NAPTR</td> <td>RFC 3403</td> <td>Naming Authority Pointer</td> <td>tnet_dns_naptr_t</td></tr>
-* <tr><td>NS</td> <td>RFC 1035</td> <td>Name Server</td> <td>tnet_dns_ns_t</td></tr>
-* <tr><td>OPT</td> <td>RFC 2671</td> <td>Option</td> <td>tnet_dns_opt_t</td></tr>
-* <tr><td>PTR</td> <td>RFC 1035</td> <td>Pointer record</td> <td>tnet_dns_ptr_t</td></tr>
-* <tr><td>SOA</td> <td>RFC1035</td> <td>Start Of Authority record</td> <td>tnet_dns_soa_t</td></tr>
-* <tr><td>SRV</td> <td>RFC 2782</td> <td>Service locator</td> <td>tnet_dns_srv_t</td></tr>
-* </table>
-*
-* Here is an example of how to use the DNS stack to perform DNS NAPTR resolution and print the result to the console.
-*
-* @code
-tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
-tnet_dns_response_t *response = tsk_null;
-const tsk_list_item_t* item;
-const tnet_dns_rr_t* rr;
-
-if((response = tnet_dns_resolve(ctx, "sip2sip.info", qclass_in, qtype_naptr)))
-{
- if(TNET_DNS_RESPONSE_IS_SUCCESS(response)){
- TSK_DEBUG_INFO("We got a success response from the DNS server.");
- // loop through the answers
- tsk_list_foreach(item, response->Answers){
- rr = item->data;
- if(rr->qtype == qtype_naptr){
- const tnet_dns_naptr_t *naptr = (const tnet_dns_naptr_t*)rr;
-
- TSK_DEBUG_INFO("order=%u pref=%u flags=%s services=%s regexp=%s replacement=%s",
- naptr->order,
- naptr->preference,
- naptr->flags,
- naptr->services,
- naptr->regexp,
- naptr->replacement);
- }
- }
- }
- else{
- TSK_DEBUG_ERROR("We got an error response from the DNS server. Error code: %u", response->Header.RCODE);
- }
-}
-
-TSK_OBJECT_SAFE_FREE(response);
-TSK_OBJECT_SAFE_FREE(ctx);
-
-* @endcode
-* The @a ctx could be used several times and is a well-defined object.<br>
-* The console will output:
-* <i>INFO: We got a success response from the DNS server.</i><br>
-* <i>INFO: order=10 pref=0 flags=S services=SIP+d2u regexp=(null) replacement=_sip._udp.sip2sip.info</i><br>
-*
-* <h2>11.2 ENUM</h2>
-* ENUM (E.164 Number Mapping) protocol has been defined in RFC 3761.
-* ENUM protocol is used to transform telephone numbers of the PSTN network (e.g. +33600000) into internet resource addresses (e.g. sip:diopmamadou@example.com) by using DNS lookup (NAPTR). The internet resource address could be an email, ICQ, IAX2, H.323 …
-* In our case (3GPP IMS) it is typically used to convert TEL URIs (e.g. tel:+33600000) into SIP URIs (sip:+33600000;user=phone). The telephone number to convert should be a valid E.164 number.
-*
-* <h3>11.2.1 Usage</h3>
-* The code below shows how to gets the SIP address (with the higher order) associated to an E.164 telephone number.
-*
-* @code
-tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
-tnet_dns_response_t* response = tsk_null;
-char* uri = tsk_null;
-
-if((uri = tnet_dns_enum_2(ctx, "E2U+SIP", "+1-800-555-5555","e164.org"))){
- TSK_DEBUG_INFO("URI=%s", uri);
- TSK_FREE(uri);
-}
-else{
- TSK_DEBUG_ERROR("ENUM(%s) failed", "+1-800-555-5555");
-}
-
-TSK_OBJECT_SAFE_FREE(response);
-TSK_OBJECT_SAFE_FREE(ctx);
-* @endcode
-*
-* Console Output:<br>
-* <i>INFO: URI=sip:16416418000-555-5555@sip.tollfreegateway.com</i><br>
-*
-* E2U+SIP is the name of SIP ENUM service assigned by the IANA. Any assigned service () could be used even if the associated addresse type isn’t a well-knonw internet address.
-* To get all internet addresses (email, IAX2, ICQ, H.323 …) associated to the telephone, use @ref tnet_dns_enum() instead of @ref tnet_dns_enum_2().
-*/
-
-/**@ingroup tnet_dns_group
-* Creates new DNS context.
-*/
-tnet_dns_ctx_t* tnet_dns_ctx_create()
-{
- return tsk_object_new(tnet_dns_ctx_def_t);
-}
-
-/**@ingroup tnet_dns_group
-* Creates new DNS cache entry.
-*/
-tnet_dns_cache_entry_t* tnet_dns_cache_entry_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tnet_dns_response_t* answer)
-{
- return tsk_object_new(tnet_dns_cache_entry_def_t, qname, qclass, qtype, answer);
-}
-
-
-/**@ingroup tnet_dns_group
-* Cleanup the internal DNS cache.
-* @param ctx The DNS context containing the cache to cleanup.
-* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
-* @retval Zero if succeeed and non-zero error code otherwise.
-*/
-int tnet_dns_cache_clear(tnet_dns_ctx_t* ctx)
-{
- if(ctx){
- tsk_safeobj_lock(ctx);
- tsk_list_clear_items(ctx->cache);
- tsk_safeobj_unlock(ctx);
-
- return 0;
- }
- return -1;
-}
-
-/**@ingroup tnet_dns_group
-* Sends DNS request over the network. The request will be sent each 500 milliseconds until @ref TNET_DNS_TIMEOUT_DEFAULT milliseconds is reached.
-* @param ctx The DNS context to use. The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
-* @param qname The domain name (e.g. google.com).
-* @param qclass The CLASS of the query.
-* @param qtype The type of the query.
-* @retval The DNS response. The @a answers in the @a response are already filtered.
-* MUST be destroyed using @a TSK_OBJECT_SAFE_FREE() macro.
-* @sa @ref tnet_dns_query_srv, @ref tnet_dns_query_naptr_srv, @ref tnet_dns_enum.
-*
-* @code
-* tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
-* tnet_dns_response_t *response = tnet_dns_resolve(ctx, "sip2sip.info", qclass_in, qtype_srv);
-* TSK_OBJECT_SAFE_FREE(response);
-* TSK_OBJECT_SAFE_FREE(ctx);
-* @endcode
-*/
-tnet_dns_response_t *tnet_dns_resolve(tnet_dns_ctx_t* ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)
-{
-#if HAVE_DNS_H
- struct sockaddr_storage result;
- struct sockaddr *from;
- uint32_t fromlen;
- char buf[TNET_DNS_DGRAM_SIZE_DEFAULT];
- int32_t ret;
-
- tnet_dns_response_t *response = tsk_null;
-
- tnet_socket_t *localsocket4 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, tnet_socket_type_udp_ipv4);
- tnet_socket_t *localsocket6 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, tnet_socket_type_udp_ipv6);
-
- tsk_safeobj_lock(ctx);
-
- // First, try with IPv4
- if(TNET_SOCKET_IS_VALID(localsocket4)){
- if((ret = tnet_get_sockaddr(localsocket4->fd, &result))){
- TNET_PRINT_LAST_ERROR("tnet_get_sockaddr() failed.");
- goto ipv6;
- }
- from = (struct sockaddr *) &result;
- fromlen = from->sa_len;
-
- if ((ret = dns_search(ctx->resolv_handle, qname, qclass, qtype, buf, TNET_DNS_DGRAM_SIZE_DEFAULT, from, &fromlen)) > 0) {
- response = tnet_dns_message_deserialize((uint8_t *) buf, ret);
- goto done;
- }
- else{
- TNET_PRINT_LAST_ERROR("dns_search_v4()");
- }
- }
-ipv6:
- // Then, try with IPv6
- if(TNET_SOCKET_IS_VALID(localsocket6)){
- if((ret = tnet_get_sockaddr(localsocket6->fd, &result))){
- TNET_PRINT_LAST_ERROR("tnet_get_sockaddr() failed.");
- goto done;
- }
- from = (struct sockaddr *) &result;
- fromlen = from->sa_len;
-
- if((ret = dns_search(ctx->resolv_handle, qname, qclass, qtype, buf, TNET_DNS_DGRAM_SIZE_DEFAULT, from, &fromlen)) > 0){
- response = tnet_dns_message_deserialize((uint8_t *) buf, ret);
- goto done;
- }
- else{
- TNET_PRINT_LAST_ERROR("dns_search_v6()");
- }
- }
-
-done:
- tsk_safeobj_unlock(ctx);
-
- TSK_OBJECT_SAFE_FREE(localsocket4);
- TSK_OBJECT_SAFE_FREE(localsocket6);
-
- return response;
-#else
- tsk_buffer_t *output = tsk_null;
- tnet_dns_query_t* query = tnet_dns_query_create(qname, qclass, qtype);
- tnet_dns_response_t *response = tsk_null;
- tsk_bool_t from_cache = tsk_false;
-
- /* Check validity */
- if(!ctx || !query){
- goto bail;
- }
-
- /* Is there any DNS Server? */
- if(TSK_LIST_IS_EMPTY(ctx->servers)){
- TSK_DEBUG_ERROR("Failed to load DNS Servers. You can add new DNS servers by using \"tnet_dns_add_server\".");
- goto bail;
- }
-
- /* Cache maintenance */
- if(!TSK_LIST_IS_EMPTY(ctx->cache)){
- /* Only do maintenance if the cache is not empty */
- tnet_dns_cache_maintenance(ctx);
- }
-
- /* Retrieve data from cache. */
- if(ctx->caching){
- const tnet_dns_cache_entry_t *entry = tnet_dns_cache_entry_get(ctx, qname, qclass, qtype);
- if(entry){
- response = tsk_object_ref(((tnet_dns_cache_entry_t*)entry)->response);
- from_cache = tsk_true;
- goto bail;
- }
- }
-
- /* Set user preference */
- query->Header.RD = ctx->recursion;
-
- /* EDNS0 */
- if(ctx->edns0){
- tnet_dns_opt_t *rr_opt = tnet_dns_opt_create(TNET_DNS_DGRAM_SIZE_DEFAULT);
- if(!query->Additionals){
- query->Additionals = tsk_list_create();
- }
- tsk_list_push_back_data(query->Additionals, (void**)&rr_opt);
- query->Header.ARCOUNT++;
- }
-
- /* Serialize and send to the server. */
- if(!(output = tnet_dns_message_serialize(query))){
- TSK_DEBUG_ERROR("Failed to serialize the DNS message.");
- goto bail;
- }
-
- /* ============================ */
- // Send and Recaive data
- /* ============================ */
- {
- int ret = -1;
- struct timeval tv;
- fd_set set;
- tnet_fd_t maxFD;
- uint64_t timeout = 0;
- tsk_list_item_t *item;
- const tnet_address_t *address;
- struct sockaddr_storage server;
- tnet_socket_t *localsocket4 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, tnet_socket_type_udp_ipv4);
- tnet_socket_t *localsocket6 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, tnet_socket_type_udp_ipv6);
- tsk_bool_t useIPv6 = TNET_SOCKET_IS_VALID(localsocket6);
-
- tsk_safeobj_lock(ctx);
-
- /* Check socket validity */
- if(!TNET_SOCKET_IS_VALID(localsocket4)){
- goto done;
- }
-
- /* Always wait 500ms before retransmission */
- tv.tv_sec = 0;
- tv.tv_usec = (500 * 1000);
-
- do
- {
- //
- // Send data (loop through all intefaces)
- //
- tsk_list_foreach(item, ctx->servers)
- {
- address = item->data;
- if(!address->ip ||
- (address->family != AF_INET && address->family != AF_INET6) ||
- (address->family == AF_INET6 && !TNET_SOCKET_IS_VALID(localsocket6))){
- continue;
- }
-
- if(tnet_sockaddr_init(address->ip, ctx->server_port, (address->family == AF_INET ? tnet_socket_type_udp_ipv4 : tnet_socket_type_udp_ipv6), &server)){
- TSK_DEBUG_ERROR("Failed to initialize the DNS server address: \"%s\"", address->ip);
- continue;
- }
-
- TSK_DEBUG_INFO("Sending DNS query to \"%s\"", address->ip);
-
- if(address->family == AF_INET6){
- if((ret = tnet_sockfd_sendto(localsocket6->fd, (const struct sockaddr*)&server, output->data, output->size))){
- // succeed?
- break;
- }
- }
- else{
- if((ret = tnet_sockfd_sendto(localsocket4->fd, (const struct sockaddr*)&server, output->data, output->size))){
- // succeed?
- break;
- }
- }
- }
-
- //
- // Received data
- //
- /* First time? ==> set timeout value */
- if(!timeout){
- timeout = tsk_time_epoch() + ctx->timeout;
- }
-
- /* Set FDs */
- FD_ZERO(&set);
- FD_SET(localsocket4->fd, &set);
- if(useIPv6){
- FD_SET(localsocket6->fd, &set);
- maxFD = TSK_MAX(localsocket4->fd, localsocket6->fd);
- }
- else{
- maxFD = localsocket4->fd;
- }
-
- /* wait for response */
- if((ret = select(maxFD+1, &set, NULL, NULL, &tv))<0){ /* Error */
- TNET_PRINT_LAST_ERROR("Select failed.");
- goto done;
- }
- else if(ret == 0){ /* timeout ==> do nothing */
-
- }
- else{ /* there is data to read */
- tsk_size_t len = 0;
- void* data = 0;
- tnet_fd_t active_fd;
-
- /* Find active file descriptor */
- if(FD_ISSET(localsocket4->fd, &set)){
- active_fd = localsocket4->fd;
- }
- else if(FD_ISSET(localsocket6->fd, &set)){
- active_fd = localsocket4->fd;
- }
- else{
- TSK_DEBUG_ERROR("FD_ISSET ==> Invalid file descriptor.");
- continue;
- }
-
- /* Check how how many bytes are pending */
- if((ret = tnet_ioctlt(active_fd, FIONREAD, &len))<0){
- TSK_DEBUG_ERROR("tnet_ioctlt failed with error code:%d", tnet_geterrno());
- goto done;
- }
-
- /* Receive pending data */
- data = tsk_calloc(len, sizeof(uint8_t));
- if((ret = tnet_sockfd_recv(active_fd, data, len, 0))<0){
- TSK_FREE(data);
-
- TSK_DEBUG_ERROR("tnet_sockfd_recv failed with error code:%d", tnet_geterrno());
- goto done;
- }
-
- /* Parse the incoming response. */
- response = tnet_dns_message_deserialize(data, (tsk_size_t)ret);
- TSK_FREE(data);
-
- if(response)
- { /* response successfuly parsed */
- if(query->Header.ID != response->Header.ID || !TNET_DNS_MESSAGE_IS_RESPONSE(response)){
- /* Not same transaction id ==> continue*/
- TSK_OBJECT_SAFE_FREE(response);
- }
- else goto done;
- }
- }
- }
- while(timeout > tsk_time_epoch());
-
-done:
- tsk_safeobj_unlock(ctx);
-
- TSK_OBJECT_SAFE_FREE(localsocket4);
- TSK_OBJECT_SAFE_FREE(localsocket6);
- goto bail;
- }
-
-
-bail:
- TSK_OBJECT_SAFE_FREE(query);
- TSK_OBJECT_SAFE_FREE(output);
-
- /* Add the result to the cache. */
- if(response){
- if(!from_cache && ctx->caching){
- tnet_dns_cache_entry_add(ctx, qname, qclass, qtype, response);
- }
- }
- else{
- TSK_DEBUG_ERROR("Failed to contact the DNS server.");
- }
-
- return response;
-#endif
-}
-
-/**@ingroup tnet_dns_group
-* Gets list of URIs associated to this telephone number by using ENUM protocol (RFC 3761).
-* @param ctx The DNS context.
-* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
-* @param e164num A valid E.164 number (e.g. +1-800-555-5555).
-* @param domain The domain name (e.g e164.arpa, e164.org, ...). If Null, default value is "e164.arpa" (IANA).
-* @retval The DNS response with NAPTR RRs. The @a answers in the @a response are already filtered.
-* MUST be destroyed using @a TSK_OBJECT_SAFE_FREE macro.
-* @sa @ref tnet_dns_resolve, @ref tnet_dns_enum_2.
-*/
-tnet_dns_response_t* tnet_dns_enum(tnet_dns_ctx_t* ctx, const char* e164num, const char* domain)
-{
- char e164domain[255];
- tnet_dns_response_t* ret = tsk_null;
- tsk_size_t e164size;
- int i, j; // must be signed
-
- e164size = tsk_strlen(e164num);
-
- if(!ctx || !e164num || !e164size){
- goto bail;
- }
-
- if(e164size /* max=15 digits + ".e164.arpa" + '+' */>=(sizeof(e164domain)-1)){
- TSK_DEBUG_ERROR("%s is an invalid E.164 number.", e164num);
- goto bail;
- }
-
- memset(e164domain, '\0', sizeof(e164domain));
-
- /* RFC 3761 - 2.4. Valid Databases
- 1. Remove all characters with the exception of the digits. For
- example, the First Well Known Rule produced the Key
- "+442079460148". This step would simply remove the leading "+",
- producing "442079460148".
-
- 2. Put dots (".") between each digit. Example:
- 4.4.2.0.7.9.4.6.0.1.4.8
-
- 3. Reverse the order of the digits. Example:
- 8.4.1.0.6.4.9.7.0.2.4.4
-
- 4. Append the string ".e164.arpa" to the end. Example:
- 8.4.1.0.6.4.9.7.0.2.4.4.e164.arpa
-
- This domain-name is used to request NAPTR records which may contain
- the end result or, if the flags field is blank, produces new keys in
- the form of domain-names from the DNS.
- */
- for(i = e164size-1, j=0; i>=0; i--){
- if(!isdigit(e164num[i])){
- continue;
- }
- e164domain[j++] = e164num[i];
- e164domain[j++] = '.';
- }
-
- // append domain name
- if(domain){
- memcpy( &e164domain[j], domain, ((tsk_strlen(domain) + j) >= sizeof(e164domain)-1) ? (sizeof(e164domain)-j-1) : tsk_strlen(domain) );
- }
- else{
- memcpy(&e164domain[j], "e164.arpa", 9);
- }
-
- /* == Performs DNS (NAPTR) lookup == */
- ret = tnet_dns_resolve(ctx, e164domain, qclass_in, qtype_naptr);
-
-bail:
-
- return ret;
-}
-
-/**@ingroup tnet_dns_group
-* Gets the internate address associated to this telephone number by using ENUM protocol (RFC 3761).
-* Only terminale rules containing uris(flags="u") will be considered and the regex string will be executed on the original string for
-* substitution. <br>
-* <b> Parsing complex regexp will probably fail (99.99% chance). Please use @ref tnet_dns_enum if you want to use your own regexp parser. </b>
-* @param ctx The DNS context.
-* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
-* @param service The ENUM service (e.g. E2U+SIP).
-* @param e164num A valid E.164 number (e.g. +1-800-555-5555).
-* @param domain The domain name (e.g e164.arpa, e164.org, ...). If Null, default value is "e164.arpa" (IANA).
-* @retval The Internet address (SIP, email, ICQ, fax, ...) associated to this service.
-* MUST be freed using @a TSK_FREE macro.
-* @sa @ref tnet_dns_resolve, @ref tnet_dns_enum.
-*/
-char* tnet_dns_enum_2(tnet_dns_ctx_t* ctx, const char* service, const char* e164num, const char* domain)
-{
- tnet_dns_response_t* response;
- const tsk_list_item_t* item;
- char* ret = tsk_null;
- const tnet_dns_rr_t* rr;
-
- if((response = tnet_dns_enum(ctx, e164num, domain))){
- if(TNET_DNS_RESPONSE_IS_SUCCESS(response)){
- tsk_list_foreach(item, response->Answers){
- rr = item->data;
- if(rr->qtype == qtype_naptr){
- const tnet_dns_naptr_t *naptr = (const tnet_dns_naptr_t*)rr;
- /* RFC 3403 - 6.2 E164 Example
- Both the ENUM [18] and URI Resolution [4] Applications use the 'u'
- flag. This flag states that the Rule is terminal and that the output
- is a URI which contains the information needed to contact that
- telephone service.
- */
- if( tsk_striequals(naptr->flags, "u") && tsk_striequals(naptr->services, service)){
- /* RFC 3403 - 4.1 Packet Format
- The fields (replacement and regexp) are also mutually exclusive. If a record is
- returned that has values for both fields then it is considered to
- be in error and SHOULD be either ignored or an error returned.
- */
- if(naptr->regexp && naptr->replacement){
- continue;
- }
-
- if((ret = tnet_dns_regex_parse(e164num, naptr->regexp))){
- break;
- }
- }
- }
- }
- }
- else{
- TSK_DEBUG_ERROR("We got an error response from the DNS server. Error code: %u", response->Header.RCODE);
- }
-
- TSK_OBJECT_SAFE_FREE(response);
- }
-
- return ret;
-}
-
-/**@ingroup tnet_dns_group
-* Performs DNS SRV resolution.
-* @param ctx The DNS context.
-* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create.
-* @param service The name of the service (e.g. SIP+D2U).
-* @param hostname The result containing an IP address or FQDN.
-* @param port The port associated to the result.
-* @retval Zero if succeed and non-zero error code otherwise.
-* @sa @ref tnet_dns_resolve.
-*
-* @code
-* tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
-* char* hostname = 0;
-* tnet_port_t port = 0;
-*
-* if(!tnet_dns_query_srv(ctx, "_sip._udp.sip2sip.info", &hostname, &port)){
-* TSK_DEBUG_INFO("DNS SRV succeed ==> hostname=%s and port=%u", hostname, port);
-* }
-*
-* TSK_FREE(hostname);
-* TSK_OBJECT_SAFE_FREE(ctx);
-* @endcode
-*/
-int tnet_dns_query_srv(tnet_dns_ctx_t *ctx, const char* service, char** hostname, tnet_port_t* port)
-{
- tnet_dns_response_t *response;
-
- if(!ctx){
- return -1;
- }
-
- // tnet_dns_resolve is thread-safe
- if((response = tnet_dns_resolve(ctx, service, qclass_in, qtype_srv)))
- {
- const tsk_list_item_t *item;
- const tnet_dns_rr_t* rr;
- tsk_list_foreach(item, response->Answers) /* Already Filtered ==> Peek the first One */
- {
- rr = item->data;
- if(rr->qtype == qtype_srv){
- const tnet_dns_srv_t *srv = (const tnet_dns_srv_t*)rr;
-
- tsk_strupdate(hostname, srv->target);
- *port = srv->port;
- break;
- }
- }
- }
-
- TSK_OBJECT_SAFE_FREE(response);
-
- return (hostname && !tsk_strnullORempty(*hostname)) ? 0 : -2;
-}
-
-/**@ingroup tnet_dns_group
-* Performs DNS NAPTR followed by DNS SRV resolution.
-* @param ctx The DNS context.
-* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
-* @param domain The Name of the domain (e.g. google.com).
-* @param service The name of the service (e.g. SIP+D2U).
-* @param hostname The result containing an IP address or FQDN. Should be Null.
-* @param port The port associated to the result.
-* @retval Zero if succeed and non-zero error code otherwise.
-* @sa @ref tnet_dns_resolve.
-*
-* @code
-* tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
-* char* hostname = tsk_null;
-* tnet_port_t port = 0;
-*
-* if(!tnet_dns_query_naptr_srv(ctx, "sip2sip.info", "SIP+D2U", &hostname, &port)){
-* TSK_DEBUG_INFO("DNS NAPTR+SRV succeed ==> hostname=%s and port=%u", hostname, port);
-* }
-*
-* TSK_FREE(hostname);
-* TSK_OBJECT_SAFE_FREE(ctx);
-* @endcode
-*/
-int tnet_dns_query_naptr_srv(tnet_dns_ctx_t *ctx, const char* domain, const char* service, char** hostname, tnet_port_t* port)
-{
- tnet_dns_response_t *response;
-
- if(!ctx || !hostname){
- TSK_DEBUG_ERROR("Invalid parameters.");
- return -1;
- }
-
- /* reset (do not free the user supplied value). trying to free dummy value will cause access violation error ==> zero. */
- *hostname = tsk_null;
-
- // tnet_dns_resolve is thread-safe
- if((response = tnet_dns_resolve(ctx, domain, qclass_in, qtype_naptr))){
- const tsk_list_item_t *item;
- const tnet_dns_rr_t* rr;
-
- char* replacement = tsk_null; /* e.g. _sip._udp.example.com */
- char* flags = tsk_null;/* e.g. S, A, AAAA, A6, U, P ... */
-
- tsk_list_foreach(item, response->Answers) /* Already Filtered ==> Peek the first One */
- {
- rr = item->data;
- if(rr->qtype == qtype_naptr){
- tnet_dns_naptr_t *naptr = (tnet_dns_naptr_t*)rr;
-
- if(tsk_striequals(service, naptr->services)){
- tsk_strupdate(&replacement, naptr->replacement);
- tsk_strupdate(&flags, naptr->flags);
-
- break;
- }
- }
- }
-
- if(flags && replacement){
- if(tsk_striequals(flags, "S")){
- tnet_dns_query_srv(ctx, replacement, hostname, port);
- }
- else if(tsk_striequals(flags, "A") || tsk_striequals(flags, "AAAA") ||tsk_striequals(flags, "A6")){
- TSK_DEBUG_WARN("Defaulting port value.");
- tsk_strupdate(hostname, replacement);
- *port = 5060;
- }
- else{
- TSK_DEBUG_ERROR("DNS NAPTR query returned invalid falgs.");
- }
- }
- else{
- TSK_DEBUG_ERROR("DNS NAPTR query returned zero result.");
- }
-
- TSK_FREE(flags);
- TSK_FREE(replacement);
- }
-
- TSK_OBJECT_SAFE_FREE(response);
-
- return (hostname && *hostname && !tsk_strempty(*hostname)) ? 0 : -2;
-}
-
-// remove timedout entries
-int tnet_dns_cache_maintenance(tnet_dns_ctx_t *ctx)
-{
-
- if(ctx)
- {
- tsk_list_item_t *item;
- tsk_safeobj_lock(ctx);
-again:
-
- tsk_list_foreach(item, ctx->cache)
- {
- // FIXME: ttl should be from RR::ttl
- tnet_dns_cache_entry_t *entry = (tnet_dns_cache_entry_t*)item->data;
- if((entry ->epoch + ctx->cache_ttl) < tsk_time_epoch()){
- tsk_list_remove_item_by_data(ctx->cache, entry);
- goto again; /* Do not delete data while looping */
- }
- }
-
- tsk_safeobj_unlock(ctx);
-
- return 0;
- }
- return -1;
-}
-
-// add an entry to the cache
-int tnet_dns_cache_entry_add(tnet_dns_ctx_t *ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tnet_dns_response_t* response)
-{
- int ret = -1;
-
- if(ctx)
- {
- tnet_dns_cache_entry_t *entry;
-
- tsk_safeobj_lock(ctx);
-
- entry = 0;
-
- /* Retrieve from cache */
- entry = (tnet_dns_cache_entry_t*)tnet_dns_cache_entry_get(ctx, qname, qclass, qtype);
-
- if(entry){
- /* UPDATE */
- TSK_OBJECT_SAFE_FREE(entry->response);
- entry->response = tsk_object_ref(response);
- entry->epoch = tsk_time_epoch();
- ret = 0;
- goto done;
- }
- else{
- /* CREATE */
- entry = tnet_dns_cache_entry_create(qname, qclass, qtype, response);
- if(entry){
- tsk_list_push_back_data(ctx->cache, (void**)&entry);
- ret = 0;
- goto done;
- }
- else{
- ret = -2;
- goto done;
- }
- }
-done:
- tsk_safeobj_unlock(ctx);
- }
- return ret;
-}
-
-// get an entry from the cache
-const tnet_dns_cache_entry_t* tnet_dns_cache_entry_get(tnet_dns_ctx_t *ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)
-{
- tnet_dns_cache_entry_t *ret = tsk_null;
- if(ctx)
- {
- tsk_list_item_t *item;
-
- tsk_safeobj_lock(ctx);
-
- tsk_list_foreach(item, ctx->cache){
- tnet_dns_cache_entry_t *entry = (tnet_dns_cache_entry_t*)item->data;
- if(entry->qtype == qtype && entry->qclass == qclass && tsk_strequals(entry->qname, qname)){
- ret = entry;
- break;
- }
- }
-
- tsk_safeobj_unlock(ctx);
- }
-
- return ret;
-}
-
-
-/**@ingroup tnet_dns_group
-* Adds new DNS server to the list of the list of servers to query.
-* @param ctx DNS context containing the user parameters. The new DNS server will be added to this context.
-* @param host The IP address (or FQDN) of the dns server to add to the server.
-* @retval zero if succeed and non-zero error code otherwise.
-*/
-int tnet_dns_add_server(tnet_dns_ctx_t *ctx, const char* host)
-{
- tnet_address_t *address;
-
- if(!ctx || !host){
- return -1;
- }
-
- if(!ctx->servers){
- ctx->servers = tsk_list_create();
- }
-
- if((address = tnet_address_create(host))){
- address->family = tnet_get_family(host, TNET_DNS_SERVER_PORT_DEFAULT);
- address->dnsserver = 1;
- tsk_list_push_ascending_data(ctx->servers, (void**)&address);
-
- return 0;
- }
-
- return -2;
-}
-
-//=================================================================================================
-// [[DNS CACHE ENTRY]] object definition
-//
-static tsk_object_t* tnet_dns_cache_entry_ctor(tsk_object_t * self, va_list * app)
-{
- tnet_dns_cache_entry_t *entry = self;
- if(entry){
- entry->qname = tsk_strdup(va_arg(*app, const char*));
- entry->qclass = va_arg(*app, tnet_dns_qtype_t);
- entry->qtype = va_arg(*app, tnet_dns_qtype_t);
- entry->response = tsk_object_ref(va_arg(*app, tnet_dns_response_t*));
-
- entry->epoch = tsk_time_epoch();
- }
- return self;
-}
-
-static tsk_object_t* tnet_dns_cache_entry_dtor(tsk_object_t * self)
-{
- tnet_dns_cache_entry_t *entry = self;
- if(entry){
- TSK_OBJECT_SAFE_FREE(entry->response);
- }
- return self;
-}
-
-static const tsk_object_def_t tnet_dns_cache_entry_def_s =
-{
- sizeof(tnet_dns_cache_entry_t),
- tnet_dns_cache_entry_ctor,
- tnet_dns_cache_entry_dtor,
- tsk_null,
-};
-const tsk_object_def_t *tnet_dns_cache_entry_def_t = &tnet_dns_cache_entry_def_s;
-
-
-//=================================================================================================
-// [[DNS CONTEXT]] object definition
-//
-static tsk_object_t* tnet_dns_ctx_ctor(tsk_object_t * self, va_list * app)
-{
- tnet_dns_ctx_t *ctx = self;
- if(ctx){
- ctx->timeout = TNET_DNS_TIMEOUT_DEFAULT;
- ctx->recursion = tsk_true;
- ctx->edns0 = tsk_true;
- ctx->caching = tsk_false;
-
- ctx->cache_ttl = TNET_DNS_CACHE_TTL;
-
- ctx->server_port = TNET_DNS_SERVER_PORT_DEFAULT;
-
- /* Gets all dns servers. */
- ctx->servers = tnet_get_addresses_all_dnsservers();
- /* Creates empty cache. */
- ctx->cache = tsk_list_create();
-
-#if HAVE_DNS_H
- ctx->resolv_handle = dns_open(NULL);
-#endif
-
- tsk_safeobj_init(ctx);
- }
- return self;
-}
-
-static tsk_object_t* tnet_dns_ctx_dtor(tsk_object_t * self)
-{
- tnet_dns_ctx_t *ctx = self;
- if(ctx){
- tsk_safeobj_deinit(ctx);
-
- TSK_OBJECT_SAFE_FREE(ctx->servers);
- TSK_OBJECT_SAFE_FREE(ctx->cache);
-
-#if HAVE_DNS_H
- dns_free(ctx->resolv_handle);
-#endif
- }
- return self;
-}
-
-static const tsk_object_def_t tnet_dns_ctx_def_s =
-{
- sizeof(tnet_dns_ctx_t),
- tnet_dns_ctx_ctor,
- tnet_dns_ctx_dtor,
- tsk_null,
-};
-const tsk_object_def_t *tnet_dns_ctx_def_t = &tnet_dns_ctx_def_s;
OpenPOWER on IntegriCloud