diff --git a/CHANGES b/CHANGES
index 2c4bd037..6463d177 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
18 Jan 2010 - 2.5.12
--------------------
+ * Trim whitespace around phrases used with @pmFromFile and allow
+ for both LF and CRLF terminated lines.
+
* Allow for more robust parsing for multipart header folding. Reported
by Sogeti/ESEC R&D.
diff --git a/apache2/re_operators.c b/apache2/re_operators.c
index ab75fdf9..311c466f 100644
--- a/apache2/re_operators.c
+++ b/apache2/re_operators.c
@@ -255,7 +255,8 @@ static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) {
char buf[HUGE_STRING_LEN + 1];
char *fn;
char *next;
- char *ptr;
+ char *start;
+ char *end;
const char *rulefile_path;
apr_status_t rc;
apr_file_t *fd;
@@ -301,7 +302,7 @@ static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) {
}
/* Open file and read */
- rc = apr_file_open(&fd, fn, APR_READ | APR_FILE_NOCLEANUP, 0, rule->ruleset->mp);
+ rc = apr_file_open(&fd, fn, APR_READ | APR_BUFFERED | APR_FILE_NOCLEANUP, 0, rule->ruleset->mp);
if (rc != APR_SUCCESS) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Could not open phrase file \"%s\": %s", fn, apr_strerror(rc, errstr, 1024));
return 0;
@@ -321,21 +322,24 @@ static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) {
return 0;
}
- /* Remove newline */
- ptr = buf;
- while(*ptr != '\0') ptr++;
- if ((ptr > buf) && (*(ptr - 1) == '\n')) *(ptr - 1) = '\0';
+ /* Trim Whitespace */
+ start = buf;
+ while ((apr_isspace(*start) != 0) && (*start != '\0')) start++;
+ end = buf + strlen(buf);
+ if (end > start) end--;
+ while ((end > start) && (apr_isspace(*end) != 0)) end--;
+ if (end > start) {
+ *(++end) = '\0';
+ }
/* Ignore empty lines and comments */
- ptr = buf;
- while((*ptr != '\0') && apr_isspace(*ptr)) ptr++;
- if ((*ptr == '\0') || (*ptr == '#')) continue;
+ if ((start == end) || (*start == '#')) continue;
#ifdef DEBUG_CONF
fprintf(stderr, "Adding phrase file pattern: \"%s\"\n", buf);
#endif
- acmp_add_pattern(p, buf, NULL, NULL, strlen(buf));
+ acmp_add_pattern(p, start, NULL, NULL, (end - start));
}
fn = next;
}
diff --git a/doc/modsecurity2-apache-reference.xml b/doc/modsecurity2-apache-reference.xml
index 54faf0ea..a635afe1 100644
--- a/doc/modsecurity2-apache-reference.xml
+++ b/doc/modsecurity2-apache-reference.xml
@@ -5804,8 +5804,8 @@ end
The contents of the files should be one phrase per line. End
- of line markers will be stripped from the phrases, however,
- whitespace will not be trimmed from phrases in the file. Empty lines
+ of line markers will be stripped from the phrases (LF and CRLF), and
+ whitespace is trimmed from both sides of the phrases. Empty lines
and comment lines (beginning with a '#') are ignored.
@@ -5815,6 +5815,24 @@ end
path of the file containing the rule is prepended to the phrase file
path.
+
+
+ To allow easier matching of whole IP addresses, you can add
+ boundary characters to the phrases. For example, use "/1.2.3.4/"
+ instead of "1.2.3.4". You can then insert these characters into the
+ target prior to a match:
+
+ SecAction "phase:1,pass,nolog,setvar:tx.remote_addr=/%{REMOTE_ADDR}/"
+SecRule TX:REMOTE_ADDR "@pmFromFile ip-blacklist.txt" "deny,status:403
+
+# ip-blacklist.txt contents:
+# NOTE: All IPs must be prefixed/suffixed with "/" as the rules
+# will add in this character as a boundary to ensure
+# the entire IP is matched.
+# SecAction "phase:1,pass,nolog,setvar:tx.remote_addr='/%{REMOTE_ADDR}/'"
+/1.2.3.4/
+/5.6.7.8/
+
Example: