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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [ns/] [dns/] [current/] [include/] [dns_impl.inl] - Blame information for rev 856

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
#ifndef CYGONCE_NS_DNS_DNS_IMPL_H
2
#define CYGONCE_NS_DNS_DNS_IMPL_H
3
//=============================================================================
4
//
5
//      dns_impl.inl
6
//
7
//      DNS client code implementation.
8
//
9
//=============================================================================
10
// ####ECOSGPLCOPYRIGHTBEGIN####
11
// -------------------------------------------
12
// This file is part of eCos, the Embedded Configurable Operating System.
13
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
14
//
15
// eCos is free software; you can redistribute it and/or modify it under
16
// the terms of the GNU General Public License as published by the Free
17
// Software Foundation; either version 2 or (at your option) any later
18
// version.
19
//
20
// eCos is distributed in the hope that it will be useful, but WITHOUT
21
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23
// for more details.
24
//
25
// You should have received a copy of the GNU General Public License
26
// along with eCos; if not, write to the Free Software Foundation, Inc.,
27
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
28
//
29
// As a special exception, if other files instantiate templates or use
30
// macros or inline functions from this file, or you compile this file
31
// and link it with other works to produce a work based on this file,
32
// this file does not by itself cause the resulting work to be covered by
33
// the GNU General Public License. However the source code for this file
34
// must still be made available in accordance with section (3) of the GNU
35
// General Public License v2.
36
//
37
// This exception does not invalidate any other reasons why a work based
38
// on this file might be covered by the GNU General Public License.
39
// -------------------------------------------
40
// ####ECOSGPLCOPYRIGHTEND####
41
//=============================================================================
42
//#####DESCRIPTIONBEGIN####
43
//
44
// Author(s):   andrew.lunn
45
// Contributors:andrew.lunn, jskov
46
// Date:        2001-09-18
47
// Description: The code is kept in this separate file to allow it to be
48
//              used from RedBoot.
49
//
50
//####DESCRIPTIONEND####
51
//
52
//=============================================================================
53
 
54
#include 
55
 
56
/* Validate a hostname is legal as defined in RFC 1035 */
57
static int
58
valid_hostname(const char *hostname)
59
{
60
    const char * label;
61
    const char * label_end;
62
 
63
    if (!hostname) {
64
        return false;
65
    }
66
    label = hostname;
67
    while (*label) {
68
        if (!isalpha(*label))
69
            return false;
70
        label_end = strchr(label, (int)'.') - 1;
71
        if (label_end == (char *)-1) {
72
            label_end = strchr(label, (int)'\0') - 1;
73
        }
74
        while (label != label_end) {
75
            if (!isalnum(*label) && (*label != '-')) {
76
                return false;
77
            }
78
            label++;
79
        }
80
        label = label_end+1;            /* Move onto the . or the null. */
81
        if (*label == '.') {            /* Move over the . if there is one */
82
            label++;
83
        }
84
    }
85
    return true;
86
}
87
 
88
/* Build a qname structure. The structure consists of pairs of
89
   
90
   the length of the label. */
91
static int
92
build_qname(unsigned char *ptr, const char *hostname)
93
{
94
    const char *label = hostname;
95
    char *end_label;
96
    int total_len = 0;
97
    int len;
98
 
99
    while (*label) {
100
        end_label = strchr(label, (int)'.') - 1;
101
        if (end_label == (char *)-1) {
102
            end_label = strchr(label, (int)'\0') - 1;
103
        }
104
        len = end_label - label + 1;
105
        if (len > 63) {
106
            return -1;
107
        }
108
        *ptr++ = (char) len;            /* Put the length of the label */
109
        memcpy(ptr, label, len);        /* and now the label */
110
        ptr += len;
111
 
112
        total_len += len +1;
113
        label = end_label+1;            /* Move onto the . or the null. */
114
        if (*label == '.') {            /* Move over the . if there is one */
115
            label++;
116
        }
117
    }
118
    *ptr = 0;                           /* Add the last length of zero
119
                                           to mark the end */
120
    return (total_len+1);
121
}
122
 
