mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-28 12:48:01 +00:00
postfix-3.2-20160527
This commit is contained in:
parent
84739fb911
commit
4a9d39443f
@ -22316,3 +22316,14 @@ Apologies for any names omitted.
|
||||
Cleanup: existing if/endif support for pcre and regexp
|
||||
tables, in preparation for new if/endif support for cidr
|
||||
tables. Files: util/dict_regexp.c, util/dict_pcre.c.
|
||||
|
||||
20160526
|
||||
|
||||
Feature: cidr tables now support if/endif and negation (by
|
||||
prepending "!" to a pattern), just like regexp and pcre
|
||||
tables. The primarily purpose is to improve readability of
|
||||
complex tables. Files: util/cidr_match.[hc], util/dict_cidr.c,
|
||||
proto/cidr_table.
|
||||
|
||||
Cleanup: make regexp: and pcre: parser warning messages more
|
||||
similar. Files: dict_regexp.c, dict_pcre.c.
|
||||
|
@ -15,3 +15,12 @@ specifies the release date of a stable release or snapshot release.
|
||||
|
||||
If you upgrade from Postfix 3.0 or earlier, read RELEASE_NOTES-3.1
|
||||
before proceeding.
|
||||
|
||||
Major changes with snapshot 20160527
|
||||
====================================
|
||||
|
||||
Postfix cidr tables now support if..endif, and pattern negation
|
||||
with "!", just like regexp and pcre tables. The if..endif can speed
|
||||
up lookups by skipping over irrelevant patterns, and can make rule
|
||||
maintenance easier because rules for a network can now be placed
|
||||
inside if..endif. See the cidr_table(5) manpage for syntax details.
|
||||
|
@ -30,30 +30,39 @@ CIDR_TABLE(5) CIDR_TABLE(5)
|
||||
<b>TABLE FORMAT</b>
|
||||
The general form of a Postfix CIDR table is:
|
||||
|
||||
<i>network</i><b>_</b><i>address</i><b>/</b><i>network</i><b>_</b><i>mask result</i>
|
||||
When a search string matches the specified network block, use
|
||||
the corresponding <i>result</i> value. Specify 0.0.0.0/0 to match every
|
||||
IPv4 address, and ::/0 to match every IPv6 address.
|
||||
<i>pattern result</i>
|
||||
When a search string matches the specified <i>pattern</i>, use the cor-
|
||||
responding <i>result</i> value. The <i>pattern</i> must be in <i>network/prefix</i>
|
||||
or <i>network</i><b>_</b><i>address</i> form (see ADDRESS PATTERN SYNTAX below).
|
||||
|
||||
An IPv4 network address is a sequence of four decimal octets
|
||||
separated by ".", and an IPv6 network address is a sequence of
|
||||
three to eight hexadecimal octet pairs separated by ":".
|
||||
<b>!</b><i>pattern result</i>
|
||||
When a search string does not match the specified <i>pattern</i>, use
|
||||
the specified <i>result</i> value. The <i>pattern</i> must be in <i>network/pre-</i>
|
||||
<i>fix</i> or <i>network</i><b>_</b><i>address</i> form (see ADDRESS PATTERN SYNTAX below).
|
||||
|
||||
The <i>network</i><b>_</b><i>mask</i> is the number of high-order bits in the <i>net-</i>
|
||||
<i>work</i><b>_</b><i>address</i> that the search string must match.
|
||||
This feature is available in Postfix 3.2 and later.
|
||||
|
||||
Before comparisons are made, lookup keys and table entries are
|
||||
converted from string to binary. Therefore table entries will be
|
||||
matched regardless of redundant zero characters.
|
||||
<b>if</b> <i>pattern</i>
|
||||
|
||||
Note: address information may be enclosed inside "[]" but this
|
||||
form is not required.
|
||||
<b>endif</b> When a search string matches the specified <i>pattern</i>, match that
|
||||
search string against the patterns between <b>if</b> and <b>endif</b>. The
|
||||
<i>pattern</i> must be in <i>network/prefix</i> or <i>network</i><b>_</b><i>address</i> form (see
|
||||
ADDRESS PATTERN SYNTAX below). The <b>if</b>..<b>endif</b> can nest.
|
||||
|
||||
IPv6 support is available in Postfix 2.2 and later.
|
||||
Note: do not prepend whitespace to text between <b>if</b>..<b>endif</b>.
|
||||
|
||||
<i>network</i><b>_</b><i>address result</i>
|
||||
When a search string matches the specified network address, use
|
||||
the corresponding <i>result</i> value.
|
||||
This feature is available in Postfix 3.2 and later.
|
||||
|
||||
<b>if !</b><i>pattern</i>
|
||||
|
||||
<b>endif</b> When a search string does not match the specified <i>pattern</i>, match
|
||||
that search string against the patterns between <b>if</b> and <b>endif</b>.
|
||||
The <i>pattern</i> must be in <i>network/prefix</i> or <i>network</i><b>_</b><i>address</i> form
|
||||
(see ADDRESS PATTERN SYNTAX below). The <b>if</b>..<b>endif</b> can nest.
|
||||
|
||||
Note: do not prepend whitespace to text between <b>if</b>..<b>endif</b>.
|
||||
|
||||
This feature is available in Postfix 3.2 and later.
|
||||
|
||||
blank lines and comments
|
||||
Empty lines and whitespace-only lines are ignored, as are lines
|
||||
@ -67,6 +76,27 @@ CIDR_TABLE(5) CIDR_TABLE(5)
|
||||
Patterns are applied in the order as specified in the table, until a
|
||||
pattern is found that matches the search string.
|
||||
|
||||
<b>ADDRESS PATTERN SYNTAX</b>
|
||||
Postfix CIDR tables are pattern-based. A pattern is either a <i>net-</i>
|
||||
<i>work</i><b>_</b><i>address</i> which requires an exact match, or a <i>network</i><b>_</b><i>address/pre-</i>
|
||||
<i>fix</i><b>_</b><i>length</i> where the <i>prefix</i><b>_</b><i>length</i> part specifies the length of the
|
||||
<i>network</i><b>_</b><i>address</i> prefix that must be matched (the other bits in the <i>net-</i>
|
||||
<i>work</i><b>_</b><i>address</i> part must be zero).
|
||||
|
||||
An IPv4 network address is a sequence of four decimal octets separated
|
||||
by ".", and an IPv6 network address is a sequence of three to eight
|
||||
hexadecimal octets or octet pairs separated by ":". The pattern
|
||||
0.0.0.0/0 matches every IPv4 address, and ::/0 matches every IPv6
|
||||
address. IPv6 support is available in Postfix 2.2 and later.
|
||||
|
||||
Before comparisons are made, lookup keys and table entries are con-
|
||||
verted from string to binary. Therefore, IPv6 patterns will be matched
|
||||
regardless of leading zeros (a leading zero in an IPv4 address octet
|
||||
indicates octal notation).
|
||||
|
||||
Note: address information may be enclosed inside "[]" but this form is
|
||||
not required.
|
||||
|
||||
<b>EXAMPLE SMTPD ACCESS MAP</b>
|
||||
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
|
||||
<a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a> = ... <a href="cidr_table.5.html">cidr</a>:/etc/postfix/client.cidr ...
|
||||
|
@ -33,30 +33,42 @@ described in the SYNOPSIS above.
|
||||
.ad
|
||||
.fi
|
||||
The general form of a Postfix CIDR table is:
|
||||
.IP "\fInetwork_address\fB/\fInetwork_mask result\fR"
|
||||
When a search string matches the specified network block,
|
||||
use the corresponding \fIresult\fR value. Specify
|
||||
0.0.0.0/0 to match every IPv4 address, and ::/0 to match
|
||||
every IPv6 address.
|
||||
|
||||
An IPv4 network address is a sequence of four decimal octets
|
||||
separated by ".", and an IPv6 network address is a sequence
|
||||
of three to eight hexadecimal octet pairs separated by ":".
|
||||
|
||||
The \fInetwork_mask\fR is the number of high\-order bits in
|
||||
the \fInetwork_address\fR that the search string must match.
|
||||
|
||||
Before comparisons are made, lookup keys and table entries
|
||||
are converted from string to binary. Therefore table entries
|
||||
will be matched regardless of redundant zero characters.
|
||||
|
||||
Note: address information may be enclosed inside "[]" but
|
||||
this form is not required.
|
||||
|
||||
IPv6 support is available in Postfix 2.2 and later.
|
||||
.IP "\fInetwork_address result\fR"
|
||||
When a search string matches the specified network address,
|
||||
use the corresponding \fIresult\fR value.
|
||||
.IP "\fIpattern result\fR"
|
||||
When a search string matches the specified \fIpattern\fR, use
|
||||
the corresponding \fIresult\fR value. The \fIpattern\fR must be
|
||||
in \fInetwork/prefix\fR or \fInetwork_address\fR form (see
|
||||
ADDRESS PATTERN SYNTAX below).
|
||||
.IP "\fB!\fIpattern result\fR"
|
||||
When a search string does not match the specified \fIpattern\fR,
|
||||
use the specified \fIresult\fR value. The \fIpattern\fR must
|
||||
be in \fInetwork/prefix\fR or \fInetwork_address\fR form (see
|
||||
ADDRESS PATTERN SYNTAX below).
|
||||
.sp
|
||||
This feature is available in Postfix 3.2 and later.
|
||||
.IP "\fBif \fIpattern\fR"
|
||||
.IP "\fBendif\fR"
|
||||
When a search string matches the specified \fIpattern\fR, match
|
||||
that search string against the patterns between \fBif\fR and
|
||||
\fBendif\fR. The \fIpattern\fR must be in \fInetwork/prefix\fR or
|
||||
\fInetwork_address\fR form (see ADDRESS PATTERN SYNTAX below). The
|
||||
\fBif\fR..\fBendif\fR can nest.
|
||||
.sp
|
||||
Note: do not prepend whitespace to text between
|
||||
\fBif\fR..\fBendif\fR.
|
||||
.sp
|
||||
This feature is available in Postfix 3.2 and later.
|
||||
.IP "\fBif !\fIpattern\fR"
|
||||
.IP "\fBendif\fR"
|
||||
When a search string does not match the specified \fIpattern\fR,
|
||||
match that search string against the patterns between \fBif\fR and
|
||||
\fBendif\fR. The \fIpattern\fR must be in \fInetwork/prefix\fR or
|
||||
\fInetwork_address\fR form (see ADDRESS PATTERN SYNTAX below). The
|
||||
\fBif\fR..\fBendif\fR can nest.
|
||||
.sp
|
||||
Note: do not prepend whitespace to text between
|
||||
\fBif\fR..\fBendif\fR.
|
||||
.sp
|
||||
This feature is available in Postfix 3.2 and later.
|
||||
.IP "blank lines and comments"
|
||||
Empty lines and whitespace\-only lines are ignored, as
|
||||
are lines whose first non\-whitespace character is a `#'.
|
||||
@ -70,6 +82,32 @@ starts with whitespace continues a logical line.
|
||||
.fi
|
||||
Patterns are applied in the order as specified in the table, until a
|
||||
pattern is found that matches the search string.
|
||||
.SH "ADDRESS PATTERN SYNTAX"
|
||||
.na
|
||||
.nf
|
||||
.ad
|
||||
.fi
|
||||
Postfix CIDR tables are pattern\-based. A pattern is either
|
||||
a \fInetwork_address\fR which requires an exact match, or a
|
||||
\fInetwork_address/prefix_length\fR where the \fIprefix_length\fR
|
||||
part specifies the length of the \fInetwork_address\fR prefix
|
||||
that must be matched (the other bits in the \fInetwork_address\fR
|
||||
part must be zero).
|
||||
|
||||
An IPv4 network address is a sequence of four decimal octets
|
||||
separated by ".", and an IPv6 network address is a sequence
|
||||
of three to eight hexadecimal octets or octet pairs separated by
|
||||
":". The pattern 0.0.0.0/0 matches every IPv4 address, and ::/0
|
||||
matches every IPv6 address. IPv6 support is available in
|
||||
Postfix 2.2 and later.
|
||||
|
||||
Before comparisons are made, lookup keys and table entries
|
||||
are converted from string to binary. Therefore, IPv6 patterns
|
||||
will be matched regardless of leading zeros (a leading zero in
|
||||
an IPv4 address octet indicates octal notation).
|
||||
|
||||
Note: address information may be enclosed inside "[]" but
|
||||
this form is not required.
|
||||
.SH "EXAMPLE SMTPD ACCESS MAP"
|
||||
.na
|
||||
.nf
|
||||
|
@ -25,30 +25,42 @@
|
||||
# .ad
|
||||
# .fi
|
||||
# The general form of a Postfix CIDR table is:
|
||||
# .IP "\fInetwork_address\fB/\fInetwork_mask result\fR"
|
||||
# When a search string matches the specified network block,
|
||||
# use the corresponding \fIresult\fR value. Specify
|
||||
# 0.0.0.0/0 to match every IPv4 address, and ::/0 to match
|
||||
# every IPv6 address.
|
||||
#
|
||||
# An IPv4 network address is a sequence of four decimal octets
|
||||
# separated by ".", and an IPv6 network address is a sequence
|
||||
# of three to eight hexadecimal octet pairs separated by ":".
|
||||
#
|
||||
# The \fInetwork_mask\fR is the number of high-order bits in
|
||||
# the \fInetwork_address\fR that the search string must match.
|
||||
#
|
||||
# Before comparisons are made, lookup keys and table entries
|
||||
# are converted from string to binary. Therefore table entries
|
||||
# will be matched regardless of redundant zero characters.
|
||||
#
|
||||
# Note: address information may be enclosed inside "[]" but
|
||||
# this form is not required.
|
||||
#
|
||||
# IPv6 support is available in Postfix 2.2 and later.
|
||||
# .IP "\fInetwork_address result\fR"
|
||||
# When a search string matches the specified network address,
|
||||
# use the corresponding \fIresult\fR value.
|
||||
# .IP "\fIpattern result\fR"
|
||||
# When a search string matches the specified \fIpattern\fR, use
|
||||
# the corresponding \fIresult\fR value. The \fIpattern\fR must be
|
||||
# in \fInetwork/prefix\fR or \fInetwork_address\fR form (see
|
||||
# ADDRESS PATTERN SYNTAX below).
|
||||
# .IP "\fB!\fIpattern result\fR"
|
||||
# When a search string does not match the specified \fIpattern\fR,
|
||||
# use the specified \fIresult\fR value. The \fIpattern\fR must
|
||||
# be in \fInetwork/prefix\fR or \fInetwork_address\fR form (see
|
||||
# ADDRESS PATTERN SYNTAX below).
|
||||
# .sp
|
||||
# This feature is available in Postfix 3.2 and later.
|
||||
# .IP "\fBif \fIpattern\fR"
|
||||
# .IP "\fBendif\fR"
|
||||
# When a search string matches the specified \fIpattern\fR, match
|
||||
# that search string against the patterns between \fBif\fR and
|
||||
# \fBendif\fR. The \fIpattern\fR must be in \fInetwork/prefix\fR or
|
||||
# \fInetwork_address\fR form (see ADDRESS PATTERN SYNTAX below). The
|
||||
# \fBif\fR..\fBendif\fR can nest.
|
||||
# .sp
|
||||
# Note: do not prepend whitespace to text between
|
||||
# \fBif\fR..\fBendif\fR.
|
||||
# .sp
|
||||
# This feature is available in Postfix 3.2 and later.
|
||||
# .IP "\fBif !\fIpattern\fR"
|
||||
# .IP "\fBendif\fR"
|
||||
# When a search string does not match the specified \fIpattern\fR,
|
||||
# match that search string against the patterns between \fBif\fR and
|
||||
# \fBendif\fR. The \fIpattern\fR must be in \fInetwork/prefix\fR or
|
||||
# \fInetwork_address\fR form (see ADDRESS PATTERN SYNTAX below). The
|
||||
# \fBif\fR..\fBendif\fR can nest.
|
||||
# .sp
|
||||
# Note: do not prepend whitespace to text between
|
||||
# \fBif\fR..\fBendif\fR.
|
||||
# .sp
|
||||
# This feature is available in Postfix 3.2 and later.
|
||||
# .IP "blank lines and comments"
|
||||
# Empty lines and whitespace-only lines are ignored, as
|
||||
# are lines whose first non-whitespace character is a `#'.
|
||||
@ -60,6 +72,30 @@
|
||||
# .fi
|
||||
# Patterns are applied in the order as specified in the table, until a
|
||||
# pattern is found that matches the search string.
|
||||
# ADDRESS PATTERN SYNTAX
|
||||
# .ad
|
||||
# .fi
|
||||
# Postfix CIDR tables are pattern-based. A pattern is either
|
||||
# a \fInetwork_address\fR which requires an exact match, or a
|
||||
# \fInetwork_address/prefix_length\fR where the \fIprefix_length\fR
|
||||
# part specifies the length of the \fInetwork_address\fR prefix
|
||||
# that must be matched (the other bits in the \fInetwork_address\fR
|
||||
# part must be zero).
|
||||
#
|
||||
# An IPv4 network address is a sequence of four decimal octets
|
||||
# separated by ".", and an IPv6 network address is a sequence
|
||||
# of three to eight hexadecimal octets or octet pairs separated by
|
||||
# ":". The pattern 0.0.0.0/0 matches every IPv4 address, and ::/0
|
||||
# matches every IPv6 address. IPv6 support is available in
|
||||
# Postfix 2.2 and later.
|
||||
#
|
||||
# Before comparisons are made, lookup keys and table entries
|
||||
# are converted from string to binary. Therefore, IPv6 patterns
|
||||
# will be matched regardless of leading zeros (a leading zero in
|
||||
# an IPv4 address octet indicates octal notation).
|
||||
#
|
||||
# Note: address information may be enclosed inside "[]" but
|
||||
# this form is not required.
|
||||
# EXAMPLE SMTPD ACCESS MAP
|
||||
# .nf
|
||||
# /etc/postfix/main.cf:
|
||||
|
@ -20,7 +20,7 @@
|
||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||
* patchlevel; they change the release date only.
|
||||
*/
|
||||
#define MAIL_RELEASE_DATE "20160522"
|
||||
#define MAIL_RELEASE_DATE "20160527"
|
||||
#define MAIL_VERSION_NUMBER "3.2"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@ -14,6 +14,14 @@
|
||||
/* int cidr_match_execute(info, address)
|
||||
/* CIDR_MATCH *info;
|
||||
/* const char *address;
|
||||
/* AUXILIARY FUNCTIONS
|
||||
/* VSTRING *cidr_match_parse_if(info, address, why)
|
||||
/* CIDR_MATCH *info;
|
||||
/* char *address;
|
||||
/* VSTRING *why;
|
||||
/*
|
||||
/* void cidr_match_endif(info)
|
||||
/* CIDR_MATCH *info;
|
||||
/* DESCRIPTION
|
||||
/* This module parses address or address/length patterns and
|
||||
/* provides simple address matching. The implementation is
|
||||
@ -29,6 +37,12 @@
|
||||
/* (the caller should give the latter to vstring_free()).
|
||||
/* The pattern argument is destroyed.
|
||||
/*
|
||||
/* cidr_match_parse_if() parses the address that follows an IF
|
||||
/* token, and stores the result into the info argument.
|
||||
/*
|
||||
/* cidr_match_endif() handles the occurrence of an ENDIF token,
|
||||
/* and updates the info argument.
|
||||
/*
|
||||
/* cidr_match_execute() matches the specified address against
|
||||
/* a list of parsed expressions, and returns the matching
|
||||
/* expression's data structure.
|
||||
@ -39,6 +53,11 @@
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
@ -88,15 +107,44 @@
|
||||
(msg_panic("%s: bad address family %d", myname, (f)), 0))
|
||||
#endif
|
||||
|
||||
/* cidr_match_entry - match one entry */
|
||||
|
||||
static inline int cidr_match_entry(CIDR_MATCH *entry,
|
||||
unsigned char *addr_bytes)
|
||||
{
|
||||
unsigned char *mp;
|
||||
unsigned char *np;
|
||||
unsigned char *ap;
|
||||
|
||||
/* Unoptimized case: netmask with some or all bits zero. */
|
||||
if (entry->mask_shift < entry->addr_bit_count) {
|
||||
for (np = entry->net_bytes, mp = entry->mask_bytes,
|
||||
ap = addr_bytes; /* void */ ; np++, mp++, ap++) {
|
||||
if (ap >= addr_bytes + entry->addr_byte_count)
|
||||
return (entry->match);
|
||||
if ((*ap & *mp) != *np)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Optimized case: all 1 netmask (i.e. no netmask specified). */
|
||||
else {
|
||||
for (np = entry->net_bytes,
|
||||
ap = addr_bytes; /* void */ ; np++, ap++) {
|
||||
if (ap >= addr_bytes + entry->addr_byte_count)
|
||||
return (entry->match);
|
||||
if (*ap != *np)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (!entry->match);
|
||||
}
|
||||
|
||||
/* cidr_match_execute - match address against compiled CIDR pattern list */
|
||||
|
||||
CIDR_MATCH *cidr_match_execute(CIDR_MATCH *list, const char *addr)
|
||||
{
|
||||
unsigned char addr_bytes[CIDR_MATCH_ABYTES];
|
||||
unsigned addr_family;
|
||||
unsigned char *mp;
|
||||
unsigned char *np;
|
||||
unsigned char *ap;
|
||||
CIDR_MATCH *entry;
|
||||
|
||||
addr_family = CIDR_MATCH_ADDR_FAMILY(addr);
|
||||
@ -104,27 +152,26 @@ CIDR_MATCH *cidr_match_execute(CIDR_MATCH *list, const char *addr)
|
||||
return (0);
|
||||
|
||||
for (entry = list; entry; entry = entry->next) {
|
||||
if (entry->addr_family == addr_family) {
|
||||
/* Unoptimized case: netmask with some or all bits zero. */
|
||||
if (entry->mask_shift < entry->addr_bit_count) {
|
||||
for (np = entry->net_bytes, mp = entry->mask_bytes,
|
||||
ap = addr_bytes; /* void */ ; np++, mp++, ap++) {
|
||||
if (ap >= addr_bytes + entry->addr_byte_count)
|
||||
return (entry);
|
||||
if ((*ap & *mp) != *np)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Optimized case: all 1 netmask (i.e. no netmask specified). */
|
||||
else {
|
||||
for (np = entry->net_bytes,
|
||||
ap = addr_bytes; /* void */ ; np++, ap++) {
|
||||
if (ap >= addr_bytes + entry->addr_byte_count)
|
||||
return (entry);
|
||||
if (*ap != *np)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (entry->op) {
|
||||
|
||||
case CIDR_MATCH_OP_MATCH:
|
||||
if (entry->addr_family == addr_family)
|
||||
if (cidr_match_entry(entry, addr_bytes))
|
||||
return (entry);
|
||||
break;
|
||||
|
||||
case CIDR_MATCH_OP_IF:
|
||||
if (entry->addr_family == addr_family)
|
||||
if (cidr_match_entry(entry, addr_bytes))
|
||||
continue;
|
||||
/* An IF without matching ENDIF has no end-of block entry. */
|
||||
if ((entry = entry->block_end) == 0)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case CIDR_MATCH_OP_ENDIF:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
@ -141,6 +188,23 @@ VSTRING *cidr_match_parse(CIDR_MATCH *ip, char *pattern, VSTRING *why)
|
||||
unsigned char *np;
|
||||
unsigned char *mp;
|
||||
|
||||
/*
|
||||
* Process negation operators. XXX unlike dict_regexp_get_pat() and
|
||||
* dict_pcre_get_pattern(), dict_cidr_parse_rule() does not allow space
|
||||
* between ! and the remainder of a pattern. However, those spaces are
|
||||
* not documented, they were more a helpful thing.
|
||||
*/
|
||||
ip->match = 1;
|
||||
while (*pattern == '!') {
|
||||
ip->match = !ip->match;
|
||||
pattern++;
|
||||
}
|
||||
|
||||
if (*pattern == 0) {
|
||||
vstring_sprintf(why ? why : (why = vstring_alloc(20)), "no pattern");
|
||||
return (why);
|
||||
}
|
||||
|
||||
/*
|
||||
* Strip [] from [addr/len] or [addr]/len, destroying the pattern. CIDR
|
||||
* maps don't need [] to eliminate syntax ambiguity, but matchlists need
|
||||
@ -224,7 +288,30 @@ VSTRING *cidr_match_parse(CIDR_MATCH *ip, char *pattern, VSTRING *why)
|
||||
/*
|
||||
* Wrap up the result.
|
||||
*/
|
||||
ip->op = CIDR_MATCH_OP_MATCH;
|
||||
ip->next = 0;
|
||||
ip->block_end = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* cidr_match_parse_if - parse CIDR pattern after IF */
|
||||
|
||||
VSTRING *cidr_match_parse_if(CIDR_MATCH *ip, char *pattern, VSTRING *why)
|
||||
{
|
||||
VSTRING *ret;
|
||||
|
||||
if ((ret = cidr_match_parse(ip, pattern, why)) == 0)
|
||||
ip->op = CIDR_MATCH_OP_IF;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* cidr_match_endif - handle ENDIF pattern */
|
||||
|
||||
void cidr_match_endif(CIDR_MATCH *ip)
|
||||
{
|
||||
memset(ip, 0, sizeof(*ip));
|
||||
ip->op = CIDR_MATCH_OP_ENDIF;
|
||||
ip->next = 0; /* maybe not all bits 0 */
|
||||
ip->block_end = 0;
|
||||
}
|
||||
|
@ -38,6 +38,8 @@
|
||||
* Each parsed CIDR pattern can be member of a linked list.
|
||||
*/
|
||||
typedef struct CIDR_MATCH {
|
||||
int op; /* operation, match or control flow */
|
||||
int match; /* positive or negative match */
|
||||
unsigned char net_bytes[CIDR_MATCH_ABYTES]; /* network portion */
|
||||
unsigned char mask_bytes[CIDR_MATCH_ABYTES]; /* network mask */
|
||||
unsigned char addr_family; /* AF_XXX */
|
||||
@ -45,9 +47,17 @@ typedef struct CIDR_MATCH {
|
||||
unsigned char addr_bit_count; /* optimization */
|
||||
unsigned char mask_shift; /* optimization */
|
||||
struct CIDR_MATCH *next; /* next entry */
|
||||
struct CIDR_MATCH *block_end; /* block terminator */
|
||||
} CIDR_MATCH;
|
||||
|
||||
#define CIDR_MATCH_OP_MATCH 1 /* Match this pattern */
|
||||
#define CIDR_MATCH_OP_IF 2 /* Increase if/endif nesting on match */
|
||||
#define CIDR_MATCH_OP_ENDIF 3 /* Decrease if/endif nesting on match */
|
||||
|
||||
extern VSTRING *cidr_match_parse(CIDR_MATCH *, char *, VSTRING *);
|
||||
extern VSTRING *cidr_match_parse_if(CIDR_MATCH *, char *, VSTRING *);
|
||||
extern void cidr_match_endif(CIDR_MATCH *);
|
||||
|
||||
extern CIDR_MATCH *cidr_match_execute(CIDR_MATCH *, const char *);
|
||||
|
||||
/* LICENSE
|
||||
@ -59,6 +69,11 @@ extern CIDR_MATCH *cidr_match_execute(CIDR_MATCH *, const char *);
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
#endif
|
||||
|
@ -27,6 +27,11 @@
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
@ -54,6 +59,7 @@
|
||||
#include <cidr_match.h>
|
||||
#include <dict_cidr.h>
|
||||
#include <warn_stat.h>
|
||||
#include <mvect.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
@ -63,6 +69,7 @@
|
||||
typedef struct DICT_CIDR_ENTRY {
|
||||
CIDR_MATCH cidr_info; /* must be first */
|
||||
char *value; /* lookup result */
|
||||
int lineno;
|
||||
} DICT_CIDR_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
@ -106,7 +113,8 @@ static void dict_cidr_close(DICT *dict)
|
||||
|
||||
/* dict_cidr_parse_rule - parse CIDR table rule into network, mask and value */
|
||||
|
||||
static DICT_CIDR_ENTRY *dict_cidr_parse_rule(char *p, VSTRING *why)
|
||||
static DICT_CIDR_ENTRY *dict_cidr_parse_rule(char *p, int lineno, int nesting,
|
||||
VSTRING *why)
|
||||
{
|
||||
DICT_CIDR_ENTRY *rule;
|
||||
char *pattern;
|
||||
@ -115,33 +123,76 @@ static DICT_CIDR_ENTRY *dict_cidr_parse_rule(char *p, VSTRING *why)
|
||||
MAI_HOSTADDR_STR hostaddr;
|
||||
|
||||
/*
|
||||
* Split the rule into key and value. We already eliminated leading
|
||||
* whitespace, comments, empty lines or lines with whitespace only. This
|
||||
* means a null key can't happen but we will handle this anyway.
|
||||
* IF must be followed by a pattern.
|
||||
*/
|
||||
pattern = p;
|
||||
while (*p && !ISSPACE(*p)) /* Skip over key */
|
||||
p++;
|
||||
if (*p) /* Terminate key */
|
||||
*p++ = 0;
|
||||
while (*p && ISSPACE(*p)) /* Skip whitespace */
|
||||
p++;
|
||||
value = p;
|
||||
trimblanks(value, 0)[0] = 0; /* Trim trailing blanks */
|
||||
if (*pattern == 0) {
|
||||
vstring_sprintf(why, "no address pattern");
|
||||
return (0);
|
||||
}
|
||||
if (*value == 0) {
|
||||
vstring_sprintf(why, "no lookup result");
|
||||
return (0);
|
||||
if (strncasecmp(p, "IF", 2) == 0 && !ISALNUM(p[2])) {
|
||||
p += 2;
|
||||
while (*p && ISSPACE(*p)) /* Skip whitespace */
|
||||
p++;
|
||||
if (*p == 0) {
|
||||
vstring_sprintf(why, "no address pattern");
|
||||
return (0);
|
||||
}
|
||||
trimblanks(p, 0)[0] = 0; /* Trim trailing blanks */
|
||||
if (cidr_match_parse_if(&cidr_info, p, why) != 0)
|
||||
return (0);
|
||||
value = "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the pattern, destroying it in the process.
|
||||
* ENDIF must not be followed by other text.
|
||||
*/
|
||||
if (cidr_match_parse(&cidr_info, pattern, why) != 0)
|
||||
return (0);
|
||||
else if (strncasecmp(p, "ENDIF", 5) == 0 && !ISALNUM(p[5])) {
|
||||
p += 5;
|
||||
while (*p && ISSPACE(*p)) /* Skip whitespace */
|
||||
p++;
|
||||
if (*p != 0) {
|
||||
vstring_sprintf(why, "garbage after ENDIF");
|
||||
return (0);
|
||||
}
|
||||
if (nesting == 0) {
|
||||
vstring_sprintf(why, "ENDIF without IF");
|
||||
return (0);
|
||||
}
|
||||
cidr_match_endif(&cidr_info);
|
||||
value = "";
|
||||
}
|
||||
|
||||
/*
|
||||
* An address pattern.
|
||||
*/
|
||||
else {
|
||||
|
||||
/*
|
||||
* Split the rule into key and value. We already eliminated leading
|
||||
* whitespace, comments, empty lines or lines with whitespace only.
|
||||
* This means a null key can't happen but we will handle this anyway.
|
||||
*/
|
||||
pattern = p;
|
||||
while (*p && !ISSPACE(*p)) /* Skip over key */
|
||||
p++;
|
||||
if (*p) /* Terminate key */
|
||||
*p++ = 0;
|
||||
while (*p && ISSPACE(*p)) /* Skip whitespace */
|
||||
p++;
|
||||
value = p;
|
||||
trimblanks(value, 0)[0] = 0; /* Trim trailing blanks */
|
||||
if (*pattern == 0) {
|
||||
vstring_sprintf(why, "no address pattern");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the pattern, destroying it in the process.
|
||||
*/
|
||||
if (cidr_match_parse(&cidr_info, pattern, why) != 0)
|
||||
return (0);
|
||||
|
||||
if (*value == 0) {
|
||||
vstring_sprintf(why, "no lookup result");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Bundle up the result.
|
||||
@ -149,6 +200,7 @@ static DICT_CIDR_ENTRY *dict_cidr_parse_rule(char *p, VSTRING *why)
|
||||
rule = (DICT_CIDR_ENTRY *) mymalloc(sizeof(DICT_CIDR_ENTRY));
|
||||
rule->cidr_info = cidr_info;
|
||||
rule->value = mystrdup(value);
|
||||
rule->lineno = lineno;
|
||||
|
||||
if (msg_verbose) {
|
||||
if (inet_ntop(cidr_info.addr_family, cidr_info.net_bytes,
|
||||
@ -164,6 +216,7 @@ static DICT_CIDR_ENTRY *dict_cidr_parse_rule(char *p, VSTRING *why)
|
||||
|
||||
DICT *dict_cidr_open(const char *mapname, int open_flags, int dict_flags)
|
||||
{
|
||||
const char myname[] = "dict_cidr_open";
|
||||
DICT_CIDR *dict_cidr;
|
||||
VSTREAM *map_fp = 0;
|
||||
struct stat st;
|
||||
@ -173,6 +226,9 @@ DICT *dict_cidr_open(const char *mapname, int open_flags, int dict_flags)
|
||||
DICT_CIDR_ENTRY *last_rule = 0;
|
||||
int last_line = 0;
|
||||
int lineno;
|
||||
int nesting = 0;
|
||||
DICT_CIDR_ENTRY **rule_stack = 0;
|
||||
MVECT mvect;
|
||||
|
||||
/*
|
||||
* Let the optimizer worry about eliminating redundant code.
|
||||
@ -225,12 +281,35 @@ DICT *dict_cidr_open(const char *mapname, int open_flags, int dict_flags)
|
||||
dict_cidr->dict.owner.status = (st.st_uid != 0);
|
||||
|
||||
while (readllines(line_buffer, map_fp, &last_line, &lineno)) {
|
||||
rule = dict_cidr_parse_rule(vstring_str(line_buffer), why);
|
||||
rule = dict_cidr_parse_rule(vstring_str(line_buffer), lineno,
|
||||
nesting, why);
|
||||
if (rule == 0) {
|
||||
msg_warn("cidr map %s, line %d: %s: skipping this rule",
|
||||
mapname, lineno, vstring_str(why));
|
||||
continue;
|
||||
}
|
||||
if (rule->cidr_info.op == CIDR_MATCH_OP_IF) {
|
||||
if (rule_stack == 0)
|
||||
rule_stack = (DICT_CIDR_ENTRY **) mvect_alloc(&mvect,
|
||||
sizeof(*rule_stack), nesting + 1,
|
||||
(MVECT_FN) 0, (MVECT_FN) 0);
|
||||
else
|
||||
rule_stack =
|
||||
(DICT_CIDR_ENTRY **) mvect_realloc(&mvect, nesting + 1);
|
||||
rule_stack[nesting] = rule;
|
||||
nesting++;
|
||||
} else if (rule->cidr_info.op == CIDR_MATCH_OP_ENDIF) {
|
||||
DICT_CIDR_ENTRY *if_rule;
|
||||
|
||||
if (nesting-- <= 0)
|
||||
/* Already handled in dict_cidr_parse_rule(). */
|
||||
msg_panic("%s: ENDIF without IF", myname);
|
||||
if_rule = rule_stack[nesting];
|
||||
if (if_rule->cidr_info.op != CIDR_MATCH_OP_IF)
|
||||
msg_panic("%s: unexpected rule stack element type %d",
|
||||
myname, if_rule->cidr_info.op);
|
||||
if_rule->cidr_info.block_end = &(rule->cidr_info);
|
||||
}
|
||||
if (last_rule == 0)
|
||||
dict_cidr->head = rule;
|
||||
else
|
||||
@ -238,5 +317,12 @@ DICT *dict_cidr_open(const char *mapname, int open_flags, int dict_flags)
|
||||
last_rule = rule;
|
||||
}
|
||||
|
||||
while (nesting-- > 0)
|
||||
msg_warn("cidr map %s, line %d: IF has no matching ENDIF",
|
||||
mapname, rule_stack[nesting]->lineno);
|
||||
|
||||
if (rule_stack)
|
||||
(void) mvect_free(&mvect);
|
||||
|
||||
DICT_CIDR_OPEN_RETURN(DICT_DEBUG (&dict_cidr->dict));
|
||||
}
|
||||
|
@ -9,3 +9,15 @@ get 2001:240:5c7:0:2d0:b7ff:fe88:2ca7
|
||||
get 2001:240:5c7:0:2d0:b7ff:febe:ca9f
|
||||
get 1.1.1.1
|
||||
get 1:1:1:1:1:1:1:1
|
||||
get 1.2.3.3
|
||||
get 1.2.3.4
|
||||
get 1.2.3.5
|
||||
get 1.2.3.6
|
||||
get 1.2.3.7
|
||||
get 1.2.3.8
|
||||
get ::f3
|
||||
get ::f4
|
||||
get ::f5
|
||||
get ::f6
|
||||
get ::f7
|
||||
get ::f8
|
||||
|
@ -7,6 +7,32 @@
|
||||
172.999.0.0/21 whatever
|
||||
172.16.1.999 whatever
|
||||
172.16.1.4
|
||||
if 1.2.0.0/16
|
||||
if 1.2.3.4/30
|
||||
1.2.3.3 1.2.3.3 can't happen
|
||||
1.2.3.4 1.2.3.4 can happen
|
||||
1.2.3.5 1.2.3.5 can happen
|
||||
1.2.3.6 1.2.3.6 can happen
|
||||
1.2.3.7 1.2.3.7 can happen
|
||||
1.2.3.8 1.2.3.8 can't happen
|
||||
endif
|
||||
endif
|
||||
if !1.2.3.4/30
|
||||
1.2.3.3 1.2.3.3 can happen
|
||||
1.2.3.8 1.2.3.8 can happen
|
||||
endif
|
||||
if ::f4/126
|
||||
::f3 ::f3 can't happen
|
||||
::f4 ::f4 can happen
|
||||
::f5 ::f5 can happen
|
||||
::f6 ::f6 can happen
|
||||
::f7 ::f7 can happen
|
||||
::f8 ::f8 can't happen
|
||||
endif
|
||||
if !::f4/126
|
||||
::f3 ::f3 can happen
|
||||
::f8 ::f8 can happen
|
||||
endif
|
||||
2001:240:5c7:0:2d0:b7ff:fe88:2ca7 match 2001:240:5c7:0:2d0:b7ff:fe88:2ca7
|
||||
2001:240:5c7::/64 match netblock 2001:240:5c7::/64
|
||||
1.0.0.0/0 match 0.0.0.0/0
|
||||
@ -16,3 +42,9 @@
|
||||
[1234 foo
|
||||
[1234]junk bar
|
||||
172.16.1.3/3x whatever
|
||||
endif
|
||||
endif
|
||||
if 1:2::3:4
|
||||
if 1:2::3:5
|
||||
if !
|
||||
!
|
||||
|
@ -3,11 +3,17 @@
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 7: bad net/mask pattern: "172.999.0.0/21": skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 8: bad address pattern: "172.16.1.999": skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 9: no lookup result: skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 12: non-null host address bits in "1.0.0.0/0", perhaps you should use "0.0.0.0/0" instead: skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 14: non-null host address bits in "1::/0", perhaps you should use "::/0" instead: skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 16: missing ']' character after "[1234": skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 17: garbage after "[1234]": skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 18: bad net/mask pattern: "172.16.1.3/3x": skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 38: non-null host address bits in "1.0.0.0/0", perhaps you should use "0.0.0.0/0" instead: skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 40: non-null host address bits in "1::/0", perhaps you should use "::/0" instead: skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 42: missing ']' character after "[1234": skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 43: garbage after "[1234]": skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 44: bad net/mask pattern: "172.16.1.3/3x": skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 45: ENDIF without IF: skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 46: ENDIF without IF: skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 49: no pattern: skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 50: no pattern: skipping this rule
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 48: IF has no matching ENDIF
|
||||
./dict_open: warning: cidr map dict_cidr.map, line 47: IF has no matching ENDIF
|
||||
owner=untrusted (uid=USER)
|
||||
> get 172.16.0.0
|
||||
172.16.0.0=554 match bad netblock 172.16.0.0/21
|
||||
@ -31,3 +37,27 @@ owner=untrusted (uid=USER)
|
||||
1.1.1.1=match 0.0.0.0/0
|
||||
> get 1:1:1:1:1:1:1:1
|
||||
1:1:1:1:1:1:1:1=match ::/0
|
||||
> get 1.2.3.3
|
||||
1.2.3.3=1.2.3.3 can happen
|
||||
> get 1.2.3.4
|
||||
1.2.3.4=1.2.3.4 can happen
|
||||
> get 1.2.3.5
|
||||
1.2.3.5=1.2.3.5 can happen
|
||||
> get 1.2.3.6
|
||||
1.2.3.6=1.2.3.6 can happen
|
||||
> get 1.2.3.7
|
||||
1.2.3.7=1.2.3.7 can happen
|
||||
> get 1.2.3.8
|
||||
1.2.3.8=1.2.3.8 can happen
|
||||
> get ::f3
|
||||
::f3=::f3 can happen
|
||||
> get ::f4
|
||||
::f4=::f4 can happen
|
||||
> get ::f5
|
||||
::f5=::f5 can happen
|
||||
> get ::f6
|
||||
::f6=::f6 can happen
|
||||
> get ::f7
|
||||
::f7=::f7 can happen
|
||||
> get ::f8
|
||||
::f8=::f8 can happen
|
||||
|
@ -27,6 +27,11 @@
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
#include "sys_defs.h"
|
||||
@ -614,8 +619,8 @@ static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
|
||||
while (*p && ISSPACE(*p))
|
||||
++p;
|
||||
if (!*p)
|
||||
msg_warn("%s, line %d: no replacement text: using empty string",
|
||||
mapname, lineno);
|
||||
msg_warn("pcre map %s, line %d: no replacement text: "
|
||||
"using empty string", mapname, lineno);
|
||||
|
||||
/*
|
||||
* Sanity check the $number instances in the replacement text.
|
||||
@ -882,6 +887,7 @@ DICT *dict_pcre_open(const char *mapname, int open_flags, int dict_flags)
|
||||
DICT_PCRE_IF_RULE *if_rule;
|
||||
|
||||
if (nesting-- <= 0)
|
||||
/* Already handled in dict_pcre_parse_rule(). */
|
||||
msg_panic("%s: ENDIF without IF", myname);
|
||||
if (rule_stack[nesting]->op != DICT_PCRE_OP_IF)
|
||||
msg_panic("%s: unexpected rule stack element type %d",
|
||||
|
@ -6,6 +6,7 @@ get 3
|
||||
get true3
|
||||
get c
|
||||
get d
|
||||
get 1235
|
||||
get 1234
|
||||
get 123
|
||||
get bar/find
|
||||
|
@ -2,14 +2,14 @@
|
||||
./dict_open: warning: pcre map dict_pcre.map, line 1: do not prepend whitespace to statements between IF and ENDIF
|
||||
./dict_open: warning: pcre map dict_pcre.map, line 5: ignoring extra text after ENDIF
|
||||
./dict_open: warning: pcre map dict_pcre.map, line 8: unknown regexp option "!": skipping this rule
|
||||
./dict_open: warning: dict_pcre.map, line 9: no replacement text: using empty string
|
||||
./dict_open: warning: pcre map dict_pcre.map, line 9: no replacement text: using empty string
|
||||
./dict_open: warning: pcre map dict_pcre.map, line 10: out of range replacement index "5": skipping this rule
|
||||
./dict_open: warning: pcre map dict_pcre.map, line 17: $number found in negative match replacement text: skipping this rule
|
||||
./dict_open: warning: pcre map dict_pcre.map, line 22: no regexp: skipping this rule
|
||||
./dict_open: warning: pcre map dict_pcre.map, line 23: ignoring ENDIF without matching IF
|
||||
./dict_open: warning: pcre map dict_pcre.map, line 24: ignoring ENDIF without matching IF
|
||||
./dict_open: warning: pcre map dict_pcre.map, line 25: ignoring ENDIF without matching IF
|
||||
./dict_open: warning: pcre map dict_pcre.map, line 27: IF has no matching ENDIF
|
||||
./dict_open: warning: pcre map dict_pcre.map, line 26: IF has no matching ENDIF
|
||||
./dict_open: warning: pcre map dict_pcre.map, line 25: IF has no matching ENDIF
|
||||
owner=untrusted (uid=USER)
|
||||
> get true
|
||||
true: not found
|
||||
@ -27,6 +27,8 @@ true3=3
|
||||
c=
|
||||
> get d
|
||||
d: not found
|
||||
> get 1235
|
||||
1235=(1)(2)(3)
|
||||
> get 1234
|
||||
1234=(1)(2)(3)(4)
|
||||
> get 123
|
||||
|
@ -31,6 +31,11 @@
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
@ -575,8 +580,8 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *mapname, int lineno,
|
||||
while (*p && ISSPACE(*p))
|
||||
++p;
|
||||
if (!*p) {
|
||||
msg_warn("regexp map %s, line %d: using empty replacement string",
|
||||
mapname, lineno);
|
||||
msg_warn("regexp map %s, line %d: no replacement text: "
|
||||
"using empty string", mapname, lineno);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -819,6 +824,7 @@ DICT *dict_regexp_open(const char *mapname, int open_flags, int dict_flags)
|
||||
DICT_REGEXP_IF_RULE *if_rule;
|
||||
|
||||
if (nesting-- <= 0)
|
||||
/* Already handled in dict_regexp_parseline(). */
|
||||
msg_panic("%s: ENDIF without IF", myname);
|
||||
if (rule_stack[nesting]->op != DICT_REGEXP_OP_IF)
|
||||
msg_panic("%s: unexpected rule stack element type %d",
|
||||
|
@ -1,7 +1,7 @@
|
||||
./dict_open: warning: regexp map dict_regexp.map, line 1: ignoring extra text after IF statement: "fodder"
|
||||
./dict_open: warning: regexp map dict_regexp.map, line 1: do not prepend whitespace to statements between IF and ENDIF
|
||||
./dict_open: warning: regexp map dict_regexp.map, line 5: ignoring extra text after ENDIF
|
||||
./dict_open: warning: regexp map dict_regexp.map, line 9: using empty replacement string
|
||||
./dict_open: warning: regexp map dict_regexp.map, line 9: no replacement text: using empty string
|
||||
./dict_open: warning: regexp map dict_regexp.map, line 10: out of range replacement index "5": skipping this rule
|
||||
./dict_open: warning: regexp map dict_regexp.map, line 17: $number found in negative match replacement text: skipping this rule
|
||||
./dict_open: warning: regexp map dict_regexp.map, line 22: no regexp: skipping this rule
|
||||
|
@ -54,6 +54,11 @@
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user