mirror of
https://github.com/bol-van/zapret.git
synced 2024-12-20 23:11:34 +03:00
281 lines
6.8 KiB
C
281 lines
6.8 KiB
C
#include <stdio.h>
|
|
#include "hostlist.h"
|
|
#include "gzip.h"
|
|
#include "helpers.h"
|
|
|
|
// inplace tolower() and add to pool
|
|
static bool addpool(strpool **hostlist, char **s, const char *end, int *ct)
|
|
{
|
|
char *p=*s;
|
|
|
|
// comment line
|
|
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\r' || *p == '\n')
|
|
{
|
|
// advance until eol
|
|
for (; p<end && *p && *p!='\r' && *p != '\n'; p++);
|
|
}
|
|
else
|
|
{
|
|
// advance until eol lowering all chars
|
|
for (; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
|
|
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
|
|
{
|
|
StrPoolDestroy(hostlist);
|
|
*hostlist = NULL;
|
|
return false;
|
|
}
|
|
(*ct)++;
|
|
}
|
|
// advance to the next line
|
|
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
|
|
*s = p;
|
|
return true;
|
|
}
|
|
|
|
bool AppendHostList(strpool **hostlist, const char *filename)
|
|
{
|
|
char *p, *e, s[256], *zbuf;
|
|
size_t zsize;
|
|
int ct = 0;
|
|
FILE *F;
|
|
int r;
|
|
|
|
DLOG_CONDUP("Loading hostlist %s\n",filename);
|
|
|
|
if (!(F = fopen(filename, "rb")))
|
|
{
|
|
DLOG_ERR("Could not open %s\n", filename);
|
|
return false;
|
|
}
|
|
|
|
if (is_gzip(F))
|
|
{
|
|
r = z_readfile(F,&zbuf,&zsize);
|
|
fclose(F);
|
|
if (r==Z_OK)
|
|
{
|
|
DLOG_CONDUP("zlib compression detected. uncompressed size : %zu\n", zsize);
|
|
|
|
p = zbuf;
|
|
e = zbuf + zsize;
|
|
while(p<e)
|
|
{
|
|
if (!addpool(hostlist,&p,e,&ct))
|
|
{
|
|
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
|
|
free(zbuf);
|
|
return false;
|
|
}
|
|
}
|
|
free(zbuf);
|
|
}
|
|
else
|
|
{
|
|
DLOG_ERR("zlib decompression failed : result %d\n",r);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DLOG_CONDUP("loading plain text list\n");
|
|
|
|
while (fgets(s, sizeof(s), F))
|
|
{
|
|
p = s;
|
|
if (!addpool(hostlist,&p,p+strlen(p),&ct))
|
|
{
|
|
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
|
|
fclose(F);
|
|
return false;
|
|
}
|
|
}
|
|
fclose(F);
|
|
}
|
|
|
|
DLOG_CONDUP("Loaded %d hosts from %s\n", ct, filename);
|
|
return true;
|
|
}
|
|
|
|
static bool LoadHostList(struct hostlist_file *hfile)
|
|
{
|
|
time_t t = file_mod_time(hfile->filename);
|
|
if (!t)
|
|
{
|
|
// stat() error
|
|
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
|
return true;
|
|
}
|
|
if (t==hfile->mod_time) return true; // up to date
|
|
StrPoolDestroy(&hfile->hostlist);
|
|
if (!AppendHostList(&hfile->hostlist, hfile->filename))
|
|
{
|
|
StrPoolDestroy(&hfile->hostlist);
|
|
return false;
|
|
}
|
|
hfile->mod_time=t;
|
|
return true;
|
|
}
|
|
static bool LoadHostLists(struct hostlist_files_head *list)
|
|
{
|
|
bool bres=true;
|
|
struct hostlist_file *hfile;
|
|
|
|
LIST_FOREACH(hfile, list, next)
|
|
{
|
|
if (!LoadHostList(hfile))
|
|
// at least one failed
|
|
bres=false;
|
|
}
|
|
return bres;
|
|
}
|
|
|
|
bool NonEmptyHostlist(strpool **hostlist)
|
|
{
|
|
// add impossible hostname if the list is empty
|
|
return *hostlist ? true : StrPoolAddStrLen(hostlist, "@&()", 4);
|
|
}
|
|
|
|
static void MakeAutolistsNonEmpty()
|
|
{
|
|
struct desync_profile_list *dpl;
|
|
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
|
{
|
|
if (dpl->dp.hostlist_auto)
|
|
NonEmptyHostlist(&dpl->dp.hostlist_auto->hostlist);
|
|
}
|
|
}
|
|
|
|
bool LoadAllHostLists()
|
|
{
|
|
if (!LoadHostLists(¶ms.hostlists))
|
|
return false;
|
|
MakeAutolistsNonEmpty();
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
static bool SearchHostList(strpool *hostlist, const char *host)
|
|
{
|
|
if (hostlist)
|
|
{
|
|
const char *p = host;
|
|
bool bInHostList;
|
|
while (p)
|
|
{
|
|
bInHostList = StrPoolCheckStr(hostlist, p);
|
|
DLOG("hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative");
|
|
if (bInHostList) return true;
|
|
p = strchr(p, '.');
|
|
if (p) p++;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
static bool HostlistsReloadCheck(const struct hostlist_collection_head *hostlists)
|
|
{
|
|
struct hostlist_item *item;
|
|
LIST_FOREACH(item, hostlists, next)
|
|
{
|
|
if (!LoadHostList(item->hfile))
|
|
return false;
|
|
}
|
|
MakeAutolistsNonEmpty();
|
|
return true;
|
|
}
|
|
bool HostlistsReloadCheckForProfile(const struct desync_profile *dp)
|
|
{
|
|
return HostlistsReloadCheck(&dp->hl_collection) && HostlistsReloadCheck(&dp->hl_collection_exclude);
|
|
}
|
|
// return : true = apply fooling, false = do not apply
|
|
static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, const struct hostlist_collection_head *hostlists_exclude, const char *host, bool *excluded, bool bSkipReloadCheck)
|
|
{
|
|
struct hostlist_item *item;
|
|
|
|
if (excluded) *excluded = false;
|
|
|
|
if (!bSkipReloadCheck)
|
|
if (!HostlistsReloadCheck(hostlists) || !HostlistsReloadCheck(hostlists_exclude))
|
|
return false;
|
|
|
|
LIST_FOREACH(item, hostlists_exclude, next)
|
|
{
|
|
DLOG("[%s] exclude ", item->hfile->filename);
|
|
if (SearchHostList(item->hfile->hostlist, host))
|
|
{
|
|
if (excluded) *excluded = true;
|
|
return false;
|
|
}
|
|
}
|
|
// old behavior compat: all include lists are empty means check passes
|
|
if (!hostlist_collection_is_empty(hostlists))
|
|
{
|
|
LIST_FOREACH(item, hostlists, next)
|
|
{
|
|
DLOG("[%s] include ", item->hfile->filename);
|
|
if (SearchHostList(item->hfile->hostlist, host))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
// return : true = apply fooling, false = do not apply
|
|
bool HostlistCheck(const struct desync_profile *dp, const char *host, bool *excluded, bool bSkipReloadCheck)
|
|
{
|
|
DLOG("* hostlist check for profile %d\n",dp->n);
|
|
return HostlistCheck_(&dp->hl_collection, &dp->hl_collection_exclude, host, excluded, bSkipReloadCheck);
|
|
}
|
|
|
|
|
|
static struct hostlist_file *RegisterHostlist_(struct hostlist_files_head *hostlists, struct hostlist_collection_head *hl_collection, const char *filename)
|
|
{
|
|
struct hostlist_file *hfile;
|
|
if (!(hfile=hostlist_files_search(hostlists, filename)))
|
|
if (!(hfile=hostlist_files_add(hostlists, filename)))
|
|
return NULL;
|
|
if (!hostlist_collection_search(hl_collection, filename))
|
|
if (!hostlist_collection_add(hl_collection, hfile))
|
|
return NULL;
|
|
return hfile;
|
|
}
|
|
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename)
|
|
{
|
|
if (!file_mod_time(filename))
|
|
{
|
|
DLOG_ERR("cannot access hostlist file '%s'\n",filename);
|
|
return NULL;
|
|
}
|
|
return RegisterHostlist_(
|
|
¶ms.hostlists,
|
|
bExclude ? &dp->hl_collection_exclude : &dp->hl_collection,
|
|
filename);
|
|
}
|
|
|
|
void HostlistsDebug()
|
|
{
|
|
if (!params.debug) return;
|
|
|
|
struct hostlist_file *hfile;
|
|
struct desync_profile_list *dpl;
|
|
struct hostlist_item *hl_item;
|
|
|
|
LIST_FOREACH(hfile, ¶ms.hostlists, next)
|
|
DLOG("hostlist file %s%s\n",hfile->filename,hfile->hostlist ? "" : " (empty)");
|
|
|
|
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
|
{
|
|
LIST_FOREACH(hl_item, &dpl->dp.hl_collection, next)
|
|
if (hl_item->hfile!=dpl->dp.hostlist_auto)
|
|
DLOG("profile %d include hostlist %s%s\n",dpl->dp.n, hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
|
|
LIST_FOREACH(hl_item, &dpl->dp.hl_collection_exclude, next)
|
|
DLOG("profile %d exclude hostlist %s%s\n",dpl->dp.n,hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
|
|
if (dpl->dp.hostlist_auto)
|
|
DLOG("profile %d auto hostlist %s%s\n",dpl->dp.n,dpl->dp.hostlist_auto->filename,dpl->dp.hostlist_auto->hostlist ? "" : " (empty)");
|
|
}
|
|
}
|