Cleanup: make regexp: and pcre: parser warning messages more
similar. Files: dict_regexp.c, dict_pcre.c.
+
+20160601
+
+ Cleanup: moved parsing of '!' operators from cidr_match.c
+ to dict_cidr.c. Files: util/cidr_match.[hc], util/dict_cidr.c,
+ util/match_ops.c.
+
+20160604
+
+ Cleanup: made parsing of '!' operators in regexp and pcre
+ tables consistent with cidr tables. Files: util/dict_regexp.c,
+ util/dict_pcre.c.
Fix "make test" bitrot.
+ Move DNS-based tests from porcupine.org to postfix.org.
+
Document dns_ncache_ttl_fix_enable use case in POSTSCREEN_README
and RELEASE_NOTES.
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20160527"
+#define MAIL_RELEASE_DATE "20160604"
#define MAIL_VERSION_NUMBER "3.2"
#ifdef SNAPSHOT
/* SYNOPSIS
/* #include <cidr_match.h>
/*
-/* VSTRING *cidr_match_parse(info, pattern, why)
+/* VSTRING *cidr_match_parse(info, pattern, match, why)
/* CIDR_MATCH *info;
/* char *pattern;
/* VSTRING *why;
/* CIDR_MATCH *info;
/* const char *address;
/* AUXILIARY FUNCTIONS
-/* VSTRING *cidr_match_parse_if(info, address, why)
+/* VSTRING *cidr_match_parse_if(info, pattern, match, why)
/* CIDR_MATCH *info;
-/* char *address;
+/* char *pattern;
/* VSTRING *why;
/*
/* void cidr_match_endif(info)
/*
/* cidr_match_parse() parses an address or address/mask
/* expression and stores the result into the info argument.
+/* A non-zero (or zero) match argument requests a positive (or
+/* negative) match. The symbolic constants CIDR_MATCH_TRUE and
+/* CIDR_MATCH_FALSE may help to improve code readability.
/* The result is non-zero in case of problems: either the
/* value of the why argument, or a newly allocated VSTRING
/* (the caller should give the latter to vstring_free()).
/*
/* cidr_match_parse_if() parses the address that follows an IF
/* token, and stores the result into the info argument.
+/* The arguments are the same as for cidr_match_parse().
/*
/* cidr_match_endif() handles the occurrence of an ENDIF token,
/* and updates the info argument.
/* cidr_match_parse - parse CIDR pattern */
-VSTRING *cidr_match_parse(CIDR_MATCH *ip, char *pattern, VSTRING *why)
+VSTRING *cidr_match_parse(CIDR_MATCH *ip, char *pattern, int match,
+ VSTRING *why)
{
const char *myname = "cidr_match_parse";
char *mask_search;
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
* Wrap up the result.
*/
ip->op = CIDR_MATCH_OP_MATCH;
+ ip->match = match;
ip->next = 0;
ip->block_end = 0;
/* cidr_match_parse_if - parse CIDR pattern after IF */
-VSTRING *cidr_match_parse_if(CIDR_MATCH *ip, char *pattern, VSTRING *why)
+VSTRING *cidr_match_parse_if(CIDR_MATCH *ip, char *pattern, int match,
+ VSTRING *why)
{
VSTRING *ret;
- if ((ret = cidr_match_parse(ip, pattern, why)) == 0)
+ if ((ret = cidr_match_parse(ip, pattern, match, why)) == 0)
ip->op = CIDR_MATCH_OP_IF;
return (ret);
}
#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 *);
+#define CIDR_MATCH_TRUE 1 /* Request positive match */
+#define CIDR_MATCH_FALSE 0 /* Request negative match */
+
+extern VSTRING *cidr_match_parse(CIDR_MATCH *, char *, int, VSTRING *);
+extern VSTRING *cidr_match_parse_if(CIDR_MATCH *, char *, int, VSTRING *);
extern void cidr_match_endif(CIDR_MATCH *);
extern CIDR_MATCH *cidr_match_execute(CIDR_MATCH *, const char *);
char *value;
CIDR_MATCH cidr_info;
MAI_HOSTADDR_STR hostaddr;
+ int match = 1;
/*
* IF must be followed by a pattern.
*/
if (strncasecmp(p, "IF", 2) == 0 && !ISALNUM(p[2])) {
p += 2;
- while (*p && ISSPACE(*p)) /* Skip whitespace */
+ for (;;) {
+ if (*p == '!')
+ match = !match;
+ else if (!ISSPACE(*p))
+ break;
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)
+ if (cidr_match_parse_if(&cidr_info, p, match, why) != 0)
return (0);
value = "";
}
*/
else {
+ /*
+ * Process negation operators.
+ */
+ for (;;) {
+ if (*p == '!')
+ match = !match;
+ else if (!ISSPACE(*p))
+ break;
+ p++;
+ }
+
/*
* Split the rule into key and value. We already eliminated leading
* whitespace, comments, empty lines or lines with whitespace only.
/*
* Parse the pattern, destroying it in the process.
*/
- if (cidr_match_parse(&cidr_info, pattern, why) != 0)
+ if (cidr_match_parse(&cidr_info, pattern, match, why) != 0)
return (0);
if (*value == 0) {
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
-0.0.0.0/0 match 0.0.0.0/0
+! ! 0.0.0.0/0 match 0.0.0.0/0
1::/0 match ::/0
::/0 match ::/0
-[1234 foo
-[1234]junk bar
-172.16.1.3/3x whatever
+[1234 can't happen
+[1234]junk can't happen
+172.16.1.3/3x can't happen
endif
endif
if 1:2::3:4
./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 49: no address pattern: skipping this rule
+./dict_open: warning: cidr map dict_cidr.map, line 50: no address 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)
* Process negation operators.
*/
pattern->match = 1;
- while (*p == '!') {
- pattern->match = !pattern->match;
+ for (;;) {
+ if (*p == '!')
+ pattern->match = !pattern->match;
+ else if (!ISSPACE(*p))
+ break;
p++;
}
-
- /*
- * Grr...aceful handling of whitespace after '!'.
- */
- while (*p && ISSPACE(*p))
- p++;
if (*p == 0) {
msg_warn("pcre map %s, line %d: no regexp: skipping this rule",
mapname, lineno);
* Process negation operators.
*/
pat->match = 1;
- while (*p == '!') {
- pat->match = !pat->match;
+ for (;;) {
+ if (*p == '!')
+ pat->match = !pat->match;
+ else if (!ISSPACE(*p))
+ break;
p++;
}
-
- /*
- * Grr...aceful handling of whitespace after '!'.
- */
- while (*p && ISSPACE(*p))
- p++;
if (*p == 0) {
msg_warn("regexp map %s, line %d: no regexp: skipping this rule",
mapname, lineno);
* everything into to binary form, and to do the comparison there.
*/
saved_patt = mystrdup(pattern);
- err = cidr_match_parse(&match_info, saved_patt, (VSTRING *) 0);
+ err = cidr_match_parse(&match_info, saved_patt, CIDR_MATCH_TRUE,
+ (VSTRING *) 0);
myfree(saved_patt);
if (err != 0) {
list->error = DICT_ERR_RETRY;