123
/* Given a pointer to a qname, find the length of the qname. This is
124
   the number of bytes needed to represent the qname, not the length
125
   of the name. A qname is terminated by either a 00, or a pointer
126
   into another qname. This pointer has the top two bits set. */
127
static int
128
qname_len(unsigned char * qname)
129
{
130
    unsigned char * ptr = qname;
131
 
132
    while ((*ptr != 0) && ((*ptr & 0xc0) != 0xc0)) {
133
        ptr += *ptr + 1;
134
    }
135
    /* Pointers are two bytes */
136
    if ((*ptr & 0xc0) == 0xc0) {
137
        ptr++;
138
    }
139
    ptr++;                              /* Skip over the trailing byte */
140
 
141
    return (ptr - qname);
142
}
143
 
144
/* Build a real name from a qname. Alloc the memory needed and return
145
   it. Return NULL on error */
146
char *
147
real_name(unsigned char *msg, unsigned char *qname)
148
{
149
    unsigned char * ptr = qname;
150
    char * name;
151
    char * label;
152
    int len = 0;
153
    int offset;
154
 
155
    /* First pass works out the length of the name */
156
    while (*ptr != 0) {
157
        if ((*ptr & 0xc0) == 0xc0) {
158
            /* pointer to somewhere else. Follow the pointer */
159
            offset = ((*ptr & 0x3f) << 8) | *(ptr+1);
160
            ptr = msg + offset;
161
        } else {
162
            len += *ptr + 1;
163
            ptr += *ptr + 1;
164
        }
165
    }
166
 
167
    /* Now allocate the memory needed and copy the host name into it */
168
    name = alloc_string(len+1);
169
    if (name) {
170
        label = name;
171
        ptr = qname;
172
        while (*ptr != 0) {
173
            if ((*ptr & 0xc0) == 0xc0) {
174
                /* pointer to somewhere else. Follow the pointer */
175
                offset = ((*ptr & 0x3f) << 8) | *(ptr+1);
176
                ptr = msg + offset;
177
            } else {
178
                len = *ptr;
179
                memcpy(label, (ptr+1), len);
180
                label += len;
181
                *label++ = '.';
182
                ptr += *ptr + 1;
183
            }
184
        }
185
        *label = '\0';
186
    }
187
    return name;
188
}
189
 
190
/* Build a query message which can be sent to the server. If something
191
   goes wrong return -1, otherwise the length of the query message */
192
static int
193
build_query(const unsigned char * msg, const char * hostname, short rr_type)
194
{
195
    struct dns_header *dns_hdr;
196
    unsigned char *ptr;
197
    int len;
198
 
199
    /* Fill out the header */
200
    dns_hdr = (struct dns_header *) msg;
201
    dns_hdr->id = (cyg_uint16)htons(id++);
202
    dns_hdr->rd = true;
203
    dns_hdr->opcode = DNS_QUERY;
204
    dns_hdr->qdcount = htons(1);
205
 
206
    /* Now the question we want to ask */
207
    ptr = (unsigned char *)&dns_hdr[1];
208
 
209
    len = build_qname(ptr, hostname);
210
 
211
    if (len < 0) {
212
        h_errno = NO_RECOVERY;
213
        return -1;
214
    }
215
    ptr += len;
216
 
217
    /* Set the type and class fields */
218
    *ptr++ = (rr_type >> 8) & 0xff;
219
    *ptr++ = rr_type & 0xff;
220
    *ptr++ = (DNS_CLASS_IN >> 8) & 0xff;
221
    *ptr++ = DNS_CLASS_IN & 0xff;
222
 
223
    len = ptr - msg;
224
 
225
    return len;
226
}
227
 
228
/* Check if the hostname is actually of dot format. If so convert it
229
   and return host entity structure. If not, return NULL. */
230
static struct hostent *
231
dot_hostname(const char *hostname)
232
{
233
    struct hostent *hent = NULL;
234
    struct in_addr addr;
235
 
236
    if (inet_aton(hostname, &addr)) {
237
        hent = alloc_hent();
238
        if (hent) {
239
            memcpy(hent->h_addr_list[0], &addr, sizeof(struct in_addr));
240
            hent->h_addrtype = AF_INET;
241
            hent->h_length = sizeof(struct in_addr);
242
            hent->h_name = alloc_string(strlen(hostname)+1);
243
            if (!hent->h_name) {
244
                free_hent(hent);
245
                return NULL;
246
            }
247
            strcpy(hent->h_name, hostname);
248
        }
249
    }
250
    return hent;
251
}
252
 
253
#ifdef CYGPKG_NET_INET6
254
/* Check if the hostname is actually colon format of IPv6. If so convert it
255
   and return host entity structure. If not, return NULL. */
256
static struct hostent *
257
colon_hostname(const char *hostname)
258
{
259
  struct sockaddr_in6 addr;
260
  struct hostent *hent = NULL;
261
 
262
  if (inet_pton(AF_INET6, hostname, (void *)&addr)) {
263
    hent = alloc_hent();
264
    if (hent) {
265
      memcpy(hent->h_addr_list[0], &addr, sizeof(addr));
266
      hent->h_addrtype = AF_INET6;
267
      hent->h_length = sizeof(addr);
268
      hent->h_name = alloc_string(strlen(hostname)+1);
269
      if (!hent->h_name) {
270
        free_hent(hent);
271
        return NULL;
272
      }
273
      strcpy(hent->h_name, hostname);
274
    }
275
  }
276
  return hent;
277
}
278
#endif
279
 
280
/* Decode the answer from the server. Returns NULL if failed, or
281
   a hostent structure containing different data depending on the
282
   query type:
283
    DNS_TYPE_A:
284
      h_name:         a pointer to the hostname
285
      h_addr_list[0]: a pointer to in_addr structure
286
    DNS_TYPE_PTR:
287
      h_name:         a pointer to the hostname
288
      h_addr_list[0]: a pointer to an empty in_addr structure. Caller
289
                      must fill out!
290
*/
291
static struct hostent *
292
parse_answer(unsigned char * msg, short rr_type)
293
{
294
    static struct hostent *hent;
295
    struct dns_header *dns_hdr;
296
    struct resource_record rr, *rr_p = NULL;
297
    unsigned char *qname = NULL;
298
    unsigned char *ptr;
299
 
300
    dns_hdr = (struct dns_header *)msg;
301
 
302
    if (DNS_REPLY_NAME_ERROR == dns_hdr->rcode) {
303
        h_errno = HOST_NOT_FOUND;
304
        return NULL;
305
    }
306
 
307
    if ((dns_hdr->qr != 1) ||
308
        (dns_hdr->opcode != DNS_QUERY) ||
309
        (dns_hdr->rcode != DNS_REPLY_NOERR)) {
310
        h_errno = NO_RECOVERY;
311
        return NULL;
312
    }
313
 
314
    dns_hdr->ancount = ntohs(dns_hdr->ancount);
315
    dns_hdr->qdcount = ntohs(dns_hdr->qdcount);
316
    ptr = (unsigned char *)&dns_hdr[1];
317
 
318
    /* Skip over the query section */
319
    if (dns_hdr->qdcount > 0) {
320
        while (dns_hdr->qdcount) {
321
            ptr += qname_len(ptr);
322
            ptr += 4;                   /* skip type & class */
323
            dns_hdr->qdcount--;
324
        }
325
    }
326
    /* Skip over the answers resource records to find an answer of the
327
       correct type. */
328
    while (dns_hdr->ancount) {
329
        qname = ptr;
330
        ptr += qname_len(ptr);
331
        rr_p = (struct resource_record *)ptr;
332
        memcpy(&rr, ptr, sizeof(rr));
333
        if ((rr.rr_type == htons(rr_type)) &&
334
            (rr.class == htons(DNS_CLASS_IN))) {
335
            break;
336
        }
337
        ptr += sizeof(struct resource_record) - sizeof(rr.rdata) + ntohs(rr.rdlength);
338
        dns_hdr->ancount--;
339
    }
340
 
341
    /* If we found one. decode it */
342
    if (dns_hdr->ancount > 0) {
343
        hent = alloc_hent();
344
        if (!hent)
345
            return NULL;
346
        switch (rr_type) {
347
        case DNS_TYPE_A:
348
            hent->h_name = real_name(msg, qname);
349
            if (!hent->h_name) {
350
                free_hent(hent);
351
                return NULL;
352
            }
353
            memcpy(hent->h_addr_list[0], rr_p->rdata, sizeof(struct in_addr));
354
            hent->h_addrtype = AF_INET;
355
            hent->h_length = sizeof(struct in_addr);
356
            return hent;
357
        case DNS_TYPE_PTR:
358
            hent->h_name = real_name(msg, (unsigned char *)rr_p->rdata);
359
            if (!hent->h_name) {
360
                free_hent(hent);
361
                return NULL;
362
            }
363
            hent->h_addrtype = AF_INET;
364
            hent->h_length = sizeof(struct in_addr);
365
            return hent;
366
        default:
367
            free_hent(hent);
368
        }
369
    }
370
    h_errno = NO_DATA;
371
    return NULL;
372
}
373
 
