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