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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [ns/] [dns/] [v2_0/] [include/] [dns_impl.inl] - Blame information for rev 174

Details | Compare with Previous | View Log

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