Annotation of qemu/roms/ipxe/src/net/udp/dns.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2006 Michael Brown <[email protected]>.
        !             3:  *
        !             4:  * Portions copyright (C) 2004 Anselm M. Hoffmeister
        !             5:  * <[email protected]>.
        !             6:  *
        !             7:  * This program is free software; you can redistribute it and/or
        !             8:  * modify it under the terms of the GNU General Public License as
        !             9:  * published by the Free Software Foundation; either version 2 of the
        !            10:  * License, or any later version.
        !            11:  *
        !            12:  * This program is distributed in the hope that it will be useful, but
        !            13:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            15:  * General Public License for more details.
        !            16:  *
        !            17:  * You should have received a copy of the GNU General Public License
        !            18:  * along with this program; if not, write to the Free Software
        !            19:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            20:  */
        !            21: 
        !            22: FILE_LICENCE ( GPL2_OR_LATER );
        !            23: 
        !            24: #include <stdint.h>
        !            25: #include <stdlib.h>
        !            26: #include <string.h>
        !            27: #include <stdio.h>
        !            28: #include <errno.h>
        !            29: #include <byteswap.h>
        !            30: #include <ipxe/refcnt.h>
        !            31: #include <ipxe/iobuf.h>
        !            32: #include <ipxe/xfer.h>
        !            33: #include <ipxe/open.h>
        !            34: #include <ipxe/resolv.h>
        !            35: #include <ipxe/retry.h>
        !            36: #include <ipxe/tcpip.h>
        !            37: #include <ipxe/settings.h>
        !            38: #include <ipxe/features.h>
        !            39: #include <ipxe/dns.h>
        !            40: 
        !            41: /** @file
        !            42:  *
        !            43:  * DNS protocol
        !            44:  *
        !            45:  */
        !            46: 
        !            47: FEATURE ( FEATURE_PROTOCOL, "DNS", DHCP_EB_FEATURE_DNS, 1 );
        !            48: 
        !            49: /* Disambiguate the various error causes */
        !            50: #define ENXIO_NO_RECORD __einfo_error ( EINFO_ENXIO_NO_RECORD )
        !            51: #define EINFO_ENXIO_NO_RECORD \
        !            52:        __einfo_uniqify ( EINFO_ENXIO, 0x01, "DNS name does not exist" )
        !            53: #define ENXIO_NO_NAMESERVER __einfo_error ( EINFO_ENXIO_NO_NAMESERVER )
        !            54: #define EINFO_ENXIO_NO_NAMESERVER \
        !            55:        __einfo_uniqify ( EINFO_ENXIO, 0x02, "No DNS servers available" )
        !            56: 
        !            57: /** The DNS server */
        !            58: static struct sockaddr_tcpip nameserver = {
        !            59:        .st_port = htons ( DNS_PORT ),
        !            60: };
        !            61: 
        !            62: /** The local domain */
        !            63: static char *localdomain;
        !            64: 
        !            65: /** A DNS request */
        !            66: struct dns_request {
        !            67:        /** Reference counter */
        !            68:        struct refcnt refcnt;
        !            69:        /** Name resolution interface */
        !            70:        struct interface resolv;
        !            71:        /** Data transfer interface */
        !            72:        struct interface socket;
        !            73:        /** Retry timer */
        !            74:        struct retry_timer timer;
        !            75: 
        !            76:        /** Socket address to fill in with resolved address */
        !            77:        struct sockaddr sa;
        !            78:        /** Current query packet */
        !            79:        struct dns_query query;
        !            80:        /** Location of query info structure within current packet
        !            81:         *
        !            82:         * The query info structure is located immediately after the
        !            83:         * compressed name.
        !            84:         */
        !            85:        struct dns_query_info *qinfo;
        !            86:        /** Recursion counter */
        !            87:        unsigned int recursion;
        !            88: };
        !            89: 
        !            90: /**
        !            91:  * Mark DNS request as complete
        !            92:  *
        !            93:  * @v dns              DNS request
        !            94:  * @v rc               Return status code
        !            95:  */
        !            96: static void dns_done ( struct dns_request *dns, int rc ) {
        !            97: 
        !            98:        /* Stop the retry timer */
        !            99:        stop_timer ( &dns->timer );
        !           100: 
        !           101:        /* Shut down interfaces */
        !           102:        intf_shutdown ( &dns->socket, rc );
        !           103:        intf_shutdown ( &dns->resolv, rc );
        !           104: }
        !           105: 
        !           106: /**
        !           107:  * Compare DNS reply name against the query name from the original request
        !           108:  *
        !           109:  * @v dns              DNS request
        !           110:  * @v reply            DNS reply
        !           111:  * @v rname            Reply name
        !           112:  * @ret        zero            Names match
        !           113:  * @ret non-zero       Names do not match
        !           114:  */
        !           115: static int dns_name_cmp ( struct dns_request *dns,
        !           116:                          const struct dns_header *reply, 
        !           117:                          const char *rname ) {
        !           118:        const char *qname = dns->query.payload;
        !           119:        int i;
        !           120: 
        !           121:        while ( 1 ) {
        !           122:                /* Obtain next section of rname */
        !           123:                while ( ( *rname ) & 0xc0 ) {
        !           124:                        rname = ( ( ( char * ) reply ) +
        !           125:                                  ( ntohs( *((uint16_t *)rname) ) & ~0xc000 ));
        !           126:                }
        !           127:                /* Check that lengths match */
        !           128:                if ( *rname != *qname )
        !           129:                        return -1;
        !           130:                /* If length is zero, we have reached the end */
        !           131:                if ( ! *qname )
        !           132:                        return 0;
        !           133:                /* Check that data matches */
        !           134:                for ( i = *qname + 1; i > 0 ; i-- ) {
        !           135:                        if ( *(rname++) != *(qname++) )
        !           136:                                return -1;
        !           137:                }
        !           138:        }
        !           139: }
        !           140: 
        !           141: /**
        !           142:  * Skip over a (possibly compressed) DNS name
        !           143:  *
        !           144:  * @v name             DNS name
        !           145:  * @ret name           Next DNS name
        !           146:  */
        !           147: static const char * dns_skip_name ( const char *name ) {
        !           148:        while ( 1 ) {
        !           149:                if ( ! *name ) {
        !           150:                        /* End of name */
        !           151:                        return ( name + 1);
        !           152:                }
        !           153:                if ( *name & 0xc0 ) {
        !           154:                        /* Start of a compressed name */
        !           155:                        return ( name + 2 );
        !           156:                }
        !           157:                /* Uncompressed name portion */
        !           158:                name += *name + 1;
        !           159:        }
        !           160: }
        !           161: 
        !           162: /**
        !           163:  * Find an RR in a reply packet corresponding to our query
        !           164:  *
        !           165:  * @v dns              DNS request
        !           166:  * @v reply            DNS reply
        !           167:  * @ret rr             DNS RR, or NULL if not found
        !           168:  */
        !           169: static union dns_rr_info * dns_find_rr ( struct dns_request *dns,
        !           170:                                         const struct dns_header *reply ) {
        !           171:        int i, cmp;
        !           172:        const char *p = ( ( char * ) reply ) + sizeof ( struct dns_header );
        !           173:        union dns_rr_info *rr_info;
        !           174: 
        !           175:        /* Skip over the questions section */
        !           176:        for ( i = ntohs ( reply->qdcount ) ; i > 0 ; i-- ) {
        !           177:                p = dns_skip_name ( p ) + sizeof ( struct dns_query_info );
        !           178:        }
        !           179: 
        !           180:        /* Process the answers section */
        !           181:        for ( i = ntohs ( reply->ancount ) ; i > 0 ; i-- ) {
        !           182:                cmp = dns_name_cmp ( dns, reply, p );
        !           183:                p = dns_skip_name ( p );
        !           184:                rr_info = ( ( union dns_rr_info * ) p );
        !           185:                if ( cmp == 0 )
        !           186:                        return rr_info;
        !           187:                p += ( sizeof ( rr_info->common ) +
        !           188:                       ntohs ( rr_info->common.rdlength ) );
        !           189:        }
        !           190: 
        !           191:        return NULL;
        !           192: }
        !           193: 
        !           194: /**
        !           195:  * Append DHCP domain name if available and name is not fully qualified
        !           196:  *
        !           197:  * @v string           Name as a NUL-terminated string
        !           198:  * @ret fqdn           Fully-qualified domain name, malloc'd copy
        !           199:  *
        !           200:  * The caller must free fqdn which is allocated even if the name is already
        !           201:  * fully qualified.
        !           202:  */
        !           203: static char * dns_qualify_name ( const char *string ) {
        !           204:        char *fqdn;
        !           205: 
        !           206:        /* Leave unchanged if already fully-qualified or no local domain */
        !           207:        if ( ( ! localdomain ) || ( strchr ( string, '.' ) != 0 ) )
        !           208:                return strdup ( string );
        !           209: 
        !           210:        /* Append local domain to name */
        !           211:        asprintf ( &fqdn, "%s.%s", string, localdomain );
        !           212:        return fqdn;
        !           213: }
        !           214: 
        !           215: /**
        !           216:  * Convert a standard NUL-terminated string to a DNS name
        !           217:  *
        !           218:  * @v string           Name as a NUL-terminated string
        !           219:  * @v buf              Buffer in which to place DNS name
        !           220:  * @ret next           Byte following constructed DNS name
        !           221:  *
        !           222:  * DNS names consist of "<length>element" pairs.
        !           223:  */
        !           224: static char * dns_make_name ( const char *string, char *buf ) {
        !           225:        char *length_byte = buf++;
        !           226:        char c;
        !           227: 
        !           228:        while ( ( c = *(string++) ) ) {
        !           229:                if ( c == '.' ) {
        !           230:                        *length_byte = buf - length_byte - 1;
        !           231:                        length_byte = buf;
        !           232:                }
        !           233:                *(buf++) = c;
        !           234:        }
        !           235:        *length_byte = buf - length_byte - 1;
        !           236:        *(buf++) = '\0';
        !           237:        return buf;
        !           238: }
        !           239: 
        !           240: /**
        !           241:  * Convert an uncompressed DNS name to a NUL-terminated string
        !           242:  *
        !           243:  * @v name             DNS name
        !           244:  * @ret string         NUL-terminated string
        !           245:  *
        !           246:  * Produce a printable version of a DNS name.  Used only for debugging.
        !           247:  */
        !           248: static inline char * dns_unmake_name ( char *name ) {
        !           249:        char *p;
        !           250:        unsigned int len;
        !           251: 
        !           252:        p = name;
        !           253:        while ( ( len = *p ) ) {
        !           254:                *(p++) = '.';
        !           255:                p += len;
        !           256:        }
        !           257: 
        !           258:        return name + 1;
        !           259: }
        !           260: 
        !           261: /**
        !           262:  * Decompress a DNS name
        !           263:  *
        !           264:  * @v reply            DNS replay
        !           265:  * @v name             DNS name
        !           266:  * @v buf              Buffer into which to decompress DNS name
        !           267:  * @ret next           Byte following decompressed DNS name
        !           268:  */
        !           269: static char * dns_decompress_name ( const struct dns_header *reply,
        !           270:                                    const char *name, char *buf ) {
        !           271:        int i, len;
        !           272: 
        !           273:        do {
        !           274:                /* Obtain next section of name */
        !           275:                while ( ( *name ) & 0xc0 ) {
        !           276:                        name = ( ( char * ) reply +
        !           277:                                 ( ntohs ( *((uint16_t *)name) ) & ~0xc000 ) );
        !           278:                }
        !           279:                /* Copy data */
        !           280:                len = *name;
        !           281:                for ( i = len + 1 ; i > 0 ; i-- ) {
        !           282:                        *(buf++) = *(name++);
        !           283:                }
        !           284:        } while ( len );
        !           285:        return buf;
        !           286: }
        !           287: 
        !           288: /**
        !           289:  * Send next packet in DNS request
        !           290:  *
        !           291:  * @v dns              DNS request
        !           292:  */
        !           293: static int dns_send_packet ( struct dns_request *dns ) {
        !           294:        static unsigned int qid = 0;
        !           295:        size_t qlen;
        !           296: 
        !           297:        /* Increment query ID */
        !           298:        dns->query.dns.id = htons ( ++qid );
        !           299: 
        !           300:        DBGC ( dns, "DNS %p sending query ID %d\n", dns, qid );
        !           301: 
        !           302:        /* Start retransmission timer */
        !           303:        start_timer ( &dns->timer );
        !           304: 
        !           305:        /* Send the data */
        !           306:        qlen = ( ( ( void * ) dns->qinfo ) - ( ( void * ) &dns->query )
        !           307:                 + sizeof ( dns->qinfo ) );
        !           308:        return xfer_deliver_raw ( &dns->socket, &dns->query, qlen );
        !           309: }
        !           310: 
        !           311: /**
        !           312:  * Handle DNS retransmission timer expiry
        !           313:  *
        !           314:  * @v timer            Retry timer
        !           315:  * @v fail             Failure indicator
        !           316:  */
        !           317: static void dns_timer_expired ( struct retry_timer *timer, int fail ) {
        !           318:        struct dns_request *dns =
        !           319:                container_of ( timer, struct dns_request, timer );
        !           320: 
        !           321:        if ( fail ) {
        !           322:                dns_done ( dns, -ETIMEDOUT );
        !           323:        } else {
        !           324:                dns_send_packet ( dns );
        !           325:        }
        !           326: }
        !           327: 
        !           328: /**
        !           329:  * Receive new data
        !           330:  *
        !           331:  * @v dns              DNS request
        !           332:  * @v iobuf            I/O buffer
        !           333:  * @v meta             Data transfer metadata
        !           334:  * @ret rc             Return status code
        !           335:  */
        !           336: static int dns_xfer_deliver ( struct dns_request *dns,
        !           337:                              struct io_buffer *iobuf,
        !           338:                              struct xfer_metadata *meta __unused ) {
        !           339:        const struct dns_header *reply = iobuf->data;
        !           340:        union dns_rr_info *rr_info;
        !           341:        struct sockaddr_in *sin;
        !           342:        unsigned int qtype = dns->qinfo->qtype;
        !           343:        int rc;
        !           344: 
        !           345:        /* Sanity check */
        !           346:        if ( iob_len ( iobuf ) < sizeof ( *reply ) ) {
        !           347:                DBGC ( dns, "DNS %p received underlength packet length %zd\n",
        !           348:                       dns, iob_len ( iobuf ) );
        !           349:                rc = -EINVAL;
        !           350:                goto done;
        !           351:        }
        !           352: 
        !           353:        /* Check reply ID matches query ID */
        !           354:        if ( reply->id != dns->query.dns.id ) {
        !           355:                DBGC ( dns, "DNS %p received unexpected reply ID %d "
        !           356:                       "(wanted %d)\n", dns, ntohs ( reply->id ),
        !           357:                       ntohs ( dns->query.dns.id ) );
        !           358:                rc = -EINVAL;
        !           359:                goto done;
        !           360:        }
        !           361: 
        !           362:        DBGC ( dns, "DNS %p received reply ID %d\n", dns, ntohs ( reply->id ));
        !           363: 
        !           364:        /* Stop the retry timer.  After this point, each code path
        !           365:         * must either restart the timer by calling dns_send_packet(),
        !           366:         * or mark the DNS operation as complete by calling
        !           367:         * dns_done()
        !           368:         */
        !           369:        stop_timer ( &dns->timer );
        !           370: 
        !           371:        /* Search through response for useful answers.  Do this
        !           372:         * multiple times, to take advantage of useful nameservers
        !           373:         * which send us e.g. the CNAME *and* the A record for the
        !           374:         * pointed-to name.
        !           375:         */
        !           376:        while ( ( rr_info = dns_find_rr ( dns, reply ) ) ) {
        !           377:                switch ( rr_info->common.type ) {
        !           378: 
        !           379:                case htons ( DNS_TYPE_A ):
        !           380: 
        !           381:                        /* Found the target A record */
        !           382:                        DBGC ( dns, "DNS %p found address %s\n",
        !           383:                               dns, inet_ntoa ( rr_info->a.in_addr ) );
        !           384:                        sin = ( struct sockaddr_in * ) &dns->sa;
        !           385:                        sin->sin_family = AF_INET;
        !           386:                        sin->sin_addr = rr_info->a.in_addr;
        !           387: 
        !           388:                        /* Return resolved address */
        !           389:                        resolv_done ( &dns->resolv, &dns->sa );
        !           390: 
        !           391:                        /* Mark operation as complete */
        !           392:                        dns_done ( dns, 0 );
        !           393:                        rc = 0;
        !           394:                        goto done;
        !           395: 
        !           396:                case htons ( DNS_TYPE_CNAME ):
        !           397: 
        !           398:                        /* Found a CNAME record; update query and recurse */
        !           399:                        DBGC ( dns, "DNS %p found CNAME\n", dns );
        !           400:                        dns->qinfo = ( void * ) dns_decompress_name ( reply,
        !           401:                                                         rr_info->cname.cname,
        !           402:                                                         dns->query.payload );
        !           403:                        dns->qinfo->qtype = htons ( DNS_TYPE_A );
        !           404:                        dns->qinfo->qclass = htons ( DNS_CLASS_IN );
        !           405:                        
        !           406:                        /* Terminate the operation if we recurse too far */
        !           407:                        if ( ++dns->recursion > DNS_MAX_CNAME_RECURSION ) {
        !           408:                                DBGC ( dns, "DNS %p recursion exceeded\n",
        !           409:                                       dns );
        !           410:                                dns_done ( dns, -ELOOP );
        !           411:                                rc = 0;
        !           412:                                goto done;
        !           413:                        }
        !           414:                        break;
        !           415: 
        !           416:                default:
        !           417:                        DBGC ( dns, "DNS %p got unknown record type %d\n",
        !           418:                               dns, ntohs ( rr_info->common.type ) );
        !           419:                        break;
        !           420:                }
        !           421:        }
        !           422:        
        !           423:        /* Determine what to do next based on the type of query we
        !           424:         * issued and the reponse we received
        !           425:         */
        !           426:        switch ( qtype ) {
        !           427: 
        !           428:        case htons ( DNS_TYPE_A ):
        !           429:                /* We asked for an A record and got nothing;
        !           430:                 * try the CNAME.
        !           431:                 */
        !           432:                DBGC ( dns, "DNS %p found no A record; trying CNAME\n", dns );
        !           433:                dns->qinfo->qtype = htons ( DNS_TYPE_CNAME );
        !           434:                dns_send_packet ( dns );
        !           435:                rc = 0;
        !           436:                goto done;
        !           437: 
        !           438:        case htons ( DNS_TYPE_CNAME ):
        !           439:                /* We asked for a CNAME record.  If we got a response
        !           440:                 * (i.e. if the next A query is already set up), then
        !           441:                 * issue it, otherwise abort.
        !           442:                 */
        !           443:                if ( dns->qinfo->qtype == htons ( DNS_TYPE_A ) ) {
        !           444:                        dns_send_packet ( dns );
        !           445:                        rc = 0;
        !           446:                        goto done;
        !           447:                } else {
        !           448:                        DBGC ( dns, "DNS %p found no CNAME record\n", dns );
        !           449:                        dns_done ( dns, -ENXIO_NO_RECORD );
        !           450:                        rc = 0;
        !           451:                        goto done;
        !           452:                }
        !           453: 
        !           454:        default:
        !           455:                assert ( 0 );
        !           456:                dns_done ( dns, -EINVAL );
        !           457:                rc = -EINVAL;
        !           458:                goto done;
        !           459:        }
        !           460: 
        !           461:  done:
        !           462:        /* Free I/O buffer */
        !           463:        free_iob ( iobuf );
        !           464:        return rc;
        !           465: }
        !           466: 
        !           467: /**
        !           468:  * Receive new data
        !           469:  *
        !           470:  * @v dns              DNS request
        !           471:  * @v rc               Reason for close
        !           472:  */
        !           473: static void dns_xfer_close ( struct dns_request *dns, int rc ) {
        !           474: 
        !           475:        if ( ! rc )
        !           476:                rc = -ECONNABORTED;
        !           477: 
        !           478:        dns_done ( dns, rc );
        !           479: }
        !           480: 
        !           481: /** DNS socket interface operations */
        !           482: static struct interface_operation dns_socket_operations[] = {
        !           483:        INTF_OP ( xfer_deliver, struct dns_request *, dns_xfer_deliver ),
        !           484:        INTF_OP ( intf_close, struct dns_request *, dns_xfer_close ),
        !           485: };
        !           486: 
        !           487: /** DNS socket interface descriptor */
        !           488: static struct interface_descriptor dns_socket_desc =
        !           489:        INTF_DESC ( struct dns_request, socket, dns_socket_operations );
        !           490: 
        !           491: /** DNS resolver interface operations */
        !           492: static struct interface_operation dns_resolv_op[] = {
        !           493:        INTF_OP ( intf_close, struct dns_request *, dns_done ),
        !           494: };
        !           495: 
        !           496: /** DNS resolver interface descriptor */
        !           497: static struct interface_descriptor dns_resolv_desc =
        !           498:        INTF_DESC ( struct dns_request, resolv, dns_resolv_op );
        !           499: 
        !           500: /**
        !           501:  * Resolve name using DNS
        !           502:  *
        !           503:  * @v resolv           Name resolution interface
        !           504:  * @v name             Name to resolve
        !           505:  * @v sa               Socket address to fill in
        !           506:  * @ret rc             Return status code
        !           507:  */
        !           508: static int dns_resolv ( struct interface *resolv,
        !           509:                        const char *name, struct sockaddr *sa ) {
        !           510:        struct dns_request *dns;
        !           511:        char *fqdn;
        !           512:        int rc;
        !           513: 
        !           514:        /* Fail immediately if no DNS servers */
        !           515:        if ( ! nameserver.st_family ) {
        !           516:                DBG ( "DNS not attempting to resolve \"%s\": "
        !           517:                      "no DNS servers\n", name );
        !           518:                rc = -ENXIO_NO_NAMESERVER;
        !           519:                goto err_no_nameserver;
        !           520:        }
        !           521: 
        !           522:        /* Ensure fully-qualified domain name if DHCP option was given */
        !           523:        fqdn = dns_qualify_name ( name );
        !           524:        if ( ! fqdn ) {
        !           525:                rc = -ENOMEM;
        !           526:                goto err_qualify_name;
        !           527:        }
        !           528: 
        !           529:        /* Allocate DNS structure */
        !           530:        dns = zalloc ( sizeof ( *dns ) );
        !           531:        if ( ! dns ) {
        !           532:                rc = -ENOMEM;
        !           533:                goto err_alloc_dns;
        !           534:        }
        !           535:        ref_init ( &dns->refcnt, NULL );
        !           536:        intf_init ( &dns->resolv, &dns_resolv_desc, &dns->refcnt );
        !           537:        intf_init ( &dns->socket, &dns_socket_desc, &dns->refcnt );
        !           538:        timer_init ( &dns->timer, dns_timer_expired, &dns->refcnt );
        !           539:        memcpy ( &dns->sa, sa, sizeof ( dns->sa ) );
        !           540: 
        !           541:        /* Create query */
        !           542:        dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
        !           543:                                       DNS_FLAG_RD );
        !           544:        dns->query.dns.qdcount = htons ( 1 );
        !           545:        dns->qinfo = ( void * ) dns_make_name ( fqdn, dns->query.payload );
        !           546:        dns->qinfo->qtype = htons ( DNS_TYPE_A );
        !           547:        dns->qinfo->qclass = htons ( DNS_CLASS_IN );
        !           548: 
        !           549:        /* Open UDP connection */
        !           550:        if ( ( rc = xfer_open_socket ( &dns->socket, SOCK_DGRAM,
        !           551:                                       ( struct sockaddr * ) &nameserver,
        !           552:                                       NULL ) ) != 0 ) {
        !           553:                DBGC ( dns, "DNS %p could not open socket: %s\n",
        !           554:                       dns, strerror ( rc ) );
        !           555:                goto err_open_socket;
        !           556:        }
        !           557: 
        !           558:        /* Send first DNS packet */
        !           559:        dns_send_packet ( dns );
        !           560: 
        !           561:        /* Attach parent interface, mortalise self, and return */
        !           562:        intf_plug_plug ( &dns->resolv, resolv );
        !           563:        ref_put ( &dns->refcnt );
        !           564:        free ( fqdn );
        !           565:        return 0;       
        !           566: 
        !           567:  err_open_socket:
        !           568:  err_alloc_dns:
        !           569:        ref_put ( &dns->refcnt );
        !           570:  err_qualify_name:
        !           571:        free ( fqdn );
        !           572:  err_no_nameserver:
        !           573:        return rc;
        !           574: }
        !           575: 
        !           576: /** DNS name resolver */
        !           577: struct resolver dns_resolver __resolver ( RESOLV_NORMAL ) = {
        !           578:        .name = "DNS",
        !           579:        .resolv = dns_resolv,
        !           580: };
        !           581: 
        !           582: /******************************************************************************
        !           583:  *
        !           584:  * Settings
        !           585:  *
        !           586:  ******************************************************************************
        !           587:  */
        !           588: 
        !           589: /** DNS server setting */
        !           590: struct setting dns_setting __setting ( SETTING_IPv4_EXTRA ) = {
        !           591:        .name = "dns",
        !           592:        .description = "DNS server",
        !           593:        .tag = DHCP_DNS_SERVERS,
        !           594:        .type = &setting_type_ipv4,
        !           595: };
        !           596: 
        !           597: /** Domain name setting */
        !           598: struct setting domain_setting __setting ( SETTING_IPv4_EXTRA ) = {
        !           599:        .name = "domain",
        !           600:        .description = "DNS domain",
        !           601:        .tag = DHCP_DOMAIN_NAME,
        !           602:        .type = &setting_type_string,
        !           603: };
        !           604: 
        !           605: /**
        !           606:  * Apply DNS settings
        !           607:  *
        !           608:  * @ret rc             Return status code
        !           609:  */
        !           610: static int apply_dns_settings ( void ) {
        !           611:        struct sockaddr_in *sin_nameserver =
        !           612:                ( struct sockaddr_in * ) &nameserver;
        !           613:        int len;
        !           614: 
        !           615:        /* Fetch DNS server address */
        !           616:        nameserver.st_family = 0;
        !           617:        if ( ( len = fetch_ipv4_setting ( NULL, &dns_setting,
        !           618:                                          &sin_nameserver->sin_addr ) ) >= 0 ){
        !           619:                nameserver.st_family = AF_INET;
        !           620:                DBG ( "DNS using nameserver %s\n",
        !           621:                      inet_ntoa ( sin_nameserver->sin_addr ) );
        !           622:        }
        !           623: 
        !           624:        /* Get local domain DHCP option */
        !           625:        free ( localdomain );
        !           626:        if ( ( len = fetch_string_setting_copy ( NULL, &domain_setting,
        !           627:                                                 &localdomain ) ) < 0 ) {
        !           628:                DBG ( "DNS could not fetch local domain: %s\n",
        !           629:                      strerror ( len ) );
        !           630:        }
        !           631:        if ( localdomain )
        !           632:                DBG ( "DNS local domain %s\n", localdomain );
        !           633: 
        !           634:        return 0;
        !           635: }
        !           636: 
        !           637: /** DNS settings applicator */
        !           638: struct settings_applicator dns_applicator __settings_applicator = {
        !           639:        .apply = apply_dns_settings,
        !           640: };

unix.superglobalmegacorp.com

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