374
/* Given an address, find out the hostname. */
375
struct hostent *
376
gethostbyaddr(const char *addr, int len, int type)
377
{
378
    unsigned char msg[MAXDNSMSGSIZE];
379
    char hostname[40];
380
    struct hostent * hent;
381
 
382
    CYG_REPORT_FUNCNAMETYPE( "gethostbyaddr", "returning %08x" );
383
    CYG_REPORT_FUNCARG3( "addr=%08x, len=%d, type=%d", addr, len, type );
384
 
385
    if ( !addr || 0 == len) {
386
        CYG_REPORT_RETVAL( NULL );
387
        return NULL;
388
    }
389
 
390
    CYG_CHECK_DATA_PTR( addr, "addr is not a valid pointer!" );
391
 
392
    /* Has the socket to the DNS server been opened? */
393
    if (s < 0) {
394
        CYG_REPORT_RETVAL( NULL );
395
        return NULL;
396
    }
397
 
398
    /* See if there is an answer to an old query. If so free the memory
399
       it uses. */
400
    free_stored_hent();
401
 
402
    /* Only IPv4 addresses accepted */
403
    if ((type != AF_INET) || (len != sizeof(struct in_addr))) {
404
        CYG_REPORT_RETVAL( NULL );
405
        return NULL;
406
    }
407
 
408
    cyg_drv_mutex_lock(&dns_mutex);
409
 
410
    /* Build the 'hostname' we want to lookup. */
411
    sprintf(hostname, "%d.%d.%d.%d.IN-ADDR.ARPA.",
412
            (unsigned char)addr[3],
413
            (unsigned char)addr[2],
414
            (unsigned char)addr[1],
415
            (unsigned char)addr[0]);
416
 
417
    memset(msg, 0, sizeof(msg));
418
 
419
    /* Build a PTR type request using the hostname */
420
    len = build_query(msg, hostname, DNS_TYPE_PTR);
421
    if (len < 0) {
422
        cyg_drv_mutex_unlock(&dns_mutex);
423
        CYG_REPORT_RETVAL( NULL );
424
        return NULL;
425
    }
426
 
427
    /* Send the request and wait for an answer */
428
    len = send_recv(msg, len, sizeof(msg));
429
    if (len < 0) {
430
        cyg_drv_mutex_unlock(&dns_mutex);
431
        CYG_REPORT_RETVAL( NULL );
432
        return NULL;
433
    }
434
 
435
    /* Fill in the missing address */
436
    hent = parse_answer(msg, DNS_TYPE_PTR);
437
    if (hent) {
438
        memcpy(hent->h_addr_list[0], addr, sizeof(struct in_addr));
439
        store_hent(hent);
440
    }
441
    cyg_drv_mutex_unlock(&dns_mutex);
442
 
443
    CYG_REPORT_RETVAL( hent );
444
    return hent;
445
}
446
 
