2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-22 01:49:35 +00:00

- 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.  [ISC-Bugs #8155]
This commit is contained in:
David Hankins 2007-06-07 15:52:30 +00:00
parent a546f2a714
commit dd3282251e
9 changed files with 179 additions and 12 deletions

View File

@ -54,6 +54,11 @@ suggested fixes to <dhcp-users@isc.org>.
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

View File

@ -1,4 +1,4 @@
.\" $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
@ -114,7 +114,7 @@ treated as false in conditionals.
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,
@ -123,7 +123,20 @@ either the left-hand side or the right-hand side are null, the
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
@ -133,7 +146,7 @@ the expression on the left-hand side or the expression on the
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

View File

@ -34,7 +34,7 @@
#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"
@ -3195,6 +3195,7 @@ int parse_if_statement (result, cfile, lose)
* 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
@ -4559,6 +4560,35 @@ int parse_expression (expr, cfile, lose, context, plhs, binop)
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);
@ -4685,6 +4715,23 @@ int parse_expression (expr, cfile, lose, context, plhs, binop)
}
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) &&

View File

@ -34,7 +34,7 @@
#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"
@ -517,6 +517,21 @@ static unsigned print_subexpression (expr, buf, len)
}
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;

View File

@ -34,7 +34,7 @@
#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"
@ -42,6 +42,10 @@ static char copyright[] =
#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 *,
@ -968,6 +972,8 @@ int evaluate_dns_expression (result, packet, lease, client_state, in_options,
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:
@ -1061,6 +1067,10 @@ int evaluate_boolean_expression (result, packet, lease, client_state,
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:
@ -1153,6 +1163,57 @@ int evaluate_boolean_expression (result, packet, lease, client_state,
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,
@ -2296,6 +2357,8 @@ int evaluate_data_expression (result, 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:
@ -2374,6 +2437,8 @@ int evaluate_numeric_expression (result, 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:
@ -2990,6 +3055,8 @@ void expression_dereference (eptr, file, line)
/* 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:
@ -3211,6 +3278,8 @@ int is_boolean_expression (expr)
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 ||
@ -3350,6 +3419,8 @@ static int op_val (op)
case expr_equal:
case expr_not_equal:
case expr_regex_match:
case expr_iregex_match:
return 4;
case expr_or:
@ -3443,6 +3514,8 @@ enum expression_context op_context (op)
case expr_equal:
case expr_not_equal:
case expr_regex_match:
case expr_iregex_match:
return context_data;
case expr_and:
@ -3498,6 +3571,14 @@ int write_expression (file, expr, col, indent, firstp)
"\"", (char *)0);
break;
case expr_regex_match:
s = "~=";
goto binary;
case expr_iregex_match:
s = "~~";
goto binary;
case expr_not_equal:
s = "!=";
goto binary;
@ -4179,6 +4260,8 @@ int data_subexpression_length (int *rv,
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:

View File

@ -86,9 +86,7 @@ else
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])
@ -102,6 +100,9 @@ AC_SEARCH_LIBS(inet_aton, [socket nsl], ,
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],

View File

@ -59,7 +59,7 @@
#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

View File

@ -43,6 +43,7 @@ enum dhcp_token {
LPAREN = '(',
RPAREN = ')',
EQUAL = '=',
TILDE = '~',
BANG = '!',
PERCENT = '%',
PLUS = '+',

View File

@ -193,7 +193,9 @@ enum expr_op {
expr_binary_xor,
expr_client_state,
expr_ucase,
expr_lcase
expr_lcase,
expr_regex_match,
expr_iregex_match
};
struct expression {