- Timestamp:
- May 12, 2016 3:24:18 PM (9 years ago)
- 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 5 5 6 6 /* 7 * Copyright (C) 201 4-2015Oracle Corporation7 * Copyright (C) 2016 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 16 16 */ 17 17 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 18 26 #include <iprt/assert.h> 19 #include <iprt/initterm.h>20 27 #include <iprt/net.h> 21 28 #include <iprt/string.h> … … 23 30 #include <iprt/thread.h> 24 31 32 #include <VBox/log.h> 33 25 34 #ifdef RT_OS_FREEBSD 26 35 # include <sys/socket.h> … … 29 38 #include <arpa/inet.h> 30 39 31 #include <ctype.h>32 33 40 #include "resolv_conf_parser.h" 34 41 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 48 static int rcp_address_trailer(char **ppszNext, PRTNETADDR pNetAddr, RTNETADDRTYPE enmType); 49 static 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 63 int main(int argc, char **argv) 38 64 { 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 } 495 97 496 98 return 0; 497 99 } 498 499 500 int rcp_parse(struct rcp_state* state, const char *filename) 100 #endif 101 102 103 int rcp_parse(struct rcp_state *state, const char *filename) 501 104 { 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; 502 114 unsigned i; 503 uint32_t flags;504 115 int rc; 505 struct rcp_parser parser; 116 117 AssertPtrReturn(state, VERR_INVALID_PARAMETER); 506 118 flags = state->rcps_flags; 507 119 508 RT_ZERO(parser);509 120 RT_ZERO(*state); 510 511 121 state->rcps_flags = flags; 512 122 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 { 523 125 #ifdef RCP_STANDALONE 524 if (filename == NULL) 525 parser.rcpp_stream = g_pStdIn; 126 stream = g_pStdIn; /* for testing/debugging */ 526 127 #else 527 if (filename == NULL)528 return -1; 529 #endif 128 return VERR_INVALID_PARAMETER; 129 #endif 130 } 530 131 else 531 132 { 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 } 537 400 538 401 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) 554 414 { 555 415 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; 559 418 } 560 419 #endif 561 420 562 421 if ( state->rcps_domain == NULL 563 && state->rcps_searchlist[0] != NULL) 422 && state->rcps_num_searchlist > 0) 423 { 564 424 state->rcps_domain = state->rcps_searchlist[0]; 565 566 return 0; 425 } 426 427 return VINF_SUCCESS; 567 428 } 429 430 431 static int 432 rcp_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 463 static 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 45 45 */ 46 46 #define RCPSF_IGNORE_IPV6 RT_BIT(0) 47 47 48 /** 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. 50 53 */ 51 54 #define RCPSF_NO_STR2IPCONV RT_BIT(1) 55 52 56 53 57 struct rcp_state … … 76 80 77 81 char rcps_domain_buffer[RCPS_BUFFER_SIZE]; 78 char rcps_searchlist_buffer[ RCPS_BUFFER_SIZE];82 char rcps_searchlist_buffer[20 /*RCPS_BUFFER_SIZE*/]; 79 83 char rcps_nameserver_str_buffer[RCPS_MAX_NAMESERVERS * RCPS_IPVX_SIZE]; 80 84 };
Note:
See TracChangeset
for help on using the changeset viewer.