From 66eaae186e42e4bd5ae016af723fde9d6f5c518f Mon Sep 17 00:00:00 2001 From: Shane Kerr Date: Wed, 23 May 2007 15:29:49 +0000 Subject: [PATCH] Handle hostnames that start with numbers. This involved needing to look at more than one token at a time, so this patch moves from read() to mmap() of files, as a way to gracefully rewind. See RT ticket #16516 for (a lot) more. --- common/conflex.c | 108 ++++++++++++++++++++++------------------------- common/parse.c | 38 ++++++++++++++--- includes/dhcpd.h | 5 ++- 3 files changed, 84 insertions(+), 67 deletions(-) diff --git a/common/conflex.c b/common/conflex.c index 52b7e43f..89a4f465 100644 --- a/common/conflex.c +++ b/common/conflex.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: conflex.c,v 1.107 2007/05/19 19:16:24 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n"; +"$Id: conflex.c,v 1.108 2007/05/23 15:29:49 shane Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -63,29 +63,36 @@ isc_result_t new_parse (cfile, file, inbuf, buflen, name, eolp) return ISC_R_NOMEMORY; memset (tmp, 0, sizeof *tmp); - tmp -> token = 0; - tmp -> tlname = name; - tmp -> lpos = tmp -> line = 1; - tmp -> cur_line = tmp -> line1; - tmp -> prev_line = tmp -> line2; - tmp -> token_line = tmp -> cur_line; - tmp -> cur_line [0] = tmp -> prev_line [0] = 0; - tmp -> warnings_occurred = 0; - tmp -> file = file; - tmp -> eol_token = eolp; + tmp->token = 0; + tmp->tlname = name; + tmp->lpos = tmp -> line = 1; + tmp->cur_line = tmp -> line1; + tmp->prev_line = tmp -> line2; + tmp->token_line = tmp -> cur_line; + tmp->cur_line [0] = tmp -> prev_line [0] = 0; + tmp->warnings_occurred = 0; + tmp->file = file; + tmp->eol_token = eolp; + + tmp->bufix = 0; - tmp -> bufix = 0; - tmp -> buflen = buflen; if (inbuf) { - tmp -> bufsiz = 0; - tmp -> inbuf = inbuf; + tmp->inbuf = inbuf; + tmp->buflen = buflen; + tmp->bufsiz = 0; } else { - tmp -> inbuf = dmalloc (8192, MDL); - if (!tmp -> inbuf) { - dfree (tmp, MDL); - return ISC_R_NOMEMORY; + struct stat sb; + + if (fstat(file, &sb) < 0) + return ISC_R_IOERROR; + + tmp->bufsiz = tmp->buflen = (size_t) sb.st_size; + tmp->inbuf = mmap(NULL, tmp->bufsiz, PROT_READ, MAP_SHARED, + file, 0); + + if (tmp->inbuf == MAP_FAILED) { + return ISC_R_IOERROR; } - tmp -> bufsiz = 8192; } *cfile = tmp; @@ -96,11 +103,11 @@ isc_result_t end_parse (cfile) struct parse **cfile; { /* "Memory" config files have no file. */ - if ((*cfile)->file != -1) + if ((*cfile)->file != -1) { + munmap((*cfile)->inbuf, (*cfile)->bufsiz); close((*cfile)->file); - - if ((*cfile)->bufsiz) - dfree((*cfile)->inbuf, MDL); + } + dfree(*cfile, MDL); *cfile = NULL; return ISC_R_SUCCESS; @@ -112,49 +119,34 @@ static int get_char (cfile) /* My kingdom for WITH... */ int c; - if (cfile -> bufix == cfile -> buflen) { - if (cfile -> file != -1) { - cfile -> buflen = - read (cfile -> file, - cfile -> inbuf, cfile -> bufsiz); - if (cfile -> buflen == 0) { - c = EOF; - cfile -> bufix = 0; - } else if (cfile -> buflen < 0) { - c = EOF; - cfile -> bufix = cfile -> buflen = 0; - } else { - c = cfile -> inbuf [0]; - cfile -> bufix = 1; - } - } else - c = EOF; - } else { - c = cfile -> inbuf [cfile -> bufix]; - cfile -> bufix++; + if (cfile->bufix == cfile->buflen) + c = EOF; + else { + c = cfile->inbuf [cfile->bufix]; + cfile->bufix++; } - if (!cfile -> ugflag) { + if (!cfile->ugflag) { if (c == EOL) { - if (cfile -> cur_line == cfile -> line1) { - cfile -> cur_line = cfile -> line2; - cfile -> prev_line = cfile -> line1; + if (cfile->cur_line == cfile->line1) { + cfile->cur_line = cfile->line2; + cfile->prev_line = cfile->line1; } else { - cfile -> cur_line = cfile -> line1; - cfile -> prev_line = cfile -> line2; + cfile->cur_line = cfile->line1; + cfile->prev_line = cfile->line2; } - cfile -> line++; - cfile -> lpos = 1; - cfile -> cur_line [0] = 0; + cfile->line++; + cfile->lpos = 1; + cfile->cur_line [0] = 0; } else if (c != EOF) { - if (cfile -> lpos <= 80) { - cfile -> cur_line [cfile -> lpos - 1] = c; - cfile -> cur_line [cfile -> lpos] = 0; + if (cfile->lpos <= 80) { + cfile->cur_line [cfile->lpos - 1] = c; + cfile->cur_line [cfile->lpos] = 0; } - cfile -> lpos++; + cfile->lpos++; } } else - cfile -> ugflag = 0; + cfile->ugflag = 0; return c; } diff --git a/common/parse.c b/common/parse.c index 3d123a34..6287193f 100644 --- a/common/parse.c +++ b/common/parse.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: parse.c,v 1.124 2007/05/19 19:16:24 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n"; +"$Id: parse.c,v 1.125 2007/05/23 15:29:49 shane Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -257,7 +257,11 @@ char *parse_host_name (cfile) Parse an ip address or a hostname. If uniform is zero, put in an expr_substring node to limit hostnames that evaluate to more - than one IP address. */ + than one IP address. + + Note that RFC1123 permits hostnames to consist of all digits, + making it difficult to quickly disambiguate them from ip addresses. +*/ int parse_ip_addr_or_hostname (expr, cfile, uniform) struct expression **expr; @@ -270,9 +274,33 @@ int parse_ip_addr_or_hostname (expr, cfile, uniform) unsigned len = sizeof addr; char *name; struct expression *x = (struct expression *)0; + struct parse cfile0; + int ipaddr = 0; token = peek_token (&val, (unsigned *)0, cfile); - if (is_identifier (token)) { + + if (token == NUMBER) { + /* + * a hostname may be numeric, but domain names must + * start with a letter, so we can disambiguate by + * looking ahead a few tokens. we save the parse + * context first, and restore it after we know what + * we're dealing with. + */ + memcpy(&cfile0, cfile, sizeof(struct parse)); + (void) next_token(NULL, NULL, cfile); + if (next_token(NULL, NULL, cfile) == DOT && + next_token(NULL, NULL, cfile) == NUMBER) + ipaddr = 1; + memcpy(cfile, &cfile0, sizeof(struct parse)); + + if (ipaddr && + parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) + return make_const_data (expr, addr, len, 0, 1, MDL); + + } + + if (is_identifier (token) || token == NUMBER) { name = parse_host_name (cfile); if (!name) return 0; @@ -287,10 +315,6 @@ int parse_ip_addr_or_hostname (expr, cfile, uniform) expression_dereference (expr, MDL); *expr = x; } - } else if (token == NUMBER) { - if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) - return 0; - return make_const_data (expr, addr, len, 0, 1, MDL); } else { if (token != RBRACE && token != LBRACE) token = next_token (&val, (unsigned *)0, cfile); diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 69feb44c..2fade44e 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -272,8 +273,8 @@ struct parse { int warnings_occurred; int file; char *inbuf; - unsigned bufix, buflen; - unsigned bufsiz; + size_t bufix, buflen; + size_t bufsiz; }; /* Variable-length array of data. */