OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [Common/] [ethernet/] [lwIP_130/] [src/] [core/] [dns.c] - Blame information for rev 606

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 606 jeremybenn
/**
2
 * @file
3
 * DNS - host name to IP address resolver.
4
 *
5
 */
6
 
7
/**
8
 
9
 * This file implements a DNS host name to IP address resolver.
10
 
11
 * Port to lwIP from uIP
12
 * by Jim Pettinato April 2007
13
 
14
 * uIP version Copyright (c) 2002-2003, Adam Dunkels.
15
 * All rights reserved.
16
 *
17
 * Redistribution and use in source and binary forms, with or without
18
 * modification, are permitted provided that the following conditions
19
 * are met:
20
 * 1. Redistributions of source code must retain the above copyright
21
 *    notice, this list of conditions and the following disclaimer.
22
 * 2. Redistributions in binary form must reproduce the above copyright
23
 *    notice, this list of conditions and the following disclaimer in the
24
 *    documentation and/or other materials provided with the distribution.
25
 * 3. The name of the author may not be used to endorse or promote
26
 *    products derived from this software without specific prior
27
 *    written permission.
28
 *
29
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
30
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
33
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
35
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
37
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
 *
41
 *
42
 * DNS.C
43
 *
44
 * The lwIP DNS resolver functions are used to lookup a host name and
45
 * map it to a numerical IP address. It maintains a list of resolved
46
 * hostnames that can be queried with the dns_lookup() function.
47
 * New hostnames can be resolved using the dns_query() function.
48
 *
49
 * The lwIP version of the resolver also adds a non-blocking version of
50
 * gethostbyname() that will work with a raw API application. This function
51
 * checks for an IP address string first and converts it if it is valid.
52
 * gethostbyname() then does a dns_lookup() to see if the name is
53
 * already in the table. If so, the IP is returned. If not, a query is
54
 * issued and the function returns with a ERR_INPROGRESS status. The app
55
 * using the dns client must then go into a waiting state.
56
 *
57
 * Once a hostname has been resolved (or found to be non-existent),
58
 * the resolver code calls a specified callback function (which
59
 * must be implemented by the module that uses the resolver).
60
 */
61
 
62
/*-----------------------------------------------------------------------------
63
 * RFC 1035 - Domain names - implementation and specification
64
 * RFC 2181 - Clarifications to the DNS Specification
65
 *----------------------------------------------------------------------------*/
66
 
67
/** @todo: define good default values (rfc compliance) */
68
/** @todo: improve answer parsing, more checkings... */
69
/** @todo: check RFC1035 - 7.3. Processing responses */
70
 
71
/*-----------------------------------------------------------------------------
72
 * Includes
73
 *----------------------------------------------------------------------------*/
74
 
75
#include "lwip/opt.h"
76
 
77
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
78
 
79
#include "lwip/udp.h"
80
#include "lwip/mem.h"
81
#include "lwip/dns.h"
82
 
83
#include <string.h>
84
 
85
/** DNS server IP address */
86
#ifndef DNS_SERVER_ADDRESS
87
#define DNS_SERVER_ADDRESS        inet_addr("208.67.222.222") /* resolver1.opendns.com */
88
#endif
89
 
90
/** DNS server port address */
91
#ifndef DNS_SERVER_PORT
92
#define DNS_SERVER_PORT           53
93
#endif
94
 
95
/** DNS maximum number of retries when asking for a name, before "timeout". */
96
#ifndef DNS_MAX_RETRIES
97
#define DNS_MAX_RETRIES           4
98
#endif
99
 
100
/** DNS resource record max. TTL (one week as default) */
101
#ifndef DNS_MAX_TTL
102
#define DNS_MAX_TTL               604800
103
#endif
104
 
