Skip to content
Snippets Groups Projects
Commit a19d58c1 authored by Rob Swindell's avatar Rob Swindell :speech_balloon:
Browse files

New findstr functions that can search for (up to) two strings in one go

Many searches are done (e.g. in the mail server, QWK import) for either of 2
strings in single file or list, so let's optimize that to a single iteration
through the file/list. This should reduce some redundant file I/O.

I do find this API a little confusing with the filename or list at the end
of the argument list, but kept it consistent with the existing single string
findstr functions (which are now just wrappers for the new 2-string flavors).

I noticed during this update that findstr() did not share the same behavior
as findstr_in_list() (feature added in commit f08f2137) whereby if all the
patterns were negative searches (beginning with '!'), then *all* the
negative matches would have to be successful (not just the first) for the
function to return true. So now findstr() behaves like findstr_in_list()
in this regard.

I also added some optimizations to findstr_in_string().
parent 1332d96b
No related branches found
No related tags found
No related merge requests found
Pipeline #4985 failed
......@@ -23,7 +23,7 @@
#include "findstr.h"
/****************************************************************************/
/* Pattern matching string search of 'insearchof' in 'pattern'. */
/* Pattern matching string search of 'search' in 'pattern'. */
/* pattern matching is case-insensitive */
/* patterns beginning with ';' are comments (never match) */
/* patterns beginning with '!' are reverse-matched (returns FALSE if match) */
......@@ -35,18 +35,15 @@
BOOL findstr_in_string(const char* search, const char* pattern)
{
char buf[256];
char* p;
char* p = (char*)pattern;
char* last;
const char* splat;
size_t len;
BOOL found = FALSE;
if(pattern == NULL || search == NULL)
if(pattern == NULL)
return FALSE;
SAFECOPY(buf, pattern);
p = buf;
if(*p == ';') /* comment */
return FALSE;
......@@ -55,6 +52,12 @@ BOOL findstr_in_string(const char* search, const char* pattern)
p++;
}
if(search == NULL)
return found;
SAFECOPY(buf, p);
p = buf;
truncsp(p);
len = strlen(p);
if(len > 0) {
......@@ -98,6 +101,8 @@ static uint32_t parse_ipv4_address(const char* str)
{
unsigned int byte[4];
if(str == NULL)
return 0;
if(sscanf(str, "%u.%u.%u.%u", &byte[0], &byte[1], &byte[2], &byte[3]) != 4)
return 0;
return encode_ipv4_address(byte);
......@@ -129,27 +134,45 @@ static BOOL is_cidr_match(const char *p, uint32_t ip_addr, uint32_t cidr, unsign
return match;
}
static BOOL findstr_compare(const char* str, uint32_t ip_addr, const char* pattern)
{
uint32_t cidr;
unsigned subnet;
if(ip_addr != 0 && (cidr = parse_cidr(pattern, &subnet)) != 0)
return is_cidr_match(pattern, ip_addr, cidr, subnet);
return findstr_in_string(str, pattern);
}
/****************************************************************************/
/* Pattern matching string search of 'insearchof' in 'list'. */
/****************************************************************************/
BOOL findstr_in_list(const char* insearchof, str_list_t list)
{
return find2strs_in_list(insearchof, NULL, list);
}
/****************************************************************************/
/* Pattern matching string search of 'str1' or 'str2' in 'list'. */
/****************************************************************************/
BOOL find2strs_in_list(const char* str1, const char* str2, str_list_t list)
{
size_t index;
BOOL found=FALSE;
char* p;
uint32_t ip_addr, cidr;
unsigned subnet;
uint32_t ip_addr1, ip_addr2;
if(list==NULL || insearchof==NULL)
if(list == NULL)
return FALSE;
ip_addr = parse_ipv4_address(insearchof);
ip_addr1 = parse_ipv4_address(str1);
ip_addr2 = parse_ipv4_address(str2);
for(index=0; list[index]!=NULL; index++) {
p=list[index];
// SKIP_WHITESPACE(p);
if(ip_addr != 0 && (cidr = parse_cidr(p, &subnet)) != 0)
found = is_cidr_match(p, ip_addr, cidr, subnet);
else
found = findstr_in_string(insearchof,p);
if(*p == '\0')
continue;
found = findstr_compare(str1, ip_addr1, p);
if(!found && str2 != NULL)
found = findstr_compare(str2, ip_addr2, p);
if(found != (*p=='!'))
break;
}
......@@ -160,30 +183,41 @@ BOOL findstr_in_list(const char* insearchof, str_list_t list)
/* Pattern matching string search of 'insearchof' in 'fname'. */
/****************************************************************************/
BOOL findstr(const char* insearchof, const char* fname)
{
return find2strs(insearchof, NULL, fname);
}
/****************************************************************************/
/* Pattern matching string search of 'str1' or 'str2' in 'fname'. */
/****************************************************************************/
BOOL find2strs(const char* str1, const char* str2, const char* fname)
{
char str[256];
BOOL found=FALSE;
FILE* fp;
uint32_t ip_addr, cidr;
unsigned subnet;
uint32_t ip_addr1, ip_addr2;
if(insearchof==NULL || fname==NULL || *fname == '\0')
if(fname == NULL || *fname == '\0')
return FALSE;
if((fp=fopen(fname,"r"))==NULL)
return FALSE;
ip_addr = parse_ipv4_address(insearchof);
while(!feof(fp) && !ferror(fp) && !found) {
ip_addr1 = parse_ipv4_address(str1);
ip_addr2 = parse_ipv4_address(str2);
while(!feof(fp) && !ferror(fp)) {
if(!fgets(str,sizeof(str),fp))
break;
char* p = str;
SKIP_WHITESPACE(p);
if(*p == '\0')
continue;
c_unescape_str(p);
if(ip_addr !=0 && (cidr = parse_cidr(p, &subnet)) != 0)
found = is_cidr_match(p, ip_addr, cidr, subnet);
else
found = findstr_in_string(insearchof, p);
found = findstr_compare(str1, ip_addr1, p);
if(!found && str2 != NULL)
found = findstr_compare(str2, ip_addr2, p);
if(found != (*p=='!'))
break;
}
fclose(fp);
......
......@@ -30,8 +30,10 @@ extern "C" {
#endif
DLLEXPORT BOOL findstr(const char *insearch, const char *fname);
DLLEXPORT BOOL find2strs(const char *str1, const char* str2, const char *fname);
DLLEXPORT BOOL findstr_in_string(const char* insearchof, const char* pattern);
DLLEXPORT BOOL findstr_in_list(const char* insearchof, str_list_t list);
DLLEXPORT BOOL find2strs_in_list(const char* str1, const char* str2, str_list_t list);
DLLEXPORT str_list_t findstr_list(const char* fname);
#ifdef __cplusplus
......
......@@ -1856,9 +1856,7 @@ static ulong dns_blacklisted(SOCKET sock, const char* prot, union xp_sockaddr *a
SAFEPRINTF(fname,"%sdnsbl_exempt.cfg",scfg.ctrl_dir);
inet_addrtop(addr, ip, sizeof(ip));
if(findstr(ip,fname))
return(FALSE);
if(findstr(host_name,fname))
if(find2strs(ip, host_name, fname))
return(FALSE);
SAFEPRINTF(fname,"%sdns_blacklist.cfg", scfg.ctrl_dir);
......@@ -3035,7 +3033,7 @@ static bool smtp_client_thread(smtp_t* smtp)
return false;
}
spam_block_exempt = findstr(host_ip,spam_block_exemptions) || findstr(host_name,spam_block_exemptions);
spam_block_exempt = find2strs(host_ip, host_name, spam_block_exemptions);
if(trashcan(&scfg,host_ip,"ip")
|| ((!spam_block_exempt) && findstr(host_ip,spam_block))) {
lprintf(LOG_NOTICE,"%04d %s !CLIENT IP ADDRESS BLOCKED: %s (%lu total)"
......@@ -3173,7 +3171,7 @@ static bool smtp_client_thread(smtp_t* smtp)
/* Twit-listing (sender's name and e-mail addresses) here */
twitlist_fname(&scfg, path, sizeof path);
if(fexist(path) && (findstr(sender,path) || findstr(sender_addr,path))) {
if(fexist(path) && find2strs(sender, sender_addr, path)) {
lprintf(LOG_NOTICE,"%04d %s %s !FILTERING TWIT-LISTED SENDER: '%s' <%s> (%lu total)"
,socket, client.protocol, client_id, sender, sender_addr, ++stats.msgs_refused);
SAFEPRINTF2(tmp,"Twit-listed sender: '%s' <%s>", sender, sender_addr);
......@@ -4630,8 +4628,7 @@ static bool smtp_client_thread(smtp_t* smtp)
(!(startup->options&MAIL_OPT_ALLOW_RELAY)
|| relay_user.number==0
|| relay_user.rest&(FLAG('G')|FLAG('M'))) &&
!findstr(host_name,relay_list) &&
!findstr(host_ip,relay_list)) {
!find2strs(host_name, host_ip, relay_list)) {
lprintf(LOG_NOTICE,"%04d %s %s !ILLEGAL RELAY ATTEMPT from %s [%s] to %s"
,socket, client.protocol, client_id, reverse_path, host_ip, p);
SAFEPRINTF(tmp,"Relay attempt to: %s", p);
......@@ -4697,7 +4694,7 @@ static bool smtp_client_thread(smtp_t* smtp)
if(!chk_ar(&scfg,mailproc_list[i].ar,&relay_user,&client))
continue;
if(findstr_in_list(p, mailproc_list[i].to) || findstr_in_list(rcpt_addr, mailproc_list[i].to)) {
if(find2strs_in_list(p, rcpt_addr, mailproc_list[i].to)) {
mailproc_to_match[i]=TRUE;
if(!mailproc_list[i].passthru)
mailproc_match = i;
......
......@@ -1191,7 +1191,7 @@ bool sbbs_t::qwk_msg_filtered(smbmsg_t* msg, msg_filters filters)
return true;
}
if(findstr_in_list(msg->from, filters.twit_list) || findstr_in_list(msg->to, filters.twit_list)) {
if(find2strs_in_list(msg->from, msg->to, filters.twit_list)) {
lprintf(LOG_NOTICE,"!Filtering QWK message from '%s' to '%s'"
,msg->from
,msg->to);
......
......@@ -3207,7 +3207,7 @@ int fmsgtosmsg(char* fbuf, fmsghdr_t* hdr, uint usernumber, uint subnum)
time32_t now=time32(NULL);
ulong max_msg_age = (subnum == INVALID_SUB) ? cfg.max_netmail_age : cfg.max_echomail_age;
if(findstr_in_list(hdr->from, twit_list) || findstr_in_list(hdr->to, twit_list)) {
if(find2str_in_list(hdr->from, hdr->to, twit_list)) {
lprintf(LOG_INFO,"Filtering message from %s to %s",hdr->from,hdr->to);
return IMPORT_FILTERED_TWIT;
}
......
......@@ -3599,7 +3599,7 @@ BOOL is_host_exempt(scfg_t* cfg, const char* ip_addr, const char* host_name)
char exempt[MAX_PATH+1];
SAFEPRINTF2(exempt, "%s%s", cfg->ctrl_dir, strIpFilterExemptConfigFile);
return findstr(ip_addr, exempt) || findstr(host_name, exempt);
return find2strs(ip_addr, host_name, exempt);
}
/****************************************************************************/
......@@ -3619,9 +3619,7 @@ BOOL filter_ip(scfg_t* cfg, const char* prot, const char* reason, const char* ho
return(FALSE);
SAFEPRINTF2(exempt, "%s%s", cfg->ctrl_dir, strIpFilterExemptConfigFile);
if(findstr(ip_addr, exempt))
return(FALSE);
if(findstr(host, exempt))
if(find2strs(ip_addr, host, exempt))
return(FALSE);
SAFEPRINTF(ip_can,"%sip.can",cfg->text_dir);
......@@ -3905,10 +3903,7 @@ ulong loginBanned(scfg_t* cfg, link_list_t* list, SOCKET sock, const char* host_
return 0;
if(inet_addrtop(&client_addr, ip_addr, sizeof(ip_addr)) != NULL
&& findstr(ip_addr, exempt))
return 0;
if(host_name != NULL
&& findstr(host_name, exempt))
&& find2strs(ip_addr, host_name, exempt))
return 0;
if(!listLock(list))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment