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

Fork of PicoTCP by Daniele Lacamera

Committer:
daniele
Date:
Sat Aug 03 08:50:27 2013 +0000
Revision:
51:18637a3d071f
Parent:
10:dd7111d4279f
Branch for CDC-ECM: Work in progress

Who changed what in which revision?

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