Annotation of qemu/roms/ipxe/src/net/udp/dns.c, revision 1.1.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.