105
/* DNS protocol flags */
106
#define DNS_FLAG1_RESPONSE        0x80
107
#define DNS_FLAG1_OPCODE_STATUS   0x10
108
#define DNS_FLAG1_OPCODE_INVERSE  0x08
109
#define DNS_FLAG1_OPCODE_STANDARD 0x00
110
#define DNS_FLAG1_AUTHORATIVE     0x04
111
#define DNS_FLAG1_TRUNC           0x02
112
#define DNS_FLAG1_RD              0x01
113
#define DNS_FLAG2_RA              0x80
114
#define DNS_FLAG2_ERR_MASK        0x0f
115
#define DNS_FLAG2_ERR_NONE        0x00
116
#define DNS_FLAG2_ERR_NAME        0x03
117
 
118
/* DNS protocol states */
119
#define DNS_STATE_UNUSED          0
120
#define DNS_STATE_NEW             1
121
#define DNS_STATE_ASKING          2
122
#define DNS_STATE_DONE            3
123
 
124
#ifdef PACK_STRUCT_USE_INCLUDES
125
#  include "arch/bpstruct.h"
126
#endif
127
PACK_STRUCT_BEGIN
128
#if (defined(__MWERKS__)  || defined(__CWCC__))
129
        #pragma options align= packed
130
#endif
131
/** DNS message header */
132
struct dns_hdr {
133
  u16_t id;
134
  u8_t flags1;
135
  u8_t flags2;
136
  u16_t numquestions;
137
  u16_t numanswers;
138
  u16_t numauthrr;
139
  u16_t numextrarr;
140
} PACK_STRUCT_STRUCT;
141
PACK_STRUCT_END
142
#ifdef PACK_STRUCT_USE_INCLUDES
143
#  include "arch/epstruct.h"
144
#endif
145
 
146
#ifdef PACK_STRUCT_USE_INCLUDES
147
#  include "arch/bpstruct.h"
148
#endif
149
PACK_STRUCT_BEGIN
150
#if (defined(__MWERKS__)  || defined(__CWCC__))
151
        #pragma options align= packed
152
#endif
153
/** DNS query message structure */
154
struct dns_query {
155
  /* DNS query record starts with either a domain name or a pointer
156
     to a name already present somewhere in the packet. */
157
  u16_t type;
158
  u16_t class;
159
} PACK_STRUCT_STRUCT;
160
PACK_STRUCT_END
161
#ifdef PACK_STRUCT_USE_INCLUDES
162
#  include "arch/epstruct.h"
163
#endif
164
 
165
#ifdef PACK_STRUCT_USE_INCLUDES
166
#  include "arch/bpstruct.h"
167
#endif
168
PACK_STRUCT_BEGIN
169
#if (defined(__MWERKS__)  || defined(__CWCC__))
170
        #pragma options align= packed
171
#endif
172
/** DNS answer message structure */
173
struct dns_answer {
174
  /* DNS answer record starts with either a domain name or a pointer
175
     to a name already present somewhere in the packet. */
176
  u16_t type;
177
  u16_t class;
178
  u32_t ttl;
179
  u16_t len;
180
} PACK_STRUCT_STRUCT;
181
PACK_STRUCT_END
182
#ifdef PACK_STRUCT_USE_INCLUDES
183
#  include "arch/epstruct.h"
184
#endif
185
 
186
/** DNS table entry */
187
struct dns_table_entry {
188
  u8_t  state;
189
  u8_t  numdns;
190
  u8_t  tmr;
191
  u8_t  retries;
192
  u8_t  seqno;
193
  u8_t  err;
194
  u32_t ttl;
195
  char name[DNS_MAX_NAME_LENGTH];
196
  struct ip_addr ipaddr;
197
  /* pointer to callback on DNS query done */
198
  dns_found_callback found;
199
  void *arg;
200
};
201
 
202
 
203
/* forward declarations */
204
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
205
static void dns_check_entries(void);
206
 
207
/*-----------------------------------------------------------------------------
208
 * Globales
209
 *----------------------------------------------------------------------------*/
210
 
211
/* DNS variables */
212
static struct udp_pcb        *dns_pcb;
213
static u8_t                   dns_seqno;
214
static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
215
static struct ip_addr         dns_servers[DNS_MAX_SERVERS];
216
 
217
#if (DNS_USES_STATIC_BUF == 1)
218
static u8_t                   dns_payload[DNS_MSG_SIZE];
219
#endif /* (DNS_USES_STATIC_BUF == 1) */
220
 
221
/**
222
 * Initialize the resolver: set up the UDP pcb and configure the default server
223
 * (DNS_SERVER_ADDRESS).
224
 */
225
void
226
dns_init()
227
{
228
  struct ip_addr dnsserver;
229
 
230
  /* initialize default DNS server address */
231
  dnsserver.addr = DNS_SERVER_ADDRESS;
232
 
233
  LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
234
 
235
  /* if dns client not yet initialized... */
236
  if (dns_pcb == NULL) {
237
    dns_pcb = udp_new();
238
 
239
    if (dns_pcb != NULL) {
240
      /* initialize DNS table not needed (initialized to zero since it is a
241
       * global variable) */
242
      LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
243
        DNS_STATE_UNUSED == 0);
244
 
245
      /* initialize DNS client */
246
      udp_bind(dns_pcb, IP_ADDR_ANY, 0);
247
      udp_recv(dns_pcb, dns_recv, NULL);
248
 
249
      /* initialize default DNS primary server */
250
      dns_setserver(0, &dnsserver);
251
    }
252
  }
253
}
254
 
255
/**
256
 * Initialize one of the DNS servers.
257
 *
258
 * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
259
 * @param dnsserver IP address of the DNS server to set
260
 */
261
void
262
dns_setserver(u8_t numdns, struct ip_addr *dnsserver)
263
{
264
  if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
265
      (dnsserver != NULL) && (dnsserver->addr !=0 )) {
266
    dns_servers[numdns] = (*dnsserver);
267
  }
268
}
269
 
270
/**
271
 * Obtain one of the currently configured DNS server.
272
 *
273
 * @param numdns the index of the DNS server
274
 * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
275
 *         server has not been configured.
276
 */
277
struct ip_addr
278
dns_getserver(u8_t numdns)
279
{
280
  if (numdns < DNS_MAX_SERVERS) {
281
    return dns_servers[numdns];
282
  } else {
283
    return *IP_ADDR_ANY;
284
  }
285
}
286
 
287
/**
288
 * The DNS resolver client timer - handle retries and timeouts and should
289
 * be called every DNS_TMR_INTERVAL milliseconds (every second by default).
290
 */
291
void
292
dns_tmr(void)
293
{
294
  if (dns_pcb != NULL) {
295
    LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
296
    dns_check_entries();
297
  }
298
}
299
 
300
/**
301
 * Look up a hostname in the array of known hostnames.
302
 *
303
 * @note This function only looks in the internal array of known
304
 * hostnames, it does not send out a query for the hostname if none
305
 * was found. The function dns_enqueue() can be used to send a query
306
 * for a hostname.
307
 *
308
 * @param name the hostname to look up
309
 * @return the hostname's IP address, as u32_t (instead of struct ip_addr to
310
 *         better check for failure: != 0) or 0 if the hostname was not found
311
 *         in the cached dns_table.
312
 */
313
static u32_t
314
dns_lookup(const char *name)
315
{
316
  u8_t i;
317
 
318
  /* Walk through name list, return entry if found. If not, return NULL. */
319
  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
320
    if ((dns_table[i].state == DNS_STATE_DONE) &&
321
        (strcmp(name, dns_table[i].name) == 0)) {
322
      LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
323
      ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
324
      LWIP_DEBUGF(DNS_DEBUG, ("\n"));
325
      return dns_table[i].ipaddr.addr;
326
    }
327
  }
328
 
329
  return 0;
330
}
331
 
332
#if DNS_DOES_NAME_CHECK
333
/**
334
 * Compare the "dotted" name "query" with the encoded name "response"
335
 * to make sure an answer from the DNS server matches the current dns_table
336
 * entry (otherwise, answers might arrive late for hostname not on the list
337
 * any more).
338
 *
339
 * @param query hostname (not encoded) from the dns_table
340
 * @param response encoded hostname in the DNS response
341
 * @return 0: names equal; 1: names differ
342
 */
