Annotation of qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c, revision 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.