447
/* Build message, send, receive and decode */
448
static struct hostent *
449
do_query(const char * hostname)
450
{
451
    unsigned char msg[MAXDNSMSGSIZE];
452
    int len;
453
 
454
    memset(msg, 0, sizeof(msg));
455
    len = build_query(msg, hostname, DNS_TYPE_A);
456
    if (len < 0) {
457
        return NULL;
458
    }
459
 
460
    /* Send the query and wait for an answer */
461
    len = send_recv(msg, len, sizeof(msg));
462
    if (len < 0) {
463
        return NULL;
464
    }
465
 
466
    /* Decode the answer */
467
    return parse_answer(msg, DNS_TYPE_A);
468
}
469
 
470
 
471
/* Given a hostname find out the IP address */
472
struct hostent *
473
gethostbyname(const char * hostname)
474
{
475
    char name[256];
476
    char * dot;
477
    struct hostent *hent;
478
 
479
    CYG_REPORT_FUNCNAMETYPE( "gethostbyname", "returning %08x" );
480
    CYG_REPORT_FUNCARG1( "hostname=%08x", hostname );
481
 
482
    if ( !hostname ) {
483
        CYG_REPORT_RETVAL( NULL );
484
        return NULL;
485
    }
486
 
487
    CYG_CHECK_DATA_PTR( hostname, "hostname is not a valid pointer!" );
488
 
489
    /* Has the socket to the DNS server been opened? */
490
    if (s < 0) {
491
        CYG_REPORT_RETVAL( NULL );
492
        return NULL;
493
    }
494
 
495
    /* See if there is an answer to an old query. If so free the memory
496
       it uses */
497
    free_stored_hent();
498
 
499
    if (!valid_hostname(hostname)) {
500
         /* It could be a dot address */
501
         if ((hent = dot_hostname(hostname)) != NULL) {
502
              store_hent(hent);
503
              CYG_REPORT_RETVAL( hent );
504
              return hent;
505
         }
506
#ifdef CYGPKG_NET_INET6
507
         /* It could be a colon seperated IPv6 address */
508
         if ((hent = colon_hostname(hostname)) != NULL) {
509
              store_hent(hent);
510
              CYG_REPORT_RETVAL( hent );
511
              return hent;
512
         }
513
#endif
514
         CYG_REPORT_RETVAL( hent );
515
         return hent;
516
    }
517
    cyg_drv_mutex_lock(&dns_mutex);
518
 
519
    if (domainname) {
520
        if ((strlen(hostname) + strlen(domainname)) > 254) {
521
            h_errno = NO_RECOVERY;
522
            cyg_drv_mutex_unlock(&dns_mutex);
523
            CYG_REPORT_RETVAL( NULL );
524
            return NULL;
525
        }
526
        strcpy(name, hostname);
527
        strcat(name, ".");
528
        strcat(name, domainname);
529
    }
530
 
531
        /* If the hostname ends with . it a FQDN. Don't bother adding the
532
    domainname. If it does not contain a . , try appending with the
533
    domainname first. If it does have a . , try without a domain name
534
    first. */
535
 
536
    dot = strrchr(hostname,'.');
537
    if (dot) {
538
        if (*(dot+1) == '\0') {
539
            /* FQDN */
540
            hent = do_query(hostname);
541
        } else {
542
          /* Dot somewhere */
543
          hent = do_query(hostname);
544
          if (domainname && (hent == NULL)) {
545
            hent = do_query(name);
546
          }
547
        }
548
    } else {
549
    /* No Dot. Try adding domainname first */
550
        hent = NULL;
551
        if (domainname) {
552
            hent = do_query(name);
553
        }
554
        if (hent == NULL) {
555
            hent = do_query(hostname);
556
        }
557
    }
558
 
559
    cyg_drv_mutex_unlock(&dns_mutex);
560
    store_hent(hent);
561
    CYG_REPORT_RETVAL( hent );
562
    return hent;
563
}
564
 
