VirtualBox

Changeset 60960 in vbox for trunk


Ignore:
Timestamp:
May 12, 2016 3:24:18 PM (9 years ago)
Author:
vboxsync
Message:

NAT: rewrite resolv.conf parser. The old code tried to be fancy, but
somehow manged to miss the fact that resolv.conf is line-oriented.

Location:
trunk/src/VBox/Devices/Network/slirp
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/slirp/resolv_conf_parser.c

    r56292 r60960  
    55
    66/*
    7  * Copyright (C) 2014-2015 Oracle Corporation
     7 * Copyright (C) 2016 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1616 */
    1717
     18#ifdef RCP_STANDALONE
     19#define IN_RING3
     20#endif
     21
     22#ifndef LOG_GROUP
     23# define LOG_GROUP LOG_GROUP_DRV_NAT
     24#endif
     25
    1826#include <iprt/assert.h>
    19 #include <iprt/initterm.h>
    2027#include <iprt/net.h>
    2128#include <iprt/string.h>
     
    2330#include <iprt/thread.h>
    2431
     32#include <VBox/log.h>
     33
    2534#ifdef RT_OS_FREEBSD
    2635# include <sys/socket.h>
     
    2938#include <arpa/inet.h>
    3039
    31 #include <ctype.h>
    32 
    3340#include "resolv_conf_parser.h"
    3441
    35 /* XXX: it's required to add the aliases for keywords and
    36  * types to handle conditions more clearly */
    37 enum RCP_TOKEN
     42#if !defined(RCP_ACCEPT_PORT)
     43# if defined(RT_OS_DARWIN)
     44#  define RCP_ACCEPT_PORT
     45# endif
     46#endif
     47
     48static int rcp_address_trailer(char **ppszNext, PRTNETADDR pNetAddr, RTNETADDRTYPE enmType);
     49static char *getToken(char *psz, char **ppszSavePtr);
     50
     51#if 0
     52#undef  Log2
     53#define Log2 LogRel
     54#endif
     55
     56#ifdef RCP_STANDALONE
     57#undef  LogRel
     58#define LogRel(a) RTPrintf a
     59#endif
     60
     61
     62#ifdef RCP_STANDALONE
     63int main(int argc, char **argv)
    3864{
    39   tok_eof = -1, /* EOF */
    40   tok_string = -2, /* string */
    41   tok_number = -3, /* number */
    42   tok_ipv4 = -4, /* ipv4 */
    43   tok_ipv4_port = -5, /* ipv4 port */
    44   tok_ipv6 = -6, /* ipv6 */
    45   tok_ipv6_port = -7, /* ipv6 port */
    46   /* keywords */
    47   tok_nameserver = -8, /* nameserver */
    48   tok_port = -9, /* port, Mac OSX specific */
    49   tok_domain = -10, /* domain */
    50   tok_search = -11, /* search */
    51   tok_search_order = -12, /* search order */
    52   tok_sortlist = -13, /* sortlist */
    53   tok_timeout = -14, /* timeout */
    54   tok_options = -15, /* options */
    55   tok_option = -16, /* option */
    56   tok_comment = -17, /* comment */
    57   tok_error = -20
    58 };
    59 
    60 #define RCP_BUFFER_SIZE 256
    61 
    62 
    63 struct rcp_parser
    64 {
    65     enum RCP_TOKEN rcpp_token;
    66     char rcpp_str_buffer[RCP_BUFFER_SIZE];
    67     struct rcp_state *rcpp_state;
    68     PRTSTREAM rcpp_stream;
    69 };
    70 
    71 
    72 #define GETCHAR(parser) (RTStrmGetCh((parser)->rcpp_stream))
    73 #define EOF (-1)
    74 
    75 
    76 #define PARSER_STOP(tok, parser, ptr) (   (tok) != EOF \
    77                                        && (((ptr) - (parser)->rcpp_str_buffer) != (RCP_BUFFER_SIZE - 1)))
    78 #define PARSER_BUFFER_EXCEEDED(parser, ptr)                             \
    79   do {                                                                  \
    80       if (((ptr) - (parser)->rcpp_str_buffer) == (RCP_BUFFER_SIZE - 1)) { \
    81           return tok_error;                                             \
    82       }                                                                 \
    83   }while(0);
    84 
    85 static int rcp_get_token(struct rcp_parser *parser)
    86 {
    87     char tok = ' ';
    88     char *ptr;
    89     size_t ptr_len;
    90 
    91     while (isspace(tok))
    92         tok = GETCHAR(parser);
    93 
    94     ptr = parser->rcpp_str_buffer;
    95 
    96     /* tok can't be ipv4 */
    97     if (isalnum(tok)) {
    98         int xdigit, digit, dot_number;
    99         RT_ZERO(parser->rcpp_str_buffer);
    100 
    101         dot_number = 0;
    102         xdigit = 1;
    103         digit = 1;
    104         do {
    105             *ptr++ = tok;
    106             tok = GETCHAR(parser);
    107 
    108             if (!isalnum(tok) && tok != ':' && tok != '.' && tok != '-' && tok != '_')
    109                 break;
    110 
    111             /**
    112              * if before ':' there were only [0-9][a-f][A-F],
    113              * then it can't be option.
    114              */
    115             xdigit &= (isxdigit(tok) || (tok == ':'));
    116             /**
    117              * We want hint to differ ipv4 and network name.
    118              */
    119             digit &= (isdigit(tok) || (tok == '.'));
    120 
    121             if (tok == ':')
    122             {
    123                 if (xdigit == 1)
    124                 {
    125                     int port = 0;
    126                     do
    127                     {
    128                         *ptr++ = tok;
    129                         tok = GETCHAR(parser);
    130 
    131                         if (tok == '.')
    132                             port++;
    133 
    134                     } while(PARSER_STOP(tok, parser, ptr) && (tok == ':' || tok == '.' || isxdigit(tok)));
    135 
    136                     PARSER_BUFFER_EXCEEDED(parser, ptr);
    137 
    138                     if (port == 0)
    139                         return tok_ipv6;
    140                     else if (port == 1)
    141                         return tok_ipv6_port;
    142                     else
    143                     {
    144                         /* eats rest of the token */
    145                         do
    146                         {
    147                             *ptr++ = tok;
    148                             tok = GETCHAR(parser);
    149                         } while(   PARSER_STOP(tok, parser, ptr)
    150                                 && (isalnum(tok) || tok == '.'  || tok == '_' || tok == '-'));
    151 
    152                         PARSER_BUFFER_EXCEEDED(parser, ptr);
    153 
    154                         return tok_string;
    155                     }
    156                 }
    157                 else {
    158                     /* XXX: need further experiments */
    159                     return tok_option; /* option with value */
    160                 }
    161             }
    162 
    163             if (tok == '.')
    164             {
    165                 do {
    166                     if (tok == '.') dot_number++;
    167 
    168                     *ptr++ = tok;
    169                     digit &= (isdigit(tok) || (tok == '.'));
    170                     tok = GETCHAR(parser);
    171                 } while(   PARSER_STOP(tok, parser, ptr)
    172                         && (isalnum(tok) || tok == '.' || tok == '_' || tok == '-'));
    173 
    174                 PARSER_BUFFER_EXCEEDED(parser, ptr);
    175 
    176                 if (dot_number == 3 && digit)
    177                     return tok_ipv4;
    178                 else if (dot_number == 4 && digit)
    179                     return tok_ipv4_port;
    180                 else
    181                     return tok_string;
    182             }
    183         } while(   PARSER_STOP(tok, parser, ptr)
    184                 && (isalnum(tok) || tok == ':' || tok == '.' || tok == '-' || tok == '_'));
    185 
    186         PARSER_BUFFER_EXCEEDED(parser, ptr);
    187 
    188         if (digit || xdigit)
    189             return tok_number;
    190         if (RTStrCmp(parser->rcpp_str_buffer, "nameserver") == 0)
    191             return tok_nameserver;
    192         if (RTStrCmp(parser->rcpp_str_buffer, "port") == 0)
    193             return tok_port;
    194         if (RTStrCmp(parser->rcpp_str_buffer, "domain") == 0)
    195             return tok_domain;
    196         if (RTStrCmp(parser->rcpp_str_buffer, "search") == 0)
    197             return tok_search;
    198         if (RTStrCmp(parser->rcpp_str_buffer, "search_order") == 0)
    199             return tok_search_order;
    200         if (RTStrCmp(parser->rcpp_str_buffer, "sortlist") == 0)
    201             return tok_sortlist;
    202         if (RTStrCmp(parser->rcpp_str_buffer, "timeout") == 0)
    203             return tok_timeout;
    204         if (RTStrCmp(parser->rcpp_str_buffer, "options") == 0)
    205             return tok_options;
    206 
    207         return tok_string;
    208     }
    209 
    210     if (tok == EOF) return tok_eof;
    211 
    212     if (tok == '#')
    213     {
    214         do{
    215             tok = GETCHAR(parser);
    216         } while (tok != EOF && tok != '\r' && tok != '\n');
    217 
    218         if (tok == EOF) return tok_eof;
    219 
    220         return tok_comment;
    221     }
    222     return tok;
    223 }
    224 
    225 #undef PARSER_STOP
    226 #undef PARSER_BUFFER_EXCEEDED
    227 
    228 /**
    229  * nameserverexpr ::= 'nameserver' ip+
    230  * @note: resolver(5) ip ::= (ipv4|ipv6)(.number)?
    231  */
    232 static enum RCP_TOKEN rcp_parse_nameserver(struct rcp_parser *parser)
    233 {
    234     enum RCP_TOKEN tok = rcp_get_token(parser); /* eats 'nameserver' */
    235 
    236     if (  (   tok != tok_ipv4
    237            && tok != tok_ipv4_port
    238            && tok != tok_ipv6
    239            && tok != tok_ipv6_port)
    240         || tok == EOF)
    241         return tok_error;
    242 
    243     while (   tok == tok_ipv4
    244            || tok == tok_ipv4_port
    245            || tok == tok_ipv6
    246            || tok == tok_ipv6_port)
    247     {
    248         struct rcp_state *st;
    249         RTNETADDR *address;
    250         char *str_address;
    251 
    252         Assert(parser->rcpp_state);
    253 
    254         st = parser->rcpp_state;
    255 
    256         /* It's still valid resolv.conf file, just rest of the nameservers should be ignored */
    257         if (st->rcps_num_nameserver >= RCPS_MAX_NAMESERVERS)
    258             return rcp_get_token(parser);
    259 
    260         address = &st->rcps_nameserver[st->rcps_num_nameserver];
    261         str_address = &st->rcps_nameserver_str_buffer[st->rcps_num_nameserver * RCPS_IPVX_SIZE];
    262 #ifdef RT_OS_DARWIN
    263         if (   tok == tok_ipv4_port
    264             || (   tok == tok_ipv6_port
    265                 && (st->rcps_flags & RCPSF_IGNORE_IPV6) == 0))
    266         {
    267             char *ptr = &parser->rcpp_str_buffer[strlen(parser->rcpp_str_buffer)];
    268             while (*(--ptr) != '.');
    269             *ptr = '\0';
    270             address->uPort = RTStrToUInt16(ptr + 1);
    271 
    272             if (address->uPort == 0) return tok_error;
    273         }
    274 #endif
    275         /**
    276          * if we on Darwin upper code will cut off port if it's.
    277          */
    278         if ((st->rcps_flags & RCPSF_NO_STR2IPCONV) != 0)
    279         {
    280             if (strlen(parser->rcpp_str_buffer) > RCPS_IPVX_SIZE)
    281                 return tok_error;
    282 
    283             strcpy(str_address, parser->rcpp_str_buffer);
    284 
    285             st->rcps_str_nameserver[st->rcps_num_nameserver] = str_address;
    286 
    287             goto loop_prolog;
    288         }
    289 
    290         switch (tok)
    291         {
    292             case tok_ipv4:
    293             case tok_ipv4_port:
    294                 {
    295                     int rc = RTNetStrToIPv4Addr(parser->rcpp_str_buffer, &address->uAddr.IPv4);
    296                     if (RT_FAILURE(rc)) return tok_error;
    297 
    298                     address->enmType = RTNETADDRTYPE_IPV4;
    299                 }
    300 
    301                 break;
    302             case tok_ipv6:
    303             case tok_ipv6_port:
    304                 {
    305                     int rc;
    306 
    307                     if ((st->rcps_flags & RCPSF_IGNORE_IPV6) != 0)
    308                         return rcp_get_token(parser);
    309 
    310                     rc = inet_pton(AF_INET6, parser->rcpp_str_buffer,
    311                                        &address->uAddr.IPv6);
    312                     if (rc == -1)
    313                         return tok_error;
    314 
    315                     address->enmType = RTNETADDRTYPE_IPV6;
    316                 }
    317 
    318                 break;
    319             default: /* loop condition doesn't let enter enything */
    320                 AssertMsgFailed(("shouldn't ever happen tok:%d, %s", tok,
    321                                  isprint(tok) ? parser->rcpp_str_buffer : "#"));
    322                 break;
    323         }
    324 
    325     loop_prolog:
    326         st->rcps_num_nameserver++;
    327         tok = rcp_get_token(parser);
    328     }
    329     return tok;
    330 }
    331 
    332 /**
    333  * portexpr ::= 'port' [0-9]+
    334  */
    335 static enum RCP_TOKEN rcp_parse_port(struct rcp_parser *parser)
    336 {
    337     struct rcp_state *st;
    338     enum RCP_TOKEN tok = rcp_get_token(parser); /* eats 'port' */
    339 
    340     Assert(parser->rcpp_state);
    341     st = parser->rcpp_state;
    342 
    343     if (   tok != tok_number
    344         || tok == tok_eof)
    345         return tok_error;
    346 
    347     st->rcps_port = RTStrToUInt16(parser->rcpp_str_buffer);
    348 
    349     if (st->rcps_port == 0)
    350         return tok_error;
    351 
    352     return rcp_get_token(parser);
    353 }
    354 
    355 /**
    356  * domainexpr ::= 'domain' string
    357  */
    358 static enum RCP_TOKEN rcp_parse_domain(struct rcp_parser *parser)
    359 {
    360     struct rcp_state *st;
    361     enum RCP_TOKEN tok = rcp_get_token(parser); /* eats 'domain' */
    362 
    363     Assert(parser->rcpp_state);
    364     st = parser->rcpp_state;
    365 
    366     /**
    367      * It's nowhere specified how resolver should react on dublicats
    368      * of 'domain' declarations, let's assume that resolv.conf is broken.
    369      */
    370     if (   tok == tok_eof
    371         || tok == tok_error
    372         || st->rcps_domain != NULL)
    373         return tok_error;
    374 
    375     strcpy(st->rcps_domain_buffer, parser->rcpp_str_buffer);
    376     /**
    377      * We initialize this pointer in place, just make single pointer check
    378      * in 'domain'-less resolv.conf.
    379      */
    380     st->rcps_domain = st->rcps_domain_buffer;
    381 
    382     return rcp_get_token(parser);
    383 }
    384 
    385 /**
    386  * searchexpr ::= 'search' (string)+
    387  * @note: resolver (5) Mac OSX:
    388  * "The search list is currently limited to six domains with a total of 256 characters."
    389  * @note: resolv.conf (5) Linux:
    390  * "The search list is currently limited to six domains with a total of 256 characters."
    391  * @note: 'search' parameter could contains numbers only hex or decimal, 1c1e or 111
    392  */
    393 static enum RCP_TOKEN rcp_parse_search(struct rcp_parser *parser)
    394 {
    395     unsigned i, len, trailing;
    396     char *ptr;
    397     struct rcp_state *st;
    398     enum RCP_TOKEN tok = rcp_get_token(parser); /* eats 'search' */
    399 
    400     Assert(parser->rcpp_state);
    401     st = parser->rcpp_state;
    402 
    403     if (   tok == tok_eof
    404         || tok == tok_error)
    405         return tok_error;
    406 
    407     /* just ignore "too many search list" */
    408     if (st->rcps_num_searchlist >= RCPS_MAX_SEARCHLIST)
    409         return rcp_get_token(parser);
    410 
    411     /* we don't want accept keywords */
    412     if (tok <= tok_nameserver)
    413         return tok;
    414 
    415     /* if there're several entries of "search" we compose them together */
    416     i = st->rcps_num_searchlist;
    417     if ( i == 0)
    418         trailing = RCPS_BUFFER_SIZE;
    419     else
    420     {
    421         ptr = st->rcps_searchlist[i - 1];
    422         trailing = RCPS_BUFFER_SIZE - (ptr -
    423                                        st->rcps_searchlist_buffer + strlen(ptr) + 1);
    424     }
    425 
    426     while (1)
    427     {
    428         len = strlen(parser->rcpp_str_buffer);
    429 
    430         if (len + 1 > trailing)
    431             break; /* not enough room for new entry */
    432 
    433         if (i >= RCPS_MAX_SEARCHLIST)
    434             break; /* not enought free entries for 'search' items */
    435 
    436         ptr = st->rcps_searchlist_buffer + RCPS_BUFFER_SIZE - trailing;
    437         strcpy(ptr, parser->rcpp_str_buffer);
    438 
    439         trailing -= len + 1; /* 1 reserved for '\0' */
    440 
    441         st->rcps_searchlist[i++] = ptr;
    442         tok = rcp_get_token(parser);
    443 
    444         /* token filter */
    445         if (   tok == tok_eof
    446             || tok == tok_error
    447             || tok <= tok_nameserver)
    448             break;
    449     }
    450 
    451     st->rcps_num_searchlist = i;
    452 
    453     return tok;
    454 }
    455 
    456 /**
    457  * expr ::= nameserverexpr | expr
    458  *      ::= portexpr | expr
    459  *      ::= domainexpr | expr
    460  *      ::= searchexpr | expr
    461  *      ::= searchlistexpr | expr
    462  *      ::= search_orderexpr | expr
    463  *      ::= timeoutexpr | expr
    464  *      ::= optionsexpr | expr
    465  */
    466 static int rcp_parse_primary(struct rcp_parser *parser)
    467 {
    468     enum RCP_TOKEN tok;
    469     tok = rcp_get_token(parser);
    470 
    471     while(   tok != tok_eof
    472           && tok != tok_error)
    473     {
    474         switch (tok)
    475         {
    476             case tok_nameserver:
    477                 tok = rcp_parse_nameserver(parser);
    478                 break;
    479             case tok_port:
    480                 tok = rcp_parse_port(parser);
    481                 break;
    482             case tok_domain:
    483                 tok = rcp_parse_domain(parser);
    484                 break;
    485             case tok_search:
    486                 tok = rcp_parse_search(parser);
    487                 break;
    488             default:
    489                 tok = rcp_get_token(parser);
    490         }
    491     }
    492 
    493     if (tok == tok_error)
    494         return -1;
     65    struct rcp_state state;
     66    int i;
     67    int rc;
     68
     69    rc = rcp_parse(&state, NULL);
     70    if (RT_FAILURE(rc))
     71    {
     72        RTPrintf(">>> Failed: %Rrc\n", rc);
     73        return 1;
     74    }
     75
     76    RTPrintf(">>> Success:\n");
     77
     78    RTPrintf("rcps_num_nameserver = %u\n", state.rcps_num_nameserver);
     79    for (i = 0; i < state.rcps_num_nameserver; ++i)
     80    {
     81        if (state.rcps_str_nameserver[i] == NULL)
     82            LogRel(("  nameserver %RTnaddr\n",
     83                    &state.rcps_nameserver[i]));
     84        else
     85            LogRel(("  nameserver %RTnaddr (from \"%s\")\n",
     86                    &state.rcps_nameserver[i], state.rcps_str_nameserver[i]));
     87    }
     88
     89    if (state.rcps_domain != NULL)
     90        RTPrintf("domain %s\n", state.rcps_domain);
     91
     92    RTPrintf("rcps_num_searchlist = %u\n", state.rcps_num_searchlist);
     93    for (i = 0; i < state.rcps_num_searchlist; ++i)
     94    {
     95        RTPrintf("... %s\n", state.rcps_searchlist[i] ? state.rcps_searchlist[i] : "(null)");
     96    }
    49597
    49698    return 0;
    49799}
    498 
    499 
    500 int rcp_parse(struct rcp_state* state, const char *filename)
     100#endif
     101
     102
     103int rcp_parse(struct rcp_state *state, const char *filename)
    501104{
     105    PRTSTREAM stream;
     106#   define RCP_BUFFER_SIZE 256
     107    char buf[RCP_BUFFER_SIZE];
     108    char *pszAddrBuf;
     109    size_t cbAddrBuf;
     110    char *pszSearchBuf;
     111    size_t cbSearchBuf;
     112    uint32_t flags;
     113    uint32_t default_port = RTNETADDR_PORT_NA;
    502114    unsigned i;
    503     uint32_t flags;
    504115    int rc;
    505     struct rcp_parser parser;
     116
     117    AssertPtrReturn(state, VERR_INVALID_PARAMETER);
    506118    flags = state->rcps_flags;
    507119
    508     RT_ZERO(parser);
    509120    RT_ZERO(*state);
    510 
    511121    state->rcps_flags = flags;
    512122
    513     parser.rcpp_state = state;
    514 
    515     /**
    516      * for debugging need: with RCP_STANDALONE it's possible
    517      * to run simplefied scenarious like
    518      *
    519      * # cat /etc/resolv.conf | rcp-test-0
    520      * or in lldb
    521      * # process launch -i /etc/resolv.conf
    522      */
     123    if (RT_UNLIKELY(filename == NULL))
     124    {
    523125#ifdef RCP_STANDALONE
    524     if (filename == NULL)
    525         parser.rcpp_stream = g_pStdIn;
     126        stream = g_pStdIn;      /* for testing/debugging */
    526127#else
    527     if (filename == NULL)
    528         return -1;
    529 #endif
     128        return VERR_INVALID_PARAMETER;
     129#endif
     130    }
    530131    else
    531132    {
    532         rc = RTStrmOpen(filename, "r", &parser.rcpp_stream);
    533         if (RT_FAILURE(rc)) return -1;
    534     }
    535 
    536     rc = rcp_parse_primary(&parser);
     133        rc = RTStrmOpen(filename, "r", &stream);
     134        if (RT_FAILURE(rc))
     135            return rc;
     136    }
     137
     138
     139    pszAddrBuf = state->rcps_nameserver_str_buffer;
     140    cbAddrBuf = sizeof(state->rcps_nameserver_str_buffer);
     141
     142    pszSearchBuf = state->rcps_searchlist_buffer;
     143    cbSearchBuf = sizeof(state->rcps_searchlist_buffer);
     144
     145    for (;;)
     146    {
     147        char *s, *tok;
     148
     149        rc = RTStrmGetLine(stream, buf, sizeof(buf));
     150        if (RT_FAILURE(rc))
     151        {
     152            if (rc == VERR_EOF)
     153                rc = VINF_SUCCESS;
     154            break;
     155        }
     156
     157
     158        tok = getToken(buf, &s);
     159
     160        /* no more tokens or a comment */
     161#       define NO_VALUE(tok)  (tok == NULL || tok[0] == '#' || tok[0] == ';')
     162
     163        if (NO_VALUE(tok))
     164            continue;
     165
     166
     167        /*
     168         * NAMESERVER
     169         */
     170        if (RTStrCmp(tok, "nameserver") == 0)
     171        {
     172            RTNETADDR NetAddr;
     173            const char *pszAddr;
     174            char *pszNext;
     175
     176            if (RT_UNLIKELY(state->rcps_num_nameserver >= RCPS_MAX_NAMESERVERS))
     177            {
     178                LogRel(("NAT: resolv.conf: too many nameserver lines, ignoring %s\n", s));
     179                continue;
     180            }
     181
     182            /* XXX: TODO: don't save strings unless asked to */
     183            if (RT_UNLIKELY(cbAddrBuf == 0))
     184            {
     185                LogRel(("NAT: resolv.conf: no buffer space, ignoring %s\n", s));
     186                continue;
     187            }
     188
     189
     190            /*
     191             * parse next token as an IP address
     192             */
     193            tok = getToken(NULL, &s);
     194            if (NO_VALUE(tok))
     195            {
     196                LogRel(("NAT: resolv.conf: nameserver line without value\n"));
     197                continue;
     198            }
     199
     200            pszAddr = tok;
     201            RT_ZERO(NetAddr);
     202            NetAddr.uPort = RTNETADDR_PORT_NA;
     203
     204            /* if (NetAddr.enmType == RTNETADDRTYPE_INVALID) */
     205            {
     206                rc = RTNetStrToIPv4AddrEx(tok, &NetAddr.uAddr.IPv4, &pszNext);
     207                if (RT_SUCCESS(rc))
     208                {
     209                    rc = rcp_address_trailer(&pszNext, &NetAddr, RTNETADDRTYPE_IPV4);
     210                    if (RT_FAILURE(rc))
     211                    {
     212                        LogRel(("NAT: resolv.conf: garbage at the end of IPv4 address %s\n", tok));
     213                        continue;
     214                    }
     215
     216                    LogRel(("NAT: resolv.conf: nameserver %RTnaddr\n", &NetAddr));
     217                }
     218            } /* IPv4 */
     219
     220            if (NetAddr.enmType == RTNETADDRTYPE_INVALID)
     221            {
     222                rc = RTNetStrToIPv6AddrEx(tok, &NetAddr.uAddr.IPv6, &pszNext);
     223                if (RT_SUCCESS(rc))
     224                {
     225                    if (*pszNext == '%') /* XXX: TODO: IPv6 zones */
     226                    {
     227                        size_t zlen = RTStrOffCharOrTerm(pszNext, '.');
     228                        LogRel(("NAT: resolv.conf: FIXME: ignoring IPv6 zone %*.*s\n",
     229                                zlen, zlen, pszNext));
     230                        pszNext += zlen;
     231                    }
     232
     233                    rc = rcp_address_trailer(&pszNext, &NetAddr, RTNETADDRTYPE_IPV6);
     234                    if (RT_FAILURE(rc))
     235                    {
     236                        LogRel(("NAT: resolv.conf: garbage at the end of IPv6 address %s\n", tok));
     237                        continue;
     238                    }
     239
     240                    LogRel(("NAT: resolv.conf: nameserver %RTnaddr\n", &NetAddr));
     241                }
     242            } /* IPv6 */
     243
     244            if (NetAddr.enmType == RTNETADDRTYPE_INVALID)
     245            {
     246                LogRel(("NAT: resolv.conf: bad nameserver address %s\n", tok));
     247                continue;               
     248            }
     249
     250
     251            tok = getToken(NULL, &s);
     252            if (!NO_VALUE(tok))
     253                LogRel(("NAT: resolv.conf: ignoring unexpected trailer on the nameserver line\n"));
     254
     255            if ((flags & RCPSF_IGNORE_IPV6) && NetAddr.enmType == RTNETADDRTYPE_IPV6)
     256            {
     257                Log2(("NAT: resolv.conf: IPv6 address ignored\n"));
     258                continue;
     259            }
     260
     261            /* seems ok, save it */
     262            {
     263                i = state->rcps_num_nameserver;
     264
     265                state->rcps_nameserver[i] = NetAddr;
     266
     267                /* XXX: TODO: don't save strings unless asked to */
     268                Log2(("NAT: resolv.conf: saving address @%td,+%zu\n",
     269                      pszAddrBuf - state->rcps_nameserver_str_buffer, cbAddrBuf));
     270                state->rcps_str_nameserver[i] = pszAddrBuf;
     271                rc = RTStrCopyP(&pszAddrBuf, &cbAddrBuf, pszAddr);
     272                if (RT_SUCCESS(rc))
     273                {
     274                    ++pszAddrBuf; /* skip '\0' */
     275                    if (cbAddrBuf > 0) /* on overflow we get 1 (for the '\0'), but be defensive */
     276                        --cbAddrBuf;
     277                    ++state->rcps_num_nameserver;
     278                }
     279                else
     280                {
     281                    Log2(("NAT: resolv.conf: ... truncated\n"));
     282                }
     283            }
     284
     285            continue;
     286        }
     287
     288
     289#ifdef RCP_ACCEPT_PORT /* OS X extention */
     290        /*
     291         * PORT
     292         */
     293        if (RTStrCmp(tok, "port") == 0)
     294        {
     295            uint16_t port;
     296
     297            if (default_port != RTNETADDR_PORT_NA)
     298            {
     299                LogRel(("NAT: resolv.conf: ignoring multiple port lines\n"));
     300                continue;
     301            }
     302
     303            tok = getToken(NULL, &s);
     304            if (NO_VALUE(tok))
     305            {
     306                LogRel(("NAT: resolv.conf: port line without value\n"));
     307                continue;
     308            }
     309
     310            rc = RTStrToUInt16Full(tok, 10, &port);
     311            if (RT_SUCCESS(rc))
     312            {
     313                if (port != 0)
     314                    default_port = port;
     315                else
     316                    LogRel(("NAT: resolv.conf: port 0 is invalid\n"));
     317            }
     318
     319            continue;
     320        }
     321#endif
     322
     323
     324        /*
     325         * DOMAIN
     326         */
     327        if (RTStrCmp(tok, "domain") == 0)
     328        {
     329            if (state->rcps_domain != NULL)
     330            {
     331                LogRel(("NAT: resolv.conf: ignoring multiple domain lines\n"));
     332                continue;
     333            }
     334
     335            tok = getToken(NULL, &s);
     336            if (NO_VALUE(tok))
     337            {
     338                LogRel(("NAT: resolv.conf: domain line without value\n"));
     339                continue;
     340            }
     341
     342            rc = RTStrCopy(state->rcps_domain_buffer, sizeof(state->rcps_domain_buffer), tok);
     343            if (RT_SUCCESS(rc))
     344            {
     345                state->rcps_domain = state->rcps_domain_buffer;
     346            }
     347            else
     348            {
     349                LogRel(("NAT: resolv.conf: domain name too long\n"));
     350                RT_ZERO(state->rcps_domain_buffer);
     351            }
     352
     353            continue;
     354        }
     355
     356
     357        /*
     358         * SEARCH
     359         */
     360        if (RTStrCmp(tok, "search") == 0)
     361        {
     362            if (cbSearchBuf == 0)
     363            {
     364                LogRel(("NAT: resolv.conf: no buffer space, ignoring search list %s\n", s));
     365                break;
     366            }
     367
     368            while ((tok = getToken(NULL, &s)) && !NO_VALUE(tok))
     369            {
     370                i = state->rcps_num_searchlist;
     371
     372                Log2(("NAT: resolv.conf: saving search @%td,+%zu\n",
     373                      pszSearchBuf - state->rcps_searchlist_buffer, cbSearchBuf));
     374                state->rcps_searchlist[i] = pszSearchBuf;
     375                rc = RTStrCopyP(&pszSearchBuf, &cbSearchBuf, tok);
     376                if (RT_SUCCESS(rc))
     377                {
     378                    ++pszSearchBuf; /* skip '\0' */
     379                    if (cbSearchBuf > 0) /* on overflow we get 1 (for the '\0'), but be defensive */
     380                        --cbSearchBuf;
     381                    ++state->rcps_num_searchlist;
     382                }
     383                else
     384                {
     385                    Log2(("NAT: resolv.conf: truncated: %s\n", tok));
     386                    pszSearchBuf = state->rcps_searchlist[i];
     387                    cbSearchBuf = sizeof(state->rcps_searchlist_buffer)
     388                        - (pszSearchBuf - state->rcps_searchlist_buffer);
     389                    Log2(("NAT: resolv.conf: backtracking to @%td,+%zu\n",
     390                          pszSearchBuf - state->rcps_searchlist_buffer, cbSearchBuf));
     391                }
     392            }
     393
     394            continue;
     395        }
     396
     397
     398        LogRel(("NAT: resolv.conf: ignoring \"%s %s\"\n", tok, s));
     399    }
    537400
    538401    if (filename != NULL)
    539         RTStrmClose(parser.rcpp_stream);
    540 
    541     if (rc == -1)
    542         return -1;
    543 
    544 #ifdef RT_OS_DARWIN
    545     /**
    546      * port recolv.conf's option and IP.port are Mac OSX extentions, there're no need to care on
    547      * other hosts.
    548      */
    549     if (state->rcps_port == 0)
    550         state->rcps_port = 53;
    551 
    552     for(i = 0;  (state->rcps_flags & RCPSF_NO_STR2IPCONV) == 0
    553              && i != RCPS_MAX_NAMESERVERS; ++i)
     402        RTStrmClose(stream);
     403
     404    if (RT_FAILURE(rc))
     405        return rc;
     406
     407
     408    /* XXX: I don't like that OS X would return a different result here */
     409#ifdef RCP_ACCEPT_PORT /* OS X extention */
     410    if (default_port == RTNETADDR_PORT_NA)
     411        default_port = 53;
     412
     413    for (i = 0; i < state->rcps_num_nameserver; ++i)
    554414    {
    555415        RTNETADDR *addr = &state->rcps_nameserver[i];
    556 
    557         if (addr->uPort == 0)
    558             addr->uPort = state->rcps_port;
     416        if (addr->uPort == RTNETADDR_PORT_NA || addr->uPort == 0)
     417            addr->uPort = (uint16_t)default_port;
    559418    }
    560419#endif
    561420
    562421    if (   state->rcps_domain == NULL
    563         && state->rcps_searchlist[0] != NULL)
     422        && state->rcps_num_searchlist > 0)
     423    {
    564424        state->rcps_domain = state->rcps_searchlist[0];
    565 
    566     return 0;
     425    }
     426
     427    return VINF_SUCCESS;
    567428}
     429
     430
     431static int
     432rcp_address_trailer(char **ppszNext, PRTNETADDR pNetAddr, RTNETADDRTYPE enmType)
     433{
     434    char *pszNext = *ppszNext;
     435    uint16_t port;
     436    int rc = VINF_SUCCESS;
     437
     438    if (*pszNext == '\0')
     439    {
     440        pNetAddr->enmType = enmType;
     441        rc = VINF_SUCCESS;
     442    }
     443#ifdef RCP_ACCEPT_PORT /* OS X extention */
     444    else if (*pszNext == '.')
     445    {
     446        rc = RTStrToUInt16Ex(++pszNext, NULL, 10, &port);
     447        if (RT_SUCCESS(rc))
     448        {
     449            pNetAddr->enmType = enmType;
     450            pNetAddr->uPort = port;
     451        }
     452    }
     453#endif
     454    else
     455    {
     456        rc = VERR_TRAILING_CHARS;
     457    }
     458
     459    return rc;
     460}
     461
     462
     463static char *getToken(char *psz, char **ppszSavePtr)
     464{
     465    char *pszToken;
     466
     467    AssertPtrReturn(ppszSavePtr, NULL);
     468
     469    if (psz == NULL)
     470    {
     471        psz = *ppszSavePtr;
     472        if (psz == NULL)
     473            return NULL;
     474    }
     475
     476    while (*psz && *psz == ' ' && *psz == '\t')
     477        ++psz;
     478
     479    if (*psz == '\0')
     480    {
     481        *ppszSavePtr = NULL;
     482        return NULL;
     483    }
     484
     485    pszToken = psz;
     486    while (*psz && *psz != ' ' && *psz != '\t')
     487        ++psz;
     488
     489    if (*psz == '\0')
     490        psz = NULL;
     491    else
     492        *psz++ = '\0';
     493
     494    *ppszSavePtr = psz;
     495    return pszToken;
     496}
  • trunk/src/VBox/Devices/Network/slirp/resolv_conf_parser.h

    r56292 r60960  
    4545 */
    4646#define RCPSF_IGNORE_IPV6 RT_BIT(0)
     47
    4748/**
    48  * In Main, we perhaps don't need parsed IPv6 and IPv4, because parsed values are
    49  * used in Network services.
     49 * This flag used to request just the strings in rcps_str_nameserver,
     50 * but no addresses in rcps_nameserver.  This is not very useful,
     51 * since we need to validate addresses anyway.  This flag is ignored
     52 * now.
    5053 */
    5154#define RCPSF_NO_STR2IPCONV RT_BIT(1)
     55
    5256
    5357struct rcp_state
     
    7680
    7781    char rcps_domain_buffer[RCPS_BUFFER_SIZE];
    78     char rcps_searchlist_buffer[RCPS_BUFFER_SIZE];
     82    char rcps_searchlist_buffer[20 /*RCPS_BUFFER_SIZE*/];
    7983    char rcps_nameserver_str_buffer[RCPS_MAX_NAMESERVERS * RCPS_IPVX_SIZE];
    8084};
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette