Annotation of qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c, revision 1.1.1.1

1.1       root        1: /******************************************************************************
                      2:  * Copyright (c) 2004, 2008 IBM Corporation
                      3:  * All rights reserved.
                      4:  * This program and the accompanying materials
                      5:  * are made available under the terms of the BSD License
                      6:  * which accompanies this distribution, and is available at
                      7:  * http://www.opensource.org/licenses/bsd-license.php
                      8:  *
                      9:  * Contributors:
                     10:  *     IBM Corporation - initial implementation
                     11:  *****************************************************************************/
                     12: 
                     13: /*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
                     14: 
                     15: #include <dns.h>
                     16: #include <stdio.h>
                     17: #include <string.h>
                     18: #include <time.h>
                     19: #include <sys/socket.h>
                     20: 
                     21: #include <ethernet.h>
                     22: #include <ipv4.h>
                     23: #include <udp.h>
                     24: 
                     25: #define DNS_FLAG_MSGTYPE    0xF800     /**< Message type mask (opcode) */
                     26: #define DNS_FLAG_SQUERY     0x0000     /**< Standard query type        */
                     27: #define DNS_FLAG_SRESPONSE  0x8000     /**< Standard response type     */
                     28: #define DNS_FLAG_RD         0x0100  /**< Recursion desired flag     */
                     29: #define DNS_FLAG_RCODE      0x000F     /**< Response code mask
                     30:                                          (stores err.cond.) code    */
                     31: #define DNS_RCODE_NERROR    0       /**< "No errors" code           */
                     32: 
                     33: #define DNS_QTYPE_A         1       /**< A 32-bit IP record type */
                     34: #define DNS_QTYPE_CNAME     5       /**< Canonical name record type */
                     35: 
                     36: #define DNS_QCLASS_IN       1       /**< Query class for internet msgs */
                     37: 
                     38: /** \struct dnshdr
                     39:  *  A header for DNS-messages (see RFC 1035, paragraph 4.1.1).
                     40:  *  <p>
                     41:  *  DNS-message consist of DNS-header and 4 optional sections,
                     42:  *  arranged in the following order:<ul>
                     43:  *    <li> DNS-header
                     44:  *    <li> question section
                     45:  *    <li> answer section
                     46:  *    <li> authority section
                     47:  *    <li> additional section
                     48:  *  </ul>
                     49:  */
                     50: struct dnshdr {
                     51:        uint16_t   id;      /**< an identifier used to match up replies */
                     52:        uint16_t   flags;   /**< contains op_code, err_code, etc. */
                     53:        uint16_t   qdcount; /**< specifies the number of entries in the 
                     54:                                 question section */
                     55:        uint16_t   ancount; /**< specifies the number of entries in the 
                     56:                                 answer section */
                     57:        uint16_t   nscount; /**< specifies the number of entries in the
                     58:                                 authority section */
                     59:        uint16_t   arcount; /**< specifies the number of entries in the 
                     60:                                 additional section */
                     61: };
                     62: 
                     63: 
                     64: /*>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
                     65: 
                     66: static void
                     67: dns_send_query(int8_t * domain_name);
                     68: 
                     69: static void
                     70: fill_dnshdr(uint8_t * packet, int8_t * domain_name);
                     71: 
                     72: static uint8_t *
                     73: dns_extract_name(uint8_t * dnsh, int8_t * head, int8_t * domain_name);
                     74: 
                     75: static int8_t
                     76: urltohost(char * url, char * host_name);
                     77: 
                     78: static int8_t
                     79: hosttodomain(char * host_name, char * domain_name);
                     80: 
                     81: /*>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
                     82: 
                     83: static uint8_t ether_packet[ETH_MTU_SIZE];
                     84: static int32_t dns_server_ip     = 0;
                     85: static int32_t dns_result_ip     = 0;
                     86: static int8_t  dns_error         = 0;        /**< Stores error code or 0 */
                     87: static int8_t  dns_domain_name[0x100];       /**< Raw domain name        */
                     88: static int8_t  dns_domain_cname[0x100];      /**< Canonical domain name  */
                     89: 
                     90: /*>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
                     91: 
                     92: /**
                     93:  * DNS: Initialize the environment for DNS client.
                     94:  *      To perfrom DNS-queries use the function dns_get_ip.
                     95:  *
                     96:  * @param  device_socket a socket number used to send and recieve packets
                     97:  * @param  server_ip     DNS-server IPv4 address (e.g. 127.0.0.1)
                     98:  * @return               TRUE in case of successful initialization;
                     99:  *                       FALSE in case of fault (e.g. can't obtain MAC).
                    100:  * @see                  dns_get_ip
                    101:  */
                    102: int8_t
                    103: dns_init(uint32_t _dns_server_ip) {
                    104:        dns_server_ip = _dns_server_ip;
                    105:        return 0;
                    106: }
                    107: 
                    108: /**
                    109:  * DNS: For given URL retrieves IPv4 from DNS-server.
                    110:  *      <p>
                    111:  *      URL can be given in one of the following form: <ul>
                    112:  *      <li> scheme with full path with (without) user and password
                    113:  *           <br>(e.g. "http://user:[email protected]/url-path");
                    114:  *      <li> host name with url-path
                    115:  *           <br>(e.g. "www.host.org/url-path");
                    116:  *      <li> nothing but host name
                    117:  *           <br>(e.g. "www.host.org");
                    118:  *      </ul>
                    119:  *
                    120:  * @param  url       the URL to be resolved
                    121:  * @param  domain_ip In case of SUCCESS stores extracted IP.
                    122:  *                   In case of FAULT stores zeros (0.0.0.0).
                    123:  * @return           TRUE - IP successfuly retrieved;
                    124:  *                   FALSE - error condition occurs.
                    125:  */
                    126: int8_t
                    127: dns_get_ip(int8_t * url, uint32_t * domain_ip) {
                    128:        /* this counter is used so that we abort after 30 DNS request */
                    129:        int32_t i;
                    130:        /* this buffer stores host name retrieved from url */
                    131:        static int8_t host_name[0x100];
                    132: 
                    133:        (* domain_ip) = 0;
                    134: 
                    135:        // Retrieve host name from URL
                    136:        if (!urltohost((char *) url, (char *) host_name)) {
                    137:                printf("\nERROR:\t\t\tBad URL!\n");
                    138:                return 0;
                    139:        }
                    140: 
                    141:        // Reformat host name into a series of labels
                    142:        if (!hosttodomain((char *) host_name, (char *) dns_domain_name)) {
                    143:                printf("\nERROR:\t\t\tBad host name!\n");
                    144:                return 0;
                    145:        }
                    146: 
                    147:        // Check if DNS server is presented and accessable
                    148:        if (dns_server_ip == 0) {
                    149:                printf("\nERROR:\t\t\tCan't resolve domain name "
                    150:                       "(DNS server is not presented)!\n");
                    151:                return 0;
                    152:        }
                    153: 
                    154:        // Use DNS-server to obtain IP
                    155:        dns_result_ip = 0;
                    156:        dns_error     = 0;
                    157:        strcpy((char *) dns_domain_cname, "");
                    158: 
                    159:        for(i = 0; i < 30; ++i) {
                    160:                // Use canonical name in case we obtained it
                    161:                if (strlen((char *) dns_domain_cname))
                    162:                  dns_send_query(dns_domain_cname);
                    163:                else
                    164:                  dns_send_query(dns_domain_name);
                    165: 
                    166:                // setting up a timer with a timeout of one seconds
                    167:                set_timer(TICKS_SEC);
                    168:                do {
                    169:                        receive_ether();
                    170:                        if (dns_error)
                    171:                                return 0; // FALSE - error
                    172:                        if (dns_result_ip != 0) {
                    173:                                (* domain_ip) = dns_result_ip;
                    174:                                return 1; // TRUE - success (domain IP retrieved)
                    175:                        }
                    176:                } while (get_timer() > 0);
                    177:        }
                    178: 
                    179:        printf("\nGiving up after %d DNS requests\n", i);
                    180:        return 0; // FALSE - domain name wasn't retrieved
                    181: }
                    182: 
                    183: /**
                    184:  * DNS: Handles DNS-messages according to Receive-handle diagram.
                    185:  *      Sets dns_result_ip for given dns_domain_name (see dns_get_ip)
                    186:  *      or signals error condition occurs during DNS-resolving proccess
                    187:  *      by setting dns_error flag.
                    188:  *
                    189:  * @param  packet     DNS-packet to be handled
                    190:  * @param  packetsize length of the packet
                    191:  * @return            ZERO - packet handled successfully;
                    192:  *                    NON ZERO - packet was not handled (e.g. bad format)
                    193:  * @see               dns_get_ip
                    194:  * @see               receive_ether
                    195:  * @see               dnshdr
                    196:  */
                    197: int32_t
                    198: handle_dns(uint8_t * packet, int32_t packetsize) {
                    199:        struct dnshdr * dnsh = (struct dnshdr *) packet;
                    200:        uint8_t * resp_section = packet + sizeof(struct dnshdr);
                    201:        /* This string stores domain name from DNS-packets */
                    202:        static int8_t handle_domain_name[0x100]; 
                    203:        int i;
                    204: 
                    205:        // verify ID - is it response for our query?
                    206:        if (dnsh -> id != htons(0x1234))
                    207:                return 0;
                    208: 
                    209:        // Is it DNS response?
                    210:        if ((dnsh -> flags & htons(DNS_FLAG_MSGTYPE)) != htons(DNS_FLAG_SRESPONSE))
                    211:                return 0;
                    212: 
                    213:        // Is error condition occurs? (check error field in incoming packet)
                    214:        if ((dnsh -> flags & htons(DNS_FLAG_RCODE)) != DNS_RCODE_NERROR) {
                    215:                dns_error = 1;
                    216:                return 0;
                    217:        }
                    218: 
                    219:        /*        Pass all (qdcount) records in question section         */
                    220: 
                    221:        for (i = 0; i < htons(dnsh -> qdcount); i++) {
                    222:                // pass QNAME
                    223:                resp_section = dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section,
                    224:                                                handle_domain_name);
                    225:                if (resp_section == NULL) {
                    226:                        return -1; // incorrect domain name (bad packet)
                    227:                }
                    228:                // pass QTYPE & QCLASS
                    229:                resp_section += 4;
                    230:        }
                    231: 
                    232:        /*       Handle all (ancount) records in answer section          */
                    233: 
                    234:        for (i = 0; i < htons(dnsh -> ancount); i++) {
                    235:                // retrieve domain name from the packet
                    236:                resp_section = dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section,
                    237:                                                handle_domain_name);
                    238: 
                    239:                if (resp_section == NULL) {
                    240:                        return -1; // incorrect domain name (bad packet)
                    241:                }
                    242: 
                    243:                // Check the class of the query (should be IN for Internet)
                    244:                if (* (uint16_t *) (resp_section + 2) == htons(DNS_QCLASS_IN)) {
                    245:                        // check if retrieved name fit raw or canonical domain name
                    246:                        if (!strcmp((char *) handle_domain_name, (char *) dns_domain_name) ||
                    247:                                !strcmp((char *) handle_domain_name, (char *) dns_domain_cname)) {
                    248:                                switch (htons(* (uint16_t *) resp_section)) {
                    249: 
                    250:                                case DNS_QTYPE_A :
                    251:                                        // rdata contains IP
                    252:                                        dns_result_ip = htonl(* (uint32_t *) (resp_section + 10));
                    253:                                        return 0; // IP successfully obtained
                    254: 
                    255:                                case DNS_QTYPE_CNAME :
                    256:                                        // rdata contains canonical name, store it for further requests
                    257:                                        if (dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section + 10,
                    258:                                                             dns_domain_cname) == NULL) {
                    259:                                                // incorrect domain name (bad packet)
                    260:                                                return -1;
                    261:                                        }
                    262:                                        break;
                    263:                                }
                    264:                        }
                    265:                        // continue with next record in answer section
                    266:                        resp_section += htons(* (uint16_t *) (resp_section + 8)) + 10;
                    267:                }
                    268:        }
                    269:        return 0; // Packet succesfuly handled but IP wasn't obtained
                    270: }
                    271: 
                    272: /**
                    273:  * DNS: Sends a standard DNS-query (read request package) to a DNS-server.
                    274:  *      DNS-server respones with host IP or signals some error condition.
                    275:  *      Responses from the server are handled by handle_dns function.
                    276:  *
                    277:  * @param  domain_name the domain name given as series of labels preceded
                    278:  *                     with length(label) and terminated with 0  
                    279:  *                     <br>(e.g. "\3,w,w,w,\4,h,o,s,t,\3,o,r,g,\0")
                    280:  * @see                handle_dns
                    281:  */
                    282: static void
                    283: dns_send_query(int8_t * domain_name) {
                    284:        int qry_len = strlen((char *) domain_name) + 5;
                    285: 
                    286:        uint32_t packetsize = sizeof(struct iphdr) +
                    287:                              sizeof(struct udphdr) + sizeof(struct dnshdr) +
                    288:                              qry_len;
                    289: 
                    290:        memset(ether_packet, 0, packetsize);
                    291:        fill_dnshdr(&ether_packet[
                    292:                    sizeof(struct iphdr) + sizeof(struct udphdr)],
                    293:                    domain_name);
                    294:        fill_udphdr(&ether_packet[
                    295:                    sizeof(struct iphdr)], sizeof(struct dnshdr) +
                    296:                    sizeof(struct udphdr) + qry_len,
                    297:                    UDPPORT_DNSC, UDPPORT_DNSS);
                    298:        fill_iphdr(ether_packet,
                    299:                   sizeof(struct dnshdr) + sizeof(struct udphdr) +
                    300:                   sizeof(struct iphdr) + qry_len,
                    301:                   IPTYPE_UDP, 0, dns_server_ip);
                    302: 
                    303:        send_ipv4(ether_packet, packetsize);
                    304: }
                    305: 
                    306: /**
                    307:  * DNS: Creates standard DNS-query package. Places DNS-header
                    308:  *      and question section in a packet and fills it with
                    309:  *      corresponding information.
                    310:  *      <p>
                    311:  *      Use this function with similar functions for other network layers
                    312:  *      (fill_udphdr, fill_iphdr, fill_ethhdr).
                    313:  *
                    314:  * @param  packet      Points to the place where ARP-header must be placed.
                    315:  * @param  domain_name the domain name given as series of labels preceded
                    316:  *                     with length(label) and terminated with 0  
                    317:  *                     <br>(e.g. "\3,w,w,w,\4,h,o,s,t,\3,o,r,g,\0")
                    318:  * @see                fill_udphdr
                    319:  * @see                fill_iphdr
                    320:  * @see                fill_ethhdr
                    321:  */
                    322: static void
                    323: fill_dnshdr(uint8_t * packet, int8_t * domain_name) {
                    324:        struct dnshdr * dnsh = (struct dnshdr *) packet;
                    325:        uint8_t * qry_section = packet + sizeof(struct dnshdr);
                    326: 
                    327:        dnsh -> id = htons(0x1234);
                    328:        dnsh -> flags = htons(DNS_FLAG_SQUERY) | htons(DNS_FLAG_RD);
                    329:        dnsh -> qdcount = htons(1);
                    330: 
                    331:        strcpy((char *) qry_section, (char *) domain_name);
                    332:        qry_section += strlen((char *) domain_name) + 1;
                    333: 
                    334:        // fill QTYPE (ask for IP)
                    335:        * (uint16_t *) qry_section = htons(DNS_QTYPE_A);
                    336:        qry_section += 2;
                    337:        // fill QCLASS (IN is a standard class for Internet)
                    338:        * (uint16_t *) qry_section = htons(DNS_QCLASS_IN);
                    339: }
                    340: 
                    341: /**
                    342:  * DNS: Extracts domain name from the question or answer section of
                    343:  *      the DNS-message. This function is need to support message  
                    344:  *      compression requirement (see RFC 1035, paragraph 4.1.4).
                    345:  *
                    346:  * @param  dnsh        Points at the DNS-header.
                    347:  * @param  head        Points at the beginning of the domain_name
                    348:  *                     which has to be extracted.
                    349:  * @param  domain_name In case of SUCCESS this string stores extracted name.
                    350:  *                     In case of FAULT this string is empty.
                    351:  * @return             NULL in case of FAULT (domain name > 255 octets); 
                    352:  *                     otherwise pointer to the data following the name.
                    353:  * @see                dnshdr
                    354:  */
                    355: static uint8_t *
                    356: dns_extract_name(uint8_t * dnsh, int8_t * head, int8_t * domain_name) {
                    357:        int8_t * tail = domain_name;
                    358:        int8_t * ptr = head;
                    359:        int8_t * next_section = NULL;
                    360: 
                    361:        while (1) {
                    362:                if ((ptr[0] & 0xC0) == 0xC0) {
                    363:                        // message compressed (reference is used)
                    364:                        next_section = ptr + 2;
                    365:                        ptr = (int8_t *) dnsh + (htons(* (uint16_t *) ptr) & 0x3FFF);
                    366:                        continue;
                    367:                }
                    368:                if (ptr[0] == 0) {
                    369:                        // message termination
                    370:                        tail[0] = 0;
                    371:                        ptr += 1;
                    372:                        break;
                    373:                }
                    374:                // maximum length for domain name is 255 octets w/o termination sym
                    375:                if (tail - domain_name + ptr[0] + 1 > 255) {
                    376:                        strcpy((char *) domain_name, "");
                    377:                        return NULL;
                    378:                }
                    379:                memcpy(tail, ptr, ptr[0] + 1);
                    380:                tail += ptr[0] + 1;
                    381:                ptr += ptr[0] + 1;
                    382:        }
                    383: 
                    384:        if (next_section == NULL)
                    385:                next_section = ptr;
                    386: 
                    387:        return (uint8_t *) next_section;
                    388: }
                    389: 
                    390: /**
                    391:  * DNS: Parses URL and returns host name.
                    392:  *      Input string can be given as: <ul>
                    393:  *      <li> scheme with full path with (without) user and password
                    394:  *           <br>(e.g. "http://user:[email protected]/url-path");
                    395:  *      <li> host name with url-path
                    396:  *           <br>(e.g. "www.host.org/url-path");
                    397:  *      <li> nothing but host name
                    398:  *           <br>(e.g. "www.host.org");
                    399:  *      </ul>
                    400:  *
                    401:  * @param  url        string that stores incoming URL
                    402:  * @param  host_name  In case of SUCCESS this string stores the host name,
                    403:  *                    In case of FAULT this string is empty.
                    404:  * @return            TRUE - host name retrieved,
                    405:  *                    FALSE - host name > 255 octets or empty.
                    406:  */
                    407: static int8_t
                    408: urltohost(char * url, char * host_name) {
                    409:        uint16_t length1;
                    410:        uint16_t length2;
                    411: 
                    412:        strcpy(host_name, "");
                    413: 
                    414:        if (strstr(url, "://") != NULL)
                    415:                url = strstr(url, "//") + 2;  // URL
                    416: 
                    417:        if (strstr(url, "@") != NULL) // truncate user & password
                    418:                url = strstr(url, "@") + 1;
                    419: 
                    420:        if (strstr(url, "/") != NULL) // truncate url path
                    421:                length1 = strstr(url, "/") - url;
                    422:        else
                    423:                length1 = strlen(url);
                    424: 
                    425:        if (strstr(url, ":") != NULL) // truncate port path
                    426:                length2 = strstr(url, ":") - url;
                    427:        else
                    428:                length2 = strlen(url);
                    429: 
                    430:        if(length1 > length2)
                    431:                length1 = length2;
                    432: 
                    433:        if (length1 == 0)
                    434:                return 0; // string is empty
                    435:        if(length1 >= 256)
                    436:                return 0; // host name is too big
                    437: 
                    438:        strncpy(host_name, url, length1);
                    439:        host_name[length1] = 0;
                    440: 
                    441:        return 1; // Host name is retrieved
                    442: }
                    443: 
                    444: /**
                    445:  * DNS: Transforms host name string into a series of labels
                    446:  *      each of them preceded with length(label). 0 is a terminator.
                    447:  *      "www.domain.dom" -> "\3,w,w,w,\6,d,o,m,a,i,n,\3,c,o,m,\0"
                    448:  *      <p>
                    449:  *      This format is used in DNS-messages.
                    450:  *
                    451:  * @param  host_name   incoming string with the host name
                    452:  * @param  domain_name resulting string with series of labels
                    453:  *                     or empty string in case of FAULT
                    454:  * @return             TRUE - host name transformed,
                    455:  *                     FALSE - host name > 255 octets or label > 63 octets.
                    456:  */
                    457: static int8_t
                    458: hosttodomain(char * host_name, char * domain_name) {
                    459:        char * domain_iter = domain_name;
                    460:        char * host_iter   = host_name;
                    461: 
                    462:        strcpy(domain_name, "");
                    463: 
                    464:        if(strlen(host_name) > 255)
                    465:                return 0; // invalid host name (refer to RFC 1035)
                    466: 
                    467:        for(; 1; ++host_iter) {
                    468:                if(*host_iter != '.' && *host_iter != 0)
                    469:                        continue;
                    470:                *domain_iter = host_iter - host_name;
                    471:                if (*domain_iter > 63) {
                    472:                        strcpy(domain_name, "");
                    473:                        return 0; // invalid host name (refer to RFC 1035)
                    474:                }
                    475:                ++domain_iter;
                    476:                strncpy(domain_iter, host_name, host_iter - host_name);
                    477:                domain_iter += (host_iter - host_name);
                    478:                if(*host_iter == 0) {
                    479:                        *domain_iter = 0;
                    480:                        break;
                    481:                }
                    482:                host_name = host_iter + 1;
                    483:        }
                    484:        return 1; // ok
                    485: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.