343
static u8_t
344
dns_compare_name(unsigned char *query, unsigned char *response)
345
{
346
  unsigned char n;
347
 
348
  do {
349
    n = *response++;
350
    /** @see RFC 1035 - 4.1.4. Message compression */
351
    if ((n & 0xc0) == 0xc0) {
352
      /* Compressed name */
353
      break;
354
    } else {
355
      /* Not compressed name */
356
      while (n > 0) {
357
        if ((*query) != (*response)) {
358
          return 1;
359
        }
360
        ++response;
361
        ++query;
362
        --n;
363
      };
364
      ++query;
365
    }
366
  } while (*response != 0);
367
 
368
  return 0;
369
}
370
#endif /* DNS_DOES_NAME_CHECK */
371
 
372
/**
373
 * Walk through a compact encoded DNS name and return the end of the name.
374
 *
375
 * @param query encoded DNS name in the DNS server response
376
 * @return end of the name
377
 */
378
static unsigned char *
379
dns_parse_name(unsigned char *query)
380
{
381
  unsigned char n;
382
 
383
  do {
384
    n = *query++;
385
    /** @see RFC 1035 - 4.1.4. Message compression */
386
    if ((n & 0xc0) == 0xc0) {
387
      /* Compressed name */
388
      break;
389
    } else {
390
      /* Not compressed name */
391
      while (n > 0) {
392
        ++query;
393
        --n;
394
      };
395
    }
396
  } while (*query != 0);
397
 
398
  return query + 1;
399
}
400
 
401
/**
402
 * Send a DNS query packet.
403
 *
404
 * @param numdns index of the DNS server in the dns_servers table
405
 * @param name hostname to query
406
 * @param id index of the hostname in dns_table, used as transaction ID in the
407
 *        DNS query packet
408
 * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
409
 */
410
static err_t
411
dns_send(u8_t numdns, const char* name, u8_t id)
412
{
413
  err_t err;
414
  struct dns_hdr *hdr;
415
  struct dns_query qry;
416
  struct pbuf *p;
417
  char *query, *nptr;
418
  const char *pHostname;
419
  u8_t n;
420
 
421
  LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
422
              (u16_t)(numdns), name));
423
  LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
424
  LWIP_ASSERT("dns server has no IP address set", dns_servers[numdns].addr != 0);
425
 
426
  /* if here, we have either a new query or a retry on a previous query to process */
427
  p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dns_hdr) + DNS_MAX_NAME_LENGTH +
428
                 sizeof(struct dns_query), PBUF_RAM);
429
  if (p != NULL) {
430
    LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
431
    /* fill dns header */
432
    hdr = (struct dns_hdr*)p->payload;
433
    memset(hdr, 0, sizeof(struct dns_hdr));
434
    hdr->id = htons(id);
435
    hdr->flags1 = DNS_FLAG1_RD;
436
    hdr->numquestions = htons(1);
437
    query = (char*)hdr + sizeof(struct dns_hdr);
438
    pHostname = name;
439
    --pHostname;
440
 
441
    /* convert hostname into suitable query format. */
442
    do {
443
      ++pHostname;
444
      nptr = query;
445
      ++query;
446
      for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
447
        *query = *pHostname;
448
        ++query;
449
        ++n;
450
      }
451
      *nptr = n;
452
    } while(*pHostname != 0);
453
    *query++='\0';
454
 
455
    /* fill dns query */
456
    qry.type  = htons(DNS_RRTYPE_A);
457
    qry.class = htons(DNS_RRCLASS_IN);
458
    MEMCPY( query, &qry, sizeof(struct dns_query));
459
 
460
    /* resize pbuf to the exact dns query */
461
    pbuf_realloc(p, (query + sizeof(struct dns_query)) - ((char*)(p->payload)));
462
 
463
    /* connect to the server for faster receiving */
464
    udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
465
    /* send dns packet */
466
    err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);
467
 
468
    /* free pbuf */
469
    pbuf_free(p);
470
  } else {
471
    err = ERR_MEM;
472
  }
473
 
474
  return err;
475
}
476
 
477
/**
478
 * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.
479
 * Check an entry in the dns_table:
480
 * - send out query for new entries
481
 * - retry old pending entries on timeout (also with different servers)
482
 * - remove completed entries from the table if their TTL has expired
483
 *
484
 * @param i index of the dns_table entry to check
485
 */
