Changes since 4.0.0a1
+- Two new operators, ~= and ~~, have been integrated to implement
+ boolean matches by regular expression (such as may be used in
+ class matching statements). Thanks to a patch by Alexandr S.
+ Agranovsky, which underwent slight modification.
+
- Fix for icmp packets on 64-bit systems (bug introduced in 4.0).
- A bug was fixed in interface discovery wherein an error identifying
-.\" $Id: dhcp-eval.5,v 1.26 2007/05/19 19:16:24 dhankins Exp $
+.\" $Id: dhcp-eval.5,v 1.27 2007/06/07 15:52:29 dhankins Exp $
.\"
.\" Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
.\" Copyright (c) 1996-2003 by Internet Software Consortium
The following is the current list of boolean expressions that are
supported by the DHCP distribution.
.PP
-.I data-expression-1 \fB=\fI data-expression-2\fR
+.I data-expression-1 \fB=\fR \fIdata-expression-2\fR
.RS 0.25i
.PP
The \fB=\fR operator compares the values of two data expressions,
result is also null.
.RE
.PP
-.I boolean-expression-1 \fBand\fI boolean-expression-2\fR
+.I data-expression-1 \fB~=\fR \fIdata-expression-2\fR
+.I data-expression-1 \fB~~\fR \fIdata-expression-2\fR
+.RS 0.25i
+.PP
+The \fB~=\fR and \fB~~\fR operators (not available on all systems) perform
+extended regex(7) matching of the values of two data expressions, returning
+true if \fIdata-expression-1\fR matches against the regular expression
+evaluated by \fIdata-expression-2\fR, or false if it does not match or
+encounters some error. If either the left-hand side or the right-hand side
+are null, the result is also false. The \fB~~\fR operator differs from the
+\fB~=\fR operator in that it is case-insensitive.
+.RE
+.PP
+.I boolean-expression-1 \fBand\fR \fIboolean-expression-2\fR
.PP
.RS 0.25i
The \fBand\fR operator evaluates to true if the boolean expression on
right-hand side are null, the result is null.
.RE
.PP
-.I boolean-expression-1 \fBor\fI boolean-expression-2\fR
+.I boolean-expression-1 \fBor\fR \fIboolean-expression-2\fR
.PP
.RS 0.25i
The \fBor\fR operator evaluates to true if either the boolean
#ifndef lint
static char copyright[] =
-"$Id: parse.c,v 1.126 2007/05/29 18:11:55 each Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n";
+"$Id: parse.c,v 1.127 2007/06/07 15:52:29 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
* NOT boolean-expression |
* data-expression EQUAL data-expression |
* data-expression BANG EQUAL data-expression |
+ * data-expression REGEX_MATCH data-expression |
* boolean-expression AND boolean-expression |
* boolean-expression OR boolean-expression
* EXISTS OPTION-NAME
context = expression_context (rhs);
break;
+ case TILDE:
+#ifdef HAVE_REGEX_H
+ token = next_token(&val, NULL, cfile);
+ token = peek_token(&val, NULL, cfile);
+
+ if (token == TILDE)
+ next_op = expr_iregex_match;
+ else if (token == EQUAL)
+ next_op = expr_regex_match;
+ else {
+ parse_warn(cfile, "expecting ~= or ~~ operator");
+ *lose = 1;
+ skip_to_semi(cfile);
+ if (lhs)
+ expression_dereference(&lhs, MDL);
+ return 0;
+ }
+
+ context = expression_context(rhs);
+#else
+ parse_warn(cfile, "No support for regex operator.");
+ *lose = 1;
+ skip_to_semi(cfile);
+ if (lhs != NULL)
+ expression_dereference(&lhs, MDL);
+ return 0;
+#endif
+ break;
+
case AND:
next_op = expr_and;
context = expression_context (rhs);
}
break;
+ case expr_regex_match:
+#ifdef HAVE_REGEX_H
+ if (expression_context(rhs) != context_data) {
+ parse_warn(cfile, "expecting data expression");
+ skip_to_semi(cfile);
+ expression_dereference(&rhs, MDL);
+ *lose = 1;
+ return 0;
+ }
+#else
+ /* It should not be possible to attempt to parse the right
+ * hand side of an operator there is no support for.
+ */
+ log_fatal("Impossible condition at %s:%d.", MDL);
+#endif
+ break;
+
case expr_and:
case expr_or:
if ((rhs_context != context_boolean) &&
#ifndef lint
static char copyright[] =
-"$Id: print.c,v 1.66 2007/05/29 18:11:55 each Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n";
+"$Id: print.c,v 1.67 2007/06/07 15:52:29 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
}
break;
+ case expr_regex_match:
+ if (len > 10) {
+ rv = 4;
+ strcpy(buf, "(regex ");
+ rv += print_subexpression(expr->data.equal[0],
+ buf + rv, len - rv - 2);
+ buf[rv++] = ' ';
+ rv += print_subexpression(expr->data.equal[1],
+ buf + rv, len - rv - 1);
+ buf[rv++] = ')';
+ buf[rv] = 0;
+ return rv;
+ }
+ break;
+
case expr_substring:
if (len > 11) {
rv = 8;
#ifndef lint
static char copyright[] =
-"$Id: tree.c,v 1.115 2007/05/19 19:16:24 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n";
+"$Id: tree.c,v 1.116 2007/06/07 15:52:29 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
#include <ctype.h>
#include <sys/wait.h>
+#ifdef HAVE_REGEX_H
+# include <regex.h>
+#endif
+
struct binding_scope *global_scope;
static int do_host_lookup PROTO ((struct data_string *,
case expr_check:
case expr_equal:
case expr_not_equal:
+ case expr_regex_match:
+ case expr_iregex_match:
case expr_and:
case expr_or:
case expr_not:
int sleft, sright;
struct binding *binding;
struct binding_value *bv, *obv;
+#ifdef HAVE_REGEX_H
+ int reg_st, regflags = REG_EXTENDED | REG_NOSUB;
+ regex_t re;
+#endif
switch (expr -> op) {
case expr_check:
binding_value_dereference (&obv, MDL);
return 1;
+ case expr_iregex_match:
+#ifdef HAVE_REGEX_H
+ regflags |= REG_ICASE;
+#endif
+ /* FALL THROUGH */
+ case expr_regex_match:
+#ifdef HAVE_REGEX_H
+ memset(&left, 0, sizeof left);
+ bleft = evaluate_data_expression(&left, packet, lease,
+ client_state,
+ in_options, cfg_options,
+ scope,
+ expr->data.equal[0], MDL);
+ memset(&right, 0, sizeof right);
+ bright = evaluate_data_expression(&right, packet, lease,
+ client_state,
+ in_options, cfg_options,
+ scope,
+ expr->data.equal[1], MDL);
+
+ *result = 0;
+ memset(&re, 0, sizeof(re));
+ if (bleft && bright &&
+ (regcomp(&re, right.data, regflags) == 0) &&
+ (regexec(&re, left.data, (size_t)0, NULL, 0) == 0))
+ *result = 1;
+
+#if defined (DEBUG_EXPRESSIONS)
+ log_debug("bool: %s ~= %s yields %s",
+ bleft ? print_hex_1(left.len, left.data, 20)
+ : "NULL",
+ bright ? print_hex_2 (right.len, right.data, 20)
+ : "NULL",
+ *result ? "true" : "false");
+#endif
+
+ if (bleft)
+ data_string_forget(&left, MDL);
+ if (bright)
+ data_string_forget(&right, MDL);
+
+ regfree(&re);
+ return reg_st;
+#else
+ /* It shouldn't be possible to configure a regex operator
+ * when there's no support.
+ */
+ log_fatal("Impossible condition at %s:%d.", MDL);
+ break;
+#endif
+
case expr_and:
sleft = evaluate_boolean_expression (&bleft, packet, lease,
client_state,
case expr_check:
case expr_equal:
case expr_not_equal:
+ case expr_regex_match:
+ case expr_iregex_match:
case expr_and:
case expr_or:
case expr_not:
case expr_check:
case expr_equal:
case expr_not_equal:
+ case expr_regex_match:
+ case expr_iregex_match:
case expr_and:
case expr_or:
case expr_not:
/* All the binary operators can be handled the same way. */
case expr_equal:
case expr_not_equal:
+ case expr_regex_match:
+ case expr_iregex_match:
case expr_concat:
case expr_and:
case expr_or:
expr -> op == expr_variable_exists ||
expr -> op == expr_equal ||
expr -> op == expr_not_equal ||
+ expr->op == expr_regex_match ||
+ expr->op == expr_iregex_match ||
expr -> op == expr_and ||
expr -> op == expr_or ||
expr -> op == expr_not ||
case expr_equal:
case expr_not_equal:
+ case expr_regex_match:
+ case expr_iregex_match:
return 4;
case expr_or:
case expr_equal:
case expr_not_equal:
+ case expr_regex_match:
+ case expr_iregex_match:
return context_data;
case expr_and:
"\"", (char *)0);
break;
+ case expr_regex_match:
+ s = "~=";
+ goto binary;
+
+ case expr_iregex_match:
+ s = "~~";
+ goto binary;
+
case expr_not_equal:
s = "!=";
goto binary;
case expr_match:
case expr_check:
case expr_equal:
+ case expr_regex_match:
+ case expr_iregex_match:
case expr_and:
case expr_or:
case expr_not:
fi
# Look for optional headers.
-AC_CHECK_HEADER(net/if_dl.h,
- AC_DEFINE([HAVE_IF_DL], [1],
- [Define to 1 if the system has a net/if_dl.h header.]))
+AC_CHECK_HEADERS(net/if_dl.h regex.h)
# find an MD5 library
AC_SEARCH_LIBS(MD5_Init, [crypto])
AC_DEFINE([NEED_INET_ATON], [1],
[Define to 1 if the inet_aton() function is missing.]))
+# Check for a standalone regex library.
+AC_SEARCH_LIBS(regcomp, [regex])
+
# check for /dev/random (declares HAVE_DEV_RANDOM)
AC_CHECK_FILE(/dev/random,
AC_DEFINE([HAVE_DEV_RANDOM], [1],
#include <net/if.h>
#include <net/route.h>
#include <net/if_arp.h>
-#if HAVE_IF_DL
+#if HAVE_IF_DL_H
# include <net/if_dl.h>
#endif
LPAREN = '(',
RPAREN = ')',
EQUAL = '=',
+ TILDE = '~',
BANG = '!',
PERCENT = '%',
PLUS = '+',
expr_binary_xor,
expr_client_state,
expr_ucase,
- expr_lcase
+ expr_lcase,
+ expr_regex_match,
+ expr_iregex_match
};
struct expression {