]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
- Two new operators, ~= and ~~, have been integrated to implement
authorDavid Hankins <dhankins@isc.org>
Thu, 7 Jun 2007 15:52:30 +0000 (15:52 +0000)
committerDavid Hankins <dhankins@isc.org>
Thu, 7 Jun 2007 15:52:30 +0000 (15:52 +0000)
  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]

RELNOTES
common/dhcp-eval.5
common/parse.c
common/print.c
common/tree.c
configure.ac
includes/dhcpd.h
includes/dhctoken.h
includes/tree.h

index 7c99f43db65eddb93d8f9ee512be34b7474dfbd3..441e5456ddb02d3d47df76384cb43e08de6a433a 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -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
index 0647d27d1c55e3d9e3dc0f5802332275f20e132a..1bde0b2b453513a17e5323e7c452abe5b2aeba63 100644 (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=\fdata-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\fboolean-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
index 258468802478fba56c8264c6c4d896431c95e33a..c11ce0d0a1edd8860003959c5377b36131d3323a 100644 (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) &&
index e9a64632dddf073a220b53f434fd81a846eca8f7..51ce2d30557cf3c3ae31710483f3e3dcfa80a12c 100644 (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;
index dc3d7149dd2f442b6d459063990dc000036d1894..aa7cd03837a0d89fb1fc2abafd4732c33428afff 100644 (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:
index e6bf322e673be86ad4c82f7adaca14fc7086d401..333c39f18a90cd252005f2037f26bf170822b634 100644 (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], 
index 51ff4f714914e85cce936640357fdc18f3d0995f..7a62c71acc1ab18b4e36eb2769f3bfe580679019 100644 (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
 
index 7e4e14697f59afb6a145f1000250b0d933a01b9e..8bbd06ef7973d189a779d7d5d51c5482841a1401 100644 (file)
@@ -43,6 +43,7 @@ enum dhcp_token {
        LPAREN = '(',
        RPAREN = ')',
        EQUAL = '=',
+       TILDE = '~',
        BANG = '!',
        PERCENT = '%',
        PLUS = '+',
index b357b25ce652931a8c7ae5b506a42ae78c30df6b..8ce66c4ba296de249441d0730a81f79fc53a2c0f 100644 (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 {