486
static void
487
dns_check_entry(u8_t i)
488
{
489
  struct dns_table_entry *pEntry = &dns_table[i];
490
 
491
  LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
492
 
493
  switch(pEntry->state) {
494
 
495
    case DNS_STATE_NEW: {
496
      /* initialize new entry */
497
      pEntry->state   = DNS_STATE_ASKING;
498
      pEntry->numdns  = 0;
499
      pEntry->tmr     = 1;
500
      pEntry->retries = 0;
501
 
502
      /* send DNS packet for this entry */
503
      dns_send(pEntry->numdns, pEntry->name, i);
504
      break;
505
    }
506
 
507
    case DNS_STATE_ASKING: {
508
      if (--pEntry->tmr == 0) {
509
        if (++pEntry->retries == DNS_MAX_RETRIES) {
510
          if ((pEntry->numdns+1<DNS_MAX_SERVERS) && (dns_servers[pEntry->numdns+1].addr!=0)) {
511
            /* change of server */
512
            pEntry->numdns++;
513
            pEntry->tmr     = 1;
514
            pEntry->retries = 0;
515
            break;
516
          } else {
517
            LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));
518
            /* call specified callback function if provided */
519
            if (pEntry->found)
520
              (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
521
            /* flush this entry */
522
            pEntry->state   = DNS_STATE_UNUSED;
523
            pEntry->found   = NULL;
524
            break;
525
          }
526
        }
527
 
528
        /* wait longer for the next retry */
529
        pEntry->tmr = pEntry->retries;
530
 
531
        /* send DNS packet for this entry */
532
        dns_send(pEntry->numdns, pEntry->name, i);
533
      }
534
      break;
535
    }
536
 
537
    case DNS_STATE_DONE: {
538
      /* if the time to live is nul */
539
      if (--pEntry->ttl == 0) {
540
        LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
541
        /* flush this entry */
542
        pEntry->state = DNS_STATE_UNUSED;
543
        pEntry->found = NULL;
544
      }
545
      break;
546
    }
547
    case DNS_STATE_UNUSED:
548
      /* nothing to do */
549
      break;
550
    default:
551
      LWIP_ASSERT("unknown dns_table entry state:", 0);
552
      break;
553
  }
554
}
555
 
556
/**
557
 * Call dns_check_entry for each entry in dns_table - check all entries.
558
 */
559
static void
560
dns_check_entries(void)
561
{
562
  u8_t i;
563
 
564
  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
565
    dns_check_entry(i);
566
  }
567
}
568
 
569
/**
570
 * Receive input function for DNS response packets arriving for the dns UDP pcb.
571
 *
572
 * @params see udp.h
573
 */
