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

Fork of PicoTCP by Daniele Lacamera

Committer:
daniele
Date:
Fri May 24 15:25:25 2013 +0000
Revision:
3:b4047e8a0123
Updated from main repo + fixed Mutexes;

Who changed what in which revision?

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