565
/* Set the domain names, as used by the DNS server */
566
int
567
setdomainname(const char *name, size_t len)
568
{
569
    char * ptr;
570
    int length;
571
 
572
    CYG_REPORT_FUNCNAMETYPE( "setdomainname", "returning %d" );
573
    CYG_REPORT_FUNCARG2( "name=%08x, len=%d", name, len );
574
 
575
    if ((len < 0) || (len > 255)) {
576
        h_errno = NO_RECOVERY;
577
        CYG_REPORT_RETVAL( -1 );
578
        return -1;
579
    }
580
    if (len != 0) {
581
        CYG_CHECK_DATA_PTR( name, "name is not a valid pointer!" );
582
        length = strlen(name);
583
        if (length > len) {
584
            h_errno = NO_RECOVERY;
585
            CYG_REPORT_RETVAL( -1 );
586
            return -1;
587
        }
588
        if (name[length-1] != '.') {
589
                length++;
590
        }
591
        ptr = alloc_string(length+1);
592
        if (!ptr) {
593
            h_errno = NO_RECOVERY;
594
            CYG_REPORT_RETVAL( -1 );
595
            return -1;
596
        }
597
        memcpy(ptr, name, len);
598
        if (name[length-1] != '.') {
599
            ptr[length-1] = '.';
600
            ptr[length] = '\0';
601
        } else {
602
            ptr[len]=0;
603
        }
604
    } else {
605
        ptr = NULL;
606
    }
607
 
608
    if (domainname) {
609
        free_string(domainname);
610
    }
611
    domainname = ptr;
612
    CYG_REPORT_RETVAL( 0 );
613
    return 0;
614
}
615
 
616
/* Return the domain name as used by the DNS server */
617
int
618
getdomainname(char *name, size_t len)
619
{
620
    CYG_REPORT_FUNCNAMETYPE( "getdomainname", "returning %d" );
621
    CYG_REPORT_FUNCARG2( "name=%08x, len=%d", name, len );
622
 
623
    if ( !name || 0 == len) {
624
        CYG_REPORT_RETVAL( -1 );
625
        return -1;
626
    }
627
 
628
    CYG_CHECK_DATA_PTR( name, "name is not a valid pointer!" );
629
 
630
    /* No domainname set, return a 0 */
631
    if (!domainname) {
632
        if (len == 0) {
633
            h_errno = HOST_NOT_FOUND;
634
            CYG_REPORT_RETVAL( -1 );
635
            return -1;
636
        }
637
        name[0]='\0';
638
    } else {
639
        if ((strlen(domainname) + 1) > len) {
640
            h_errno = NO_RECOVERY;
641
            CYG_REPORT_RETVAL( -1 );
642
            return -1;
643
        }
644
        strncpy(name, domainname, len);
645
    }
646
    CYG_REPORT_RETVAL( 0 );
647
    return 0;
648
}
649
 
650
int h_errno = DNS_SUCCESS;
651
 
652
const char*
653
hstrerror(int err)
654
{
655
    CYG_REPORT_FUNCNAMETYPE( "hstrerror", "returning %08x" );
656
    CYG_REPORT_FUNCARG1( "err=%d", err );
657
 
658
    switch (err) {
659
    case DNS_SUCCESS:
660
        return "No error";
661
    case HOST_NOT_FOUND:
662
        return "No such host is known";
663
    case TRY_AGAIN:
664
        return "Timeout";
665
    case NO_RECOVERY:
666
        return "Server failure or invalid input";
667
    case NO_DATA:
668
        return "No data for type";
669
    default:
670
        return "Uknown error";
671
    }
672
}
673
 
674
//-----------------------------------------------------------------------------
675
#endif // CYGONCE_NS_DNS_DNS_IMPL_H
676
// End of dns_impl.h

powered by: WebSVN 2.1.0

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