574
static void
575
dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
576
{
577
  u8_t i;
578
  char *pHostname;
579
  struct dns_hdr *hdr;
580
  struct dns_answer ans;
581
  struct dns_table_entry *pEntry;
582
  u8_t nquestions, nanswers;
583
#if (DNS_USES_STATIC_BUF == 0)
584
  u8_t dns_payload[DNS_MSG_SIZE];
585
#endif /* (DNS_USES_STATIC_BUF == 0) */
586
#if (DNS_USES_STATIC_BUF == 2)
587
  u8_t* dns_payload;
588
#endif /* (DNS_USES_STATIC_BUF == 2) */
589
 
590
  LWIP_UNUSED_ARG(arg);
591
  LWIP_UNUSED_ARG(pcb);
592
  LWIP_UNUSED_ARG(addr);
593
  LWIP_UNUSED_ARG(port);
594
 
595
  /* is the dns message too big ? */
596
  if (p->tot_len > DNS_MSG_SIZE) {
597
    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
598
    /* free pbuf and return */
599
    goto memerr1;
600
  }
601
 
602
  /* is the dns message big enough ? */
603
  if (p->tot_len < (sizeof(struct dns_hdr) + sizeof(struct dns_query) + sizeof(struct dns_answer))) {
604
    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
605
    /* free pbuf and return */
606
    goto memerr1;
607
  }
608
 
609
#if (DNS_USES_STATIC_BUF == 2)
610
  dns_payload = mem_malloc(p->tot_len);
611
  if (dns_payload == NULL) {
612
    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: mem_malloc error\n"));
613
    /* free pbuf and return */
614
    goto memerr1;
615
  }
616
#endif /* (DNS_USES_STATIC_BUF == 2) */
617
 
618
  /* copy dns payload inside static buffer for processing */
619
  if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
620
    /* The ID in the DNS header should be our entry into the name table. */
621
    hdr = (struct dns_hdr*)dns_payload;
622
    i = htons(hdr->id);
623
    if (i < DNS_TABLE_SIZE) {
624
      pEntry = &dns_table[i];
625
      if(pEntry->state == DNS_STATE_ASKING) {
626
        /* This entry is now completed. */
627
        pEntry->state = DNS_STATE_DONE;
628
        pEntry->err   = hdr->flags2 & DNS_FLAG2_ERR_MASK;
629
 
630
        /* We only care about the question(s) and the answers. The authrr
631
           and the extrarr are simply discarded. */
632
        nquestions = htons(hdr->numquestions);
633
        nanswers   = htons(hdr->numanswers);
634
 
635
        /* Check for error. If so, call callback to inform. */
636
        if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {
637
          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
638
          /* call callback to indicate error, clean up memory and return */
639
          goto responseerr;
640
        }
641
 
642
#if DNS_DOES_NAME_CHECK
643
        /* Check if the name in the "question" part match with the name in the entry. */
644
        if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + sizeof(struct dns_hdr)) != 0) {
645
          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
646
          /* call callback to indicate error, clean up memory and return */
647
          goto responseerr;
648
        }
649
#endif /* DNS_DOES_NAME_CHECK */
650
 
651
        /* Skip the name in the "question" part */
652
        pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + sizeof(struct dns_hdr)) + sizeof(struct dns_query);
653
 
654
        while(nanswers > 0) {
655
          /* skip answer resource record's host name */
656
          pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
657
 
658
          /* Check for IP address type and Internet class. Others are discarded. */
659
          MEMCPY(&ans, pHostname, sizeof(struct dns_answer));
660
          if((ntohs(ans.type) == DNS_RRTYPE_A) && (ntohs(ans.class) == DNS_RRCLASS_IN) && (ntohs(ans.len) == sizeof(struct ip_addr)) ) {
661
            /* read the answer resource record's TTL, and maximize it if needed */
662
            pEntry->ttl = ntohl(ans.ttl);
663
            if (pEntry->ttl > DNS_MAX_TTL) {
664
              pEntry->ttl = DNS_MAX_TTL;
665
            }
666
            /* read the IP address after answer resource record's header */
667
            MEMCPY( &(pEntry->ipaddr), (pHostname+sizeof(struct dns_answer)), sizeof(struct ip_addr));
668
            LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
669
            ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
670
            LWIP_DEBUGF(DNS_DEBUG, ("\n"));
671
            /* call specified callback function if provided */
672
            if (pEntry->found) {
673
              (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
674
            }
675
            /* deallocate memory and return */
676
            goto memerr2;
677
          } else {
678
            pHostname = pHostname + sizeof(struct dns_answer) + htons(ans.len);
679
          }
680
          --nanswers;
681
        }
682
        LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
683
        /* call callback to indicate error, clean up memory and return */
684
        goto responseerr;
685
      }
686
    }
687
  }
688
 
689
  /* deallocate memory and return */
690
  goto memerr2;
691
 
692
responseerr:
693
  /* ERROR: call specified callback function with NULL as name to indicate an error */
694
  if (pEntry->found) {
695
    (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
696
  }
697
  /* flush this entry */
698
  pEntry->state = DNS_STATE_UNUSED;
699
  pEntry->found = NULL;
700
 
701
memerr2:
702
#if (DNS_USES_STATIC_BUF == 2)
703
  /* free dns buffer */
704
  mem_free(dns_payload);
705
#endif /* (DNS_USES_STATIC_BUF == 2) */
706
 
707
memerr1:
708
  /* free pbuf */
709
  pbuf_free(p);
710
  return;
711
}
712
 
