Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Committer:
tass
Date:
Fri May 17 12:09:59 2013 +0000
Revision:
1:cfe8984a32b4
Parent:
libraries/picotcp/modules/pico_dns_client.c@0:d7f2341ab245
Update for smaller SOCKETQ

Who changed what in which revision?

UserRevisionLine numberNew contents of line
daniele 0:d7f2341ab245 1 /*********************************************************************
daniele 0:d7f2341ab245 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
daniele 0:d7f2341ab245 3 See LICENSE and COPYING for usage.
daniele 0:d7f2341ab245 4
daniele 0:d7f2341ab245 5 .
daniele 0:d7f2341ab245 6
daniele 0:d7f2341ab245 7 Authors: Kristof Roelants
daniele 0:d7f2341ab245 8 *********************************************************************/
daniele 0:d7f2341ab245 9 #include "pico_config.h"
daniele 0:d7f2341ab245 10 #include "pico_stack.h"
daniele 0:d7f2341ab245 11 #include "pico_addressing.h"
daniele 0:d7f2341ab245 12 #include "pico_socket.h"
daniele 0:d7f2341ab245 13 #include "pico_ipv4.h"
daniele 0:d7f2341ab245 14 #include "pico_dns_client.h"
daniele 0:d7f2341ab245 15 #include "pico_tree.h"
daniele 0:d7f2341ab245 16
daniele 0:d7f2341ab245 17 #ifdef PICO_SUPPORT_DNS_CLIENT
daniele 0:d7f2341ab245 18
daniele 0:d7f2341ab245 19 #define dns_dbg(...) do{}while(0)
daniele 0:d7f2341ab245 20 //#define dns_dbg dbg
daniele 0:d7f2341ab245 21
daniele 0:d7f2341ab245 22 /* DNS response length */
daniele 0:d7f2341ab245 23 #define PICO_DNS_MAX_RESPONSE_LEN 256
daniele 0:d7f2341ab245 24
daniele 0:d7f2341ab245 25 /* DNS client retransmission time (msec) + frequency */
daniele 0:d7f2341ab245 26 #define PICO_DNS_CLIENT_RETRANS 4000
daniele 0:d7f2341ab245 27 #define PICO_DNS_CLIENT_MAX_RETRANS 3
daniele 0:d7f2341ab245 28
daniele 0:d7f2341ab245 29 /* Default nameservers */
daniele 0:d7f2341ab245 30 #define PICO_DNS_NS_GOOGLE "8.8.8.8"
daniele 0:d7f2341ab245 31
daniele 0:d7f2341ab245 32 /* Nameserver port */
daniele 0:d7f2341ab245 33 #define PICO_DNS_NS_PORT 53
daniele 0:d7f2341ab245 34
daniele 0:d7f2341ab245 35 /* FLAG values */
daniele 0:d7f2341ab245 36 #define PICO_DNS_QR_QUERY 0
daniele 0:d7f2341ab245 37 #define PICO_DNS_QR_RESPONSE 1
daniele 0:d7f2341ab245 38 #define PICO_DNS_OPCODE_QUERY 0
daniele 0:d7f2341ab245 39 #define PICO_DNS_OPCODE_IQUERY 1
daniele 0:d7f2341ab245 40 #define PICO_DNS_OPCODE_STATUS 2
daniele 0:d7f2341ab245 41 #define PICO_DNS_AA_NO_AUTHORITY 0
daniele 0:d7f2341ab245 42 #define PICO_DNS_AA_IS_AUTHORITY 1
daniele 0:d7f2341ab245 43 #define PICO_DNS_TC_NO_TRUNCATION 0
daniele 0:d7f2341ab245 44 #define PICO_DNS_TC_IS_TRUNCATED 1
daniele 0:d7f2341ab245 45 #define PICO_DNS_RD_NO_DESIRE 0
daniele 0:d7f2341ab245 46 #define PICO_DNS_RD_IS_DESIRED 1
daniele 0:d7f2341ab245 47 #define PICO_DNS_RA_NO_SUPPORT 0
daniele 0:d7f2341ab245 48 #define PICO_DNS_RA_IS_SUPPORTED 1
daniele 0:d7f2341ab245 49 #define PICO_DNS_RCODE_NO_ERROR 0
daniele 0:d7f2341ab245 50 #define PICO_DNS_RCODE_EFORMAT 1
daniele 0:d7f2341ab245 51 #define PICO_DNS_RCODE_ESERVER 2
daniele 0:d7f2341ab245 52 #define PICO_DNS_RCODE_ENAME 3
daniele 0:d7f2341ab245 53 #define PICO_DNS_RCODE_ENOIMP 4
daniele 0:d7f2341ab245 54 #define PICO_DNS_RCODE_EREFUSED 5
daniele 0:d7f2341ab245 55
daniele 0:d7f2341ab245 56 /* QTYPE values */
daniele 0:d7f2341ab245 57 #define PICO_DNS_TYPE_A 1
daniele 0:d7f2341ab245 58 #define PICO_DNS_TYPE_PTR 12
daniele 0:d7f2341ab245 59
daniele 0:d7f2341ab245 60 /* QCLASS values */
daniele 0:d7f2341ab245 61 #define PICO_DNS_CLASS_IN 1
daniele 0:d7f2341ab245 62
daniele 0:d7f2341ab245 63 /* Compression values */
daniele 0:d7f2341ab245 64 #define PICO_DNS_LABEL 0
daniele 0:d7f2341ab245 65 #define PICO_DNS_POINTER 3
daniele 0:d7f2341ab245 66
daniele 0:d7f2341ab245 67 /* TTL values */
daniele 0:d7f2341ab245 68 #define PICO_DNS_MAX_TTL 604800 /* one week */
daniele 0:d7f2341ab245 69
daniele 0:d7f2341ab245 70 /* Header flags */
daniele 0:d7f2341ab245 71 #define FLAG_QR(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 15)) | (x << 15))
daniele 0:d7f2341ab245 72 #define FLAG_OPCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF << 11)) | (x << 11))
daniele 0:d7f2341ab245 73 #define FLAG_AA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 10)) | (x << 10))
daniele 0:d7f2341ab245 74 #define FLAG_TC(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 9)) | (x << 9))
daniele 0:d7f2341ab245 75 #define FLAG_RD(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 8)) | (x << 8))
daniele 0:d7f2341ab245 76 #define FLAG_RA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 7)) | (x << 7))
daniele 0:d7f2341ab245 77 #define FLAG_Z(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x7 << 4)) | (x << 4))
daniele 0:d7f2341ab245 78 #define FLAG_RCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF)) | x)
daniele 0:d7f2341ab245 79
daniele 0:d7f2341ab245 80 #define GET_FLAG_QR(hdr) ((((hdr)->flags) & (1 << 15)) != 0)
daniele 0:d7f2341ab245 81 #define GET_FLAG_OPCODE(hdr) ((((hdr)->flags) & (0xF << 11)) >> 11)
daniele 0:d7f2341ab245 82 #define GET_FLAG_AA(hdr) ((((hdr)->flags) & (1 << 10)) != 0)
daniele 0:d7f2341ab245 83 #define GET_FLAG_TC(hdr) ((((hdr)->flags) & (1 << 9)) != 0)
daniele 0:d7f2341ab245 84 #define GET_FLAG_RD(hdr) ((((hdr)->flags) & (1 << 8)) != 0)
daniele 0:d7f2341ab245 85 #define GET_FLAG_RA(hdr) ((((hdr)->flags) & (1 << 7)) != 0)
daniele 0:d7f2341ab245 86 #define GET_FLAG_Z(hdr) ((((hdr)->flags) & (0x7 << 4)) >> 4)
daniele 0:d7f2341ab245 87 #define GET_FLAG_RCODE(hdr) (((hdr)->flags) & (0x0F))
daniele 0:d7f2341ab245 88
daniele 0:d7f2341ab245 89 /* RFC 1025 section 4. MESSAGES */
daniele 0:d7f2341ab245 90 struct __attribute__((packed)) dns_message_hdr
daniele 0:d7f2341ab245 91 {
daniele 0:d7f2341ab245 92 uint16_t id;
daniele 0:d7f2341ab245 93 uint16_t flags;
daniele 0:d7f2341ab245 94 uint16_t qdcount;
daniele 0:d7f2341ab245 95 uint16_t ancount;
daniele 0:d7f2341ab245 96 uint16_t nscount;
daniele 0:d7f2341ab245 97 uint16_t arcount;
daniele 0:d7f2341ab245 98 };
daniele 0:d7f2341ab245 99
daniele 0:d7f2341ab245 100 struct __attribute__((packed)) dns_query_suffix
daniele 0:d7f2341ab245 101 {
daniele 0:d7f2341ab245 102 /* NAME - domain name to which this resource record pertains */
daniele 0:d7f2341ab245 103 uint16_t qtype;
daniele 0:d7f2341ab245 104 uint16_t qclass;
daniele 0:d7f2341ab245 105 };
daniele 0:d7f2341ab245 106
daniele 0:d7f2341ab245 107 struct __attribute__((packed)) dns_answer_suffix
daniele 0:d7f2341ab245 108 {
daniele 0:d7f2341ab245 109 /* NAME - domain name to which this resource record pertains */
daniele 0:d7f2341ab245 110 uint16_t qtype;
daniele 0:d7f2341ab245 111 uint16_t qclass;
daniele 0:d7f2341ab245 112 uint32_t ttl;
daniele 0:d7f2341ab245 113 uint16_t rdlength;
daniele 0:d7f2341ab245 114 /* RDATA - variable length string of octets that describes the resource */
daniele 0:d7f2341ab245 115 };
daniele 0:d7f2341ab245 116
daniele 0:d7f2341ab245 117 struct pico_dns_ns
daniele 0:d7f2341ab245 118 {
daniele 0:d7f2341ab245 119 struct pico_ip4 ns; /* Nameserver */
daniele 0:d7f2341ab245 120 };
daniele 0:d7f2341ab245 121
daniele 0:d7f2341ab245 122 static int dns_ns_cmp(void *ka, void *kb)
daniele 0:d7f2341ab245 123 {
daniele 0:d7f2341ab245 124 struct pico_dns_ns *a = ka, *b = kb;
daniele 0:d7f2341ab245 125 if (a->ns.addr < b->ns.addr)
daniele 0:d7f2341ab245 126 return -1;
daniele 0:d7f2341ab245 127 else if (a->ns.addr > b->ns.addr)
daniele 0:d7f2341ab245 128 return 1;
daniele 0:d7f2341ab245 129 else
daniele 0:d7f2341ab245 130 return 0;
daniele 0:d7f2341ab245 131 }
daniele 0:d7f2341ab245 132
daniele 0:d7f2341ab245 133 PICO_TREE_DECLARE(NSTable,dns_ns_cmp);
daniele 0:d7f2341ab245 134
daniele 0:d7f2341ab245 135 int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag)
daniele 0:d7f2341ab245 136 {
daniele 0:d7f2341ab245 137 struct pico_dns_ns test, *key = NULL;
daniele 0:d7f2341ab245 138
daniele 0:d7f2341ab245 139 if (!ns) {
daniele 0:d7f2341ab245 140 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 141 return -1;
daniele 0:d7f2341ab245 142 }
daniele 0:d7f2341ab245 143
daniele 0:d7f2341ab245 144 switch (flag)
daniele 0:d7f2341ab245 145 {
daniele 0:d7f2341ab245 146 case PICO_DNS_NS_ADD:
daniele 0:d7f2341ab245 147 key = pico_zalloc(sizeof(struct pico_dns_ns));
daniele 0:d7f2341ab245 148 if (!key) {
daniele 0:d7f2341ab245 149 pico_err = PICO_ERR_ENOMEM;
daniele 0:d7f2341ab245 150 return -1;
daniele 0:d7f2341ab245 151 }
daniele 0:d7f2341ab245 152 key->ns = *ns;
daniele 0:d7f2341ab245 153
daniele 0:d7f2341ab245 154 if(pico_tree_insert(&NSTable,key)){
daniele 0:d7f2341ab245 155 dns_dbg("DNS WARNING: nameserver %08X already added\n",ns->addr);
daniele 0:d7f2341ab245 156 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 157 pico_free(key);
daniele 0:d7f2341ab245 158 return -1; /* Element key already exists */
daniele 0:d7f2341ab245 159 }
daniele 0:d7f2341ab245 160 dns_dbg("DNS: nameserver %08X added\n", ns->addr);
daniele 0:d7f2341ab245 161 /* If default NS found, remove it */
daniele 0:d7f2341ab245 162 pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr);
daniele 0:d7f2341ab245 163 if (ns->addr != test.ns.addr) {
daniele 0:d7f2341ab245 164
daniele 0:d7f2341ab245 165 key = pico_tree_findKey(&NSTable,&test);
daniele 0:d7f2341ab245 166 if (key) {
daniele 0:d7f2341ab245 167 if(pico_tree_delete(&NSTable,key)) {
daniele 0:d7f2341ab245 168 dns_dbg("DNS: default nameserver %08X removed\n", test.ns.addr);
daniele 0:d7f2341ab245 169 pico_free(key);
daniele 0:d7f2341ab245 170 } else {
daniele 0:d7f2341ab245 171 pico_err = PICO_ERR_EAGAIN;
daniele 0:d7f2341ab245 172 return -1;
daniele 0:d7f2341ab245 173 }
daniele 0:d7f2341ab245 174 }
daniele 0:d7f2341ab245 175 }
daniele 0:d7f2341ab245 176 break;
daniele 0:d7f2341ab245 177
daniele 0:d7f2341ab245 178 case PICO_DNS_NS_DEL:
daniele 0:d7f2341ab245 179 test.ns = *ns;
daniele 0:d7f2341ab245 180
daniele 0:d7f2341ab245 181 key = pico_tree_findKey(&NSTable,&test);
daniele 0:d7f2341ab245 182 if (!key) {
daniele 0:d7f2341ab245 183 dns_dbg("DNS WARNING: nameserver %08X not found\n", ns->addr);
daniele 0:d7f2341ab245 184 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 185 return -1;
daniele 0:d7f2341ab245 186 }
daniele 0:d7f2341ab245 187 /* RB_REMOVE returns pointer to removed element, NULL to indicate error */
daniele 0:d7f2341ab245 188
daniele 0:d7f2341ab245 189 if(pico_tree_delete(&NSTable,key)) {
daniele 0:d7f2341ab245 190 dns_dbg("DNS: nameserver %08X removed\n",key->ns.addr);
daniele 0:d7f2341ab245 191 pico_free(key);
daniele 0:d7f2341ab245 192 } else {
daniele 0:d7f2341ab245 193 pico_err = PICO_ERR_EAGAIN;
daniele 0:d7f2341ab245 194 return -1;
daniele 0:d7f2341ab245 195 }
daniele 0:d7f2341ab245 196 /* If no NS left, add default NS */
daniele 0:d7f2341ab245 197 if(pico_tree_first(&NSTable) == NULL){
daniele 0:d7f2341ab245 198 dns_dbg("DNS: add default nameserver\n");
daniele 0:d7f2341ab245 199 return pico_dns_client_init();
daniele 0:d7f2341ab245 200 }
daniele 0:d7f2341ab245 201 break;
daniele 0:d7f2341ab245 202
daniele 0:d7f2341ab245 203 default:
daniele 0:d7f2341ab245 204 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 205 return -1;
daniele 0:d7f2341ab245 206 }
daniele 0:d7f2341ab245 207 return 0;
daniele 0:d7f2341ab245 208 }
daniele 0:d7f2341ab245 209
daniele 0:d7f2341ab245 210 int pico_dns_client_init()
daniele 0:d7f2341ab245 211 {
daniele 0:d7f2341ab245 212 struct pico_ip4 default_ns;
daniele 0:d7f2341ab245 213 if (pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &default_ns.addr) != 0) {
daniele 0:d7f2341ab245 214 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 215 return -1;
daniele 0:d7f2341ab245 216 }
daniele 0:d7f2341ab245 217 return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD);
daniele 0:d7f2341ab245 218 }
daniele 0:d7f2341ab245 219
daniele 0:d7f2341ab245 220 struct pico_dns_key
daniele 0:d7f2341ab245 221 {
daniele 0:d7f2341ab245 222 char *q_hdr;
daniele 0:d7f2341ab245 223 uint16_t len;
daniele 0:d7f2341ab245 224 uint16_t id;
daniele 0:d7f2341ab245 225 uint16_t qtype;
daniele 0:d7f2341ab245 226 uint16_t qclass;
daniele 0:d7f2341ab245 227 uint8_t retrans;
daniele 0:d7f2341ab245 228 struct pico_dns_ns q_ns;
daniele 0:d7f2341ab245 229 struct pico_socket *s;
daniele 0:d7f2341ab245 230 void (*callback)(char *, void *);
daniele 0:d7f2341ab245 231 void *arg;
daniele 0:d7f2341ab245 232 };
daniele 0:d7f2341ab245 233
daniele 0:d7f2341ab245 234 static int dns_cmp(void *ka, void *kb)
daniele 0:d7f2341ab245 235 {
daniele 0:d7f2341ab245 236 struct pico_dns_key *a = ka,*b = kb;
daniele 0:d7f2341ab245 237 if (a->id < b->id)
daniele 0:d7f2341ab245 238 return -1;
daniele 0:d7f2341ab245 239 else if (a->id > b->id)
daniele 0:d7f2341ab245 240 return 1;
daniele 0:d7f2341ab245 241 else
daniele 0:d7f2341ab245 242 return 0;
daniele 0:d7f2341ab245 243 }
daniele 0:d7f2341ab245 244
daniele 0:d7f2341ab245 245 PICO_TREE_DECLARE(DNSTable,dns_cmp);
daniele 0:d7f2341ab245 246
daniele 0:d7f2341ab245 247 static int pico_dns_client_strlen(const char *url)
daniele 0:d7f2341ab245 248 {
daniele 0:d7f2341ab245 249 uint16_t len = 0;
daniele 0:d7f2341ab245 250 int p;
daniele 0:d7f2341ab245 251
daniele 0:d7f2341ab245 252 if (!url)
daniele 0:d7f2341ab245 253 return -1;
daniele 0:d7f2341ab245 254
daniele 0:d7f2341ab245 255 while ((p = *url++) != 0) {
daniele 0:d7f2341ab245 256 len++;
daniele 0:d7f2341ab245 257 }
daniele 0:d7f2341ab245 258 return len;
daniele 0:d7f2341ab245 259 }
daniele 0:d7f2341ab245 260
daniele 0:d7f2341ab245 261 /* Replace '.' by the label length */
daniele 0:d7f2341ab245 262 static int pico_dns_client_label(char *ptr)
daniele 0:d7f2341ab245 263 {
daniele 0:d7f2341ab245 264 char *l;
daniele 0:d7f2341ab245 265 uint8_t lbl_len = 0;
daniele 0:d7f2341ab245 266 int p;
daniele 0:d7f2341ab245 267
daniele 0:d7f2341ab245 268 if (!ptr)
daniele 0:d7f2341ab245 269 return -1;
daniele 0:d7f2341ab245 270
daniele 0:d7f2341ab245 271 l = ptr++;
daniele 0:d7f2341ab245 272 while ((p = *ptr++) != 0){
daniele 0:d7f2341ab245 273 if (p == '.') {
daniele 0:d7f2341ab245 274 *l = lbl_len;
daniele 0:d7f2341ab245 275 l = ptr - 1;
daniele 0:d7f2341ab245 276 lbl_len = 0;
daniele 0:d7f2341ab245 277 } else {
daniele 0:d7f2341ab245 278 lbl_len++;
daniele 0:d7f2341ab245 279 }
daniele 0:d7f2341ab245 280 }
daniele 0:d7f2341ab245 281 *l = lbl_len;
daniele 0:d7f2341ab245 282 return 0;
daniele 0:d7f2341ab245 283 }
daniele 0:d7f2341ab245 284
daniele 0:d7f2341ab245 285 /* Replace the label length by '.' */
daniele 0:d7f2341ab245 286 static int pico_dns_client_reverse_label(char *ptr)
daniele 0:d7f2341ab245 287 {
daniele 0:d7f2341ab245 288 char *l;
daniele 0:d7f2341ab245 289 int p;
daniele 0:d7f2341ab245 290
daniele 0:d7f2341ab245 291 if(!ptr)
daniele 0:d7f2341ab245 292 return -1;
daniele 0:d7f2341ab245 293
daniele 0:d7f2341ab245 294 l = ptr;
daniele 0:d7f2341ab245 295 while ((p = *ptr++) != 0){
daniele 0:d7f2341ab245 296 ptr += p;
daniele 0:d7f2341ab245 297 *l = '.';
daniele 0:d7f2341ab245 298 l = ptr;
daniele 0:d7f2341ab245 299 }
daniele 0:d7f2341ab245 300 return 0;
daniele 0:d7f2341ab245 301 }
daniele 0:d7f2341ab245 302
daniele 0:d7f2341ab245 303 /* Seek the end of a string */
daniele 0:d7f2341ab245 304 static char *pico_dns_client_seek(char *ptr)
daniele 0:d7f2341ab245 305 {
daniele 0:d7f2341ab245 306 int p;
daniele 0:d7f2341ab245 307
daniele 0:d7f2341ab245 308 if (!ptr)
daniele 0:d7f2341ab245 309 return NULL;
daniele 0:d7f2341ab245 310
daniele 0:d7f2341ab245 311 while ((p = *ptr++) != 0);
daniele 0:d7f2341ab245 312
daniele 0:d7f2341ab245 313 return ptr++;
daniele 0:d7f2341ab245 314 }
daniele 0:d7f2341ab245 315
daniele 0:d7f2341ab245 316 static inline void pico_dns_client_construct_hdr(struct dns_message_hdr *hdr, uint16_t id)
daniele 0:d7f2341ab245 317 {
daniele 0:d7f2341ab245 318 hdr->id = short_be(id);
daniele 0:d7f2341ab245 319 FLAG_QR(hdr, PICO_DNS_QR_QUERY);
daniele 0:d7f2341ab245 320 FLAG_OPCODE(hdr, PICO_DNS_OPCODE_QUERY);
daniele 0:d7f2341ab245 321 FLAG_AA(hdr, PICO_DNS_AA_NO_AUTHORITY);
daniele 0:d7f2341ab245 322 FLAG_TC(hdr, PICO_DNS_TC_NO_TRUNCATION);
daniele 0:d7f2341ab245 323 FLAG_RD(hdr, PICO_DNS_RD_IS_DESIRED);
daniele 0:d7f2341ab245 324 FLAG_RA(hdr, PICO_DNS_RA_NO_SUPPORT);
daniele 0:d7f2341ab245 325 FLAG_Z(hdr, 0);
daniele 0:d7f2341ab245 326 FLAG_RCODE(hdr, PICO_DNS_RCODE_NO_ERROR);
daniele 0:d7f2341ab245 327 hdr->flags = short_be(hdr->flags);
daniele 0:d7f2341ab245 328 hdr->qdcount = short_be(1);
daniele 0:d7f2341ab245 329 hdr->ancount = short_be(0);
daniele 0:d7f2341ab245 330 hdr->nscount = short_be(0);
daniele 0:d7f2341ab245 331 hdr->arcount = short_be(0);
daniele 0:d7f2341ab245 332 }
daniele 0:d7f2341ab245 333
daniele 0:d7f2341ab245 334 static inline void pico_dns_client_hdr_ntoh(struct dns_message_hdr *hdr)
daniele 0:d7f2341ab245 335 {
daniele 0:d7f2341ab245 336 hdr->id = short_be(hdr->id);
daniele 0:d7f2341ab245 337 hdr->flags = short_be(hdr->flags);
daniele 0:d7f2341ab245 338 hdr->qdcount = short_be(hdr->qdcount);
daniele 0:d7f2341ab245 339 hdr->ancount = short_be(hdr->ancount);
daniele 0:d7f2341ab245 340 hdr->nscount = short_be(hdr->nscount);
daniele 0:d7f2341ab245 341 hdr->arcount = short_be(hdr->arcount);
daniele 0:d7f2341ab245 342 }
daniele 0:d7f2341ab245 343
daniele 0:d7f2341ab245 344
daniele 0:d7f2341ab245 345 static int pico_dns_client_mirror(char *ptr)
daniele 0:d7f2341ab245 346 {
daniele 0:d7f2341ab245 347 unsigned char buf[4] = {0};
daniele 0:d7f2341ab245 348 char *m;
daniele 0:d7f2341ab245 349 int cnt = 0;
daniele 0:d7f2341ab245 350 int p, i;
daniele 0:d7f2341ab245 351
daniele 0:d7f2341ab245 352 if (!ptr)
daniele 0:d7f2341ab245 353 return -1;
daniele 0:d7f2341ab245 354
daniele 0:d7f2341ab245 355 m = ptr;
daniele 0:d7f2341ab245 356 while ((p = *ptr++) != 0)
daniele 0:d7f2341ab245 357 {
daniele 0:d7f2341ab245 358 if (pico_is_digit(p)) {
daniele 0:d7f2341ab245 359 buf[cnt] = (10 * buf[cnt]) + (p - '0');
daniele 0:d7f2341ab245 360 } else if (p == '.') {
daniele 0:d7f2341ab245 361 cnt++;
daniele 0:d7f2341ab245 362 } else {
daniele 0:d7f2341ab245 363 return -1;
daniele 0:d7f2341ab245 364 }
daniele 0:d7f2341ab245 365 }
daniele 0:d7f2341ab245 366
daniele 0:d7f2341ab245 367 /* Handle short notation */
daniele 0:d7f2341ab245 368 if(cnt == 1){
daniele 0:d7f2341ab245 369 buf[3] = buf[1];
daniele 0:d7f2341ab245 370 buf[1] = 0;
daniele 0:d7f2341ab245 371 buf[2] = 0;
daniele 0:d7f2341ab245 372 }else if (cnt == 2){
daniele 0:d7f2341ab245 373 buf[3] = buf[2];
daniele 0:d7f2341ab245 374 buf[2] = 0;
daniele 0:d7f2341ab245 375 }else if(cnt != 3){
daniele 0:d7f2341ab245 376 /* String could not be parsed, return error */
daniele 0:d7f2341ab245 377 return -1;
daniele 0:d7f2341ab245 378 }
daniele 0:d7f2341ab245 379
daniele 0:d7f2341ab245 380 ptr = m;
daniele 0:d7f2341ab245 381 for(i = 3; i >= 0; i--)
daniele 0:d7f2341ab245 382 {
daniele 0:d7f2341ab245 383 if(buf[i] > 99){
daniele 0:d7f2341ab245 384 *ptr++ = '0' + (buf[i] / 100);
daniele 0:d7f2341ab245 385 *ptr++ = '0' + ((buf[i] % 100) / 10);
daniele 0:d7f2341ab245 386 *ptr++ = '0' + ((buf[i] % 100) % 10);
daniele 0:d7f2341ab245 387 }else if(buf[i] > 9){
daniele 0:d7f2341ab245 388 *ptr++ = '0' + (buf[i] / 10);
daniele 0:d7f2341ab245 389 *ptr++ = '0' + (buf[i] % 10);
daniele 0:d7f2341ab245 390 }else{
daniele 0:d7f2341ab245 391 *ptr++ = '0' + buf[i];
daniele 0:d7f2341ab245 392 }
daniele 0:d7f2341ab245 393 if(i > 0)
daniele 0:d7f2341ab245 394 *ptr++ = '.';
daniele 0:d7f2341ab245 395 }
daniele 0:d7f2341ab245 396
daniele 0:d7f2341ab245 397 return 0;
daniele 0:d7f2341ab245 398 }
daniele 0:d7f2341ab245 399
daniele 0:d7f2341ab245 400 static struct pico_dns_key *pico_dns_client_idcheck(uint16_t id)
daniele 0:d7f2341ab245 401 {
daniele 0:d7f2341ab245 402 struct pico_dns_key test;
daniele 0:d7f2341ab245 403
daniele 0:d7f2341ab245 404 test.id = id;
daniele 0:d7f2341ab245 405 return pico_tree_findKey(&DNSTable,&test);
daniele 0:d7f2341ab245 406 }
daniele 0:d7f2341ab245 407
daniele 0:d7f2341ab245 408 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s);
daniele 0:d7f2341ab245 409
daniele 0:d7f2341ab245 410 static int pico_dns_client_send(struct pico_dns_key *key)
daniele 0:d7f2341ab245 411 {
daniele 0:d7f2341ab245 412 struct pico_socket *s;
daniele 0:d7f2341ab245 413 int w = 0;
daniele 0:d7f2341ab245 414
daniele 0:d7f2341ab245 415 dns_dbg("DNS: sending query to %08X\n", key->q_ns.ns.addr);
daniele 0:d7f2341ab245 416 s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback);
daniele 0:d7f2341ab245 417 if (!s)
daniele 0:d7f2341ab245 418 return -1;
daniele 0:d7f2341ab245 419 key->s = s;
daniele 0:d7f2341ab245 420 if (pico_socket_connect(s, &key->q_ns.ns, short_be(PICO_DNS_NS_PORT)) != 0)
daniele 0:d7f2341ab245 421 return -1;
daniele 0:d7f2341ab245 422 w = pico_socket_send(s, key->q_hdr, key->len);
daniele 0:d7f2341ab245 423 if (w <= 0)
daniele 0:d7f2341ab245 424 return -1;
daniele 0:d7f2341ab245 425
daniele 0:d7f2341ab245 426 return 0;
daniele 0:d7f2341ab245 427 }
daniele 0:d7f2341ab245 428
daniele 0:d7f2341ab245 429 static void pico_dns_client_retransmission(unsigned long now, void *arg)
daniele 0:d7f2341ab245 430 {
daniele 0:d7f2341ab245 431 struct pico_dns_key *key = (struct pico_dns_key *)arg;
daniele 0:d7f2341ab245 432 struct pico_dns_ns *q_ns = NULL;
daniele 0:d7f2341ab245 433
daniele 0:d7f2341ab245 434 if (!key->retrans) {
daniele 0:d7f2341ab245 435 dns_dbg("DNS: no retransmission!\n");
daniele 0:d7f2341ab245 436 pico_free(key->q_hdr);
daniele 0:d7f2341ab245 437
daniele 0:d7f2341ab245 438 if(pico_tree_delete(&DNSTable,key))
daniele 0:d7f2341ab245 439 pico_free(key);
daniele 0:d7f2341ab245 440 }
daniele 0:d7f2341ab245 441 else if (key->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) {
daniele 0:d7f2341ab245 442 key->retrans++;
daniele 0:d7f2341ab245 443 dns_dbg("DNS: retransmission! (%u attempts)\n", key->retrans);
daniele 0:d7f2341ab245 444 // ugly hack
daniele 0:d7f2341ab245 445 q_ns = pico_tree_next(pico_tree_findNode(&NSTable,&key->q_ns))->keyValue;
daniele 0:d7f2341ab245 446 if (q_ns)
daniele 0:d7f2341ab245 447 key->q_ns = *q_ns;
daniele 0:d7f2341ab245 448 else
daniele 0:d7f2341ab245 449 key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
daniele 0:d7f2341ab245 450 pico_dns_client_send(key);
daniele 0:d7f2341ab245 451 pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
daniele 0:d7f2341ab245 452 } else {
daniele 0:d7f2341ab245 453 dns_dbg("DNS ERROR: no reply from nameservers! (%u attempts)\n", key->retrans);
daniele 0:d7f2341ab245 454 pico_socket_close(key->s);
daniele 0:d7f2341ab245 455 pico_err = PICO_ERR_EIO;
daniele 0:d7f2341ab245 456 key->callback(NULL, key->arg);
daniele 0:d7f2341ab245 457 pico_free(key->q_hdr);
daniele 0:d7f2341ab245 458 /* RB_REMOVE returns pointer to removed element, NULL to indicate error */
daniele 0:d7f2341ab245 459
daniele 0:d7f2341ab245 460 if(pico_tree_delete(&DNSTable,key))
daniele 0:d7f2341ab245 461 pico_free(key);
daniele 0:d7f2341ab245 462 }
daniele 0:d7f2341ab245 463 }
daniele 0:d7f2341ab245 464
daniele 0:d7f2341ab245 465 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s)
daniele 0:d7f2341ab245 466 {
daniele 0:d7f2341ab245 467 char *q_qname, *q_suf, *a_hdr, *a_qname, *a_suf, *a_rdata;
daniele 0:d7f2341ab245 468 struct dns_message_hdr *hdr;
daniele 0:d7f2341ab245 469 struct dns_query_suffix query_suf;
daniele 0:d7f2341ab245 470 struct dns_answer_suffix answer_suf;
daniele 0:d7f2341ab245 471 struct pico_dns_key test, *key;
daniele 0:d7f2341ab245 472 char *answer;
daniele 0:d7f2341ab245 473 char dns_answer[PICO_DNS_MAX_RESPONSE_LEN] = {0};
daniele 0:d7f2341ab245 474 uint8_t valid_suffix = 0;
daniele 0:d7f2341ab245 475 uint16_t compression = 0;
daniele 0:d7f2341ab245 476 int i = 0, r = 0;
daniele 0:d7f2341ab245 477
daniele 0:d7f2341ab245 478 if (ev & PICO_SOCK_EV_RD) {
daniele 0:d7f2341ab245 479 r = pico_socket_read(s, dns_answer, PICO_DNS_MAX_RESPONSE_LEN);
daniele 0:d7f2341ab245 480 pico_socket_close(s);
daniele 0:d7f2341ab245 481 if (r == PICO_DNS_MAX_RESPONSE_LEN || r < (int)sizeof(struct dns_message_hdr)) {
daniele 0:d7f2341ab245 482 dns_dbg("DNS ERROR: received incorrect number(%d) of bytes\n", r);
daniele 0:d7f2341ab245 483 return;
daniele 0:d7f2341ab245 484 }
daniele 0:d7f2341ab245 485
daniele 0:d7f2341ab245 486 /* Check header validity */
daniele 0:d7f2341ab245 487 a_hdr = dns_answer;
daniele 0:d7f2341ab245 488 hdr = (struct dns_message_hdr *) a_hdr;
daniele 0:d7f2341ab245 489 pico_dns_client_hdr_ntoh(hdr);
daniele 0:d7f2341ab245 490 if (GET_FLAG_QR(hdr) != PICO_DNS_QR_RESPONSE || GET_FLAG_OPCODE(hdr) != PICO_DNS_OPCODE_QUERY
daniele 0:d7f2341ab245 491 || GET_FLAG_TC(hdr) == PICO_DNS_TC_IS_TRUNCATED || GET_FLAG_RCODE(hdr) != PICO_DNS_RCODE_NO_ERROR) {
daniele 0:d7f2341ab245 492 dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", GET_FLAG_OPCODE(hdr), GET_FLAG_TC(hdr), GET_FLAG_RCODE(hdr));
daniele 0:d7f2341ab245 493 return;
daniele 0:d7f2341ab245 494 }
daniele 0:d7f2341ab245 495
daniele 0:d7f2341ab245 496 if (hdr->ancount < 1 || r < (int)(sizeof(struct dns_message_hdr) + hdr->qdcount * sizeof(struct dns_query_suffix)
daniele 0:d7f2341ab245 497 + hdr->ancount * sizeof(struct dns_answer_suffix))) {
daniele 0:d7f2341ab245 498 dns_dbg("DNS ERROR: ancount < 1 OR received number(%d) of bytes too low\n", r);
daniele 0:d7f2341ab245 499 return;
daniele 0:d7f2341ab245 500 }
daniele 0:d7f2341ab245 501
daniele 0:d7f2341ab245 502 /* Find DNS key */
daniele 0:d7f2341ab245 503 test.id = hdr->id;
daniele 0:d7f2341ab245 504
daniele 0:d7f2341ab245 505 key = pico_tree_findKey(&DNSTable,&test);
daniele 0:d7f2341ab245 506 if (!key) {
daniele 0:d7f2341ab245 507 dns_dbg("DNS WARNING: key with id %u not found\n", hdr->id);
daniele 0:d7f2341ab245 508 return;
daniele 0:d7f2341ab245 509 }
daniele 0:d7f2341ab245 510 key->retrans = 0;
daniele 0:d7f2341ab245 511
daniele 0:d7f2341ab245 512 /* Check query suffix validity */
daniele 0:d7f2341ab245 513 q_qname = a_hdr + sizeof(struct dns_message_hdr);
daniele 0:d7f2341ab245 514 q_suf = pico_dns_client_seek(q_qname);
daniele 0:d7f2341ab245 515 query_suf = *(struct dns_query_suffix *) q_suf;
daniele 0:d7f2341ab245 516 if (short_be(query_suf.qtype) != key->qtype || short_be(query_suf.qclass) != key->qclass) {
daniele 0:d7f2341ab245 517 dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(query_suf.qtype), short_be(query_suf.qclass));
daniele 0:d7f2341ab245 518 return;
daniele 0:d7f2341ab245 519 }
daniele 0:d7f2341ab245 520
daniele 0:d7f2341ab245 521 /* Seek answer suffix */
daniele 0:d7f2341ab245 522 a_qname = q_suf + sizeof(struct dns_query_suffix);
daniele 0:d7f2341ab245 523 a_suf = a_qname;
daniele 0:d7f2341ab245 524 while(i++ < hdr->ancount) {
daniele 0:d7f2341ab245 525 compression = short_be(*(uint16_t *)a_suf);
daniele 0:d7f2341ab245 526 switch (compression >> 14)
daniele 0:d7f2341ab245 527 {
daniele 0:d7f2341ab245 528 case PICO_DNS_POINTER:
daniele 0:d7f2341ab245 529 while (compression >> 14 == PICO_DNS_POINTER) {
daniele 0:d7f2341ab245 530 dns_dbg("DNS: pointer\n");
daniele 0:d7f2341ab245 531 a_suf += sizeof(uint16_t);
daniele 0:d7f2341ab245 532 compression = short_be(*(uint16_t *)a_suf);
daniele 0:d7f2341ab245 533 }
daniele 0:d7f2341ab245 534 break;
daniele 0:d7f2341ab245 535
daniele 0:d7f2341ab245 536 case PICO_DNS_LABEL:
daniele 0:d7f2341ab245 537 dns_dbg("DNS: label\n");
daniele 0:d7f2341ab245 538 a_suf = pico_dns_client_seek(a_qname);
daniele 0:d7f2341ab245 539 break;
daniele 0:d7f2341ab245 540
daniele 0:d7f2341ab245 541 default:
daniele 0:d7f2341ab245 542 dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression);
daniele 0:d7f2341ab245 543 return;
daniele 0:d7f2341ab245 544 }
daniele 0:d7f2341ab245 545
daniele 0:d7f2341ab245 546 /* Check answer suffix validity */
daniele 0:d7f2341ab245 547 answer_suf = *(struct dns_answer_suffix *)a_suf;
daniele 0:d7f2341ab245 548 if (short_be(answer_suf.qtype) != key->qtype || short_be(answer_suf.qclass) != key->qclass) {
daniele 0:d7f2341ab245 549 dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(answer_suf.qtype), short_be(answer_suf.qclass));
daniele 0:d7f2341ab245 550 a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength);
daniele 0:d7f2341ab245 551 continue;
daniele 0:d7f2341ab245 552 }
daniele 0:d7f2341ab245 553
daniele 0:d7f2341ab245 554 if (short_be(answer_suf.ttl) > PICO_DNS_MAX_TTL) {
daniele 0:d7f2341ab245 555 dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(answer_suf.ttl), PICO_DNS_MAX_TTL);
daniele 0:d7f2341ab245 556 a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength);
daniele 0:d7f2341ab245 557 continue;
daniele 0:d7f2341ab245 558 }
daniele 0:d7f2341ab245 559
daniele 0:d7f2341ab245 560 valid_suffix = 1;
daniele 0:d7f2341ab245 561 break;
daniele 0:d7f2341ab245 562 }
daniele 0:d7f2341ab245 563
daniele 0:d7f2341ab245 564 if (!valid_suffix) {
daniele 0:d7f2341ab245 565 dns_dbg("DNS ERROR: invalid dns answer suffix\n");
daniele 0:d7f2341ab245 566 return;
daniele 0:d7f2341ab245 567 }
daniele 0:d7f2341ab245 568
daniele 0:d7f2341ab245 569 a_rdata = a_suf + sizeof(struct dns_answer_suffix);
daniele 0:d7f2341ab245 570 if (key->qtype == PICO_DNS_TYPE_A) {
daniele 0:d7f2341ab245 571 dns_dbg("DNS: length %u | ip %08X\n", short_be(answer_suf.rdlength), long_be(*(uint32_t *)a_rdata));
daniele 0:d7f2341ab245 572 answer = pico_zalloc(16);
daniele 0:d7f2341ab245 573 pico_ipv4_to_string(answer, *(uint32_t *)a_rdata);
daniele 0:d7f2341ab245 574 key->callback(answer, key->arg);
daniele 0:d7f2341ab245 575 } else if (key->qtype == PICO_DNS_TYPE_PTR) {
daniele 0:d7f2341ab245 576 pico_dns_client_reverse_label((char *) a_rdata);
daniele 0:d7f2341ab245 577 dns_dbg("DNS: length %u | name %s\n", short_be(answer_suf.rdlength), (char *)a_rdata + 1);
daniele 0:d7f2341ab245 578 answer = pico_zalloc(answer_suf.rdlength - 1);
daniele 0:d7f2341ab245 579 memcpy(answer, (char *)a_rdata + 1, short_be(answer_suf.rdlength) - 1);
daniele 0:d7f2341ab245 580 key->callback(answer, key->arg);
daniele 0:d7f2341ab245 581 } else {
daniele 0:d7f2341ab245 582 dns_dbg("DNS ERROR: incorrect qtype (%u)\n", key->qtype);
daniele 0:d7f2341ab245 583 return;
daniele 0:d7f2341ab245 584 }
daniele 0:d7f2341ab245 585 }
daniele 0:d7f2341ab245 586
daniele 0:d7f2341ab245 587 if (ev == PICO_SOCK_EV_ERR) {
daniele 0:d7f2341ab245 588 dns_dbg("DNS: socket error received\n");
daniele 0:d7f2341ab245 589 }
daniele 0:d7f2341ab245 590 }
daniele 0:d7f2341ab245 591
daniele 0:d7f2341ab245 592 int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg)
daniele 0:d7f2341ab245 593 {
daniele 0:d7f2341ab245 594 char *q_hdr, *q_qname, *q_suf;
daniele 0:d7f2341ab245 595 struct dns_message_hdr *hdr;
daniele 0:d7f2341ab245 596 struct dns_query_suffix query_suf;
daniele 0:d7f2341ab245 597 struct pico_dns_key *key;
daniele 0:d7f2341ab245 598 uint16_t url_len = 0;
daniele 0:d7f2341ab245 599 uint16_t id = 0;
daniele 0:d7f2341ab245 600
daniele 0:d7f2341ab245 601 if (!url || !callback) {
daniele 0:d7f2341ab245 602 dns_dbg("DNS ERROR: NULL parameters\n");
daniele 0:d7f2341ab245 603 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 604 return -1;
daniele 0:d7f2341ab245 605 }
daniele 0:d7f2341ab245 606
daniele 0:d7f2341ab245 607 url_len = pico_dns_client_strlen(url);
daniele 0:d7f2341ab245 608 /* 2 extra bytes for url_len to account for 2 extra label length octets */
daniele 0:d7f2341ab245 609 q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix));
daniele 0:d7f2341ab245 610 if (!q_hdr) {
daniele 0:d7f2341ab245 611 pico_err = PICO_ERR_ENOMEM;
daniele 0:d7f2341ab245 612 return -1;
daniele 0:d7f2341ab245 613 }
daniele 0:d7f2341ab245 614 q_qname = q_hdr + sizeof(struct dns_message_hdr);
daniele 0:d7f2341ab245 615 q_suf = q_qname + (1 + url_len + 1);
daniele 0:d7f2341ab245 616
daniele 0:d7f2341ab245 617 /* Construct query header */
daniele 0:d7f2341ab245 618 hdr = (struct dns_message_hdr *) q_hdr;
daniele 0:d7f2341ab245 619 do {
daniele 0:d7f2341ab245 620 id = (uint16_t) (pico_rand() & 0xFFFFU);
daniele 0:d7f2341ab245 621 dns_dbg("DNS: generated id %u\n", id);
daniele 0:d7f2341ab245 622 } while (pico_dns_client_idcheck(id));
daniele 0:d7f2341ab245 623 pico_dns_client_construct_hdr(hdr, id);
daniele 0:d7f2341ab245 624 /* Add and manipulate domain name */
daniele 0:d7f2341ab245 625 memcpy(q_qname + 1, url, url_len + 1);
daniele 0:d7f2341ab245 626 pico_dns_client_label(q_qname);
daniele 0:d7f2341ab245 627 /* Add type and class of query */
daniele 0:d7f2341ab245 628 query_suf.qtype = short_be(PICO_DNS_TYPE_A);
daniele 0:d7f2341ab245 629 query_suf.qclass = short_be(PICO_DNS_CLASS_IN);
daniele 0:d7f2341ab245 630 memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix));
daniele 0:d7f2341ab245 631 /* Create RB entry */
daniele 0:d7f2341ab245 632 key = pico_zalloc(sizeof(struct pico_dns_key));
daniele 0:d7f2341ab245 633 if (!key) {
daniele 0:d7f2341ab245 634 pico_free(q_hdr);
daniele 0:d7f2341ab245 635 pico_err = PICO_ERR_ENOMEM;
daniele 0:d7f2341ab245 636 return -1;
daniele 0:d7f2341ab245 637 }
daniele 0:d7f2341ab245 638 key->q_hdr = q_hdr;
daniele 0:d7f2341ab245 639 key->len = sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix);
daniele 0:d7f2341ab245 640 key->id = id;
daniele 0:d7f2341ab245 641 key->qtype = PICO_DNS_TYPE_A;
daniele 0:d7f2341ab245 642 key->qclass = PICO_DNS_CLASS_IN;
daniele 0:d7f2341ab245 643 key->retrans = 1;
daniele 0:d7f2341ab245 644
daniele 0:d7f2341ab245 645 key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
daniele 0:d7f2341ab245 646 key->s = NULL;
daniele 0:d7f2341ab245 647 key->callback = callback;
daniele 0:d7f2341ab245 648 key->arg = arg;
daniele 0:d7f2341ab245 649 /* Send query */
daniele 0:d7f2341ab245 650 if (pico_dns_client_send(key) < 0) {
daniele 0:d7f2341ab245 651 pico_free(q_hdr);
daniele 0:d7f2341ab245 652 if (key->s)
daniele 0:d7f2341ab245 653 pico_socket_close(key->s);
daniele 0:d7f2341ab245 654 pico_free(key);
daniele 0:d7f2341ab245 655 pico_err = PICO_ERR_EAGAIN;
daniele 0:d7f2341ab245 656 return -1;
daniele 0:d7f2341ab245 657 }
daniele 0:d7f2341ab245 658 /* Insert RB entry */
daniele 0:d7f2341ab245 659
daniele 0:d7f2341ab245 660 if(pico_tree_insert(&DNSTable,key)) {
daniele 0:d7f2341ab245 661 pico_free(q_hdr);
daniele 0:d7f2341ab245 662 pico_free(key);
daniele 0:d7f2341ab245 663 pico_err = PICO_ERR_EAGAIN;
daniele 0:d7f2341ab245 664 return -1; /* Element key already exists */
daniele 0:d7f2341ab245 665 }
daniele 0:d7f2341ab245 666
daniele 0:d7f2341ab245 667 pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
daniele 0:d7f2341ab245 668 return 0;
daniele 0:d7f2341ab245 669 }
daniele 0:d7f2341ab245 670
daniele 0:d7f2341ab245 671 int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg)
daniele 0:d7f2341ab245 672 {
daniele 0:d7f2341ab245 673 char *q_hdr, *q_qname, *q_suf;
daniele 0:d7f2341ab245 674 struct dns_message_hdr *hdr;
daniele 0:d7f2341ab245 675 struct dns_query_suffix query_suf;
daniele 0:d7f2341ab245 676 struct pico_dns_key *key;
daniele 0:d7f2341ab245 677 uint16_t ip_len = 0;
daniele 0:d7f2341ab245 678 uint16_t arpa_len = 0;
daniele 0:d7f2341ab245 679 uint16_t id = 0;
daniele 0:d7f2341ab245 680
daniele 0:d7f2341ab245 681 if (!ip || !callback) {
daniele 0:d7f2341ab245 682 dns_dbg("DNS ERROR: NULL parameters\n");
daniele 0:d7f2341ab245 683 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 684 return -1;
daniele 0:d7f2341ab245 685 }
daniele 0:d7f2341ab245 686
daniele 0:d7f2341ab245 687 ip_len = pico_dns_client_strlen(ip);
daniele 0:d7f2341ab245 688 arpa_len = pico_dns_client_strlen(".in-addr.arpa");
daniele 0:d7f2341ab245 689 /* 2 extra bytes for ip_len and arpa_len to account for 2 extra length octets */
daniele 0:d7f2341ab245 690 q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix));
daniele 0:d7f2341ab245 691 if (!q_hdr) {
daniele 0:d7f2341ab245 692 pico_err = PICO_ERR_ENOMEM;
daniele 0:d7f2341ab245 693 return -1;
daniele 0:d7f2341ab245 694 }
daniele 0:d7f2341ab245 695 q_qname = q_hdr + sizeof(struct dns_message_hdr);
daniele 0:d7f2341ab245 696 q_suf = q_qname + (1 + ip_len + arpa_len + 1);
daniele 0:d7f2341ab245 697
daniele 0:d7f2341ab245 698 /* Construct query header */
daniele 0:d7f2341ab245 699 hdr = (struct dns_message_hdr *)q_hdr;
daniele 0:d7f2341ab245 700 do {
daniele 0:d7f2341ab245 701 id = (uint16_t) (pico_rand() & 0xFFFFU);
daniele 0:d7f2341ab245 702 dns_dbg("DNS: generated id %u\n", id);
daniele 0:d7f2341ab245 703 } while (pico_dns_client_idcheck(id));
daniele 0:d7f2341ab245 704 pico_dns_client_construct_hdr(hdr, id);
daniele 0:d7f2341ab245 705 /* Add and manipulate domain name */
daniele 0:d7f2341ab245 706 memcpy(q_qname + 1, ip, ip_len + 1);
daniele 0:d7f2341ab245 707 pico_dns_client_mirror(q_qname + 1);
daniele 0:d7f2341ab245 708 memcpy(q_qname + 1 + ip_len, ".in-addr.arpa", arpa_len);
daniele 0:d7f2341ab245 709 pico_dns_client_label(q_qname);
daniele 0:d7f2341ab245 710 /* Add type and class of query */
daniele 0:d7f2341ab245 711 query_suf.qtype = short_be(PICO_DNS_TYPE_PTR);
daniele 0:d7f2341ab245 712 query_suf.qclass = short_be(PICO_DNS_CLASS_IN);
daniele 0:d7f2341ab245 713 memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix));
daniele 0:d7f2341ab245 714 /* Create RB entry */
daniele 0:d7f2341ab245 715 key = pico_zalloc(sizeof(struct pico_dns_key));
daniele 0:d7f2341ab245 716 if (!key) {
daniele 0:d7f2341ab245 717 pico_free(q_hdr);
daniele 0:d7f2341ab245 718 pico_err = PICO_ERR_ENOMEM;
daniele 0:d7f2341ab245 719 return -1;
daniele 0:d7f2341ab245 720 }
daniele 0:d7f2341ab245 721 key->q_hdr = q_hdr;
daniele 0:d7f2341ab245 722 key->len = sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix);
daniele 0:d7f2341ab245 723 key->id = id;
daniele 0:d7f2341ab245 724 key->qtype = PICO_DNS_TYPE_PTR;
daniele 0:d7f2341ab245 725 key->qclass = PICO_DNS_CLASS_IN;
daniele 0:d7f2341ab245 726 key->retrans = 1;
daniele 0:d7f2341ab245 727 key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
daniele 0:d7f2341ab245 728 key->s = NULL;
daniele 0:d7f2341ab245 729 key->callback = callback;
daniele 0:d7f2341ab245 730 key->arg = arg;
daniele 0:d7f2341ab245 731 /* Send query */
daniele 0:d7f2341ab245 732 if (pico_dns_client_send(key) < 0) {
daniele 0:d7f2341ab245 733 pico_free(q_hdr);
daniele 0:d7f2341ab245 734 if (key->s)
daniele 0:d7f2341ab245 735 pico_socket_close(key->s);
daniele 0:d7f2341ab245 736 pico_free(key);
daniele 0:d7f2341ab245 737 pico_err = PICO_ERR_EAGAIN;
daniele 0:d7f2341ab245 738 return -1;
daniele 0:d7f2341ab245 739 }
daniele 0:d7f2341ab245 740 /* Insert RB entry */
daniele 0:d7f2341ab245 741
daniele 0:d7f2341ab245 742 if(pico_tree_insert(&DNSTable,key)) {
daniele 0:d7f2341ab245 743 pico_free(q_hdr);
daniele 0:d7f2341ab245 744 pico_free(key);
daniele 0:d7f2341ab245 745 pico_err = PICO_ERR_EAGAIN;
daniele 0:d7f2341ab245 746 return -1; /* Element key already exists */
daniele 0:d7f2341ab245 747 }
daniele 0:d7f2341ab245 748
daniele 0:d7f2341ab245 749 pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
daniele 0:d7f2341ab245 750 return 0;
daniele 0:d7f2341ab245 751 }
daniele 0:d7f2341ab245 752
daniele 0:d7f2341ab245 753 #ifdef PICO_DNS_CLIENT_MAIN
daniele 0:d7f2341ab245 754 int main(int argc, char *argv[])
daniele 0:d7f2341ab245 755 {
daniele 0:d7f2341ab245 756 dns_dbg(">>>>> DNS GET ADDR\n");
daniele 0:d7f2341ab245 757 pico_dns_client_getaddr("www.google.be");
daniele 0:d7f2341ab245 758 dns_dbg(">>>>> DNS GET NAME\n");
daniele 0:d7f2341ab245 759 pico_dns_client_getname("173.194.67.94");
daniele 0:d7f2341ab245 760
daniele 0:d7f2341ab245 761 return 0;
daniele 0:d7f2341ab245 762 }
daniele 0:d7f2341ab245 763 #endif /* PICO_DNS_CLIENT_MAIN */
daniele 0:d7f2341ab245 764 #endif /* PICO_SUPPORT_DNS_CLIENT */