static inline bool trie_entry_prefix(const trie_t *trie,
const trie_entry_t *entry, const char *key)
{
- return !!(strncmp(array_ptr(trie->c, entry->c_offset), key, entry->c_len) == 0);
+ int len = entry->c_len;
+ if (len > 0 && array_elt(trie->c, entry->c_offset + len - 1) == '\0') {
+ --len;
+ }
+ return !!(strncmp(array_ptr(trie->c, entry->c_offset), key, len) == 0);
}
static inline bool trie_entry_is_leaf(const trie_entry_t *entry)
static int leaves = 0;
static int depth_sum = 0;
+ if (entry == array_ptr(trie->entries, 0)) {
+ max_depth = 0;
+ leaves = 0;
+ depth_sum = 0;
+ }
if (trie_entry_is_leaf(entry)) {
if (level > max_depth) {
max_depth = level;
*/
if (argc > 1) {
trie = create_trie_from_file(argv[1]);
- trie_inspect(trie, false);
+ trie_inspect(trie, true);
trie_delete(&trie);
}
return 0;
# - strlist: match strings from the query against a list of list.
# Parameters:
-# - file: (no)?lock:(pre|suf)fix:weight:filename
+# - file: (no)?lock:(partial-)?(pre|suf)fix:weight:filename
# declare a file to load. If lock is given, the list is locked into the
# RAM. Prefix/Suffix is a parameter to tell the matcher which is the most
# efficient storage order. The strings are internally stored into a trie that
# allow high compression if a lot of prefix are shared by several strings. If
# you choose "prefix", string are stored in the natural order in memory and
# prefix compression is performed. If you choose "suffix", strings are stored
-# in reverse order in memory and suffix compression is performed. The weight
-# is a number giving the weight of this list in the string score.
+# in reverse order in memory and suffix compression is performed. If you add "partial-"
+# to the match order, the entry will match if the file contains a prefix (resp. suffix)
+# of the string. The weight is a number giving the weight of this list in the string score.
+# e.g.:
+# * a file that contains ".polytechnique.org" in "partial-suffix" mode will match
+# all subdomains of "polytechnique.org".
+# * a file that contains "postmaster@" in "partial-prefix" mode will match all
+# postmaster emails.
+# * a file open without "partial-" modifier match exact strings.
# - soft_threshold: score (default: 1)
# minimum score to match the soft_match return value
# - hard_threshold: score (default: 1)
type = strlist;
# configuration
- file = lock:1:/var/spool/postlicyd/client_whitelist;
+ file = lock:1:suffix:/var/spool/postlicyd/client_whitelist;
fields = client_name;
# hooks
on_fail = postfix:OK;
}
+hostnames3 {
+ type = strlist;
+
+ fields = client_name;
+ file = nolock:partial-suffix:1:data/test_hostnames_4;
+
+ on_hard_match = postfix:OK;
+ on_fail = postfix:OK;
+}
+
+
emails1 {
type = strlist;
on_fail = postfix:ok;
}
+emails3 {
+ type = strlist;
+
+ fields = sender;
+ file = nolock:partial-prefix:1:data/test_emails_4;
+
+ on_hard_match = postfix:ok;
+ on_fail = postfix:ok;
+}
+
ips1 {
type = iplist;
match2=fail
hostnames1=fail
hostnames2=fail
+hostnames3=fail
emails1=fail
emails2=fail
+emails3=fail
ips1=hard_match
protocol_name=SMTP
helo_name=example.org
queue_id=8045F2AB23
-sender=contact@example.com
+sender=postmaster@example.com
recipient=contact@example.org
recipient_count=0
client_address=1.2.3.4
match2=match
hostnames1=soft_match
hostnames2=hard_match
+hostnames3=hard_match
emails1=soft_match
emails2=hard_match
+emails3=hard_match
ips1=hard_match
match2=match
hostnames1=fail
hostnames2=hard_match
+hostnames3=hard_match
emails1=fail
emails2=fail
+emails3=fail
ips1=error
match2=fail
hostnames1=fail
hostnames2=hard_match
+hostnames3=hard_match
emails1=fail
emails2=fail
+emails3=fail
ips1=error
match2=match
hostnames1=fail
hostnames2=hard_match
+hostnames3=hard_match
emails1=fail
emails2=fail
+emails3=fail
ips1=fail
protocol_name=SMTP
helo_name=tata.example.org
queue_id=8045F2AB23
-sender=contact@exemple.com
+sender=postmaster@exemple.com
recipient=contact@exemple.org
recipient_count=0
client_address=2.3.4.5
match2=fail
hostnames1=fail
hostnames2=hard_match
+hostnames3=hard_match
emails1=fail
emails2=fail
+emails3=hard_match
ips1=soft_match
PA(trie_t) tries;
A(int) weights;
A(bool) reverses;
+ A(bool) partiales;
int soft_threshold;
int hard_threshold;
array_deep_wipe((*config)->tries, trie_delete);
array_wipe((*config)->weights);
array_wipe((*config)->reverses);
+ array_wipe((*config)->partiales);
p_delete(config);
}
}
bool lock = false;
int weight = 0;
bool reverse = false;
+ bool partial = false;
trie_t *trie = NULL;
const char *current = param->value;
const char *p = m_strchrnul(param->value, ':');
break;
case 1:
+ if (p - current > (ssize_t)strlen("partial-")
+ && strncmp(current, "partial-", strlen("partial-")) == 0) {
+ partial = true;
+ current += strlen("partial-");
+ }
if ((p - current) == 6 && strncmp(current, "suffix", 6) == 0) {
reverse = true;
} else if ((p - current) == 6 && strncmp(current, "prefix", 6) == 0) {
array_add(config->tries, trie);
array_add(config->weights, weight);
array_add(config->reverses, reverse);
+ array_add(config->partiales, partial);
break;
}
if (i != 3) {
for (uint32_t i = 0 ; i < config->tries.len ; ++i) { \
const int weight = array_elt(config->weights, i); \
const trie_t *trie = array_elt(config->tries, i); \
- const bool rev = array_elt(config->reverses, i); \
- if (trie_lookup(trie, rev ? reverse : normal)) { \
+ const bool rev = array_elt(config->reverses, i); \
+ const bool part = array_elt(config->partiales, i); \
+ if ((!part && trie_lookup(trie, rev ? reverse : normal)) \
+ || (part && trie_prefix(trie, rev ? reverse : normal))) { \
sum += weight; \
} \
} \