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

Fork of PicoTCP by Daniele Lacamera

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 */