713
/**
714
 * Queues a new hostname to resolve and sends out a DNS query for that hostname
715
 *
716
 * @param name the hostname that is to be queried
717
 * @param found a callback founction to be called on success, failure or timeout
718
 * @param callback_arg argument to pass to the callback function
719
 * @return @return a err_t return code.
720
 */
721
static err_t
722
dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
723
{
724
  u8_t i;
725
  u8_t lseq, lseqi;
726
  struct dns_table_entry *pEntry = NULL;
727
 
728
  /* search an unused entry, or the oldest one */
729
  lseq = lseqi = 0;
730
  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
731
    pEntry = &dns_table[i];
732
    /* is it an unused entry ? */
733
    if (pEntry->state == DNS_STATE_UNUSED)
734
      break;
735
 
736
    /* check if this is the oldest completed entry */
737
    if (pEntry->state == DNS_STATE_DONE) {
738
      if ((dns_seqno - pEntry->seqno) > lseq) {
739
        lseq = dns_seqno - pEntry->seqno;
740
        lseqi = i;
741
      }
742
    }
743
  }
744
 
745
  /* if we don't have found an unused entry, use the oldest completed one */
746
  if (i == DNS_TABLE_SIZE) {
747
    if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
748
      /* no entry can't be used now, table is full */
749
      LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
750
      return ERR_MEM;
751
    } else {
752
      /* use the oldest completed one */
753
      i = lseqi;
754
      pEntry = &dns_table[i];
755
    }
756
  }
757
 
758
  /* use this entry */
759
  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
760
 
761
  /* fill the entry */
762
  pEntry->state = DNS_STATE_NEW;
763
  pEntry->seqno = dns_seqno++;
764
  pEntry->found = found;
765
  pEntry->arg   = callback_arg;
766
  strcpy(pEntry->name, name);
767
 
768
  /* force to send query without waiting timer */
769
  dns_check_entry(i);
770
 
771
  /* dns query is enqueued */
772
  return ERR_INPROGRESS;
773
}
774
 
775
/**
776
 * Resolve a hostname (string) into an IP address.
777
 * NON-BLOCKING callback version for use with raw API!!!
778
 *
779
 * Returns immediately with one of err_t return codes:
780
 * - ERR_OK if hostname is a valid IP address string or the host
781
 *   name is already in the local names table.
782
 * - ERR_INPROGRESS enqueue a request to be sent to the DNS server
783
 *   for resolution if no errors are present.
784
 *
785
 * @param hostname the hostname that is to be queried
786
 * @param addr pointer to a struct ip_addr where to store the address if it is already
787
 *             cached in the dns_table (only valid if ERR_OK is returned!)
788
 * @param found a callback function to be called on success, failure or timeout (only if
789
 *              ERR_INPROGRESS is returned!)
790
 * @param callback_arg argument to pass to the callback function
791
 * @return a err_t return code.
792
 */
793
err_t
794
dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback found,
795
                  void *callback_arg)
796
{
797
  /* not initialized or no valid server yet, or invalid addr pointer
798
   * or invalid hostname or invalid hostname length */
799
  if ((dns_pcb == NULL) || (addr == NULL) ||
800
      (!hostname) || (!hostname[0]) ||
801
      (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
802
    return ERR_VAL;
803
  }
804
 
805
#if LWIP_HAVE_LOOPIF
806
  if (strcmp(hostname,"localhost")==0) {
807
    addr->addr = INADDR_LOOPBACK;
808
    return ERR_OK;
809
  }
810
#endif /* LWIP_HAVE_LOOPIF */
811
 
812
  /* host name already in octet notation? set ip addr and return ERR_OK
813
   * already have this address cached? */
814
  if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) ||
815
      ((addr->addr = dns_lookup(hostname)) != 0)) {
816
    return ERR_OK;
817
  }
818
 
819
  /* queue query with specified callback */
820
  return dns_enqueue(hostname, found, callback_arg);
821
}
822
 
823
#endif /* LWIP_DNS */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.