parse.c
来自「open source dhcp server client etc...」· C语言 代码 · 共 2,592 行 · 第 1/5 页
C
2,592 行
/* parse.c Common parser code for dhcpd and dhclient. *//* * Copyright (c) 1995-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about the Internet Software Consortium, see * ``http://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */#ifndef lintstatic char copyright[] ="$Id: parse.c,v 1.104.2.6 2001/06/26 18:33:32 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium. All rights reserved.\n";#endif /* not lint */#include "dhcpd.h"/* Enumerations can be specified in option formats, and are used for parsing, so we define the routines that manage them here. */struct enumeration *enumerations;void add_enumeration (struct enumeration *enumeration){ enumeration -> next = enumerations; enumerations = enumeration;}struct enumeration *find_enumeration (const char *name, int length){ struct enumeration *e; for (e = enumerations; e; e = e -> next) if (strlen (e -> name) == length && !memcmp (e -> name, name, (unsigned)length)) return e; return (struct enumeration *)0;}struct enumeration_value *find_enumeration_value (const char *name, int length, const char *value){ struct enumeration *e; int i; e = find_enumeration (name, length); if (e) { for (i = 0; e -> values [i].name; i++) { if (!strcmp (value, e -> values [i].name)) return &e -> values [i]; } } return (struct enumeration_value *)0;}/* Skip to the semicolon ending the current statement. If we encounter braces, the matching closing brace terminates the statement. If we encounter a right brace but haven't encountered a left brace, return leaving the brace in the token buffer for the caller. If we see a semicolon and haven't seen a left brace, return. This lets us skip over: statement; statement foo bar { } statement foo bar { statement { } } statement} ...et cetera. */void skip_to_semi (cfile) struct parse *cfile;{ skip_to_rbrace (cfile, 0);}void skip_to_rbrace (cfile, brace_count) struct parse *cfile; int brace_count;{ enum dhcp_token token; const char *val;#if defined (DEBUG_TOKEN) log_error ("skip_to_rbrace: %d\n", brace_count);#endif do { token = peek_token (&val, (unsigned *)0, cfile); if (token == RBRACE) { token = next_token (&val, (unsigned *)0, cfile); if (brace_count) { if (!--brace_count) return; } else return; } else if (token == LBRACE) { brace_count++; } else if (token == SEMI && !brace_count) { token = next_token (&val, (unsigned *)0, cfile); return; } else if (token == EOL) { /* EOL only happens when parsing /etc/resolv.conf, and we treat it like a semicolon because the resolv.conf file is line-oriented. */ token = next_token (&val, (unsigned *)0, cfile); return; } token = next_token (&val, (unsigned *)0, cfile); } while (token != END_OF_FILE);}int parse_semi (cfile) struct parse *cfile;{ enum dhcp_token token; const char *val; token = next_token (&val, (unsigned *)0, cfile); if (token != SEMI) { parse_warn (cfile, "semicolon expected."); skip_to_semi (cfile); return 0; } return 1;}/* string-parameter :== STRING SEMI */int parse_string (cfile, sptr, lptr) struct parse *cfile; char **sptr; unsigned *lptr;{ const char *val; enum dhcp_token token; char *s; unsigned len; token = next_token (&val, &len, cfile); if (token != STRING) { parse_warn (cfile, "expecting a string"); skip_to_semi (cfile); return 0; } s = (char *)dmalloc (len + 1, MDL); if (!s) log_fatal ("no memory for string %s.", val); memcpy (s, val, len + 1); if (!parse_semi (cfile)) { dfree (s, MDL); return 0; } if (sptr) *sptr = s; else dfree (s, MDL); if (lptr) *lptr = len; return 1;}/* * hostname :== IDENTIFIER * | IDENTIFIER DOT * | hostname DOT IDENTIFIER */char *parse_host_name (cfile) struct parse *cfile;{ const char *val; enum dhcp_token token; unsigned len = 0; char *s; char *t; pair c = (pair)0; int ltid = 0; /* Read a dotted hostname... */ do { /* Read a token, which should be an identifier. */ token = peek_token (&val, (unsigned *)0, cfile); if (!is_identifier (token) && token != NUMBER) break; token = next_token (&val, (unsigned *)0, cfile); /* Store this identifier... */ if (!(s = (char *)dmalloc (strlen (val) + 1, MDL))) log_fatal ("can't allocate temp space for hostname."); strcpy (s, val); c = cons ((caddr_t)s, c); len += strlen (s) + 1; /* Look for a dot; if it's there, keep going, otherwise we're done. */ token = peek_token (&val, (unsigned *)0, cfile); if (token == DOT) { token = next_token (&val, (unsigned *)0, cfile); ltid = 1; } else ltid = 0; } while (token == DOT); /* Should be at least one token. */ if (!len) return (char *)0; /* Assemble the hostname together into a string. */ if (!(s = (char *)dmalloc (len + ltid, MDL))) log_fatal ("can't allocate space for hostname."); t = s + len + ltid; *--t = 0; if (ltid) *--t = '.'; while (c) { pair cdr = c -> cdr; unsigned l = strlen ((char *)(c -> car)); t -= l; memcpy (t, (char *)(c -> car), l); /* Free up temp space. */ dfree (c -> car, MDL); dfree (c, MDL); c = cdr; if (t != s) *--t = '.'; } return s;}/* ip-addr-or-hostname :== ip-address | hostname ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER 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. */int parse_ip_addr_or_hostname (expr, cfile, uniform) struct expression **expr; struct parse *cfile; int uniform;{ const char *val; enum dhcp_token token; unsigned char addr [4]; unsigned len = sizeof addr; char *name; struct expression *x = (struct expression *)0; token = peek_token (&val, (unsigned *)0, cfile); if (is_identifier (token)) { name = parse_host_name (cfile); if (!name) return 0; if (!make_host_lookup (expr, name)) return 0; if (!uniform) { if (!make_limit (&x, *expr, 4)) return 0; 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); parse_warn (cfile, "%s (%d): expecting IP address or hostname", val, token); if (token != SEMI) skip_to_semi (cfile); return 0; } return 1;} /* * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER */int parse_ip_addr (cfile, addr) struct parse *cfile; struct iaddr *addr;{ const char *val; enum dhcp_token token; addr -> len = 4; if (parse_numeric_aggregate (cfile, addr -> iabuf, &addr -> len, DOT, 10, 8)) return 1; return 0;} /* * hardware-parameter :== HARDWARE hardware-type colon-seperated-hex-list SEMI * hardware-type :== ETHERNET | TOKEN_RING */void parse_hardware_param (cfile, hardware) struct parse *cfile; struct hardware *hardware;{ const char *val; enum dhcp_token token; unsigned hlen; unsigned char *t; token = next_token (&val, (unsigned *)0, cfile); switch (token) { case ETHERNET: hardware -> hbuf [0] = HTYPE_ETHER; break; case TOKEN_RING: hardware -> hbuf [0] = HTYPE_IEEE802; break; case FDDI: hardware -> hbuf [0] = HTYPE_FDDI; break; default: if (!strncmp (val, "unknown-", 8)) { hardware -> hbuf [0] = atoi (&val [8]); } else { parse_warn (cfile, "expecting a network hardware type"); skip_to_semi (cfile); return; } } /* Parse the hardware address information. Technically, it would make a lot of sense to restrict the length of the data we'll accept here to the length of a particular hardware address type. Unfortunately, there are some broken clients out there that put bogus data in the chaddr buffer, and we accept that data in the lease file rather than simply failing on such clients. Yuck. */ hlen = 0; token = peek_token (&val, (unsigned *)0, cfile); if (token == SEMI) { hardware -> hlen = 1; goto out; } t = parse_numeric_aggregate (cfile, (unsigned char *)0, &hlen, COLON, 16, 8); if (!t) { hardware -> hlen = 1; return; } if (hlen + 1 > sizeof hardware -> hbuf) { dfree (t, MDL); parse_warn (cfile, "hardware address too long"); } else { hardware -> hlen = hlen + 1; memcpy ((unsigned char *)&hardware -> hbuf [1], t, hlen); if (hlen + 1 < sizeof hardware -> hbuf) memset (&hardware -> hbuf [hlen + 1], 0, (sizeof hardware -> hbuf) - hlen - 1); dfree (t, MDL); } out: token = next_token (&val, (unsigned *)0, cfile); if (token != SEMI) { parse_warn (cfile, "expecting semicolon."); skip_to_semi (cfile); }}/* lease-time :== NUMBER SEMI */void parse_lease_time (cfile, timep) struct parse *cfile; TIME *timep;{ const char *val; enum dhcp_token token; token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "Expecting numeric lease time"); skip_to_semi (cfile); return; } convert_num (cfile, (unsigned char *)timep, val, 10, 32); /* Unswap the number - convert_num returns stuff in NBO. */ *timep = ntohl (*timep); /* XXX */ parse_semi (cfile);}/* No BNF for numeric aggregates - that's defined by the caller. What this function does is to parse a sequence of numbers seperated by the token specified in seperator. If max is zero, any number of numbers will be parsed; otherwise, exactly max numbers are expected. Base and size tell us how to internalize the numbers once they've been tokenized. */unsigned char *parse_numeric_aggregate (cfile, buf, max, seperator, base, size) struct parse *cfile; unsigned char *buf; unsigned *max; int seperator; int base; unsigned size;{ const char *val; enum dhcp_token token; unsigned char *bufp = buf, *s, *t; unsigned count = 0; pair c = (pair)0; if (!bufp && *max) { bufp = (unsigned char *)dmalloc (*max * size / 8, MDL); if (!bufp) log_fatal ("no space for numeric aggregate"); s = 0; } else s = bufp; do { if (count) { token = peek_token (&val, (unsigned *)0, cfile); if (token != seperator) { if (!*max) break; if (token != RBRACE && token != LBRACE) token = next_token (&val, (unsigned *)0, cfile); parse_warn (cfile, "too few numbers."); if (token != SEMI) skip_to_semi (cfile); return (unsigned char *)0; } token = next_token (&val, (unsigned *)0, cfile); } token = next_token (&val, (unsigned *)0, cfile); if (token == END_OF_FILE) { parse_warn (cfile, "unexpected end of file"); break; } /* Allow NUMBER_OR_NAME if base is 16. */ if (token != NUMBER && (base != 16 || token != NUMBER_OR_NAME)) { parse_warn (cfile, "expecting numeric value."); skip_to_semi (cfile); return (unsigned char *)0; } /* If we can, convert the number now; otherwise, build a linked list of all the numbers. */ if (s) { convert_num (cfile, s, val, base, size); s += size / 8; } else { t = (unsigned char *)dmalloc (strlen (val) + 1, MDL); if (!t) log_fatal ("no temp space for number."); strcpy ((char *)t, val); c = cons ((caddr_t)t, c); } } while (++count != *max); /* If we had to cons up a list, convert it now. */ if (c) { bufp = (unsigned char *)dmalloc (count * size / 8, MDL); if (!bufp) log_fatal ("no space for numeric aggregate."); s = bufp + count - size / 8; *max = count; } while (c) { pair cdr = c -> cdr; convert_num (cfile, s, (char *)(c -> car), base, size); s -= size / 8; /* Free up temp space. */ dfree (c -> car, MDL); dfree (c, MDL); c = cdr; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?