diff options
author | Mamadou DIOP <bossiel@yahoo.fr> | 2015-08-17 01:56:35 +0200 |
---|---|---|
committer | Mamadou DIOP <bossiel@yahoo.fr> | 2015-08-17 01:56:35 +0200 |
commit | 631fffee8a28b1bec5ed1f1d26a20e0135967f99 (patch) | |
tree | 74afe3bf3efe15aa82bcd0272b2b0f4d48c2d837 /tinyNET/src/dns | |
parent | 7908865936604036e6f200f1b5e069f8752f3a3a (diff) | |
download | doubango-631fffee8a28b1bec5ed1f1d26a20e0135967f99.zip doubango-631fffee8a28b1bec5ed1f1d26a20e0135967f99.tar.gz |
-
Diffstat (limited to 'tinyNET/src/dns')
32 files changed, 4817 insertions, 0 deletions
diff --git a/tinyNET/src/dns/tnet_dns.c b/tinyNET/src/dns/tnet_dns.c new file mode 100644 index 0000000..87cd9b5 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns.c @@ -0,0 +1,967 @@ +/* +* Copyright (C) 2010-2015 Mamadou DIOP. +* +* 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]). + * + */ +#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_getsockname(localsocket4->fd, &result))){ + TNET_PRINT_LAST_ERROR("tnet_getsockname() failed."); + goto ipv6; + } + from = (struct sockaddr *) &result; + fromlen = tnet_get_sockaddr_size(from); + + 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_getsockname(localsocket6->fd, &result))){ + TNET_PRINT_LAST_ERROR("tnet_getsockname() failed."); + goto done; + } + from = (struct sockaddr *) &result; + fromlen = tnet_get_sockaddr_size(from); + + 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 */ + unsigned int 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; + int e164size; + int i, j; // must be signed + + e164size = (int)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 flags"); + } + } + else{ + TSK_DEBUG_INFO("DNS NAPTR (%s) query returned zero result", domain); + } + + 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_qclass_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; diff --git a/tinyNET/src/dns/tnet_dns.h b/tinyNET/src/dns/tnet_dns.h new file mode 100644 index 0000000..d4c2e6d --- /dev/null +++ b/tinyNET/src/dns/tnet_dns.h @@ -0,0 +1,125 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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.h + * @brief DNS utilities functions (RFCS [1034 1035] [2671] [3401 3402 3403 3404] [3761]). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ + +#ifndef TNET_DNS_H +#define TNET_DNS_H + +#include "tinynet_config.h" + +#include "tnet_dns_message.h" + +#include "tnet_utils.h" + +#include "tsk_safeobj.h" + +#if HAVE_DNS_H +#include <dns.h> +#endif + +TNET_BEGIN_DECLS + +/**@ingroup tnet_dns_group +*/ +#define TNET_DNS_CACHE_TTL (15000 * 1000) + +/**@ingroup tnet_dns_group +* Default timeout (in milliseconds) value for DNS queries. +*/ +#define TNET_DNS_TIMEOUT_DEFAULT 5000 //(5 seconds) + +/**@ingroup tnet_dns_group +* Maximum supported Dgram size to advertise using EDNS0. +*/ +#define TNET_DNS_DGRAM_SIZE_DEFAULT 4096 + +/**@ingroup tnet_dns_group +*/ +#define TNET_DNS_SERVER_PORT_DEFAULT 53 + +/**DNS cache entry. +*/ +typedef struct tnet_dns_cache_entry_s +{ + TSK_DECLARE_OBJECT; + + char* qname; + tnet_dns_qclass_t qclass; + tnet_dns_qtype_t qtype; + + uint64_t epoch; + + tnet_dns_response_t *response; +} +tnet_dns_cache_entry_t; +typedef tsk_list_t tnet_dns_cache_entries_L_t; +typedef tnet_dns_cache_entries_L_t tnet_dns_cache_t; + +/**DNS context. +*/ +typedef struct tnet_dns_ctx_s +{ + TSK_DECLARE_OBJECT; + + uint64_t timeout; /**< In milliseconds. Default: @ref TNET_DNS_TIMEOUT_DEFAULT. */ + tsk_bool_t recursion; /**< Indicates whether to direct the name server to pursue the query recursively. Default: enabled.*/ + tsk_bool_t edns0; /**< Indicates whether to enable EDNS0 (Extension Mechanisms for DNS) or not. This option will allow you to send DNS packet larger than 512 bytes. Default: enabled. */ + tsk_bool_t caching; /**< Indicates whether to enable the DNS cache or not. Default: no. */ + + int32_t cache_ttl; + + tnet_port_t server_port; /**< Default port (@a TNET_DNS_SERVER_PORT_DEFAULT)) */ + + tnet_dns_cache_t *cache; + tnet_addresses_L_t *servers; + + TSK_DECLARE_SAFEOBJ; + +#if HAVE_DNS_H + dns_handle_t resolv_handle; +#endif +} +tnet_dns_ctx_t; + +TINYNET_API int tnet_dns_cache_clear(tnet_dns_ctx_t* ctx); +TINYNET_API 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); +TINYNET_API tnet_dns_response_t* tnet_dns_enum(tnet_dns_ctx_t* ctx, const char* e164num, const char* domain); +TINYNET_API char* tnet_dns_enum_2(tnet_dns_ctx_t* ctx, const char* service, const char* e164num, const char* domain); +TINYNET_API int tnet_dns_query_srv(tnet_dns_ctx_t *ctx, const char* service, char** hostname, tnet_port_t* port); +TINYNET_API int tnet_dns_query_naptr_srv(tnet_dns_ctx_t *ctx, const char* domain, const char* service, char** hostname, tnet_port_t* port); + +TINYNET_API int tnet_dns_add_server(tnet_dns_ctx_t *ctx, const char* host); + +TINYNET_API tnet_dns_ctx_t* tnet_dns_ctx_create(); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_ctx_def_t; +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_cache_entry_def_t; + +TNET_END_DECLS + +#endif /* TNET_DNS_H */ diff --git a/tinyNET/src/dns/tnet_dns_a.c b/tinyNET/src/dns/tnet_dns_a.c new file mode 100644 index 0000000..27a3603 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_a.c @@ -0,0 +1,102 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_a.c + * @brief DNS Address record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#include "tnet_dns_a.h" + +#include "../tnet_types.h" +#include "../tnet_endianness.h" + +#include "tsk_string.h" +#include "tsk_memory.h" +#include "tsk_debug.h" + +/** Creates new DNS A Resource Record. +*/ +tnet_dns_a_t* tnet_dns_a_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset) +{ + return tsk_object_new(tnet_dns_a_def_t, name, qclass, ttl, rdlength, data, offset); +} + + +//================================================================================================= +// [[DNS A]] object definition +// +static tsk_object_t* tnet_dns_a_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_a_t *a = self; + if(a){ + const char* name = va_arg(*app, const char*); + tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t); + uint32_t ttl = va_arg(*app, uint32_t); + uint16_t rdlength = tsk_va_arg_u16(*app); + const void* data = va_arg(*app, const void*); + tsk_size_t offset = va_arg(*app, tsk_size_t); + + const uint8_t* rddata = (((uint8_t*)data) + offset); + //const uint8_t* dataEnd = (rddata + rdlength); + + /* init base */ + tnet_dns_rr_init(TNET_DNS_RR(a), qtype_a, qclass); + TNET_DNS_RR(a)->name = tsk_strdup(name); + TNET_DNS_RR(a)->rdlength = rdlength; + TNET_DNS_RR(a)->ttl = ttl; + + if(rddata && rdlength && (rdlength == 4/* 32bits */)){ + // ==> DESERIALIZATION + /* ADDRESS */ + uint32_t address = (uint32_t)tnet_htonl_2(rddata); + tsk_sprintf(&(a->address), "%u.%u.%u.%u", (address>>24)&0xFF, (address>>16)&0xFF, (address>>8)&0xFF, (address>>0)&0xFF); + } + else{ + TSK_DEBUG_ERROR("Invalid IPv4 address."); + } + + } + return self; +} + +static tsk_object_t* tnet_dns_a_dtor(tsk_object_t * self) +{ + tnet_dns_a_t *a = self; + if(a){ + /* deinit base */ + tnet_dns_rr_deinit(TNET_DNS_RR(a)); + + TSK_FREE(a->address); + } + return self; +} + +static const tsk_object_def_t tnet_dns_a_def_s = +{ + sizeof(tnet_dns_a_t), + tnet_dns_a_ctor, + tnet_dns_a_dtor, + tsk_null, +}; +const tsk_object_def_t *tnet_dns_a_def_t = &tnet_dns_a_def_s; diff --git a/tinyNET/src/dns/tnet_dns_a.h b/tinyNET/src/dns/tnet_dns_a.h new file mode 100644 index 0000000..e5db962 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_a.h @@ -0,0 +1,61 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_a.h + * @brief DNS Address record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#ifndef TNET_DNS_RR_A_H +#define TNET_DNS_RR_A_H + +#include "tinynet_config.h" + +#include "tnet_dns_rr.h" + +TNET_BEGIN_DECLS + + +/**DNS A Resource Record. +*/ +typedef struct tnet_dns_a_s +{ + TNET_DECLARE_DNS_RR; + + /* RFC 1035 - 3.4.1. A RDATA format + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | ADDRESS | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + char* address; +} +tnet_dns_a_t; + +TINYNET_API tnet_dns_a_t* tnet_dns_a_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_a_def_t; + +TNET_END_DECLS + +#endif /* TNET_DNS_RR_A_H */ + diff --git a/tinyNET/src/dns/tnet_dns_aaaa.c b/tinyNET/src/dns/tnet_dns_aaaa.c new file mode 100644 index 0000000..4855827 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_aaaa.c @@ -0,0 +1,104 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_aaaA.c + * @brief DNS IPv6 address record - RR - (RFC 3596). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#include "tnet_dns_aaaa.h" + +#include "../tnet_types.h" +#include "../tnet_endianness.h" + +#include "tsk_string.h" +#include "tsk_memory.h" +#include "tsk_debug.h" + +/** Creates new DNS AAAA Resource Record. +*/ + +tnet_dns_aaaa_t* tnet_dns_aaaa_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset) +{ + return tsk_object_new(tnet_dns_aaaa_def_t, name, qclass, ttl, rdlength, data, offset); +} + + +//================================================================================================= +// [[DNS AAAA]] object definition +// +static tsk_object_t* tnet_dns_aaaa_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_aaaa_t *aaaa = self; + if(aaaa){ + const char* name = va_arg(*app, const char*); + tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t); + uint32_t ttl = va_arg(*app, uint32_t); + uint16_t rdlength = tsk_va_arg_u16(*app); + const void* data = va_arg(*app, const void*); + tsk_size_t offset = va_arg(*app, tsk_size_t); + + const uint8_t* rddata = (((uint8_t*)data) + offset); + //const uint8_t* dataEnd = (rddata + rdlength); + + /* init base */ + tnet_dns_rr_init(TNET_DNS_RR(aaaa), qtype_aaaa, qclass); + TNET_DNS_RR(aaaa)->name = tsk_strdup(name); + TNET_DNS_RR(aaaa)->rdlength = rdlength; + TNET_DNS_RR(aaaa)->ttl = ttl; + + if(rddata && rdlength && (rdlength == 16/* 128bits */)){ + // ==> DESERIALIZATION + /* ADDRESS */ + tsk_sprintf(&(aaaa->address), "%x:%x:%x:%x:%x:%x:%x:%x", + tnet_ntohs_2(&rddata[0]), tnet_ntohs_2(&rddata[2]), tnet_ntohs_2(&rddata[4]), tnet_ntohs_2(&rddata[6]), + tnet_ntohs_2(&rddata[8]), tnet_ntohs_2(&rddata[10]), tnet_ntohs_2(&rddata[12]), tnet_ntohs_2(&rddata[14])); + } + else{ + TSK_DEBUG_ERROR("Invalid IPv6 address."); + } + + } + return self; +} + +static tsk_object_t* tnet_dns_aaaa_dtor(tsk_object_t * self) +{ + tnet_dns_aaaa_t *aaaa = self; + if(aaaa){ + /* deinit base */ + tnet_dns_rr_deinit(TNET_DNS_RR(aaaa)); + + TSK_FREE(aaaa->address); + } + return self; +} + +static const tsk_object_def_t tnet_dns_aaaa_def_s = +{ + sizeof(tnet_dns_aaaa_t), + tnet_dns_aaaa_ctor, + tnet_dns_aaaa_dtor, + tsk_null, +}; +const tsk_object_def_t *tnet_dns_aaaa_def_t = &tnet_dns_aaaa_def_s; diff --git a/tinyNET/src/dns/tnet_dns_aaaa.h b/tinyNET/src/dns/tnet_dns_aaaa.h new file mode 100644 index 0000000..759adf1 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_aaaa.h @@ -0,0 +1,58 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_aaaa.h + * @brief DNS IPv6 address record - RR - (RFC 3596). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#ifndef TNET_DNS_RR_AAAA_H +#define TNET_DNS_RR_AAAA_H + +#include "tinynet_config.h" + +#include "tnet_dns_rr.h" + + +TNET_BEGIN_DECLS + +/**DNS AAAA Resource Record. +*/ +typedef struct tnet_dns_aaaa_s +{ + TNET_DECLARE_DNS_RR; + + /* RFC 3596 - + */ + char* address; +} +tnet_dns_aaaa_t; + +tnet_dns_aaaa_t* tnet_dns_aaaa_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_aaaa_def_t; + +TNET_END_DECLS + +#endif /* TNET_DNS_RR_AAAA_H */ + diff --git a/tinyNET/src/dns/tnet_dns_cname.c b/tinyNET/src/dns/tnet_dns_cname.c new file mode 100644 index 0000000..8bec3e8 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_cname.c @@ -0,0 +1,93 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_cname.c + * @brief DNS Mail eXchange record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#include "tnet_dns_cname.h" + +#include "../tnet_types.h" + +#include "tsk_string.h" +#include "tsk_memory.h" + +/** Creates new DNS CNAME Resource Record. +*/ + +tnet_dns_cname_t* tnet_dns_cname_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset) +{ + return tsk_object_new(tnet_dns_cname_def_t, name, qclass, ttl, rdlength, data, offset); +} + + +//================================================================================================= +// [[DNS CNAME]] object definition +// +static tsk_object_t* tnet_dns_cname_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_cname_t *cname = self; + if(cname){ + const char* name = va_arg(*app, const char*); + tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t); + uint32_t ttl = va_arg(*app, uint32_t); + uint16_t rdlength = tsk_va_arg_u16(*app); + const void* data = va_arg(*app, const void*); + tsk_size_t offset = va_arg(*app, tsk_size_t); + + /* init base */ + tnet_dns_rr_init(TNET_DNS_RR(cname), qtype_cname, qclass); + TNET_DNS_RR(cname)->name = tsk_strdup(name); + TNET_DNS_RR(cname)->rdlength = rdlength; + TNET_DNS_RR(cname)->ttl = ttl; + + if(rdlength){ + // ==> DESERIALIZATION + /* CNAME */ + tnet_dns_rr_qname_deserialize(data, &(cname->cname), &offset); + } + } + return self; +} + +static tsk_object_t* tnet_dns_cname_dtor(tsk_object_t * self) +{ + tnet_dns_cname_t *cname = self; + if(cname){ + /* deinit base */ + tnet_dns_rr_deinit(TNET_DNS_RR(cname)); + + TSK_FREE(cname->cname); + } + return self; +} + +static const tsk_object_def_t tnet_dns_cname_def_s = +{ + sizeof(tnet_dns_cname_t), + tnet_dns_cname_ctor, + tnet_dns_cname_dtor, + tsk_null, +}; +const tsk_object_def_t *tnet_dns_cname_def_t = &tnet_dns_cname_def_s; diff --git a/tinyNET/src/dns/tnet_dns_cname.h b/tinyNET/src/dns/tnet_dns_cname.h new file mode 100644 index 0000000..f97087d --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_cname.h @@ -0,0 +1,63 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_cname.h + * @brief DNS Mail eXchange record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#ifndef TNET_DNS_RR_CNAME_H +#define TNET_DNS_RR_CNAME_H + +#include "tinynet_config.h" + +#include "tnet_dns_rr.h" + + +TNET_BEGIN_DECLS + + +/** DNS CNAME Resource Record +*/ +typedef struct tnet_dns_cname_s +{ + TNET_DECLARE_DNS_RR; + + /* 3.3.1. CNAME RDATA format + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + / CNAME / + / / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + char* cname; +} +tnet_dns_cname_t; + +tnet_dns_cname_t* tnet_dns_cname_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_cname_def_t; + +TNET_END_DECLS + +#endif /* TNET_DNS_RR_CNAME_H */ + diff --git a/tinyNET/src/dns/tnet_dns_message.c b/tinyNET/src/dns/tnet_dns_message.c new file mode 100644 index 0000000..594f499 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_message.c @@ -0,0 +1,359 @@ +/* +* Copyright (C) 2010-2015 Mamadou DIOP. +* +* 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_message.h + * @brief DNS Message holding RRs (RFC 1035). + * + */ +#include "tnet_dns_message.h" + +#include "../tnet_utils.h" +#include "../tnet_endianness.h" + +#include "tsk_memory.h" +#include "tsk_string.h" +#include "tsk_debug.h" + +#include <string.h> + +/**@ingroup tnet_dns_group +* Creates new DNS message. +* @sa tnet_dns_message_create_null. +*/ +tnet_dns_message_t* tnet_dns_message_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tsk_bool_t isquery) +{ + return tsk_object_new(tnet_dns_message_def_t, qname, qclass, qtype, isquery); +} + +/**@ingroup tnet_dns_group +* Creates new DNS message. +* @sa tnet_dns_message_create. +*/ +tnet_dns_message_t* tnet_dns_message_create_null() +{ + return tnet_dns_message_create(tsk_null, qclass_any, qtype_any, tsk_false); +} + +/**@ingroup tnet_dns_group +* Creates new DNS response message. +* @sa tnet_dns_query_create. +*/ +tnet_dns_response_t* tnet_dns_response_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype) +{ + return tnet_dns_message_create(qname, qclass, qtype, tsk_false); +} + +/**@ingroup tnet_dns_group +* Creates new DNS query message. +* @sa tnet_dns_response_create. +*/ +tnet_dns_query_t* tnet_dns_query_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype) +{ + return tnet_dns_message_create(qname, qclass, qtype, tsk_true); +} + +/**@ingroup tnet_dns_group +* Serializes a DNS message in binary data. +* @param message The DNS message to seriablize. +* @retval The binary buffer containong the message if succeed. Otherwise, @a tsk_null is returned. +* @sa tnet_dns_message_deserialize. +*/ +tsk_buffer_t* tnet_dns_message_serialize(const tnet_dns_message_t *message) +{ + tsk_buffer_t* output = tsk_null; + uint16_t _2bytes; + tsk_list_item_t *item; + + /* Check message validity */ + if (!message){ + goto bail; + } + + /* Creates empty buffer */ + output = tsk_buffer_create_null(); + + /* ============================== + * HEADER + */ + //tsk_buffer_append(output, &(message->Header), sizeof(message->Header)); + + /* ID */ + _2bytes = tnet_ntohs(message->Header.ID); + tsk_buffer_append(output, &(_2bytes), 2); + /* |QR| Opcode |AA|TC|RD|RA| Z | RCODE | */ + { + uint16_t temp, _2bytes = 0; + + temp = message->Header.QR, temp <<= 15; + _2bytes |= temp; + + temp = message->Header.OPCODE, temp <<= 11; + _2bytes |= temp; + + temp = message->Header.AA, temp <<= 10; + _2bytes |= temp; + + temp = message->Header.TC, temp <<= 9; + _2bytes |= temp; + + temp = message->Header.RD, temp <<= 8; + _2bytes |= temp; + + temp = message->Header.RA, temp <<= 7; + _2bytes |= temp; + + temp = message->Header.Z, temp <<= 4; + _2bytes |= temp; + + temp = message->Header.RCODE, temp <<= 4; + _2bytes |= temp; + + _2bytes = tnet_ntohs(_2bytes); + tsk_buffer_append(output, &(_2bytes), 2); + } + /* QDCOUNT */ + _2bytes = tnet_ntohs(message->Header.QDCOUNT); + tsk_buffer_append(output, &(_2bytes), 2); + /* ANCOUNT */ + _2bytes = tnet_ntohs(message->Header.ANCOUNT); + tsk_buffer_append(output, &(_2bytes), 2); + /* NSCOUNT */ + _2bytes = tnet_ntohs(message->Header.NSCOUNT); + tsk_buffer_append(output, &(_2bytes), 2); + /* ARCOUNT */ + _2bytes = tnet_ntohs(message->Header.ARCOUNT); + tsk_buffer_append(output, &(_2bytes), 2); + + + /* ============================== + * QUESTION + */ + if (TNET_DNS_MESSAGE_IS_QUERY(message)) + { + /* QNAME */ + tnet_dns_rr_qname_serialize(message->Question.QNAME, output); + /* QTYPE */ + _2bytes = tnet_ntohs(message->Question.QTYPE); + tsk_buffer_append(output, &(_2bytes), 2); + /* QCLASS */ + _2bytes = tnet_ntohs(message->Question.QCLASS); + tsk_buffer_append(output, &(_2bytes), 2); + } + + /* ============================== + * ANSWERS + */ + tsk_list_foreach(item, message->Answers) + { + tnet_dns_rr_serialize((tnet_dns_rr_t *)item->data, output); + } + + /* ============================== + * AUTHORITIES + */ + tsk_list_foreach(item, message->Authorities) + { + tnet_dns_rr_serialize((tnet_dns_rr_t *)item->data, output); + } + + /* ============================== + * ADDITIONALS + */ + tsk_list_foreach(item, message->Additionals) + { + tnet_dns_rr_serialize((tnet_dns_rr_t *)item->data, output); + } + + +bail: + return output; +} + +/**@ingroup tnet_dns_group +* Deserialize a STUN message from binary data. +* @param data A pointer to the binary data. +* @param size The size of the bnary data buffer. +* @retval @ref tnet_dns_message_t object if succeed or NULL otherwise. +* @sa @ref tnet_dns_message_serialize. +*/ +tnet_dns_message_t* tnet_dns_message_deserialize(const uint8_t *data, tsk_size_t size) +{ + tnet_dns_message_t *message = 0; + uint8_t *dataPtr, *dataEnd, *dataStart; + uint16_t i; + tsk_size_t offset = 0; + + if (!data || !size){ + goto bail; + } + + dataPtr = (uint8_t*)data; + dataStart = dataPtr; + dataEnd = (dataStart + size); + + message = tnet_dns_message_create_null(); + + /* === HEADER ===*/ + /* ID */ + message->Header.ID = tnet_ntohs_2(dataPtr); + dataPtr += 2; + /* |QR| Opcode |AA|TC|RD|RA| Z | RCODE | */ + { + uint16_t flags = tnet_ntohs_2(dataPtr); + + message->Header.QR = (flags >> 15); + message->Header.OPCODE = ((flags >> 11) & 0x000F); + message->Header.AA = ((flags >> 10) & 0x0001); + message->Header.TC = ((flags >> 9) & 0x0001); + message->Header.RD = ((flags >> 8) & 0x0001); + message->Header.RA = ((flags >> 7) & 0x0001); + message->Header.Z = ((flags >> 4) & 0x0007); + message->Header.RCODE = (flags & 0x000F); + + dataPtr += 2; + } + /* QDCOUNT */ + message->Header.QDCOUNT = tnet_ntohs_2(dataPtr); + dataPtr += 2; + /* ANCOUNT */ + message->Header.ANCOUNT = tnet_ntohs_2(dataPtr); + dataPtr += 2; + /* NSCOUNT */ + message->Header.NSCOUNT = tnet_ntohs_2(dataPtr); + dataPtr += 2; + /* ARCOUNT */ + message->Header.ARCOUNT = tnet_ntohs_2(dataPtr); + dataPtr += 2; + + /* === Queries ===*/ + offset = (tsk_size_t)(dataPtr - dataStart); + for (i = 0; i < message->Header.QDCOUNT; i++) + { + /* Do not need to parse queries in the response ==> silently ignore */ + char* name = 0; + tnet_dns_rr_qname_deserialize(dataStart, &name, &offset); /* QNAME */ + dataPtr += offset; + dataPtr += 4, offset += 4; /* QTYPE + QCLASS */ + TSK_FREE(name); + } + dataPtr = (dataStart + offset); /* TODO: remove ==> obly for debug tests */ + + /* === Answers ===*/ + offset = (tsk_size_t)(dataPtr - dataStart); + for (i = 0; i < message->Header.ANCOUNT; i++) + { + tnet_dns_rr_t* rr = tnet_dns_rr_deserialize(dataStart, (tsk_size_t)(dataEnd - dataPtr), &offset); + if (rr){ + if (!message->Answers){ + message->Answers = tsk_list_create(); + } + /* Push in descending order (useful for NAPTR and SRV records). */ + tsk_list_push_descending_data(message->Answers, (void**)&rr); + } + } + dataPtr = (dataStart + offset); + + /* === Authorities ===*/ + offset = (tsk_size_t)(dataPtr - dataStart); + for (i = 0; i < message->Header.NSCOUNT; i++) + { + tnet_dns_rr_t* rr = tnet_dns_rr_deserialize(dataStart, (tsk_size_t)(dataEnd - dataPtr), &offset); + if (rr){ + if (!message->Authorities){ + message->Authorities = tsk_list_create(); + } + tsk_list_push_back_data(message->Authorities, (void**)&rr); + } + } + dataPtr = (dataStart + offset); + + /* === Additionals ===*/ + offset = (tsk_size_t)(dataPtr - dataStart); + for (i = 0; i < message->Header.ARCOUNT; i++) + { + tnet_dns_rr_t* rr = tnet_dns_rr_deserialize(dataStart, (tsk_size_t)(dataEnd - dataPtr), &offset); + if (rr){ + if (!message->Additionals){ + message->Additionals = tsk_list_create(); + } + tsk_list_push_back_data(message->Additionals, (void**)&rr); + } + } + dataPtr = (dataStart + offset); + + +bail: + return message; +} + +//================================================================================================= +// [[DNS MESSAGE]] object definition +// +static tsk_object_t* tnet_dns_message_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_message_t *message = self; + if (message){ + static uint16_t __dnsmessage_unique_id = 0; + + const char* qname = va_arg(*app, const char*); + tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t); + tnet_dns_qtype_t qtype = va_arg(*app, tnet_dns_qtype_t); + tsk_bool_t isquery = va_arg(*app, tsk_bool_t); + + /* Create random ID. */ + message->Header.ID = ++__dnsmessage_unique_id; + + /* QR field ==> query (0) - response (1) */ + message->Header.QR = isquery ? 0 : 1; + + if (isquery){ + /* QDCOUNT field ==> at least one question */ + message->Header.QDCOUNT = 1; + } + + if (qname){ + message->Question.QNAME = tsk_strdup(qname); + message->Question.QTYPE = qtype; + message->Question.QCLASS = qclass; + } + } + return self; +} + +static tsk_object_t* tnet_dns_message_dtor(tsk_object_t * self) +{ + tnet_dns_message_t *message = self; + if (message){ + TSK_FREE(message->Question.QNAME); + + TSK_OBJECT_SAFE_FREE(message->Answers); + TSK_OBJECT_SAFE_FREE(message->Authorities); + TSK_OBJECT_SAFE_FREE(message->Additionals); + } + return self; +} + +static const tsk_object_def_t tnet_dns_message_def_s = +{ + sizeof(tnet_dns_message_t), + tnet_dns_message_ctor, + tnet_dns_message_dtor, + tsk_null, +}; +const tsk_object_def_t *tnet_dns_message_def_t = &tnet_dns_message_def_s; diff --git a/tinyNET/src/dns/tnet_dns_message.h b/tinyNET/src/dns/tnet_dns_message.h new file mode 100644 index 0000000..8506ff8 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_message.h @@ -0,0 +1,209 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_message.h + * @brief DNS Message holding RRs (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ + +#ifndef TNET_DNS_MESSAGE_H +#define TNET_DNS_MESSAGE_H + +#include "tinynet_config.h" + +#include "tnet_dns_rr.h" + +#include "tsk_buffer.h" + +/**@ingroup tnet_dns_group +* @def TNET_DNS_MESSAGE_IS_RESPONSE +* Checks whether the STUN message is a response or not(query). +* @sa TNET_DNS_MESSAGE_IS_QUERY. +*/ +/**@ingroup tnet_dns_group +* @def TNET_DNS_MESSAGE_IS_QUERY +* Checks whether the STUN message is a query or not(response). +* @sa TNET_DNS_MESSAGE_IS_RESPONSE. +*/ + +TNET_BEGIN_DECLS + + +#define TNET_DNS_MESSAGE_IS_RESPONSE(message) ((message) && (message)->Header.QR == 1) +#define TNET_DNS_MESSAGE_IS_QUERY(message) ((message) && (message)->Header.QR == 0) + +/**@ingroup tnet_dns_group +* @def TNET_DNS_RESPONSE_IS_SUCCESS +* Checks whether the STUN message is a success response or not(error). +* @sa TNET_DNS_RESPONSE_IS_ERROR. +*/ +/**@ingroup tnet_dns_group +* @def TNET_DNS_RESPONSE_IS_ERROR +* Checks whether the STUN message is an error response or not(success). +* @sa TNET_DNS_RESPONSE_IS_SUCCESS. +*/ +#define TNET_DNS_RESPONSE_IS_SUCCESS(response) ((response) && (response)->Header.RCODE == rcode_noerror) +#define TNET_DNS_RESPONSE_IS_ERROR(response) !TNET_DNS_RESPONSE_IS_SUCCESS(response) + +/**Response codes as per RFC 1035 subclause 4.1.1. +*/ +typedef enum tnet_dns_rcode_e +{ + rcode_noerror = 0, + rcode_error_format = 1, + rcode_server_failure = 2, + rcode_error_name = 3, + rcode_notimplemented = 4, + rcode_refused = 5 +} +tnet_dns_rcode_t; + +/**OPCODE defining the kind of query as per RFC 1035 subclause 4.1.1. +*/ +typedef enum tnet_dns_opcode_e +{ + opcode_query = 0, /**< 0 a standard query (QUERY) */ + opcode_iquery = 1, /**< 1 an inverse query (IQUERY) */ + opcode_status = 2, /**< 2 a server status request (STATUS) */ +} +tnet_dns_opcode_t; + +/** DNS message as per RFC 1035 subclause 4. +*/ +typedef struct tnet_dns_message_s +{ + TSK_DECLARE_OBJECT; + + /* RFC 1035 - 4.1. Format + +---------------------+ + | Header | + +---------------------+ + | Question | the question for the name server + +---------------------+ + | Answer | RRs answering the question + +---------------------+ + | Authority | RRs pointing toward an authority + +---------------------+ + | Additional | RRs holding additional information + +---------------------+ + */ + + /* RFC 1035 - 4.1.1. Header section format + 1 1 1 1 1 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | ID | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | QDCOUNT | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | ANCOUNT | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | NSCOUNT | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | ARCOUNT | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + struct + { + uint16_t ID; + unsigned QR:1; + unsigned OPCODE:4; /* see @ref tnet_dns_opcode_t */ + unsigned AA:1; + unsigned TC:1; + unsigned RD:1; + unsigned RA:1; + unsigned Z:3; + unsigned RCODE:4; /* see @ref tnet_dns_rcode_t */ + uint16_t QDCOUNT; + uint16_t ANCOUNT; + uint16_t NSCOUNT; + uint16_t ARCOUNT; + } + Header; + + /* RFc 1035 - 4.1.2. Question section format + 1 1 1 1 1 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | | + / QNAME / + / / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | QTYPE | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | QCLASS | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + struct + { + /** RFC 1035 - 4.1.2. Question section format + a domain name represented as a sequence of labels, where + each label consists of a length octet followed by that + number of octets. The domain name terminates with the + zero length octet for the null label of the root. Note + that this field may be an odd number of octets; no + padding is used.*/ + void* QNAME; + /** RFC 1035 - 4.1.2. Question section format + a two octet code which specifies the type of the query. + The values for this field include all codes valid for a + TYPE field, together with some more general codes which + can match more than one type of RR.*/ + tnet_dns_qtype_t QTYPE; + /* RFC 1035 - 4.1.2. Question section format + a two octet code that specifies the class of the query. + For example, the QCLASS field is IN for the Internet. + */ + tnet_dns_qclass_t QCLASS; + } + Question; + + tnet_dns_rrs_L_t *Answers; /**< Filtered answers by priority. */ + tnet_dns_rrs_L_t *Authorities; + tnet_dns_rrs_L_t *Additionals; +} +tnet_dns_message_t; + +typedef tsk_list_t tnet_dns_messages_L_t; /**< List of @ref tnet_dns_message_t elements. */ +typedef tnet_dns_message_t tnet_dns_query_t; /**< DNS Query messsage. */ +typedef tnet_dns_message_t tnet_dns_response_t; /**< DNS response message. */ + +tsk_buffer_t* tnet_dns_message_serialize(const tnet_dns_message_t *message); +tnet_dns_message_t* tnet_dns_message_deserialize(const uint8_t *data, tsk_size_t size); + + +tnet_dns_message_t* tnet_dns_message_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tsk_bool_t isquery); +tnet_dns_message_t* tnet_dns_message_create_null(); +tnet_dns_response_t* tnet_dns_response_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype); +tnet_dns_query_t* tnet_dns_query_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_message_def_t; + +TNET_END_DECLS + +#endif /* TNET_DNS_MESSAGE_H */ + + diff --git a/tinyNET/src/dns/tnet_dns_mx.c b/tinyNET/src/dns/tnet_dns_mx.c new file mode 100644 index 0000000..edc59b1 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_mx.c @@ -0,0 +1,95 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_mx.c + * @brief DNS Mail eXchange record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#include "tnet_dns_mx.h" + +#include "../tnet_types.h" +#include "../tnet_endianness.h" + +#include "tsk_string.h" +#include "tsk_memory.h" + +/** Creates new DNS MX Resource Record. +*/ +tnet_dns_mx_t* tnet_dns_mx_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset) +{ + return tsk_object_new(tnet_dns_mx_def_t, name, qclass, ttl, rdlength, data, offset); +} + +//================================================================================================= +// [[DNS MX]] object definition +// +static tsk_object_t* tnet_dns_mx_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_mx_t *mx = self; + if(mx){ + const char* name = va_arg(*app, const char*); + tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t); + uint32_t ttl = va_arg(*app, uint32_t); + uint16_t rdlength = tsk_va_arg_u16(*app); + const void* data = va_arg(*app, const void*); + tsk_size_t offset = va_arg(*app, tsk_size_t); + + /* init base */ + tnet_dns_rr_init(TNET_DNS_RR(mx), qtype_mx, qclass); + TNET_DNS_RR(mx)->name = tsk_strdup(name); + TNET_DNS_RR(mx)->rdlength = rdlength; + TNET_DNS_RR(mx)->ttl = ttl; + + if(rdlength){ + // ==> DESERIALIZATION + /* PREFERENCE */ + mx->preference = tnet_ntohs_2(((uint8_t*)data) + offset); + offset += 2; + /* EXCHANGE */ + tnet_dns_rr_qname_deserialize(data, &(mx->exchange), &offset); + } + } + return self; +} + +static tsk_object_t* tnet_dns_mx_dtor(tsk_object_t * self) +{ + tnet_dns_mx_t *mx = self; + if(mx){ + /* deinit base */ + tnet_dns_rr_deinit(TNET_DNS_RR(mx)); + + TSK_FREE(mx->exchange); + } + return self; +} + +static const tsk_object_def_t tnet_dns_mx_def_s = +{ + sizeof(tnet_dns_mx_t), + tnet_dns_mx_ctor, + tnet_dns_mx_dtor, + tsk_null, +}; +const tsk_object_def_t *tnet_dns_mx_def_t = &tnet_dns_mx_def_s; diff --git a/tinyNET/src/dns/tnet_dns_mx.h b/tinyNET/src/dns/tnet_dns_mx.h new file mode 100644 index 0000000..98a00f1 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_mx.h @@ -0,0 +1,66 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_mx.h + * @brief DNS Mail eXchange record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#ifndef TNET_DNS_RR_MX_H +#define TNET_DNS_RR_MX_H + +#include "tinynet_config.h" + +#include "tnet_dns_rr.h" + + +TNET_BEGIN_DECLS + + +/** DNS MX Resource Record +*/ +typedef struct tnet_dns_mx_s +{ + TNET_DECLARE_DNS_RR; + + /* RFC 1035 - 3.3.9. MX RDATA format + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | PREFERENCE | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + / EXCHANGE / + / / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + uint16_t preference; + char* exchange; +} +tnet_dns_mx_t; + +tnet_dns_mx_t* tnet_dns_mx_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_mx_def_t; + +TNET_END_DECLS + +#endif /* TNET_DNS_RR_MX_H */ + diff --git a/tinyNET/src/dns/tnet_dns_naptr.c b/tinyNET/src/dns/tnet_dns_naptr.c new file mode 100644 index 0000000..79d7f70 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_naptr.c @@ -0,0 +1,142 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_naptr.c + * @brief DNS Naming Authority Pointer - RR - (RFC 3403). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#include "tnet_dns_naptr.h" + + +#include "../tnet_types.h" +#include "./tnet_endianness.h" + +#include "tsk_memory.h" +#include "tsk_string.h" + +/** Creates new DNS NAPTR Resource Record. +*/ +tnet_dns_naptr_t* tnet_dns_naptr_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset) +{ + return tsk_object_new(tnet_dns_naptr_def_t, name, qclass, ttl, rdlength, data, offset); +} + + + +//================================================================================================= +// [[DNS NAPTR]] object definition +// +static tsk_object_t* tnet_dns_naptr_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_naptr_t *naptr = self; + if(naptr){ + const char* name = va_arg(*app, const char*); + tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t); + uint32_t ttl = va_arg(*app, uint32_t); + uint16_t rdlength = tsk_va_arg_u16(*app); + const void* data = va_arg(*app, const void*); + tsk_size_t offset = va_arg(*app, tsk_size_t); + + /* init base */ + tnet_dns_rr_init(TNET_DNS_RR(naptr), qtype_naptr, qclass); + TNET_DNS_RR(naptr)->name = tsk_strdup(name); + TNET_DNS_RR(naptr)->rdlength = rdlength; + TNET_DNS_RR(naptr)->ttl = ttl; + + if(rdlength){ + // ==> DESERIALIZATION + /* ORDER */ + naptr->order = tnet_ntohs_2(((uint8_t*)data) + offset); + offset += 2; + /* PREFERENCE */ + naptr->preference = tnet_ntohs_2(((uint8_t*)data) + offset); + offset += 2; + /* FLAGS */ + tnet_dns_rr_charstring_deserialize(data, &(naptr->flags), &offset); + /* SERVICES */ + tnet_dns_rr_charstring_deserialize(data, &(naptr->services), &offset); + /* REGEXP */ + tnet_dns_rr_charstring_deserialize(data, &(naptr->regexp), &offset); + /* REPLACEMENT */ + tnet_dns_rr_qname_deserialize(data, &(naptr->replacement), &offset); + } + } + return self; +} + +static tsk_object_t* tnet_dns_naptr_dtor(tsk_object_t * self) +{ + tnet_dns_naptr_t *naptr = self; + if(naptr){ + /* deinit base */ + tnet_dns_rr_deinit(TNET_DNS_RR(naptr)); + + TSK_FREE(naptr->flags); + TSK_FREE(naptr->services); + TSK_FREE(naptr->regexp); + TSK_FREE(naptr->replacement); + } + return self; +} + +static int tnet_dns_naptr_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + const tnet_dns_rr_t* rr1 = obj1; + const tnet_dns_rr_t* rr2 = obj2; + + if(rr1 && rr2 && (rr1->qtype==qtype_naptr) && (rr2->qtype==qtype_naptr)){ + const tnet_dns_naptr_t* naptr1 = (tnet_dns_naptr_t*)rr1; + const tnet_dns_naptr_t* naptr2 = (tnet_dns_naptr_t*)rr2; + + /* Compare orders. */ + if(naptr1->order < naptr2->order){ /* Lowest order is tried first. */ + return 1; + } + else if(naptr1->order > naptr2->order){ + return -1; + } + + /* Compare preference */ + if(naptr1->order < naptr2->order){ /* Lowest preference is tried first. */ + return 1; + } + else if(naptr1->order > naptr2->order){ + return -1; + } + + return 0; + } + else{ + return -1; + } +} + +static const tsk_object_def_t tnet_dns_naptr_def_s = +{ + sizeof(tnet_dns_naptr_t), + tnet_dns_naptr_ctor, + tnet_dns_naptr_dtor, + tnet_dns_naptr_cmp, +}; +const tsk_object_def_t *tnet_dns_naptr_def_t = &tnet_dns_naptr_def_s; diff --git a/tinyNET/src/dns/tnet_dns_naptr.h b/tinyNET/src/dns/tnet_dns_naptr.h new file mode 100644 index 0000000..b960809 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_naptr.h @@ -0,0 +1,81 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_naptr.h + * @brief DNS Naming Authority Pointer - RR - (RFC 3403). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#ifndef TNET_DNS_RR_NAPTR_H +#define TNET_DNS_RR_NAPTR_H + +#include "tinynet_config.h" + +#include "tnet_dns_rr.h" + +TNET_BEGIN_DECLS + +/** DNS NAPTR Resource Record +*/ +typedef struct tnet_dns_naptr_s +{ + TNET_DECLARE_DNS_RR; + + /* RFC 3403 - 4.1 Packet Format + + The packet format for the NAPTR record is as follows + 1 1 1 1 1 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | ORDER | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | PREFERENCE | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + / FLAGS / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + / SERVICES / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + / REGEXP / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + / REPLACEMENT / + / / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + <character-string> and <domain-name> as used here are defined in RFC 1035. + */ + uint16_t order; + uint16_t preference; + char* flags; + char* services; + char* regexp; + char* replacement; +} +tnet_dns_naptr_t; + +TINYNET_API tnet_dns_naptr_t* tnet_dns_naptr_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_naptr_def_t; + +TNET_END_DECLS + +#endif /* TNET_DNS_RR_NAPTR_H */ + diff --git a/tinyNET/src/dns/tnet_dns_ns.c b/tinyNET/src/dns/tnet_dns_ns.c new file mode 100644 index 0000000..a23426c --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_ns.c @@ -0,0 +1,92 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_ns.c + * @brief DNS Name Server record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#include "tnet_dns_ns.h" + +#include "tsk_string.h" +#include "tsk_memory.h" + +#include "tnet_dns_rr.h" + +/** Creates new DNS NS Resource Record. +*/ +tnet_dns_ns_t* tnet_dns_ns_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset) +{ + return tsk_object_new(tnet_dns_ns_def_t, name, qclass, ttl, rdlength, data, offset); +} + +//================================================================================================= +// [[DNS NS]] object definition +// +static tsk_object_t* tnet_dns_ns_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_ns_t *ns = self; + if(ns){ + const char* name = va_arg(*app, const char*); + tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t); + uint32_t ttl = va_arg(*app, uint32_t); + uint16_t rdlength = tsk_va_arg_u16(*app); + const void* data = va_arg(*app, const void*); + tsk_size_t offset = va_arg(*app, tsk_size_t); + + /* init base */ + tnet_dns_rr_init(TNET_DNS_RR(ns), qtype_ns, qclass); + TNET_DNS_RR(ns)->name = tsk_strdup(name); + TNET_DNS_RR(ns)->rdlength = rdlength; + TNET_DNS_RR(ns)->ttl = ttl; + + if(rdlength){ + // ==> DESERIALIZATION + /* NSDNAME */ + tnet_dns_rr_qname_deserialize(data, &(ns->nsdname), &offset); + } + + } + return self; +} + +static tsk_object_t* tnet_dns_ns_dtor(tsk_object_t * self) +{ + tnet_dns_ns_t *ns = self; + if(ns){ + /* deinit base */ + tnet_dns_rr_deinit(TNET_DNS_RR(ns)); + + TSK_FREE(ns->nsdname); + } + return self; +} + +static const tsk_object_def_t tnet_dns_ns_def_s = +{ + sizeof(tnet_dns_ns_t), + tnet_dns_ns_ctor, + tnet_dns_ns_dtor, + tsk_null, +}; +const tsk_object_def_t *tnet_dns_ns_def_t = &tnet_dns_ns_def_s; diff --git a/tinyNET/src/dns/tnet_dns_ns.h b/tinyNET/src/dns/tnet_dns_ns.h new file mode 100644 index 0000000..9a77f26 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_ns.h @@ -0,0 +1,63 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_ns.h + * @brief DNS Name Server record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#ifndef TNET_DNS_RR_NS_H +#define TNET_DNS_RR_NS_H + +#include "tinynet_config.h" + +#include "tnet_dns_rr.h" + + +TNET_BEGIN_DECLS + + +/** DNS NS Resource Record. +*/ +typedef struct tnet_dns_ns_s +{ + TNET_DECLARE_DNS_RR; + + /* RFC 1035 - 3.3.11. NS RDATA format + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + / NSDNAME / + / / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + char* nsdname; +} +tnet_dns_ns_t; + +TINYNET_API tnet_dns_ns_t* tnet_dns_ns_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_ns_def_t; + +TNET_END_DECLS + +#endif /* TNET_DNS_RR_NS_H */ + diff --git a/tinyNET/src/dns/tnet_dns_opt.c b/tinyNET/src/dns/tnet_dns_opt.c new file mode 100644 index 0000000..dab4fea --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_opt.c @@ -0,0 +1,91 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_opt.c + * @brief DNS OPT pseudo-RR (RFC 2671). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#include "tnet_dns_opt.h" + + + +/** Creates new DNS OPT Resource Record. +*/ +tnet_dns_opt_t* tnet_dns_opt_create(tsk_size_t payload_size) +{ + return tsk_object_new(tnet_dns_opt_def_t, payload_size); +} + + + + + + + + + +//================================================================================================= +// [[DNS OPT]] object definition +// +static tsk_object_t* tnet_dns_opt_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_opt_t *rr_opt = self; + if(rr_opt){ + uint16_t payload_size = (uint16_t)va_arg(*app, tsk_size_t); + + /* init base */ + tnet_dns_rr_init(TNET_DNS_RR(rr_opt), qtype_opt, qclass_any); + + /* + NAME domain name empty (root domain) + TYPE u_int16_t OPT + CLASS u_int16_t sender's UDP payload size + TTL u_int32_t extended RCODE and flags + RDLEN u_int16_t describes RDATA + RDATA octet stream {attribute,value} pairs + + */ + TNET_DNS_RR(rr_opt)->qclass = payload_size; + } + return self; +} + +static tsk_object_t* tnet_dns_opt_dtor(tsk_object_t * self) +{ + tnet_dns_opt_t *rr_opt = self; + if(rr_opt){ + /* deinit base */ + tnet_dns_rr_deinit(TNET_DNS_RR(rr_opt)); + } + return self; +} + +static const tsk_object_def_t tnet_dns_opt_def_s = +{ + sizeof(tnet_dns_opt_t), + tnet_dns_opt_ctor, + tnet_dns_opt_dtor, + tsk_null, +}; +const tsk_object_def_t *tnet_dns_opt_def_t = &tnet_dns_opt_def_s; diff --git a/tinyNET/src/dns/tnet_dns_opt.h b/tinyNET/src/dns/tnet_dns_opt.h new file mode 100644 index 0000000..24485b9 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_opt.h @@ -0,0 +1,54 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_opt.h + * @brief DNS OPT pseudo-RR (RFC 2671). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#ifndef TNET_DNS_RR_OPT_H +#define TNET_DNS_RR_OPT_H + +#include "tinynet_config.h" + +#include "tnet_dns_rr.h" + + +TNET_BEGIN_DECLS + +/** DNS OPT Resource Record +*/ +typedef struct tnet_dns_opt_s +{ + TNET_DECLARE_DNS_RR; +} +tnet_dns_opt_t; + +tnet_dns_opt_t* tnet_dns_opt_create(tsk_size_t payload_size); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_opt_def_t; + + +TNET_END_DECLS + +#endif /* TNET_DNS_RR_OPT_H */ diff --git a/tinyNET/src/dns/tnet_dns_ptr.c b/tinyNET/src/dns/tnet_dns_ptr.c new file mode 100644 index 0000000..23b7733 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_ptr.c @@ -0,0 +1,93 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_ptr.c + * @brief DNS Pointer record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#include "tnet_dns_ptr.h" + +#include "../tnet_types.h" + +#include "tsk_string.h" +#include "tsk_memory.h" + +/** Creates new DNS PTR Resource Record. +*/ + + +tnet_dns_ptr_t* tnet_dns_ptr_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void*data, tsk_size_t offset) +{ + return tsk_object_new(tnet_dns_ptr_def_t, name, qclass, ttl, rdlength, data, offset); +} + +//================================================================================================= +// [[DNS PTR]] object definition +// +static tsk_object_t* tnet_dns_ptr_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_ptr_t *ptr = self; + if(ptr){ + const char* name = va_arg(*app, const char*); + tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t); + uint32_t ttl = va_arg(*app, uint32_t); + uint16_t rdlength = tsk_va_arg_u16(*app); + const void* data = va_arg(*app, const void*); + tsk_size_t offset = va_arg(*app, tsk_size_t); + + /* init base */ + tnet_dns_rr_init(TNET_DNS_RR(ptr), qtype_ptr, qclass); + TNET_DNS_RR(ptr)->name = tsk_strdup(name); + TNET_DNS_RR(ptr)->rdlength = rdlength; + TNET_DNS_RR(ptr)->ttl = ttl; + + if(rdlength){ + // ==> DESERIALIZATION + /* PTRDNAME */ + tnet_dns_rr_qname_deserialize(data, &(ptr->ptrdname), &offset); + } + } + return self; +} + +static tsk_object_t* tnet_dns_ptr_dtor(tsk_object_t * self) +{ + tnet_dns_ptr_t *ptr = self; + if(ptr){ + /* deinit base */ + tnet_dns_rr_deinit(TNET_DNS_RR(ptr)); + + TSK_FREE(ptr->ptrdname); + } + return self; +} + +static const tsk_object_def_t tnet_dns_ptr_def_s = +{ + sizeof(tnet_dns_ptr_t), + tnet_dns_ptr_ctor, + tnet_dns_ptr_dtor, + tsk_null, +}; +const tsk_object_def_t *tnet_dns_ptr_def_t = &tnet_dns_ptr_def_s; diff --git a/tinyNET/src/dns/tnet_dns_ptr.h b/tinyNET/src/dns/tnet_dns_ptr.h new file mode 100644 index 0000000..fc2cbdc --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_ptr.h @@ -0,0 +1,61 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_ptr.h + * @brief DNS Pointer record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#ifndef TNET_DNS_RR_PTR_H +#define TNET_DNS_RR_PTR_H + +#include "tinynet_config.h" + +#include "tnet_dns_rr.h" + +TNET_BEGIN_DECLS + + +/** DNS PTR Resource Record +*/ +typedef struct tnet_dns_ptr_s +{ + TNET_DECLARE_DNS_RR; + + /* RFC 1035 - 3.3.12. PTR RDATA format + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + / PTRDNAME / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + char* ptrdname; +} +tnet_dns_ptr_t; + +tnet_dns_ptr_t* tnet_dns_ptr_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void*data, tsk_size_t offset); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_ptr_def_t; + +TNET_END_DECLS + +#endif /* TNET_DNS_RR_PTR_H */ + diff --git a/tinyNET/src/dns/tnet_dns_regexp.c b/tinyNET/src/dns/tnet_dns_regexp.c new file mode 100644 index 0000000..5cafeb8 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_regexp.c @@ -0,0 +1,286 @@ + +/* #line 1 "./ragel/tnet_dns_regexp.rl" */ +/* +* Copyright (C) 2010-2015 Mamadou DIOP. +* +* 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_regexp.c + * @brief DNS Regex parser for NAPTR RR. + */ +#include "tnet_dns_regexp.h" + +#include "tsk_string.h" +#include "tsk_memory.h" +#include "tsk_ragel_state.h" +#include "tsk_debug.h" + +#include <string.h> + +/* === Ragel state machine === */ + +/* #line 71 "./ragel/tnet_dns_regexp.rl" */ + + +/** +* Apply @a regexp to @a e164num. +* @param e164num Original E.164 number supplied by the user (only digits or '+' are accepted). +* @param regexp A <character-string> containing a substitution expression that is +* applied to the original string held by the client in order to +* construct the next domain name to lookup. Example: "!^.*$!sip:bob@doubango.org!i". +* @retval The final Internet address. It's up to the caller to free the string. +*/ +char* tnet_dns_regex_parse(const char* e164num, const char* regexp) +{ + char* ret = tsk_null; + char* prefix = tsk_null; + const char* tag_start; + tsk_size_t e164len; + + // Ragel + int cs = 0; + const char *p = tag_start = regexp; + const char *pe; + const char *eof; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + +/* #line 63 "./src/dns/tnet_dns_regexp.c" */ +static const char _tdns_machine_regexp_actions[] = { + 0, 1, 0, 1, 1, 1, 2, 2, + 0, 1, 2, 0, 2, 2, 2, 0, + 2, 3, 0, 3, 3, 0, 2 +}; + +static const char _tdns_machine_regexp_key_offsets[] = { + 0, 0, 1, 2, 5, 6, 7, 8, + 9, 10, 11, 13, 15, 17, 19, 21, + 23, 25, 26, 27 +}; + +static const char _tdns_machine_regexp_trans_keys[] = { + 33, 94, 40, 46, 92, 40, 46, 42, + 41, 36, 33, 33, 92, 33, 92, 48, + 57, 33, 92, 33, 92, 40, 42, 36, + 40, 40, 105, 0 +}; + +static const char _tdns_machine_regexp_single_lengths[] = { + 0, 1, 1, 3, 1, 1, 1, 1, + 1, 1, 2, 2, 0, 2, 2, 2, + 2, 1, 1, 0 +}; + +static const char _tdns_machine_regexp_range_lengths[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0 +}; + +static const char _tdns_machine_regexp_index_offsets[] = { + 0, 0, 2, 4, 8, 10, 12, 14, + 16, 18, 20, 23, 26, 28, 31, 34, + 37, 40, 42, 44 +}; + +static const char _tdns_machine_regexp_trans_targs[] = { + 2, 0, 3, 0, 5, 15, 17, 4, + 5, 4, 6, 0, 7, 0, 8, 0, + 9, 0, 10, 0, 18, 12, 11, 18, + 12, 11, 13, 0, 18, 0, 14, 18, + 0, 14, 5, 16, 4, 9, 5, 4, + 5, 4, 19, 0, 0, 0 +}; + +static const char _tdns_machine_regexp_trans_actions[] = { + 0, 0, 0, 0, 7, 1, 0, 1, + 3, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 10, 10, 10, 13, + 13, 13, 0, 0, 19, 0, 16, 5, + 0, 0, 3, 0, 0, 0, 3, 0, + 7, 1, 0, 0, 0, 0 +}; + +static const int tdns_machine_regexp_start = 1; +static const int tdns_machine_regexp_first_final = 18; +static const int tdns_machine_regexp_error = 0; + +static const int tdns_machine_regexp_en_main = 1; + + +/* #line 96 "./ragel/tnet_dns_regexp.rl" */ + TSK_RAGEL_DISABLE_WARNINGS_END() + (void)(eof); + (void)(tdns_machine_regexp_first_final); + (void)(tdns_machine_regexp_error); + (void)(tdns_machine_regexp_en_main); + + if (!e164num) { + goto bail; + } + + if (!regexp) { + ret = tsk_strdup(e164num); + goto bail; + } + + e164len = (tsk_size_t)tsk_strlen(e164num); + pe = p + tsk_strlen(regexp); + eof = pe; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + +/* #line 148 "./src/dns/tnet_dns_regexp.c" */ + { + cs = tdns_machine_regexp_start; + } + +/* #line 117 "./ragel/tnet_dns_regexp.rl" */ + +/* #line 155 "./src/dns/tnet_dns_regexp.c" */ + { + int _klen; + unsigned int _trans; + const char *_acts; + unsigned int _nacts; + const char *_keys; + + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _tdns_machine_regexp_trans_keys + _tdns_machine_regexp_key_offsets[cs]; + _trans = _tdns_machine_regexp_index_offsets[cs]; + + _klen = _tdns_machine_regexp_single_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + _klen - 1; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + ((_upper-_lower) >> 1); + if ( (*p) < *_mid ) + _upper = _mid - 1; + else if ( (*p) > *_mid ) + _lower = _mid + 1; + else { + _trans += (_mid - _keys); + goto _match; + } + } + _keys += _klen; + _trans += _klen; + } + + _klen = _tdns_machine_regexp_range_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + (_klen<<1) - 2; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + (((_upper-_lower) >> 1) & ~1); + if ( (*p) < _mid[0] ) + _upper = _mid - 2; + else if ( (*p) > _mid[1] ) + _lower = _mid + 2; + else { + _trans += ((_mid - _keys)>>1); + goto _match; + } + } + _trans += _klen; + } + +_match: + cs = _tdns_machine_regexp_trans_targs[_trans]; + + if ( _tdns_machine_regexp_trans_actions[_trans] == 0 ) + goto _again; + + _acts = _tdns_machine_regexp_actions + _tdns_machine_regexp_trans_actions[_trans]; + _nacts = (unsigned int) *_acts++; + while ( _nacts-- > 0 ) + { + switch ( *_acts++ ) + { + case 0: +/* #line 36 "./ragel/tnet_dns_regexp.rl" */ + { + tag_start = p; + } + break; + case 1: +/* #line 40 "./ragel/tnet_dns_regexp.rl" */ + { + TSK_PARSER_SET_STRING(prefix); + } + break; + case 2: +/* #line 44 "./ragel/tnet_dns_regexp.rl" */ + { + int len = (int)(p - tag_start); + if (len) { + tsk_strncat(&ret, tag_start, len); + } + } + break; + case 3: +/* #line 51 "./ragel/tnet_dns_regexp.rl" */ + { + if (prefix) { + int prefixlen = (int)tsk_strlen(prefix); + tsk_strncat(&ret, e164num + prefixlen, (e164len - prefixlen)); + } + } + break; +/* #line 258 "./src/dns/tnet_dns_regexp.c" */ + } + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + _out: {} + } + +/* #line 118 "./ragel/tnet_dns_regexp.rl" */ + TSK_RAGEL_DISABLE_WARNINGS_END() + + if (cs < +/* #line 275 "./src/dns/tnet_dns_regexp.c" */ +18 +/* #line 120 "./ragel/tnet_dns_regexp.rl" */ + ){ + TSK_DEBUG_ERROR("regexp substitition failed."); + TSK_FREE(ret); + } + +bail: + TSK_FREE(prefix); + + return ret; +} diff --git a/tinyNET/src/dns/tnet_dns_regexp.h b/tinyNET/src/dns/tnet_dns_regexp.h new file mode 100644 index 0000000..d40abce --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_regexp.h @@ -0,0 +1,41 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_regexp.h + * @brief DNS Regexp parser for NAPTR RR. + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#ifndef TNET_DNS_REGEX_H +#define TNET_DNS_REGEX_H + +#include "tinynet_config.h" + +TNET_BEGIN_DECLS + +TINYNET_API char* tnet_dns_regex_parse(const char* e164num, const char* regexp); + +TNET_END_DECLS + +#endif /* TNET_DNS_REGEX_H */ + diff --git a/tinyNET/src/dns/tnet_dns_resolvconf.c b/tinyNET/src/dns/tnet_dns_resolvconf.c new file mode 100644 index 0000000..a4a0fbf --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_resolvconf.c @@ -0,0 +1,314 @@ + +/* #line 1 "./ragel/tnet_dns_resolvconf.rl" */ +/* +* Copyright (C) 2010-2015 Mamadou DIOP. +* +* 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_resolvconf.c + * @brief Parser for "/etc/resolv.conf" file to retrive DNS servers. + */ +#include "tnet_dns_resolvconf.h" + +#include "tnet_utils.h" + +#include "dns/tnet_dns.h" + +#include "tsk_string.h" +#include "tsk_memory.h" +#include "tsk_ragel_state.h" +#include "tsk_debug.h" + +#include <string.h> + + +/* === Ragel state machine === */ + +/* #line 75 "./ragel/tnet_dns_resolvconf.rl" */ + + +/** Gets list of DNS servers from a conf file. +* @param path Path of the conf file from which to retrieve the DNS servers. +* should be @a "/etc/resolv.conf". You can adjust the value by modifying @ref TNET_RESOLV_CONF_PATH.<br> +* If you are using <b>Android</b> and the resolv.conf file is missing, then run the following line in a command window: <br> +* <i>ln -s /private/var/run/resolv.conf /etc/resolv.conf</i><br> If this fails, then try to manually add the file. +* @retval List of DNS servers. +*/ +tnet_addresses_L_t * tnet_dns_resolvconf_parse(const char* path) +{ + tnet_addresses_L_t* servers = tsk_null; + tnet_ip_t ip; + const char* fullpath = path; + const char* tag_start = tsk_null; + FILE* fd; + char* buf = tsk_null; + + // Ragel + int cs = 0; + const char *p; + const char *pe; + const char *eof; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + +/* #line 69 "./src/dns/tnet_dns_resolvconf.c" */ +static const char _tdns_machine_resolvconf_actions[] = { + 0, 1, 0, 1, 1 +}; + +static const char _tdns_machine_resolvconf_key_offsets[] = { + 0, 7, 8, 9, 12, 15, 15, 22, + 24, 27, 30, 33, 36, 39, 42, 45, + 48, 51, 52, 53, 56 +}; + +static const char _tdns_machine_resolvconf_trans_keys[] = { + 10, 13, 32, 35, 59, 78, 110, 32, + 32, 10, 13, 32, 10, 13, 32, 10, + 13, 32, 35, 59, 78, 110, 10, 13, + 32, 65, 97, 32, 77, 109, 32, 69, + 101, 32, 83, 115, 32, 69, 101, 32, + 82, 114, 32, 86, 118, 32, 69, 101, + 32, 82, 114, 32, 32, 10, 13, 32, + 32, 35, 59, 78, 110, 0 +}; + +static const char _tdns_machine_resolvconf_single_lengths[] = { + 7, 1, 1, 3, 3, 0, 7, 2, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 1, 1, 3, 5 +}; + +static const char _tdns_machine_resolvconf_range_lengths[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 +}; + +static const char _tdns_machine_resolvconf_index_offsets[] = { + 0, 8, 10, 12, 16, 20, 21, 29, + 32, 36, 40, 44, 48, 52, 56, 60, + 64, 68, 70, 72, 76 +}; + +static const char _tdns_machine_resolvconf_indicies[] = { + 1, 1, 2, 3, 3, 4, 4, 0, + 5, 0, 5, 6, 7, 7, 8, 6, + 7, 7, 8, 9, 9, 1, 1, 5, + 3, 3, 4, 4, 0, 7, 7, 3, + 5, 10, 10, 0, 5, 11, 11, 0, + 5, 12, 12, 0, 5, 13, 13, 0, + 5, 14, 14, 0, 5, 15, 15, 0, + 5, 16, 16, 0, 5, 17, 17, 0, + 5, 18, 18, 0, 19, 0, 19, 20, + 22, 22, 23, 21, 2, 3, 3, 4, + 4, 0, 0 +}; + +static const char _tdns_machine_resolvconf_trans_targs[] = { + 1, 6, 20, 7, 8, 2, 3, 0, + 4, 5, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 19, 0, 4 +}; + +static const char _tdns_machine_resolvconf_trans_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 3, 3 +}; + +static const int tdns_machine_resolvconf_start = 0; +static const int tdns_machine_resolvconf_first_final = 0; +static const int tdns_machine_resolvconf_error = -1; + +static const int tdns_machine_resolvconf_en_main = 0; + + +/* #line 101 "./ragel/tnet_dns_resolvconf.rl" */ + TSK_RAGEL_DISABLE_WARNINGS_END() + (void)(eof); + (void)(tdns_machine_resolvconf_first_final); + (void)(tdns_machine_resolvconf_error); + (void)(tdns_machine_resolvconf_en_main); + + if(tsk_strnullORempty(fullpath)){ + fullpath = TNET_RESOLV_CONF_PATH; + } + + /* Open the file and read all data */ + if((fd = fopen(fullpath, "r"))){ + long len; + fseek(fd, 0L, SEEK_END); + len = ftell(fd); + fseek(fd, 0L, SEEK_SET); + if (!(buf = (char*)tsk_calloc(len + 1, 1))) { + TSK_DEBUG_ERROR("Failed to allocate buffer with size = %ld", (len + 1)); + goto bail; + } + fread(buf, 1, len, fd); + p = &buf[0]; + pe = p + len + 1/*hack*/; + eof = pe; + fclose(fd); + + buf[len] = '\n'; // hack to have perfect lines + + servers = tsk_list_create(); + } + else { +#if ANDROID || defined(__APPLE__) /* TARGET_OS_IPHONE not defined for bsd libraries */ + TSK_DEBUG_INFO("Failed to open [%s]. But don't panic, we have detected that you are using Google Android/iOS Systems.\n" + "You should look at the Progammer's Guide for more information.\n If you are not using DNS functions, don't worry about this warning.", + fullpath); +#else + TSK_DEBUG_ERROR("Failed to open %s.", fullpath); +#endif + goto bail; + } + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + +/* #line 186 "./src/dns/tnet_dns_resolvconf.c" */ + { + cs = tdns_machine_resolvconf_start; + } + +/* #line 144 "./ragel/tnet_dns_resolvconf.rl" */ + +/* #line 193 "./src/dns/tnet_dns_resolvconf.c" */ + { + int _klen; + unsigned int _trans; + const char *_acts; + unsigned int _nacts; + const char *_keys; + + if ( p == pe ) + goto _test_eof; +_resume: + _keys = _tdns_machine_resolvconf_trans_keys + _tdns_machine_resolvconf_key_offsets[cs]; + _trans = _tdns_machine_resolvconf_index_offsets[cs]; + + _klen = _tdns_machine_resolvconf_single_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + _klen - 1; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + ((_upper-_lower) >> 1); + if ( (*p) < *_mid ) + _upper = _mid - 1; + else if ( (*p) > *_mid ) + _lower = _mid + 1; + else { + _trans += (_mid - _keys); + goto _match; + } + } + _keys += _klen; + _trans += _klen; + } + + _klen = _tdns_machine_resolvconf_range_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + (_klen<<1) - 2; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + (((_upper-_lower) >> 1) & ~1); + if ( (*p) < _mid[0] ) + _upper = _mid - 2; + else if ( (*p) > _mid[1] ) + _lower = _mid + 2; + else { + _trans += ((_mid - _keys)>>1); + goto _match; + } + } + _trans += _klen; + } + +_match: + _trans = _tdns_machine_resolvconf_indicies[_trans]; + cs = _tdns_machine_resolvconf_trans_targs[_trans]; + + if ( _tdns_machine_resolvconf_trans_actions[_trans] == 0 ) + goto _again; + + _acts = _tdns_machine_resolvconf_actions + _tdns_machine_resolvconf_trans_actions[_trans]; + _nacts = (unsigned int) *_acts++; + while ( _nacts-- > 0 ) + { + switch ( *_acts++ ) + { + case 0: +/* #line 41 "./ragel/tnet_dns_resolvconf.rl" */ + { + tag_start = p; + } + break; + case 1: +/* #line 45 "./ragel/tnet_dns_resolvconf.rl" */ + { + int len = (int)(p - tag_start); + if(len && len<=sizeof(ip)){ + tnet_address_t *address; + memset(ip, '\0', sizeof(ip)); + memcpy(ip, tag_start, len); + TSK_DEBUG_INFO("Adding DNS server = %s:%d", ip, TNET_DNS_SERVER_PORT_DEFAULT); + + address = tnet_address_create(ip); + address->family = tnet_get_family(ip, TNET_DNS_SERVER_PORT_DEFAULT); + address->dnsserver = 1; + tsk_list_push_ascending_data(servers, (void**)&address); + } + } + break; +/* #line 288 "./src/dns/tnet_dns_resolvconf.c" */ + } + } + +_again: + if ( ++p != pe ) + goto _resume; + _test_eof: {} + } + +/* #line 145 "./ragel/tnet_dns_resolvconf.rl" */ + TSK_RAGEL_DISABLE_WARNINGS_END() + + if (cs < +/* #line 302 "./src/dns/tnet_dns_resolvconf.c" */ +0 +/* #line 147 "./ragel/tnet_dns_resolvconf.rl" */ + ) { + TSK_DEBUG_ERROR("Failed to parse %s.", fullpath); + TSK_OBJECT_SAFE_FREE(servers); + } + +bail: + TSK_FREE(buf); + return servers; +} + + diff --git a/tinyNET/src/dns/tnet_dns_resolvconf.h b/tinyNET/src/dns/tnet_dns_resolvconf.h new file mode 100644 index 0000000..5290c41 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_resolvconf.h @@ -0,0 +1,43 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_resolvconf.h + * @brief Parser for "/etc/resolv.conf" file to retrive DNS servers. + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#ifndef TNET_DNS_RESOLVCONF_H +#define TNET_DNS_RESOLVCONF_H + +#include "tinynet_config.h" + +#include "tnet_types.h" + +TNET_BEGIN_DECLS + +TINYNET_API tnet_addresses_L_t * tnet_dns_resolvconf_parse(const char* path); + +TNET_END_DECLS + +#endif /* TNET_DNS_RESOLVCONF_H */ + diff --git a/tinyNET/src/dns/tnet_dns_rr.c b/tinyNET/src/dns/tnet_dns_rr.c new file mode 100644 index 0000000..b74a31d --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_rr.c @@ -0,0 +1,448 @@ +/* +* Copyright (C) 2010-2015 Mamadou DIOP. +* +* 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_rr.c + * @brief DNS Resource Record (RFC 1034 and 1035). + * + */ +#include "tnet_dns_rr.h" + +#include "tnet_dns_a.h" +#include "tnet_dns_aaaa.h" +#include "tnet_dns_cname.h" +#include "tnet_dns_mx.h" +#include "tnet_dns_naptr.h" +#include "tnet_dns_ns.h" +#include "tnet_dns_opt.h" +#include "tnet_dns_ptr.h" +#include "tnet_dns_soa.h" +#include "tnet_dns_srv.h" +#include "tnet_dns_txt.h" + +#include "../tnet_types.h" +#include "../tnet_endianness.h" + +#include "tsk_memory.h" +#include "tsk_debug.h" +#include "tsk_string.h" + +#include <string.h> /* strlen ... */ + + +/** Creates a new DNS RR. +*/ + +tnet_dns_rr_t* tnet_dns_rr_create() +{ + return tsk_object_new(tnet_dns_rr_def_t); +} + +/** Initializes any DNS RR (either NAPTR or SRV ...). +* @param rr The DNS RR to initialize. +* @param qtype The type of the RR. +* @param qclass The class of the RR. +* @retval Zero if succeed and non-zero error code otherwise. +*/ +int tnet_dns_rr_init(tnet_dns_rr_t *rr, tnet_dns_qtype_t qtype, tnet_dns_qclass_t qclass) +{ + if (rr){ + if (!rr->initialized){ + rr->qtype = qtype; + rr->qclass = qclass; + + rr->initialized = tsk_true; + return 0; + } + return -2; + } + return -1; +} + +/** Deinitializes any DNS RR (either NAPTR or SRV ...). +* @param rr The DNS RR to deinitialize. +* @retval Zero if succeed and non-zero error code otherwise. +*/ +int tnet_dns_rr_deinit(tnet_dns_rr_t *rr) +{ + if (rr){ + if (rr->initialized){ + TSK_FREE(rr->name); + TSK_FREE(rr->rpdata); + + rr->initialized = tsk_false; + return 0; + } + return -2; + } + return -1; +} + +/** Deserialize <character-string>. +*/ +int tnet_dns_rr_charstring_deserialize(const void* data, char** charstring, tsk_size_t *offset) +{ + /* RFC 1035 - 3.3. Standard RRs + <character-string> is a single length octet followed by that number of characters. + <character-string> is treated as binary information, and can be up to 256 characters in + length (including the length octet). + */ + uint8_t* dataPtr = (((uint8_t*)data) + *offset); + uint8_t length = *dataPtr; + + *charstring = tsk_strndup((const char*)(dataPtr + 1), length); + *offset += (1 + length); + + return 0; +} + +/** Deserializes a QName. +*/ +int tnet_dns_rr_qname_deserialize(const void* data, char** name, tsk_size_t *offset) +{ + /* RFC 1035 - 4.1.4. Message compression + + The pointer takes the form of a two octet sequence: + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 1 1| OFFSET | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + uint8_t* dataPtr = (((uint8_t*)data) + *offset); + unsigned usingPtr = 0; /* Do not change. */ + + while (*dataPtr){ + usingPtr = ((*dataPtr & 0xC0) == 0xC0); + + if (usingPtr){ + tsk_size_t ptr_offset = (*dataPtr & 0x3F); + ptr_offset = ptr_offset << 8 | *(dataPtr + 1); + + *offset += 2; + return tnet_dns_rr_qname_deserialize(data, name, &ptr_offset); + } + else{ + uint8_t length; + + if (*name){ + tsk_strcat(name, "."); + } + + length = *dataPtr; + *offset += 1, dataPtr++; + + tsk_strncat(name, (const char*)dataPtr, length); + *offset += length, dataPtr += length; + } + } + + *offset += 1; + + return 0; +} + +//int tnet_dns_rr_qname_deserialize(const void* data, tsk_size_t size, char** name, tsk_size_t *offset) +//{ +// /* RFC 1035 - 4.1.4. Message compression +// +// The pointer takes the form of a two octet sequence: +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 1 1| OFFSET | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// */ +// uint8_t* dataPtr = (((uint8_t*)data) + *offset); +// uint8_t* dataEnd = (dataPtr + size); +// unsigned usingPtr = 0; /* Do not change. */ +// unsigned islast = 0; +// +// while(!islast) +// { +// usingPtr = ((*dataPtr & 0xC0) == 0xC0); +// +// if(usingPtr) +// { +// uint8_t *Ptr; +// uint16_t ptr_offset = (*dataPtr & 0x3F); +// ptr_offset = ptr_offset << 8 | *(dataPtr+1); +// Ptr = ((uint8_t*)data) + ptr_offset; +// +// tnet_qname_label_parse(Ptr, (dataEnd - Ptr), name, &islast); +// *offset += 2, dataPtr += 2; +// } +// else +// { +// tsk_size_t length = tnet_qname_label_parse(dataPtr, size, name, &islast); +// *offset += length, dataPtr += length; +// } +// } +// +// *offset += usingPtr ? 0 : 1; +// +// return 0; +//} + +/** Serializes a QName. +*/ +int tnet_dns_rr_qname_serialize(const char* qname, tsk_buffer_t* output) +{ + /* + QNAME a domain name represented as a sequence of labels, where + each label consists of a length octet followed by that + number of octets. The domain name terminates with the + zero length octet for the null label of the root. Note + that this field may be an odd number of octets; no + padding is used. + + Example: "doubango.com" ==> 8doubango3comNULL + */ + static uint8_t null = 0; + + if (qname){ + char* saveptr; + char* _qname = tsk_strdup(qname); + char* label = tsk_strtok_r(_qname, ".", &saveptr); + + while (label){ + uint8_t length = (uint8_t)tsk_strlen(label); + tsk_buffer_append(output, &length, 1); + tsk_buffer_append(output, label, tsk_strlen(label)); + + label = tsk_strtok_r(tsk_null, ".", &saveptr); + } + + TSK_FREE(_qname); + } + + /* terminates domain name */ + tsk_buffer_append(output, &null, 1); + + return 0; +} + +/** Deserializes a DNS RR. +*/ +tnet_dns_rr_t* tnet_dns_rr_deserialize(const void* data, tsk_size_t size, tsk_size_t* offset) +{ + tnet_dns_rr_t *rr = tsk_null; + uint8_t* dataStart = (uint8_t*)data; + uint8_t* dataPtr = (dataStart + *offset); + //uint8_t* dataEnd = (dataPtr+size); + tnet_dns_qtype_t qtype; + tnet_dns_qclass_t qclass; + uint32_t ttl; + uint16_t rdlength; + char* qname = tsk_null; + + /* Check validity */ + if (!dataPtr || !size){ + goto bail; + } + + /* == Parse QNAME == */ + tnet_dns_rr_qname_deserialize(dataStart, &qname, offset); + dataPtr = (dataStart + *offset); + /* == Parse QTYPE == */ + qtype = (tnet_dns_qtype_t)tnet_ntohs_2(dataPtr); + dataPtr += 2, *offset += 2; + /* == Parse QCLASS == */ + qclass = (tnet_dns_qclass_t)tnet_ntohs_2(dataPtr); + dataPtr += 2, *offset += 2; + /* == Parse TTL == */ + ttl = (uint32_t)tnet_htonl_2(dataPtr); + dataPtr += 4, *offset += 4; + /* == Parse RDLENGTH == */ + rdlength = tnet_ntohs_2(dataPtr); + dataPtr += 2, *offset += 2; + + switch (qtype){ + case qtype_a: + { + rr = (tnet_dns_rr_t *)tnet_dns_a_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_aaaa: + { + rr = (tnet_dns_rr_t *)tnet_dns_aaaa_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_cname: + { + rr = (tnet_dns_rr_t *)tnet_dns_cname_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_mx: + { + rr = (tnet_dns_rr_t *)tnet_dns_mx_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_naptr: + { + rr = (tnet_dns_rr_t *)tnet_dns_naptr_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_ns: + { + rr = (tnet_dns_rr_t *)tnet_dns_ns_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_opt: + { + unsigned payload_size = qclass; + rr = (tnet_dns_rr_t *)tnet_dns_opt_create(payload_size); + break; + } + + case qtype_ptr: + { + rr = (tnet_dns_rr_t *)tnet_dns_ptr_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_soa: + { + rr = (tnet_dns_rr_t *)tnet_dns_soa_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_srv: + { + rr = (tnet_dns_rr_t *)tnet_dns_srv_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + case qtype_txt: + { + rr = (tnet_dns_rr_t *)tnet_dns_txt_create(qname, qclass, ttl, rdlength, dataStart, *offset); + break; + } + + default: + { + TSK_DEBUG_ERROR("NOT IMPLEMENTED"); + break; + } + } + +bail: + TSK_FREE(qname); + + *offset += rdlength; + return rr; +} + +/** Serializes a DNS RR. +*/ +int tnet_dns_rr_serialize(const tnet_dns_rr_t* rr, tsk_buffer_t *output) +{ + if (!rr || !output){ + return -1; + } + + /*=== NAME ===*/ + { + tnet_dns_rr_qname_serialize(rr->name, output); + } + + /*=== TYPE ===*/ + { + uint16_t qtype = tnet_htons(rr->qtype); + tsk_buffer_append(output, &(qtype), 2); + } + + /*=== CLASS ===*/ + { + uint16_t qclass = tnet_htons(rr->qclass); + tsk_buffer_append(output, &(qclass), 2); + } + + /*=== TTL ===*/ + { + uint32_t ttl = (uint32_t)tnet_htonl(rr->ttl); + tsk_buffer_append(output, &(ttl), 4); + } + + /*=== RDLENGTH ===*/ + { + uint16_t length = tnet_htons(rr->rdlength); + tsk_buffer_append(output, &(length), 2); + } + + /*=== RDATA : Request never contains data + ===*/ + if (!rr->rpdata){ + goto done; + } + + switch (rr->qtype){ + case qtype_a: + case qtype_aaaa: + case qtype_cname: + case qtype_mx: + case qtype_naptr: + case qtype_ns: + case qtype_opt: + case qtype_ptr: + case qtype_soa: + case qtype_srv: + case qtype_txt: + default: + { + TSK_DEBUG_WARN("DNS Request should not contains RDATA (not supported)."); + break; + } + } + +done: + return 0; +} + + +//================================================================================================= +// [[DNS RR]] object definition +// +static tsk_object_t* tnet_dns_rr_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_rr_t *rr = self; + if (rr){ + tnet_dns_rr_init(rr, qtype_any, qclass_any); + } + return self; +} + +static tsk_object_t* tnet_dns_rr_dtor(tsk_object_t * self) +{ + tnet_dns_rr_t *rr = self; + if (rr){ + tnet_dns_rr_deinit(rr); + } + return self; +} + +static const tsk_object_def_t tnet_dns_rr_def_s = +{ + sizeof(tnet_dns_rr_t), + tnet_dns_rr_ctor, + tnet_dns_rr_dtor, + tsk_null, +}; +const tsk_object_def_t *tnet_dns_rr_def_t = &tnet_dns_rr_def_s; diff --git a/tinyNET/src/dns/tnet_dns_rr.h b/tinyNET/src/dns/tnet_dns_rr.h new file mode 100644 index 0000000..f4a1b6b --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_rr.h @@ -0,0 +1,171 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_rr.h + * @brief DNS Resource Record (RFCS 1034 and 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ + +#ifndef TNET_DNS_RR_H +#define TNET_DNS_RR_H + +#include "tinynet_config.h" + +#include "tsk_list.h" +#include "tsk_buffer.h" + +/** @def TNET_DNS_RR +* Converts any DNS RR to a pointer to @ref tnet_dns_rr_t. +* @retval A pointer to @ref tnet_dns_rr_t object. +*/ +TNET_BEGIN_DECLS + +#define TNET_DNS_RR(self) ((tnet_dns_rr_t*)(self)) + +/** RFC 1035 - 3.2.2. TYPE values +* @sa http://en.wikipedia.org/wiki/List_of_DNS_record_types +*/ +typedef enum tnet_dns_qtype_e +{ + qtype_a = 1, /**< A 1 a host address */ + qtype_ns = 2, /**< NS 2 an authoritative name server */ + qtype_md = 3, /**< MD 3 a mail destination (Obsolete - use MX) */ + qtype_mf = 4, /**< MF 4 a mail forwarder (Obsolete - use MX) */ + qtype_cname = 5, /**< CNAME 5 the canonical name for an alias */ + qtype_soa = 6, /**< SOA 6 marks the start of a zone of authority */ + qtype_mb = 7, /**< MB 7 a mailbox domain name (EXPERIMENTAL) */ + qtype_mg = 8, /**< MG 8 a mail group member (EXPERIMENTAL) */ + qtype_mr = 9, /**< MR 9 a mail rename domain name (EXPERIMENTAL) */ + qtype_null = 10, /**< NULL 10 a null RR (EXPERIMENTAL) */ + qtype_wks = 11, /**< WKS 11 a well known service description */ + qtype_ptr = 12, /**< PTR 12 a domain name pointer */ + qtype_hinfo = 13, /**< HINFO 13 host information */ + qtype_minfo = 14, /**< MINFO 14 mailbox or mail list information */ + qtype_mx = 15, /**< MX 15 mail exchange */ + qtype_txt = 16, /**< TXT 16 text strings */ + + qtype_aaaa = 28, /**< AAAA 28 IPv6 host address */ + + qtype_srv = 33, /**< SRV 33 Service locator */ + + qtype_naptr = 35, /**< NAPTR 35 Naming Authority Pointer */ + + qtype_opt = 41, /**< OPT 41 Option */ + + qtype_ipseckey = 45,/**< IPSECKEY 45 IPSEC Key */ + + qtype_spf = 99, /**< SPF 99 SPF record */ + + qtype_any = 255 /**< * 255 A request for all records (3.2.3. QTYPE values)*/ +} +tnet_dns_qtype_t; + +/** RFC 1035 - 3.2.4. CLASS values +*/ +typedef enum tnet_dns_qclass_e +{ + qclass_in = 1, /**< IN 1 the Internet */ + qclass_ics = 2, /**< CS 2 the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ + qclass_ch = 3, /**< CH 3 the CHAOS class */ + qclass_hs = 4, /**< HS 4 Hesiod [Dyer 87] */ + + qclass_any = 255 /**< * 255 any class (3.2.5. QCLASS values) */ +} +tnet_dns_qclass_t; + +/** RFC 1034 (3.6. Resource Records) and 1035 (3.2.1. Format) +*/ +typedef struct tnet_dns_rr_s +{ + TSK_DECLARE_OBJECT; + + /* RFC 1035 - 3.2.1. Format + 1 1 1 1 1 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | | + / / + / NAME / + | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | TYPE | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | CLASS | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | TTL | + | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | RDLENGTH | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / RDATA / + / / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + + tsk_bool_t initialized; + + /** An owner name, i.e., the name of the node to which this resource record pertains. */ + char* name; + + /** Two octets containing one of the RR TYPE codes. */ + tnet_dns_qtype_t qtype; + + /** Two octets containing one of the RR CLASS codes. */ + tnet_dns_qclass_t qclass; + + /** A 32 bit signed integer that specifies the time interval (seconds) that the resource record may be cached before the source + of the information should again be consulted. + Zero values are interpreted to mean that the RR can only be used for the transaction in progress, and should not be cached. + For example, SOA records are always distributed with a zero TTL to prohibit caching. Zero values can also be used for extremely volatile data. */ + int32_t ttl; + + /** An unsigned 16 bit integer that specifies the length in octets of the RDATA field. */ + uint16_t rdlength; + + /** A variable length string of octets that describes the resource. + The format of this information varies according to the TYPE and CLASS of the resource record.*/ + void *rpdata; +} +tnet_dns_rr_t; + +#define TNET_DECLARE_DNS_RR tnet_dns_rr_t dns_rr + +typedef tsk_list_t tnet_dns_rrs_L_t; /**< List of @ref tnet_dns_rr_t elements. */ + +int tnet_dns_rr_init(tnet_dns_rr_t *rr, tnet_dns_qtype_t qtype, tnet_dns_qclass_t qclass); +int tnet_dns_rr_deinit(tnet_dns_rr_t *rr); + +int tnet_dns_rr_charstring_deserialize(const void* data, char** name, tsk_size_t *offset); + +int tnet_dns_rr_qname_deserialize(const void* data, char** name, tsk_size_t *offset); +int tnet_dns_rr_qname_serialize(const char* qname, tsk_buffer_t* output); + +tnet_dns_rr_t* tnet_dns_rr_deserialize(const void* data, tsk_size_t size, tsk_size_t* offset); +int tnet_dns_rr_serialize(const tnet_dns_rr_t* rr, tsk_buffer_t *output); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_rr_def_t; + +TNET_END_DECLS + +#endif /* TNET_DNS_RR_H */ diff --git a/tinyNET/src/dns/tnet_dns_soa.c b/tinyNET/src/dns/tnet_dns_soa.c new file mode 100644 index 0000000..a1844f4 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_soa.c @@ -0,0 +1,108 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_soa.c + * @brief DNS Start Of Authority record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#include "tnet_dns_soa.h" + +#include "../tnet_types.h" +#include "../tnet_endianness.h" + +#include "tsk_string.h" +#include "tsk_memory.h" + +tnet_dns_soa_t* tnet_dns_soa_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset) +{ + return tsk_object_new(tnet_dns_soa_def_t, name, qclass, ttl, rdlength, data, offset); +} + +//================================================================================================= +// [[DNS SOA]] object definition +// +static tsk_object_t* tnet_dns_soa_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_soa_t *soa = self; + if(soa){ + const char* name = va_arg(*app, const char*); + tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t); + uint32_t ttl = va_arg(*app, uint32_t); + uint16_t rdlength = tsk_va_arg_u16(*app); + const void* data = va_arg(*app, const void*); + tsk_size_t offset = va_arg(*app, tsk_size_t); + + /* init base */ + tnet_dns_rr_init(TNET_DNS_RR(soa), qtype_soa, qclass); + TNET_DNS_RR(soa)->name = tsk_strdup(name); + TNET_DNS_RR(soa)->rdlength = rdlength; + TNET_DNS_RR(soa)->ttl = ttl; + + if(rdlength) + { // ==> DESERIALIZATION + /* MNAME */ + tnet_dns_rr_qname_deserialize(data, &(soa->mname), &offset); + /* RNAME */ + tnet_dns_rr_qname_deserialize(data, &(soa->rname), &offset); + /* SERIAL */ + soa->serial = tnet_htonl_2(((uint8_t*)data) + offset), + offset += 2; + /* REFRESH */ + soa->refresh = tnet_htonl_2(((uint8_t*)data) + offset), + offset += 2; + /* RETRY */ + soa->retry = tnet_htonl_2(((uint8_t*)data) + offset), + offset += 2; + /* EXPIRE */ + soa->expire = tnet_htonl_2(((uint8_t*)data) + offset), + offset += 2; + /* MINIMUM */ + soa->minimum = tnet_htonl_2(((uint8_t*)data) + offset), + offset += 2; + } + } + return self; +} + +static tsk_object_t* tnet_dns_soa_dtor(tsk_object_t * self) +{ + tnet_dns_soa_t *soa = self; + if(soa){ + /* deinit base */ + tnet_dns_rr_deinit(TNET_DNS_RR(soa)); + + TSK_FREE(soa->mname); + TSK_FREE(soa->rname); + } + return self; +} + +static const tsk_object_def_t tnet_dns_soa_def_s = +{ + sizeof(tnet_dns_soa_t), + tnet_dns_soa_ctor, + tnet_dns_soa_dtor, + tsk_null, +}; +const tsk_object_def_t *tnet_dns_soa_def_t = &tnet_dns_soa_def_s; diff --git a/tinyNET/src/dns/tnet_dns_soa.h b/tinyNET/src/dns/tnet_dns_soa.h new file mode 100644 index 0000000..298e907 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_soa.h @@ -0,0 +1,82 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_soa.h + * @brief DNS Start Of Authority record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#ifndef TNET_DNS_RR_SOA_H +#define TNET_DNS_RR_SOA_H + +#include "tinynet_config.h" + +#include "tnet_dns_rr.h" + +TNET_BEGIN_DECLS + +typedef struct tnet_dns_soa_s +{ + TNET_DECLARE_DNS_RR; + + /* RFC 1035 - 3.3.13. SOA RDATA format + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + / MNAME / + / / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + / RNAME / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | SERIAL | + | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | REFRESH | + | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | RETRY | + | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | EXPIRE | + | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | MINIMUM | + | | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + char* mname; + char* rname; + uint32_t serial; + uint32_t refresh; + uint32_t retry; + uint32_t expire; + uint32_t minimum; +} +tnet_dns_soa_t; + +tnet_dns_soa_t* tnet_dns_soa_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_soa_def_t; + +TNET_END_DECLS + +#endif /* TNET_DNS_RR_SOA_H */ + diff --git a/tinyNET/src/dns/tnet_dns_srv.c b/tinyNET/src/dns/tnet_dns_srv.c new file mode 100644 index 0000000..4625d68 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_srv.c @@ -0,0 +1,133 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_srv.c + * @brief DNS SeRVice locator record - RR - (RFC 2782). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#include "tnet_dns_srv.h" + +#include "../tnet_types.h" +#include "../tnet_endianness.h" + +#include "tsk_string.h" +#include "tsk_memory.h" + +/** Creates new DNS SRV Resource Record. +*/ +tnet_dns_srv_t* tnet_dns_srv_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset) +{ + return tsk_object_new(tnet_dns_srv_def_t, name, qclass, ttl, rdlength, data, offset); +} + +//================================================================================================= +// [[DNS SRV]] object definition +// +static tsk_object_t* tnet_dns_srv_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_srv_t *srv = self; + if(srv){ + const char* name = va_arg(*app, const char*); + tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t); + uint32_t ttl = va_arg(*app, uint32_t); + uint16_t rdlength = tsk_va_arg_u16(*app); + const void* data = va_arg(*app, const void*); + tsk_size_t offset = va_arg(*app, tsk_size_t); + + /* init base */ + tnet_dns_rr_init(TNET_DNS_RR(srv), qtype_srv, qclass); + TNET_DNS_RR(srv)->name = tsk_strdup(name); + TNET_DNS_RR(srv)->rdlength = rdlength; + TNET_DNS_RR(srv)->ttl = ttl; + + if(rdlength){ + // ==> DESERIALIZATION + /* Priority */ + srv->priority = tnet_ntohs_2(((uint8_t*)data) + offset), + offset += 2; + /* Weight */ + srv->weight = tnet_ntohs_2(((uint8_t*)data) + offset), + offset += 2; + /* Port */ + srv->port = tnet_ntohs_2(((uint8_t*)data) + offset), + offset += 2; + /* Target */ + tnet_dns_rr_qname_deserialize(data, &(srv->target), &offset); + } + } + return self; +} + +static tsk_object_t* tnet_dns_srv_dtor(tsk_object_t * self) +{ + tnet_dns_srv_t *srv = self; + if(srv){ + /* deinit base */ + tnet_dns_rr_deinit(TNET_DNS_RR(srv)); + + TSK_FREE(srv->target); + } + return self; +} + +static int tnet_dns_srv_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + const tnet_dns_rr_t* rr1 = obj1; + const tnet_dns_rr_t* rr2 = obj2; + + if(rr1 && rr2 && (rr1->qtype==qtype_srv) && (rr2->qtype==qtype_srv)){ + const tnet_dns_srv_t* srv1 = (tnet_dns_srv_t*)rr1; + const tnet_dns_srv_t* srv2 = (tnet_dns_srv_t*)rr2; + + /* Compare priorities. */ + if(srv1->priority < srv2->priority){ /* Lowest priority is tried first. */ + return 1; + } + else if(srv1->priority > srv2->priority){ + return -1; + } + + /* Compare weight */ + if(srv1->weight > srv2->weight){ + return 1; + } + else if(srv1->weight < srv2->weight){ + return -1; + } + + return 0; + } + else{ + return -1; + } +} + +static const tsk_object_def_t tnet_dns_srv_def_s = +{ + sizeof(tnet_dns_srv_t), + tnet_dns_srv_ctor, + tnet_dns_srv_dtor, + tnet_dns_srv_cmp, +}; +const tsk_object_def_t *tnet_dns_srv_def_t = &tnet_dns_srv_def_s; diff --git a/tinyNET/src/dns/tnet_dns_srv.h b/tinyNET/src/dns/tnet_dns_srv.h new file mode 100644 index 0000000..c8cc94d --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_srv.h @@ -0,0 +1,59 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_srv.h + * @brief DNS SeRVice locator record - RR - (RFC 2782). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#ifndef TNET_DNS_RR_SRV_H +#define TNET_DNS_RR_SRV_H + +#include "tinynet_config.h" + +#include "tnet_dns_rr.h" + + +TNET_BEGIN_DECLS + +/** DNS SRV Resource Record +*/ +typedef struct tnet_dns_srv_s +{ + TNET_DECLARE_DNS_RR; + + uint16_t priority; + uint16_t weight; + uint16_t port; + char* target; +} +tnet_dns_srv_t; + +tnet_dns_srv_t* tnet_dns_srv_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_srv_def_t; + +TNET_END_DECLS + +#endif /* TNET_DNS_RR_SRV_H */ + diff --git a/tinyNET/src/dns/tnet_dns_txt.c b/tinyNET/src/dns/tnet_dns_txt.c new file mode 100644 index 0000000..9d152e9 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_txt.c @@ -0,0 +1,92 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_txt.c + * @brief DNS TeXT record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#include "tnet_dns_txt.h" + +#include "../tnet_types.h" + +#include "tsk_string.h" +#include "tsk_memory.h" + +/** Creates new DNS TXT Resource Record. +*/ + +tnet_dns_txt_t* tnet_dns_txt_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset) +{ + return tsk_object_new(tnet_dns_txt_def_t, name, qclass, ttl, rdlength, data, offset); +} + +//================================================================================================= +// [[DNS TXT]] object definition +// +static tsk_object_t* tnet_dns_txt_ctor(tsk_object_t * self, va_list * app) +{ + tnet_dns_txt_t *txt = self; + if(txt){ + const char* name = va_arg(*app, const char*); + tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t); + uint32_t ttl = va_arg(*app, uint32_t); + uint16_t rdlength = tsk_va_arg_u16(*app); + const void* data = va_arg(*app, const void*); + tsk_size_t offset = va_arg(*app, tsk_size_t); + + /* init base */ + tnet_dns_rr_init(TNET_DNS_RR(txt), qtype_txt, qclass); + TNET_DNS_RR(txt)->name = tsk_strdup(name); + TNET_DNS_RR(txt)->rdlength = rdlength; + TNET_DNS_RR(txt)->ttl = ttl; + + if(rdlength){ + // ==> DESERIALIZATION + /* TXT-DATA */ + tnet_dns_rr_charstring_deserialize(data, &(txt->txt_data), &offset); + } + } + return self; +} + +static tsk_object_t* tnet_dns_txt_dtor(tsk_object_t * self) +{ + tnet_dns_txt_t *txt = self; + if(txt){ + /* deinit base */ + tnet_dns_rr_deinit(TNET_DNS_RR(txt)); + + TSK_FREE(txt->txt_data); + } + return self; +} + +static const tsk_object_def_t tnet_dns_txt_def_s = +{ + sizeof(tnet_dns_txt_t), + tnet_dns_txt_ctor, + tnet_dns_txt_dtor, + tsk_null, +}; +const tsk_object_def_t *tnet_dns_txt_def_t = &tnet_dns_txt_def_s; diff --git a/tinyNET/src/dns/tnet_dns_txt.h b/tinyNET/src/dns/tnet_dns_txt.h new file mode 100644 index 0000000..05f54d9 --- /dev/null +++ b/tinyNET/src/dns/tnet_dns_txt.h @@ -0,0 +1,61 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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_txt.h + * @brief DNS TeXT record - RR - (RFC 1035). + * + * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> + * + + */ +#ifndef TNET_DNS_RR_TXT_H +#define TNET_DNS_RR_TXT_H + +#include "tinynet_config.h" + +#include "tnet_dns_rr.h" + + +TNET_BEGIN_DECLS + +/** DNS TXT Resource Record +*/ +typedef struct tnet_dns_txt_s +{ + TNET_DECLARE_DNS_RR; + + /* RFC 1035 - 3.3.14. TXT RDATA format + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + / TXT-DATA / + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + */ + char* txt_data; +} +tnet_dns_txt_t; + +tnet_dns_txt_t* tnet_dns_txt_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset); + +TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_txt_def_t; + +TNET_END_DECLS + +#endif /* TNET_DNS_RR_TXT_H */ + |