Free (GPLv2) TCP/IP stack developed by TASS Belgium
Dependents: lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more
PicoTCP. Copyright (c) 2013 TASS Belgium NV.
Released under the GNU General Public License, version 2.
Different licensing models may exist, at the sole discretion of the Copyright holders.
Official homepage: http://www.picotcp.com
Bug tracker: https://github.com/tass-belgium/picotcp/issues
Development steps:
initial integration with mbed RTOSgeneric mbed Ethernet driverhigh performance NXP LPC1768 specific Ethernet driverMulti-threading support for mbed RTOSBerkeley sockets and integration with the New Socket APIFork of the apps running on top of the New Socket APIScheduling optimizations- Debugging/benchmarking/testing
Demo application (measuring TCP sender performance):
Import programlpc1768-picotcp-demo
A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.
modules/pico_dns_client.c@155:a70f34550c34, 2016-01-28 (annotated)
- Committer:
- tass
- Date:
- Thu Jan 28 15:12:00 2016 +0100
- Revision:
- 155:a70f34550c34
- Parent:
- 152:a3d286bf94e5
Adding TCP flag for FIN.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
tass | 68:0847e35d08a6 | 1 | /********************************************************************* |
TASS Belgium NV |
131:4758606c9316 | 2 | PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. |
TASS Belgium NV |
131:4758606c9316 | 3 | See LICENSE and COPYING for usage. |
TASS Belgium NV |
131:4758606c9316 | 4 | . |
TASS Belgium NV |
131:4758606c9316 | 5 | Authors: Kristof Roelants |
TASS Belgium NV |
131:4758606c9316 | 6 | *********************************************************************/ |
tass | 68:0847e35d08a6 | 7 | #include "pico_config.h" |
tass | 68:0847e35d08a6 | 8 | #include "pico_stack.h" |
tass | 68:0847e35d08a6 | 9 | #include "pico_addressing.h" |
tass | 68:0847e35d08a6 | 10 | #include "pico_socket.h" |
tass | 68:0847e35d08a6 | 11 | #include "pico_ipv4.h" |
tass picotcp@tass.be | 149:5f4cb161cec3 | 12 | #include "pico_ipv6.h" |
tass | 68:0847e35d08a6 | 13 | #include "pico_dns_client.h" |
tass | 152:a3d286bf94e5 | 14 | #include "pico_dns_common.h" |
tass | 68:0847e35d08a6 | 15 | #include "pico_tree.h" |
tass | 68:0847e35d08a6 | 16 | |
tass | 68:0847e35d08a6 | 17 | #ifdef PICO_SUPPORT_DNS_CLIENT |
tass | 68:0847e35d08a6 | 18 | |
tass | 152:a3d286bf94e5 | 19 | #ifdef PICO_SUPPORT_IPV4 |
tass | 152:a3d286bf94e5 | 20 | |
TASS Belgium NV |
131:4758606c9316 | 21 | #define dns_dbg(...) do {} while(0) |
TASS Belgium NV |
131:4758606c9316 | 22 | /* #define dns_dbg dbg */ |
tass | 68:0847e35d08a6 | 23 | |
tass | 68:0847e35d08a6 | 24 | /* DNS response length */ |
tass | 152:a3d286bf94e5 | 25 | #define PICO_DNS_MAX_QUERY_LEN 255 |
tass | 152:a3d286bf94e5 | 26 | #define PICO_DNS_MAX_QUERY_LABEL_LEN 63 |
tass | 68:0847e35d08a6 | 27 | |
tass | 68:0847e35d08a6 | 28 | /* DNS client retransmission time (msec) + frequency */ |
tass | 68:0847e35d08a6 | 29 | #define PICO_DNS_CLIENT_RETRANS 4000 |
tass | 68:0847e35d08a6 | 30 | #define PICO_DNS_CLIENT_MAX_RETRANS 3 |
tass | 68:0847e35d08a6 | 31 | |
tass | 68:0847e35d08a6 | 32 | static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s); |
tass | 128:ae39e6e81531 | 33 | static void pico_dns_client_retransmission(pico_time now, void *arg); |
tass | 152:a3d286bf94e5 | 34 | static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg); |
tass | 68:0847e35d08a6 | 35 | |
tass | 68:0847e35d08a6 | 36 | struct pico_dns_ns |
tass | 68:0847e35d08a6 | 37 | { |
TASS Belgium NV |
131:4758606c9316 | 38 | struct pico_ip4 ns; /* nameserver */ |
tass | 68:0847e35d08a6 | 39 | }; |
tass | 68:0847e35d08a6 | 40 | |
tass | 68:0847e35d08a6 | 41 | static int dns_ns_cmp(void *ka, void *kb) |
tass | 68:0847e35d08a6 | 42 | { |
TASS Belgium NV |
131:4758606c9316 | 43 | struct pico_dns_ns *a = ka, *b = kb; |
tass | 152:a3d286bf94e5 | 44 | return pico_ipv4_compare(&a->ns, &b->ns); |
TASS Belgium NV |
131:4758606c9316 | 45 | } |
tass | 68:0847e35d08a6 | 46 | PICO_TREE_DECLARE(NSTable, dns_ns_cmp); |
TASS Belgium NV |
131:4758606c9316 | 47 | |
tass | 68:0847e35d08a6 | 48 | struct pico_dns_query |
tass | 68:0847e35d08a6 | 49 | { |
TASS Belgium NV |
131:4758606c9316 | 50 | char *query; |
TASS Belgium NV |
131:4758606c9316 | 51 | uint16_t len; |
TASS Belgium NV |
131:4758606c9316 | 52 | uint16_t id; |
TASS Belgium NV |
131:4758606c9316 | 53 | uint16_t qtype; |
TASS Belgium NV |
131:4758606c9316 | 54 | uint16_t qclass; |
TASS Belgium NV |
131:4758606c9316 | 55 | uint8_t retrans; |
TASS Belgium NV |
131:4758606c9316 | 56 | struct pico_dns_ns q_ns; |
TASS Belgium NV |
131:4758606c9316 | 57 | struct pico_socket *s; |
TASS Belgium NV |
131:4758606c9316 | 58 | void (*callback)(char *, void *); |
TASS Belgium NV |
131:4758606c9316 | 59 | void *arg; |
tass | 68:0847e35d08a6 | 60 | }; |
tass | 68:0847e35d08a6 | 61 | |
tass | 68:0847e35d08a6 | 62 | static int dns_query_cmp(void *ka, void *kb) |
tass | 68:0847e35d08a6 | 63 | { |
TASS Belgium NV |
131:4758606c9316 | 64 | struct pico_dns_query *a = ka, *b = kb; |
TASS Belgium NV |
131:4758606c9316 | 65 | if (a->id == b->id) |
TASS Belgium NV |
131:4758606c9316 | 66 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 67 | |
tass picotcp@tass.be | 149:5f4cb161cec3 | 68 | return (a->id < b->id) ? (-1) : (1); |
TASS Belgium NV |
131:4758606c9316 | 69 | } |
tass | 68:0847e35d08a6 | 70 | PICO_TREE_DECLARE(DNSTable, dns_query_cmp); |
tass | 68:0847e35d08a6 | 71 | |
tass | 68:0847e35d08a6 | 72 | static int pico_dns_client_del_ns(struct pico_ip4 *ns_addr) |
tass | 68:0847e35d08a6 | 73 | { |
TASS Belgium NV |
131:4758606c9316 | 74 | struct pico_dns_ns test = {{0}}, *found = NULL; |
tass | 68:0847e35d08a6 | 75 | |
TASS Belgium NV |
131:4758606c9316 | 76 | test.ns = *ns_addr; |
TASS Belgium NV |
131:4758606c9316 | 77 | found = pico_tree_findKey(&NSTable, &test); |
TASS Belgium NV |
131:4758606c9316 | 78 | if (!found) |
TASS Belgium NV |
131:4758606c9316 | 79 | return -1; |
tass | 68:0847e35d08a6 | 80 | |
TASS Belgium NV |
131:4758606c9316 | 81 | pico_tree_delete(&NSTable, found); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 82 | PICO_FREE(found); |
tass | 68:0847e35d08a6 | 83 | |
TASS Belgium NV |
131:4758606c9316 | 84 | /* no NS left, add default NS */ |
TASS Belgium NV |
131:4758606c9316 | 85 | if (pico_tree_empty(&NSTable)) |
TASS Belgium NV |
131:4758606c9316 | 86 | pico_dns_client_init(); |
tass | 68:0847e35d08a6 | 87 | |
TASS Belgium NV |
131:4758606c9316 | 88 | return 0; |
tass | 68:0847e35d08a6 | 89 | } |
tass | 68:0847e35d08a6 | 90 | |
tass | 68:0847e35d08a6 | 91 | static struct pico_dns_ns *pico_dns_client_add_ns(struct pico_ip4 *ns_addr) |
tass | 68:0847e35d08a6 | 92 | { |
TASS Belgium NV |
131:4758606c9316 | 93 | struct pico_dns_ns *dns = NULL, *found = NULL, test = {{0}}; |
TASS Belgium NV |
131:4758606c9316 | 94 | |
tass picotcp@tass.be | 149:5f4cb161cec3 | 95 | dns = PICO_ZALLOC(sizeof(struct pico_dns_ns)); |
TASS Belgium NV |
131:4758606c9316 | 96 | if (!dns) { |
TASS Belgium NV |
131:4758606c9316 | 97 | pico_err = PICO_ERR_ENOMEM; |
TASS Belgium NV |
131:4758606c9316 | 98 | return NULL; |
TASS Belgium NV |
131:4758606c9316 | 99 | } |
TASS Belgium NV |
131:4758606c9316 | 100 | |
TASS Belgium NV |
131:4758606c9316 | 101 | dns->ns = *ns_addr; |
tass | 68:0847e35d08a6 | 102 | |
TASS Belgium NV |
131:4758606c9316 | 103 | found = pico_tree_insert(&NSTable, dns); |
TASS Belgium NV |
131:4758606c9316 | 104 | if (found) { /* nameserver already present */ |
tass picotcp@tass.be | 149:5f4cb161cec3 | 105 | PICO_FREE(dns); |
TASS Belgium NV |
131:4758606c9316 | 106 | return found; |
TASS Belgium NV |
131:4758606c9316 | 107 | } |
tass | 68:0847e35d08a6 | 108 | |
TASS Belgium NV |
131:4758606c9316 | 109 | /* default NS found, remove it */ |
tass picotcp@tass.be | 149:5f4cb161cec3 | 110 | pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&test.ns.addr); |
TASS Belgium NV |
131:4758606c9316 | 111 | found = pico_tree_findKey(&NSTable, &test); |
TASS Belgium NV |
131:4758606c9316 | 112 | if (found && (found->ns.addr != ns_addr->addr)) |
TASS Belgium NV |
131:4758606c9316 | 113 | pico_dns_client_del_ns(&found->ns); |
tass | 68:0847e35d08a6 | 114 | |
TASS Belgium NV |
131:4758606c9316 | 115 | return dns; |
tass | 68:0847e35d08a6 | 116 | } |
tass | 68:0847e35d08a6 | 117 | |
tass | 68:0847e35d08a6 | 118 | static struct pico_dns_ns pico_dns_client_next_ns(struct pico_ip4 *ns_addr) |
tass | 68:0847e35d08a6 | 119 | { |
TASS Belgium NV |
131:4758606c9316 | 120 | struct pico_dns_ns dns = {{0}}, *nxtdns = NULL; |
TASS Belgium NV |
131:4758606c9316 | 121 | struct pico_tree_node *node = NULL, *nxtnode = NULL; |
tass | 68:0847e35d08a6 | 122 | |
TASS Belgium NV |
131:4758606c9316 | 123 | dns.ns = *ns_addr; |
TASS Belgium NV |
131:4758606c9316 | 124 | node = pico_tree_findNode(&NSTable, &dns); |
TASS Belgium NV |
131:4758606c9316 | 125 | if (!node) |
TASS Belgium NV |
131:4758606c9316 | 126 | return dns; /* keep using current NS */ |
tass | 68:0847e35d08a6 | 127 | |
TASS Belgium NV |
131:4758606c9316 | 128 | nxtnode = pico_tree_next(node); |
TASS Belgium NV |
131:4758606c9316 | 129 | nxtdns = nxtnode->keyValue; |
TASS Belgium NV |
131:4758606c9316 | 130 | if (!nxtdns) |
TASS Belgium NV |
131:4758606c9316 | 131 | nxtdns = (struct pico_dns_ns *)pico_tree_first(&NSTable); |
TASS Belgium NV |
131:4758606c9316 | 132 | |
TASS Belgium NV |
131:4758606c9316 | 133 | return *nxtdns; |
tass | 68:0847e35d08a6 | 134 | } |
tass | 68:0847e35d08a6 | 135 | |
tass | 152:a3d286bf94e5 | 136 | static struct pico_dns_query *pico_dns_client_add_query(struct pico_dns_header *hdr, uint16_t len, struct pico_dns_question_suffix *suffix, |
tass | 68:0847e35d08a6 | 137 | void (*callback)(char *, void *), void *arg) |
tass | 68:0847e35d08a6 | 138 | { |
TASS Belgium NV |
131:4758606c9316 | 139 | struct pico_dns_query *q = NULL, *found = NULL; |
tass | 68:0847e35d08a6 | 140 | |
tass picotcp@tass.be | 149:5f4cb161cec3 | 141 | q = PICO_ZALLOC(sizeof(struct pico_dns_query)); |
TASS Belgium NV |
131:4758606c9316 | 142 | if (!q) |
TASS Belgium NV |
131:4758606c9316 | 143 | return NULL; |
tass | 68:0847e35d08a6 | 144 | |
TASS Belgium NV |
131:4758606c9316 | 145 | q->query = (char *)hdr; |
TASS Belgium NV |
131:4758606c9316 | 146 | q->len = len; |
TASS Belgium NV |
131:4758606c9316 | 147 | q->id = short_be(hdr->id); |
TASS Belgium NV |
131:4758606c9316 | 148 | q->qtype = short_be(suffix->qtype); |
TASS Belgium NV |
131:4758606c9316 | 149 | q->qclass = short_be(suffix->qclass); |
TASS Belgium NV |
131:4758606c9316 | 150 | q->retrans = 1; |
TASS Belgium NV |
131:4758606c9316 | 151 | q->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable)); |
TASS Belgium NV |
131:4758606c9316 | 152 | q->callback = callback; |
TASS Belgium NV |
131:4758606c9316 | 153 | q->arg = arg; |
TASS Belgium NV |
131:4758606c9316 | 154 | q->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback); |
TASS Belgium NV |
131:4758606c9316 | 155 | if (!q->s) { |
tass picotcp@tass.be | 149:5f4cb161cec3 | 156 | PICO_FREE(q); |
TASS Belgium NV |
131:4758606c9316 | 157 | return NULL; |
TASS Belgium NV |
131:4758606c9316 | 158 | } |
tass | 68:0847e35d08a6 | 159 | |
TASS Belgium NV |
131:4758606c9316 | 160 | found = pico_tree_insert(&DNSTable, q); |
TASS Belgium NV |
131:4758606c9316 | 161 | if (found) { |
TASS Belgium NV |
131:4758606c9316 | 162 | pico_err = PICO_ERR_EAGAIN; |
TASS Belgium NV |
131:4758606c9316 | 163 | pico_socket_close(q->s); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 164 | PICO_FREE(q); |
TASS Belgium NV |
131:4758606c9316 | 165 | return NULL; |
TASS Belgium NV |
131:4758606c9316 | 166 | } |
tass | 68:0847e35d08a6 | 167 | |
TASS Belgium NV |
131:4758606c9316 | 168 | return q; |
tass | 68:0847e35d08a6 | 169 | } |
tass | 68:0847e35d08a6 | 170 | |
tass | 68:0847e35d08a6 | 171 | static int pico_dns_client_del_query(uint16_t id) |
tass | 68:0847e35d08a6 | 172 | { |
TASS Belgium NV |
131:4758606c9316 | 173 | struct pico_dns_query test = { |
TASS Belgium NV |
131:4758606c9316 | 174 | 0 |
TASS Belgium NV |
131:4758606c9316 | 175 | }, *found = NULL; |
tass | 68:0847e35d08a6 | 176 | |
TASS Belgium NV |
131:4758606c9316 | 177 | test.id = id; |
TASS Belgium NV |
131:4758606c9316 | 178 | found = pico_tree_findKey(&DNSTable, &test); |
TASS Belgium NV |
131:4758606c9316 | 179 | if (!found) |
TASS Belgium NV |
131:4758606c9316 | 180 | return -1; |
tass | 68:0847e35d08a6 | 181 | |
tass picotcp@tass.be | 149:5f4cb161cec3 | 182 | PICO_FREE(found->query); |
TASS Belgium NV |
131:4758606c9316 | 183 | pico_socket_close(found->s); |
TASS Belgium NV |
131:4758606c9316 | 184 | pico_tree_delete(&DNSTable, found); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 185 | PICO_FREE(found); |
TASS Belgium NV |
131:4758606c9316 | 186 | return 0; |
tass | 68:0847e35d08a6 | 187 | } |
tass | 68:0847e35d08a6 | 188 | |
tass | 68:0847e35d08a6 | 189 | static struct pico_dns_query *pico_dns_client_find_query(uint16_t id) |
tass | 68:0847e35d08a6 | 190 | { |
TASS Belgium NV |
131:4758606c9316 | 191 | struct pico_dns_query test = { |
TASS Belgium NV |
131:4758606c9316 | 192 | 0 |
TASS Belgium NV |
131:4758606c9316 | 193 | }, *found = NULL; |
tass | 68:0847e35d08a6 | 194 | |
TASS Belgium NV |
131:4758606c9316 | 195 | test.id = id; |
TASS Belgium NV |
131:4758606c9316 | 196 | found = pico_tree_findKey(&DNSTable, &test); |
TASS Belgium NV |
131:4758606c9316 | 197 | if (found) |
TASS Belgium NV |
131:4758606c9316 | 198 | return found; |
TASS Belgium NV |
131:4758606c9316 | 199 | else |
TASS Belgium NV |
131:4758606c9316 | 200 | return NULL; |
tass | 68:0847e35d08a6 | 201 | } |
tass | 68:0847e35d08a6 | 202 | |
tass | 68:0847e35d08a6 | 203 | /* seek end of string */ |
tass | 68:0847e35d08a6 | 204 | static char *pico_dns_client_seek(char *ptr) |
tass | 68:0847e35d08a6 | 205 | { |
TASS Belgium NV |
131:4758606c9316 | 206 | if (!ptr) |
TASS Belgium NV |
131:4758606c9316 | 207 | return NULL; |
tass | 68:0847e35d08a6 | 208 | |
tass picotcp@tass.be | 134:cc4e6d2654d9 | 209 | while (*ptr != 0) |
tass picotcp@tass.be | 134:cc4e6d2654d9 | 210 | ptr++; |
tass picotcp@tass.be | 136:576dcbb16922 | 211 | return ptr + 1; |
tass | 68:0847e35d08a6 | 212 | } |
tass | 68:0847e35d08a6 | 213 | |
tass | 68:0847e35d08a6 | 214 | static struct pico_dns_query *pico_dns_client_idcheck(uint16_t id) |
tass | 68:0847e35d08a6 | 215 | { |
TASS Belgium NV |
131:4758606c9316 | 216 | struct pico_dns_query test = { |
TASS Belgium NV |
131:4758606c9316 | 217 | 0 |
TASS Belgium NV |
131:4758606c9316 | 218 | }; |
tass | 68:0847e35d08a6 | 219 | |
TASS Belgium NV |
131:4758606c9316 | 220 | test.id = id; |
TASS Belgium NV |
131:4758606c9316 | 221 | return pico_tree_findKey(&DNSTable, &test); |
tass | 68:0847e35d08a6 | 222 | } |
tass | 68:0847e35d08a6 | 223 | |
tass | 152:a3d286bf94e5 | 224 | static int pico_dns_client_query_header(struct pico_dns_header *hdr) |
tass | 68:0847e35d08a6 | 225 | { |
TASS Belgium NV |
131:4758606c9316 | 226 | uint16_t id = 0; |
TASS Belgium NV |
131:4758606c9316 | 227 | uint8_t retry = 32; |
tass | 68:0847e35d08a6 | 228 | |
TASS Belgium NV |
131:4758606c9316 | 229 | do { |
TASS Belgium NV |
131:4758606c9316 | 230 | id = (uint16_t)(pico_rand() & 0xFFFFU); |
TASS Belgium NV |
131:4758606c9316 | 231 | dns_dbg("DNS: generated id %u\n", id); |
TASS Belgium NV |
131:4758606c9316 | 232 | } while (retry-- && pico_dns_client_idcheck(id)); |
TASS Belgium NV |
131:4758606c9316 | 233 | if (!retry) |
TASS Belgium NV |
131:4758606c9316 | 234 | return -1; |
tass | 68:0847e35d08a6 | 235 | |
tass | 152:a3d286bf94e5 | 236 | hdr->id = short_be(id); |
tass | 152:a3d286bf94e5 | 237 | pico_dns_fill_packet_header(hdr, 1, 0, 0, 0); /* 1 question, 0 answers */ |
tass | 68:0847e35d08a6 | 238 | |
TASS Belgium NV |
131:4758606c9316 | 239 | return 0; |
tass | 68:0847e35d08a6 | 240 | } |
tass | 68:0847e35d08a6 | 241 | |
tass | 152:a3d286bf94e5 | 242 | static int pico_dns_client_check_header(struct pico_dns_header *pre) |
tass | 68:0847e35d08a6 | 243 | { |
TASS Belgium NV |
131:4758606c9316 | 244 | if (pre->qr != PICO_DNS_QR_RESPONSE || pre->opcode != PICO_DNS_OPCODE_QUERY || pre->rcode != PICO_DNS_RCODE_NO_ERROR) { |
TASS Belgium NV |
131:4758606c9316 | 245 | dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", pre->opcode, pre->tc, pre->rcode); |
TASS Belgium NV |
131:4758606c9316 | 246 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 247 | } |
TASS Belgium NV |
131:4758606c9316 | 248 | |
TASS Belgium NV |
131:4758606c9316 | 249 | if (short_be(pre->ancount) < 1) { |
TASS Belgium NV |
131:4758606c9316 | 250 | dns_dbg("DNS ERROR: ancount < 1\n"); |
TASS Belgium NV |
131:4758606c9316 | 251 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 252 | } |
TASS Belgium NV |
131:4758606c9316 | 253 | |
TASS Belgium NV |
131:4758606c9316 | 254 | return 0; |
tass | 68:0847e35d08a6 | 255 | } |
tass | 68:0847e35d08a6 | 256 | |
tass | 152:a3d286bf94e5 | 257 | static int pico_dns_client_check_qsuffix(struct pico_dns_question_suffix *suf, struct pico_dns_query *q) |
tass | 68:0847e35d08a6 | 258 | { |
tass | 152:a3d286bf94e5 | 259 | if (!suf) |
tass | 152:a3d286bf94e5 | 260 | return -1; |
tass | 152:a3d286bf94e5 | 261 | |
TASS Belgium NV |
131:4758606c9316 | 262 | if (short_be(suf->qtype) != q->qtype || short_be(suf->qclass) != q->qclass) { |
TASS Belgium NV |
131:4758606c9316 | 263 | dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->qtype), short_be(suf->qclass)); |
TASS Belgium NV |
131:4758606c9316 | 264 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 265 | } |
TASS Belgium NV |
131:4758606c9316 | 266 | |
TASS Belgium NV |
131:4758606c9316 | 267 | return 0; |
tass | 68:0847e35d08a6 | 268 | } |
tass | 68:0847e35d08a6 | 269 | |
tass | 152:a3d286bf94e5 | 270 | static int pico_dns_client_check_url(struct pico_dns_header *resp, struct pico_dns_query *q) |
tass | 152:a3d286bf94e5 | 271 | { |
tass | 152:a3d286bf94e5 | 272 | char *recv_name = (char*)(resp) + sizeof(struct pico_dns_header) + PICO_DNS_LABEL_INITIAL; |
tass | 152:a3d286bf94e5 | 273 | char *exp_name = (char *)(q->query) + sizeof(struct pico_dns_header) + PICO_DNS_LABEL_INITIAL; |
tass | 152:a3d286bf94e5 | 274 | if (strcasecmp(recv_name, exp_name) != 0) |
tass | 152:a3d286bf94e5 | 275 | return -1; |
tass | 152:a3d286bf94e5 | 276 | |
tass | 152:a3d286bf94e5 | 277 | return 0; |
tass | 152:a3d286bf94e5 | 278 | } |
tass | 152:a3d286bf94e5 | 279 | |
tass | 152:a3d286bf94e5 | 280 | static int pico_dns_client_check_asuffix(struct pico_dns_record_suffix *suf, struct pico_dns_query *q) |
tass | 68:0847e35d08a6 | 281 | { |
tass picotcp@tass.be | 149:5f4cb161cec3 | 282 | if (!suf) { |
tass picotcp@tass.be | 149:5f4cb161cec3 | 283 | pico_err = PICO_ERR_EINVAL; |
tass picotcp@tass.be | 149:5f4cb161cec3 | 284 | return -1; |
tass picotcp@tass.be | 149:5f4cb161cec3 | 285 | } |
tass picotcp@tass.be | 149:5f4cb161cec3 | 286 | |
tass | 152:a3d286bf94e5 | 287 | if (short_be(suf->rtype) != q->qtype || short_be(suf->rclass) != q->qclass) { |
tass | 152:a3d286bf94e5 | 288 | dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->rtype), short_be(suf->rclass)); |
TASS Belgium NV |
131:4758606c9316 | 289 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 290 | } |
TASS Belgium NV |
131:4758606c9316 | 291 | |
tass | 152:a3d286bf94e5 | 292 | if (long_be(suf->rttl) > PICO_DNS_MAX_TTL) { |
tass | 152:a3d286bf94e5 | 293 | dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(suf->rttl), PICO_DNS_MAX_TTL); |
TASS Belgium NV |
131:4758606c9316 | 294 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 295 | } |
TASS Belgium NV |
131:4758606c9316 | 296 | |
TASS Belgium NV |
131:4758606c9316 | 297 | return 0; |
tass | 68:0847e35d08a6 | 298 | } |
tass | 68:0847e35d08a6 | 299 | |
tass | 152:a3d286bf94e5 | 300 | static char *pico_dns_client_seek_suffix(char *suf, struct pico_dns_header *pre, struct pico_dns_query *q) |
tass | 68:0847e35d08a6 | 301 | { |
tass | 152:a3d286bf94e5 | 302 | struct pico_dns_record_suffix *asuffix = NULL; |
TASS Belgium NV |
131:4758606c9316 | 303 | uint16_t comp = 0, compression = 0; |
TASS Belgium NV |
131:4758606c9316 | 304 | uint16_t i = 0; |
tass | 152:a3d286bf94e5 | 305 | |
tass picotcp@tass.be | 149:5f4cb161cec3 | 306 | if (!suf) |
tass picotcp@tass.be | 149:5f4cb161cec3 | 307 | return NULL; |
tass | 68:0847e35d08a6 | 308 | |
TASS Belgium NV |
131:4758606c9316 | 309 | while (i++ < short_be(pre->ancount)) { |
tass | 152:a3d286bf94e5 | 310 | comp = short_from(suf); |
TASS Belgium NV |
131:4758606c9316 | 311 | compression = short_be(comp); |
TASS Belgium NV |
131:4758606c9316 | 312 | switch (compression >> 14) |
TASS Belgium NV |
131:4758606c9316 | 313 | { |
TASS Belgium NV |
131:4758606c9316 | 314 | case PICO_DNS_POINTER: |
TASS Belgium NV |
131:4758606c9316 | 315 | while (compression >> 14 == PICO_DNS_POINTER) { |
TASS Belgium NV |
131:4758606c9316 | 316 | dns_dbg("DNS: pointer\n"); |
tass | 152:a3d286bf94e5 | 317 | suf += sizeof(uint16_t); |
tass | 152:a3d286bf94e5 | 318 | comp = short_from(suf); |
TASS Belgium NV |
131:4758606c9316 | 319 | compression = short_be(comp); |
TASS Belgium NV |
131:4758606c9316 | 320 | } |
TASS Belgium NV |
131:4758606c9316 | 321 | break; |
tass | 68:0847e35d08a6 | 322 | |
TASS Belgium NV |
131:4758606c9316 | 323 | case PICO_DNS_LABEL: |
TASS Belgium NV |
131:4758606c9316 | 324 | dns_dbg("DNS: label\n"); |
tass | 152:a3d286bf94e5 | 325 | suf = pico_dns_client_seek(suf); |
TASS Belgium NV |
131:4758606c9316 | 326 | break; |
tass | 68:0847e35d08a6 | 327 | |
TASS Belgium NV |
131:4758606c9316 | 328 | default: |
TASS Belgium NV |
131:4758606c9316 | 329 | dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression); |
TASS Belgium NV |
131:4758606c9316 | 330 | return NULL; |
TASS Belgium NV |
131:4758606c9316 | 331 | } |
TASS Belgium NV |
131:4758606c9316 | 332 | |
tass | 152:a3d286bf94e5 | 333 | asuffix = (struct pico_dns_record_suffix *)suf; |
tass picotcp@tass.be | 149:5f4cb161cec3 | 334 | if (!asuffix) |
tass picotcp@tass.be | 149:5f4cb161cec3 | 335 | break; |
tass picotcp@tass.be | 149:5f4cb161cec3 | 336 | |
TASS Belgium NV |
131:4758606c9316 | 337 | if (pico_dns_client_check_asuffix(asuffix, q) < 0) { |
tass | 152:a3d286bf94e5 | 338 | suf += (sizeof(struct pico_dns_record_suffix) + short_be(asuffix->rdlength)); |
TASS Belgium NV |
131:4758606c9316 | 339 | continue; |
TASS Belgium NV |
131:4758606c9316 | 340 | } |
TASS Belgium NV |
131:4758606c9316 | 341 | |
tass | 152:a3d286bf94e5 | 342 | return suf; |
tass | 68:0847e35d08a6 | 343 | } |
TASS Belgium NV |
131:4758606c9316 | 344 | return NULL; |
tass | 68:0847e35d08a6 | 345 | } |
tass | 68:0847e35d08a6 | 346 | |
tass | 68:0847e35d08a6 | 347 | static int pico_dns_client_send(struct pico_dns_query *q) |
tass | 68:0847e35d08a6 | 348 | { |
tass picotcp@tass.be | 149:5f4cb161cec3 | 349 | uint16_t *paramID = PICO_ZALLOC(sizeof(uint16_t)); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 350 | if (!paramID) { |
tass picotcp@tass.be | 149:5f4cb161cec3 | 351 | pico_err = PICO_ERR_ENOMEM; |
tass picotcp@tass.be | 149:5f4cb161cec3 | 352 | return -1; |
tass picotcp@tass.be | 149:5f4cb161cec3 | 353 | } |
tass picotcp@tass.be | 149:5f4cb161cec3 | 354 | |
TASS Belgium NV |
131:4758606c9316 | 355 | dns_dbg("DNS: sending query to %08X\n", q->q_ns.ns.addr); |
TASS Belgium NV |
131:4758606c9316 | 356 | if (!q->s) |
TASS Belgium NV |
131:4758606c9316 | 357 | goto failure; |
tass | 68:0847e35d08a6 | 358 | |
TASS Belgium NV |
131:4758606c9316 | 359 | if (pico_socket_connect(q->s, &q->q_ns.ns, short_be(PICO_DNS_NS_PORT)) < 0) |
TASS Belgium NV |
131:4758606c9316 | 360 | goto failure; |
tass | 68:0847e35d08a6 | 361 | |
TASS Belgium NV |
131:4758606c9316 | 362 | pico_socket_send(q->s, q->query, q->len); |
TASS Belgium NV |
131:4758606c9316 | 363 | *paramID = q->id; |
TASS Belgium NV |
131:4758606c9316 | 364 | pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, paramID); |
TASS Belgium NV |
131:4758606c9316 | 365 | |
TASS Belgium NV |
131:4758606c9316 | 366 | return 0; |
tass | 74:c146c4e346c4 | 367 | |
tass | 74:c146c4e346c4 | 368 | failure: |
tass picotcp@tass.be | 149:5f4cb161cec3 | 369 | PICO_FREE(paramID); |
TASS Belgium NV |
131:4758606c9316 | 370 | return -1; |
tass | 68:0847e35d08a6 | 371 | } |
tass | 68:0847e35d08a6 | 372 | |
tass | 128:ae39e6e81531 | 373 | static void pico_dns_client_retransmission(pico_time now, void *arg) |
tass | 68:0847e35d08a6 | 374 | { |
TASS Belgium NV |
131:4758606c9316 | 375 | struct pico_dns_query *q = NULL; |
TASS Belgium NV |
131:4758606c9316 | 376 | struct pico_dns_query dummy; |
TASS Belgium NV |
131:4758606c9316 | 377 | IGNORE_PARAMETER(now); |
tass | 68:0847e35d08a6 | 378 | |
TASS Belgium NV |
131:4758606c9316 | 379 | if(!arg) |
TASS Belgium NV |
131:4758606c9316 | 380 | return; |
TASS Belgium NV |
131:4758606c9316 | 381 | |
TASS Belgium NV |
131:4758606c9316 | 382 | /* search for the dns query and free used space */ |
TASS Belgium NV |
131:4758606c9316 | 383 | dummy.id = *(uint16_t *)arg; |
TASS Belgium NV |
131:4758606c9316 | 384 | q = (struct pico_dns_query *)pico_tree_findKey(&DNSTable, &dummy); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 385 | PICO_FREE(arg); |
tass | 68:0847e35d08a6 | 386 | |
TASS Belgium NV |
131:4758606c9316 | 387 | /* dns query successful? */ |
TASS Belgium NV |
131:4758606c9316 | 388 | if (!q) { |
TASS Belgium NV |
131:4758606c9316 | 389 | return; |
TASS Belgium NV |
131:4758606c9316 | 390 | } |
tass | 68:0847e35d08a6 | 391 | |
tass | 152:a3d286bf94e5 | 392 | q->retrans++; |
tass | 152:a3d286bf94e5 | 393 | if (q->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) { |
TASS Belgium NV |
131:4758606c9316 | 394 | q->q_ns = pico_dns_client_next_ns(&q->q_ns.ns); |
TASS Belgium NV |
131:4758606c9316 | 395 | pico_dns_client_send(q); |
TASS Belgium NV |
131:4758606c9316 | 396 | } else { |
TASS Belgium NV |
131:4758606c9316 | 397 | pico_err = PICO_ERR_EIO; |
TASS Belgium NV |
131:4758606c9316 | 398 | q->callback(NULL, q->arg); |
TASS Belgium NV |
131:4758606c9316 | 399 | pico_dns_client_del_query(q->id); |
TASS Belgium NV |
131:4758606c9316 | 400 | } |
tass | 68:0847e35d08a6 | 401 | } |
tass | 68:0847e35d08a6 | 402 | |
tass | 152:a3d286bf94e5 | 403 | static int pico_dns_client_user_callback(struct pico_dns_record_suffix *asuffix, struct pico_dns_query *q) |
tass | 68:0847e35d08a6 | 404 | { |
TASS Belgium NV |
131:4758606c9316 | 405 | uint32_t ip = 0; |
TASS Belgium NV |
131:4758606c9316 | 406 | char *str = NULL; |
tass | 152:a3d286bf94e5 | 407 | char *rdata = (char *) asuffix + sizeof(struct pico_dns_record_suffix); |
TASS Belgium NV |
131:4758606c9316 | 408 | |
TASS Belgium NV |
131:4758606c9316 | 409 | switch (q->qtype) |
TASS Belgium NV |
131:4758606c9316 | 410 | { |
tass | 68:0847e35d08a6 | 411 | case PICO_DNS_TYPE_A: |
tass | 152:a3d286bf94e5 | 412 | ip = long_from(rdata); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 413 | str = PICO_ZALLOC(PICO_DNS_IPV4_ADDR_LEN); |
TASS Belgium NV |
131:4758606c9316 | 414 | pico_ipv4_to_string(str, ip); |
TASS Belgium NV |
131:4758606c9316 | 415 | break; |
tass picotcp@tass.be | 149:5f4cb161cec3 | 416 | #ifdef PICO_SUPPORT_IPV6 |
tass picotcp@tass.be | 149:5f4cb161cec3 | 417 | case PICO_DNS_TYPE_AAAA: |
tass picotcp@tass.be | 149:5f4cb161cec3 | 418 | { |
tass picotcp@tass.be | 149:5f4cb161cec3 | 419 | struct pico_ip6 ip6; |
tass | 152:a3d286bf94e5 | 420 | memcpy(&ip6.addr, rdata, sizeof(struct pico_ip6)); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 421 | str = PICO_ZALLOC(PICO_DNS_IPV6_ADDR_LEN); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 422 | pico_ipv6_to_string(str, ip6.addr); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 423 | break; |
tass picotcp@tass.be | 149:5f4cb161cec3 | 424 | } |
tass picotcp@tass.be | 149:5f4cb161cec3 | 425 | #endif |
tass | 68:0847e35d08a6 | 426 | case PICO_DNS_TYPE_PTR: |
tass | 152:a3d286bf94e5 | 427 | /* TODO: check for decompression / rdlength vs. decompressed length */ |
tass | 152:a3d286bf94e5 | 428 | pico_dns_notation_to_name(rdata, short_be(asuffix->rdlength)); |
tass | 152:a3d286bf94e5 | 429 | str = PICO_ZALLOC((size_t)(short_be(asuffix->rdlength) - |
tass | 152:a3d286bf94e5 | 430 | PICO_DNS_LABEL_INITIAL)); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 431 | if (!str) { |
tass picotcp@tass.be | 149:5f4cb161cec3 | 432 | pico_err = PICO_ERR_ENOMEM; |
tass picotcp@tass.be | 149:5f4cb161cec3 | 433 | return -1; |
tass picotcp@tass.be | 149:5f4cb161cec3 | 434 | } |
tass picotcp@tass.be | 149:5f4cb161cec3 | 435 | |
tass | 152:a3d286bf94e5 | 436 | memcpy(str, rdata + PICO_DNS_LABEL_INITIAL, short_be(asuffix->rdlength) - PICO_DNS_LABEL_INITIAL); |
TASS Belgium NV |
131:4758606c9316 | 437 | break; |
tass | 68:0847e35d08a6 | 438 | |
tass | 68:0847e35d08a6 | 439 | default: |
TASS Belgium NV |
131:4758606c9316 | 440 | dns_dbg("DNS ERROR: incorrect qtype (%u)\n", q->qtype); |
TASS Belgium NV |
131:4758606c9316 | 441 | break; |
TASS Belgium NV |
131:4758606c9316 | 442 | } |
tass | 68:0847e35d08a6 | 443 | |
TASS Belgium NV |
131:4758606c9316 | 444 | if (q->retrans) { |
TASS Belgium NV |
131:4758606c9316 | 445 | q->callback(str, q->arg); |
TASS Belgium NV |
131:4758606c9316 | 446 | q->retrans = 0; |
TASS Belgium NV |
131:4758606c9316 | 447 | pico_dns_client_del_query(q->id); |
TASS Belgium NV |
131:4758606c9316 | 448 | } |
TASS Belgium NV |
131:4758606c9316 | 449 | |
tass | 152:a3d286bf94e5 | 450 | if (str) |
tass | 152:a3d286bf94e5 | 451 | PICO_FREE(str); |
tass | 152:a3d286bf94e5 | 452 | |
TASS Belgium NV |
131:4758606c9316 | 453 | return 0; |
tass | 68:0847e35d08a6 | 454 | } |
tass | 68:0847e35d08a6 | 455 | |
tass | 152:a3d286bf94e5 | 456 | static char dns_response[PICO_IP_MRU] = { |
tass | 152:a3d286bf94e5 | 457 | 0 |
tass | 152:a3d286bf94e5 | 458 | }; |
tass | 152:a3d286bf94e5 | 459 | |
tass | 152:a3d286bf94e5 | 460 | static void pico_dns_try_fallback_cname(struct pico_dns_query *q, struct pico_dns_header *h, struct pico_dns_question_suffix *qsuffix) |
tass | 152:a3d286bf94e5 | 461 | { |
tass | 152:a3d286bf94e5 | 462 | uint16_t type = q->qtype; |
tass | 152:a3d286bf94e5 | 463 | uint16_t proto = PICO_PROTO_IPV4; |
tass | 152:a3d286bf94e5 | 464 | struct pico_dns_record_suffix *asuffix = NULL; |
tass | 152:a3d286bf94e5 | 465 | char *p_asuffix = NULL; |
tass | 152:a3d286bf94e5 | 466 | char *cname_orig = NULL; |
tass | 152:a3d286bf94e5 | 467 | char *cname = NULL; |
tass | 152:a3d286bf94e5 | 468 | uint16_t cname_len; |
tass | 152:a3d286bf94e5 | 469 | |
tass | 152:a3d286bf94e5 | 470 | /* Try to use CNAME only if A or AAAA query is ongoing */ |
tass | 152:a3d286bf94e5 | 471 | if (type != PICO_DNS_TYPE_A && type != PICO_DNS_TYPE_AAAA) |
tass | 152:a3d286bf94e5 | 472 | return; |
tass | 152:a3d286bf94e5 | 473 | |
tass | 152:a3d286bf94e5 | 474 | if (type == PICO_DNS_TYPE_AAAA) |
tass | 152:a3d286bf94e5 | 475 | proto = PICO_PROTO_IPV6; |
tass | 152:a3d286bf94e5 | 476 | |
tass | 152:a3d286bf94e5 | 477 | q->qtype = PICO_DNS_TYPE_CNAME; |
tass | 152:a3d286bf94e5 | 478 | p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix); |
tass | 152:a3d286bf94e5 | 479 | p_asuffix = pico_dns_client_seek_suffix(p_asuffix, h, q); |
tass | 152:a3d286bf94e5 | 480 | if (!p_asuffix) { |
tass | 152:a3d286bf94e5 | 481 | return; |
tass | 152:a3d286bf94e5 | 482 | } |
tass | 152:a3d286bf94e5 | 483 | |
tass | 152:a3d286bf94e5 | 484 | /* Found CNAME response. Re-initiating query. */ |
tass | 152:a3d286bf94e5 | 485 | asuffix = (struct pico_dns_record_suffix *)p_asuffix; |
tass | 152:a3d286bf94e5 | 486 | cname = pico_dns_decompress_name((char *)asuffix + sizeof(struct pico_dns_record_suffix), (pico_dns_packet *)h); /* allocates memory! */ |
tass | 152:a3d286bf94e5 | 487 | cname_orig = cname; /* to free later */ |
tass | 152:a3d286bf94e5 | 488 | |
tass | 152:a3d286bf94e5 | 489 | if (cname == NULL) |
tass | 152:a3d286bf94e5 | 490 | return; |
tass | 152:a3d286bf94e5 | 491 | |
tass | 152:a3d286bf94e5 | 492 | cname_len = (uint16_t)(pico_dns_strlen(cname) + 1); |
tass | 152:a3d286bf94e5 | 493 | |
tass | 152:a3d286bf94e5 | 494 | pico_dns_notation_to_name(cname, cname_len); |
tass | 152:a3d286bf94e5 | 495 | if (cname[0] == '.') |
tass | 152:a3d286bf94e5 | 496 | cname++; |
tass | 152:a3d286bf94e5 | 497 | |
tass | 152:a3d286bf94e5 | 498 | dns_dbg("Restarting query for name '%s'\n", cname); |
tass | 152:a3d286bf94e5 | 499 | pico_dns_client_getaddr_init(cname, proto, q->callback, q->arg); |
tass | 152:a3d286bf94e5 | 500 | PICO_FREE(cname_orig); |
tass | 152:a3d286bf94e5 | 501 | pico_dns_client_del_query(q->id); |
tass | 152:a3d286bf94e5 | 502 | } |
tass | 152:a3d286bf94e5 | 503 | |
tass | 68:0847e35d08a6 | 504 | static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s) |
tass | 68:0847e35d08a6 | 505 | { |
tass | 152:a3d286bf94e5 | 506 | struct pico_dns_header *header = NULL; |
tass | 152:a3d286bf94e5 | 507 | char *domain; |
tass | 152:a3d286bf94e5 | 508 | struct pico_dns_question_suffix *qsuffix = NULL; |
tass | 152:a3d286bf94e5 | 509 | struct pico_dns_record_suffix *asuffix = NULL; |
TASS Belgium NV |
131:4758606c9316 | 510 | struct pico_dns_query *q = NULL; |
TASS Belgium NV |
131:4758606c9316 | 511 | char *p_asuffix = NULL; |
tass | 68:0847e35d08a6 | 512 | |
TASS Belgium NV |
131:4758606c9316 | 513 | if (ev == PICO_SOCK_EV_ERR) { |
TASS Belgium NV |
131:4758606c9316 | 514 | dns_dbg("DNS: socket error received\n"); |
TASS Belgium NV |
131:4758606c9316 | 515 | return; |
TASS Belgium NV |
131:4758606c9316 | 516 | } |
tass | 68:0847e35d08a6 | 517 | |
TASS Belgium NV |
131:4758606c9316 | 518 | if (ev & PICO_SOCK_EV_RD) { |
tass | 152:a3d286bf94e5 | 519 | if (pico_socket_read(s, dns_response, PICO_IP_MRU) < 0) |
TASS Belgium NV |
131:4758606c9316 | 520 | return; |
TASS Belgium NV |
131:4758606c9316 | 521 | } |
tass | 68:0847e35d08a6 | 522 | |
tass | 152:a3d286bf94e5 | 523 | header = (struct pico_dns_header *)dns_response; |
tass | 152:a3d286bf94e5 | 524 | domain = (char *)header + sizeof(struct pico_dns_header); |
tass | 152:a3d286bf94e5 | 525 | qsuffix = (struct pico_dns_question_suffix *)pico_dns_client_seek(domain); |
TASS Belgium NV |
131:4758606c9316 | 526 | /* valid asuffix is determined dynamically later on */ |
TASS Belgium NV |
131:4758606c9316 | 527 | |
tass | 152:a3d286bf94e5 | 528 | if (pico_dns_client_check_header(header) < 0) |
TASS Belgium NV |
131:4758606c9316 | 529 | return; |
TASS Belgium NV |
131:4758606c9316 | 530 | |
tass | 152:a3d286bf94e5 | 531 | q = pico_dns_client_find_query(short_be(header->id)); |
TASS Belgium NV |
131:4758606c9316 | 532 | if (!q) |
TASS Belgium NV |
131:4758606c9316 | 533 | return; |
tass | 68:0847e35d08a6 | 534 | |
TASS Belgium NV |
131:4758606c9316 | 535 | if (pico_dns_client_check_qsuffix(qsuffix, q) < 0) |
TASS Belgium NV |
131:4758606c9316 | 536 | return; |
TASS Belgium NV |
131:4758606c9316 | 537 | |
tass | 152:a3d286bf94e5 | 538 | if (pico_dns_client_check_url(header, q) < 0) |
TASS Belgium NV |
131:4758606c9316 | 539 | return; |
TASS Belgium NV |
131:4758606c9316 | 540 | |
tass | 152:a3d286bf94e5 | 541 | p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix); |
tass | 152:a3d286bf94e5 | 542 | p_asuffix = pico_dns_client_seek_suffix(p_asuffix, header, q); |
tass | 152:a3d286bf94e5 | 543 | if (!p_asuffix) { |
tass | 152:a3d286bf94e5 | 544 | pico_dns_try_fallback_cname(q, header, qsuffix); |
tass | 152:a3d286bf94e5 | 545 | return; |
tass | 152:a3d286bf94e5 | 546 | } |
tass | 152:a3d286bf94e5 | 547 | |
tass | 152:a3d286bf94e5 | 548 | asuffix = (struct pico_dns_record_suffix *)p_asuffix; |
TASS Belgium NV |
131:4758606c9316 | 549 | pico_dns_client_user_callback(asuffix, q); |
TASS Belgium NV |
131:4758606c9316 | 550 | |
tass | 68:0847e35d08a6 | 551 | return; |
tass | 68:0847e35d08a6 | 552 | } |
tass | 68:0847e35d08a6 | 553 | |
tass | 152:a3d286bf94e5 | 554 | static int pico_dns_create_message(struct pico_dns_header **header, struct pico_dns_question_suffix **qsuffix, enum pico_dns_arpa arpa, const char *url, uint16_t *urlen, uint16_t *hdrlen) |
tass | 68:0847e35d08a6 | 555 | { |
tass | 152:a3d286bf94e5 | 556 | char *domain; |
tass | 152:a3d286bf94e5 | 557 | char inaddr_arpa[14]; |
tass | 152:a3d286bf94e5 | 558 | uint16_t strlen = 0, arpalen = 0; |
tass | 152:a3d286bf94e5 | 559 | |
tass | 152:a3d286bf94e5 | 560 | if (!url) { |
tass | 152:a3d286bf94e5 | 561 | pico_err = PICO_ERR_EINVAL; |
tass | 152:a3d286bf94e5 | 562 | return -1; |
tass | 152:a3d286bf94e5 | 563 | } |
tass | 152:a3d286bf94e5 | 564 | |
tass | 152:a3d286bf94e5 | 565 | if(arpa == PICO_DNS_ARPA4) { |
tass | 152:a3d286bf94e5 | 566 | strcpy(inaddr_arpa, ".in-addr.arpa"); |
tass | 152:a3d286bf94e5 | 567 | strlen = pico_dns_strlen(url); |
tass | 152:a3d286bf94e5 | 568 | } |
tass | 152:a3d286bf94e5 | 569 | |
tass | 152:a3d286bf94e5 | 570 | #ifdef PICO_SUPPORT_IPV6 |
tass | 152:a3d286bf94e5 | 571 | else if (arpa == PICO_DNS_ARPA6) { |
tass | 152:a3d286bf94e5 | 572 | strcpy(inaddr_arpa, ".IP6.ARPA"); |
tass | 152:a3d286bf94e5 | 573 | strlen = STRLEN_PTR_IP6; |
tass | 152:a3d286bf94e5 | 574 | } |
tass | 152:a3d286bf94e5 | 575 | #endif |
tass | 152:a3d286bf94e5 | 576 | else { |
tass | 152:a3d286bf94e5 | 577 | strcpy(inaddr_arpa, ""); |
tass | 152:a3d286bf94e5 | 578 | strlen = pico_dns_strlen(url); |
tass | 152:a3d286bf94e5 | 579 | } |
tass | 152:a3d286bf94e5 | 580 | |
tass | 152:a3d286bf94e5 | 581 | arpalen = pico_dns_strlen(inaddr_arpa); |
tass | 152:a3d286bf94e5 | 582 | *urlen = (uint16_t)(PICO_DNS_LABEL_INITIAL + strlen + arpalen + PICO_DNS_LABEL_ROOT); |
tass | 152:a3d286bf94e5 | 583 | *hdrlen = (uint16_t)(sizeof(struct pico_dns_header) + *urlen + sizeof(struct pico_dns_question_suffix)); |
tass | 152:a3d286bf94e5 | 584 | *header = PICO_ZALLOC(*hdrlen); |
tass | 152:a3d286bf94e5 | 585 | if (!*header) { |
tass | 152:a3d286bf94e5 | 586 | pico_err = PICO_ERR_ENOMEM; |
tass | 152:a3d286bf94e5 | 587 | return -1; |
tass | 152:a3d286bf94e5 | 588 | } |
tass | 152:a3d286bf94e5 | 589 | |
tass | 152:a3d286bf94e5 | 590 | *header = (struct pico_dns_header *)*header; |
tass | 152:a3d286bf94e5 | 591 | domain = (char *) *header + sizeof(struct pico_dns_header); |
tass | 152:a3d286bf94e5 | 592 | *qsuffix = (struct pico_dns_question_suffix *)(domain + *urlen); |
tass | 152:a3d286bf94e5 | 593 | |
tass | 152:a3d286bf94e5 | 594 | if(arpa == PICO_DNS_ARPA4) { |
tass | 152:a3d286bf94e5 | 595 | memcpy(domain + PICO_DNS_LABEL_INITIAL, url, strlen); |
tass | 152:a3d286bf94e5 | 596 | pico_dns_mirror_addr(domain + PICO_DNS_LABEL_INITIAL); |
tass | 152:a3d286bf94e5 | 597 | memcpy(domain + PICO_DNS_LABEL_INITIAL + strlen, inaddr_arpa, arpalen); |
tass | 152:a3d286bf94e5 | 598 | } |
tass | 68:0847e35d08a6 | 599 | |
tass | 152:a3d286bf94e5 | 600 | #ifdef PICO_SUPPORT_IPV6 |
tass | 152:a3d286bf94e5 | 601 | else if (arpa == PICO_DNS_ARPA6) { |
tass | 152:a3d286bf94e5 | 602 | pico_dns_ipv6_set_ptr(url, domain + PICO_DNS_LABEL_INITIAL); |
tass | 152:a3d286bf94e5 | 603 | memcpy(domain + PICO_DNS_LABEL_INITIAL + STRLEN_PTR_IP6, inaddr_arpa, arpalen); |
tass | 152:a3d286bf94e5 | 604 | } |
tass | 152:a3d286bf94e5 | 605 | #endif |
tass | 152:a3d286bf94e5 | 606 | else { |
tass | 152:a3d286bf94e5 | 607 | memcpy(domain + PICO_DNS_LABEL_INITIAL, url, strlen); |
tass | 152:a3d286bf94e5 | 608 | } |
tass | 152:a3d286bf94e5 | 609 | |
tass | 152:a3d286bf94e5 | 610 | /* assemble dns message */ |
tass | 152:a3d286bf94e5 | 611 | pico_dns_client_query_header(*header); |
tass | 152:a3d286bf94e5 | 612 | pico_dns_name_to_dns_notation(domain, strlen); |
tass | 152:a3d286bf94e5 | 613 | |
tass | 152:a3d286bf94e5 | 614 | return 0; |
tass | 152:a3d286bf94e5 | 615 | } |
tass | 152:a3d286bf94e5 | 616 | |
tass | 152:a3d286bf94e5 | 617 | static int pico_dns_client_addr_label_check_len(const char *url) |
tass | 152:a3d286bf94e5 | 618 | { |
tass | 152:a3d286bf94e5 | 619 | const char *p, *label; |
tass | 152:a3d286bf94e5 | 620 | int count; |
tass | 152:a3d286bf94e5 | 621 | label = url; |
tass | 152:a3d286bf94e5 | 622 | p = label; |
tass | 152:a3d286bf94e5 | 623 | |
tass | 152:a3d286bf94e5 | 624 | while(*p != (char) 0) { |
tass | 152:a3d286bf94e5 | 625 | count = 0; |
tass | 152:a3d286bf94e5 | 626 | while((*p != (char)0)) { |
tass | 152:a3d286bf94e5 | 627 | if (*p == '.') { |
tass | 152:a3d286bf94e5 | 628 | label = ++p; |
tass | 152:a3d286bf94e5 | 629 | break; |
tass | 152:a3d286bf94e5 | 630 | } |
tass | 152:a3d286bf94e5 | 631 | |
tass | 152:a3d286bf94e5 | 632 | count++; |
tass | 152:a3d286bf94e5 | 633 | p++; |
tass | 152:a3d286bf94e5 | 634 | if (count > PICO_DNS_MAX_QUERY_LABEL_LEN) |
tass | 152:a3d286bf94e5 | 635 | return -1; |
tass | 152:a3d286bf94e5 | 636 | } |
tass | 152:a3d286bf94e5 | 637 | } |
tass | 152:a3d286bf94e5 | 638 | return 0; |
tass | 152:a3d286bf94e5 | 639 | } |
tass | 152:a3d286bf94e5 | 640 | |
tass | 152:a3d286bf94e5 | 641 | static int pico_dns_client_getaddr_check(const char *url, void (*callback)(char *, void *)) |
tass | 152:a3d286bf94e5 | 642 | { |
TASS Belgium NV |
131:4758606c9316 | 643 | if (!url || !callback) { |
TASS Belgium NV |
131:4758606c9316 | 644 | pico_err = PICO_ERR_EINVAL; |
TASS Belgium NV |
131:4758606c9316 | 645 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 646 | } |
TASS Belgium NV |
131:4758606c9316 | 647 | |
tass | 152:a3d286bf94e5 | 648 | if (strlen(url) > PICO_DNS_MAX_QUERY_LEN) { |
tass | 152:a3d286bf94e5 | 649 | pico_err = PICO_ERR_EINVAL; |
tass | 152:a3d286bf94e5 | 650 | return -1; |
tass | 152:a3d286bf94e5 | 651 | } |
tass | 152:a3d286bf94e5 | 652 | |
tass | 152:a3d286bf94e5 | 653 | if (pico_dns_client_addr_label_check_len(url) < 0) { |
tass | 152:a3d286bf94e5 | 654 | pico_err = PICO_ERR_EINVAL; |
TASS Belgium NV |
131:4758606c9316 | 655 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 656 | } |
tass | 68:0847e35d08a6 | 657 | |
tass | 152:a3d286bf94e5 | 658 | return 0; |
tass | 152:a3d286bf94e5 | 659 | } |
TASS Belgium NV |
131:4758606c9316 | 660 | |
tass | 152:a3d286bf94e5 | 661 | static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg) |
tass | 152:a3d286bf94e5 | 662 | { |
tass | 152:a3d286bf94e5 | 663 | struct pico_dns_header *header = NULL; |
tass | 152:a3d286bf94e5 | 664 | struct pico_dns_question_suffix *qsuffix = NULL; |
tass | 152:a3d286bf94e5 | 665 | struct pico_dns_query *q = NULL; |
tass | 152:a3d286bf94e5 | 666 | uint16_t len = 0, lblen = 0; |
tass | 152:a3d286bf94e5 | 667 | (void)proto; |
tass | 152:a3d286bf94e5 | 668 | |
tass | 152:a3d286bf94e5 | 669 | if (pico_dns_client_getaddr_check(url, callback) < 0) |
tass | 152:a3d286bf94e5 | 670 | return -1; |
tass | 152:a3d286bf94e5 | 671 | |
tass | 152:a3d286bf94e5 | 672 | if(pico_dns_create_message(&header, &qsuffix, PICO_DNS_NO_ARPA, url, &lblen, &len) != 0) |
tass | 152:a3d286bf94e5 | 673 | return -1; |
tass picotcp@tass.be | 149:5f4cb161cec3 | 674 | |
tass picotcp@tass.be | 149:5f4cb161cec3 | 675 | #ifdef PICO_SUPPORT_IPV6 |
tass picotcp@tass.be | 149:5f4cb161cec3 | 676 | if (proto == PICO_PROTO_IPV6) { |
tass | 152:a3d286bf94e5 | 677 | pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_AAAA, PICO_DNS_CLASS_IN); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 678 | } else |
tass picotcp@tass.be | 149:5f4cb161cec3 | 679 | #endif |
tass | 152:a3d286bf94e5 | 680 | pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN); |
tass | 68:0847e35d08a6 | 681 | |
tass | 152:a3d286bf94e5 | 682 | q = pico_dns_client_add_query(header, len, qsuffix, callback, arg); |
TASS Belgium NV |
131:4758606c9316 | 683 | if (!q) { |
tass | 152:a3d286bf94e5 | 684 | PICO_FREE(header); |
TASS Belgium NV |
131:4758606c9316 | 685 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 686 | } |
tass | 68:0847e35d08a6 | 687 | |
TASS Belgium NV |
131:4758606c9316 | 688 | if (pico_dns_client_send(q) < 0) { |
TASS Belgium NV |
131:4758606c9316 | 689 | pico_dns_client_del_query(q->id); /* frees msg */ |
TASS Belgium NV |
131:4758606c9316 | 690 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 691 | } |
tass | 68:0847e35d08a6 | 692 | |
TASS Belgium NV |
131:4758606c9316 | 693 | return 0; |
tass | 68:0847e35d08a6 | 694 | } |
tass | 68:0847e35d08a6 | 695 | |
tass picotcp@tass.be | 149:5f4cb161cec3 | 696 | int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg) |
tass picotcp@tass.be | 149:5f4cb161cec3 | 697 | { |
tass picotcp@tass.be | 149:5f4cb161cec3 | 698 | return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV4, callback, arg); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 699 | } |
tass picotcp@tass.be | 149:5f4cb161cec3 | 700 | |
tass picotcp@tass.be | 149:5f4cb161cec3 | 701 | int pico_dns_client_getaddr6(const char *url, void (*callback)(char *, void *), void *arg) |
tass picotcp@tass.be | 149:5f4cb161cec3 | 702 | { |
tass picotcp@tass.be | 149:5f4cb161cec3 | 703 | return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV6, callback, arg); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 704 | } |
tass picotcp@tass.be | 149:5f4cb161cec3 | 705 | |
tass | 152:a3d286bf94e5 | 706 | static int pico_dns_getname_univ(const char *ip, void (*callback)(char *, void *), void *arg, enum pico_dns_arpa arpa) |
tass | 68:0847e35d08a6 | 707 | { |
tass | 152:a3d286bf94e5 | 708 | struct pico_dns_header *header = NULL; |
tass | 152:a3d286bf94e5 | 709 | struct pico_dns_question_suffix *qsuffix = NULL; |
TASS Belgium NV |
131:4758606c9316 | 710 | struct pico_dns_query *q = NULL; |
tass | 152:a3d286bf94e5 | 711 | uint16_t len = 0, lblen = 0; |
tass | 68:0847e35d08a6 | 712 | |
TASS Belgium NV |
131:4758606c9316 | 713 | if (!ip || !callback) { |
TASS Belgium NV |
131:4758606c9316 | 714 | pico_err = PICO_ERR_EINVAL; |
TASS Belgium NV |
131:4758606c9316 | 715 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 716 | } |
TASS Belgium NV |
131:4758606c9316 | 717 | |
tass | 152:a3d286bf94e5 | 718 | if(pico_dns_create_message(&header, &qsuffix, arpa, ip, &lblen, &len) != 0) |
TASS Belgium NV |
131:4758606c9316 | 719 | return -1; |
tass | 68:0847e35d08a6 | 720 | |
tass | 152:a3d286bf94e5 | 721 | pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN); |
tass | 152:a3d286bf94e5 | 722 | q = pico_dns_client_add_query(header, len, qsuffix, callback, arg); |
TASS Belgium NV |
131:4758606c9316 | 723 | if (!q) { |
tass | 152:a3d286bf94e5 | 724 | PICO_FREE(header); |
TASS Belgium NV |
131:4758606c9316 | 725 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 726 | } |
tass | 68:0847e35d08a6 | 727 | |
TASS Belgium NV |
131:4758606c9316 | 728 | if (pico_dns_client_send(q) < 0) { |
tass | 152:a3d286bf94e5 | 729 | pico_dns_client_del_query(q->id); /* frees header */ |
TASS Belgium NV |
131:4758606c9316 | 730 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 731 | } |
tass | 68:0847e35d08a6 | 732 | |
TASS Belgium NV |
131:4758606c9316 | 733 | return 0; |
tass | 68:0847e35d08a6 | 734 | } |
tass | 68:0847e35d08a6 | 735 | |
tass | 152:a3d286bf94e5 | 736 | int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg) |
tass picotcp@tass.be | 149:5f4cb161cec3 | 737 | { |
tass | 152:a3d286bf94e5 | 738 | return pico_dns_getname_univ(ip, callback, arg, PICO_DNS_ARPA4); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 739 | } |
tass picotcp@tass.be | 149:5f4cb161cec3 | 740 | |
tass picotcp@tass.be | 149:5f4cb161cec3 | 741 | |
tass picotcp@tass.be | 149:5f4cb161cec3 | 742 | int pico_dns_client_getname6(const char *ip, void (*callback)(char *, void *), void *arg) |
tass picotcp@tass.be | 149:5f4cb161cec3 | 743 | { |
tass | 152:a3d286bf94e5 | 744 | return pico_dns_getname_univ(ip, callback, arg, PICO_DNS_ARPA6); |
tass picotcp@tass.be | 149:5f4cb161cec3 | 745 | } |
tass picotcp@tass.be | 149:5f4cb161cec3 | 746 | |
tass | 68:0847e35d08a6 | 747 | int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag) |
tass | 68:0847e35d08a6 | 748 | { |
TASS Belgium NV |
131:4758606c9316 | 749 | if (!ns) { |
TASS Belgium NV |
131:4758606c9316 | 750 | pico_err = PICO_ERR_EINVAL; |
TASS Belgium NV |
131:4758606c9316 | 751 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 752 | } |
tass | 68:0847e35d08a6 | 753 | |
TASS Belgium NV |
131:4758606c9316 | 754 | switch (flag) |
TASS Belgium NV |
131:4758606c9316 | 755 | { |
tass | 68:0847e35d08a6 | 756 | case PICO_DNS_NS_ADD: |
TASS Belgium NV |
131:4758606c9316 | 757 | if (!pico_dns_client_add_ns(ns)) |
TASS Belgium NV |
131:4758606c9316 | 758 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 759 | |
TASS Belgium NV |
131:4758606c9316 | 760 | break; |
tass | 68:0847e35d08a6 | 761 | |
tass | 68:0847e35d08a6 | 762 | case PICO_DNS_NS_DEL: |
TASS Belgium NV |
131:4758606c9316 | 763 | if (pico_dns_client_del_ns(ns) < 0) { |
TASS Belgium NV |
131:4758606c9316 | 764 | pico_err = PICO_ERR_EINVAL; |
TASS Belgium NV |
131:4758606c9316 | 765 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 766 | } |
TASS Belgium NV |
131:4758606c9316 | 767 | |
TASS Belgium NV |
131:4758606c9316 | 768 | break; |
TASS Belgium NV |
131:4758606c9316 | 769 | |
TASS Belgium NV |
131:4758606c9316 | 770 | default: |
tass | 68:0847e35d08a6 | 771 | pico_err = PICO_ERR_EINVAL; |
tass | 68:0847e35d08a6 | 772 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 773 | } |
TASS Belgium NV |
131:4758606c9316 | 774 | return 0; |
tass | 68:0847e35d08a6 | 775 | } |
tass | 68:0847e35d08a6 | 776 | |
tass picotcp@tass.be | 134:cc4e6d2654d9 | 777 | int pico_dns_client_init(void) |
tass | 68:0847e35d08a6 | 778 | { |
TASS Belgium NV |
131:4758606c9316 | 779 | struct pico_ip4 default_ns = { |
TASS Belgium NV |
131:4758606c9316 | 780 | 0 |
TASS Belgium NV |
131:4758606c9316 | 781 | }; |
tass | 68:0847e35d08a6 | 782 | |
tass picotcp@tass.be | 149:5f4cb161cec3 | 783 | if (pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&default_ns.addr) < 0) |
TASS Belgium NV |
131:4758606c9316 | 784 | return -1; |
tass | 68:0847e35d08a6 | 785 | |
TASS Belgium NV |
131:4758606c9316 | 786 | return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD); |
tass | 68:0847e35d08a6 | 787 | } |
tass | 68:0847e35d08a6 | 788 | |
tass | 152:a3d286bf94e5 | 789 | #else |
tass | 152:a3d286bf94e5 | 790 | |
tass | 152:a3d286bf94e5 | 791 | int pico_dns_client_init(void) |
tass | 152:a3d286bf94e5 | 792 | { |
tass | 152:a3d286bf94e5 | 793 | dbg("ERROR Trying to initialize DNS module: IPv4 not supported in this build.\n"); |
tass | 152:a3d286bf94e5 | 794 | return -1; |
tass | 152:a3d286bf94e5 | 795 | } |
tass | 152:a3d286bf94e5 | 796 | #endif /* PICO_SUPPORT_IPV4 */ |
tass | 152:a3d286bf94e5 | 797 | |
tass | 152:a3d286bf94e5 | 798 | |
tass | 68:0847e35d08a6 | 799 | #endif /* PICO_SUPPORT_DNS_CLIENT */ |
tass | 152:a3d286bf94e5 | 800 |