#include #include "ipset.h" #include "gzip.h" #include "helpers.h" // inplace tolower() and add to pool static bool addpool(ipset *ips, char **s, const char *end, int *ct) { char *p, cidr[128]; size_t l; struct cidr4 c4; struct cidr6 c6; // advance until eol for (p=*s; p=sizeof(cidr)) l=sizeof(cidr)-1; memcpy(cidr,*s,l); cidr[l]=0; rtrim(cidr); if (parse_cidr4(cidr,&c4)) { if (!ipset4AddCidr(&ips->ips4, &c4)) { ipsetDestroy(ips); return false; } if (ct) (*ct)++; } else if (parse_cidr6(cidr,&c6)) { if (!ipset6AddCidr(&ips->ips6, &c6)) { ipsetDestroy(ips); return false; } if (ct) (*ct)++; } else DLOG_ERR("bad ip or subnet : %s\n",cidr); } // advance to the next line for (; pfilename) { time_t t = file_mod_time(hfile->filename); if (!t) { // stat() error DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename); return true; } if (t==hfile->mod_time) return true; // up to date ipsetDestroy(&hfile->ipset); if (!AppendIpset(&hfile->ipset, hfile->filename)) { ipsetDestroy(&hfile->ipset); return false; } hfile->mod_time=t; } return true; } static bool LoadIpsets(struct ipset_files_head *list) { bool bres=true; struct ipset_file *hfile; LIST_FOREACH(hfile, list, next) { if (!LoadIpset(hfile)) // at least one failed bres=false; } return bres; } bool LoadAllIpsets() { return LoadIpsets(¶ms.ipsets); } static bool SearchIpset(const ipset *ips, const struct in_addr *ipv4, const struct in6_addr *ipv6) { char s_ip[40]; bool bInSet=false; if (!!ipv4 != !!ipv6) { *s_ip=0; if (ipv4) { if (params.debug) inet_ntop(AF_INET, ipv4, s_ip, sizeof(s_ip)); if (ips->ips4) bInSet = ipset4Check(ips->ips4, ipv4, 32); } if (ipv6) { if (params.debug) inet_ntop(AF_INET6, ipv6, s_ip, sizeof(s_ip)); if (ips->ips6) bInSet = ipset6Check(ips->ips6, ipv6, 128); } DLOG("ipset check for %s : %s\n", s_ip, bInSet ? "positive" : "negative"); } else // ipv4 and ipv6 are both empty or non-empty DLOG("ipset check error !!!!!!!! ipv4=%p ipv6=%p\n",ipv4,ipv6); return bInSet; } static bool IpsetsReloadCheck(const struct ipset_collection_head *ipsets) { struct ipset_item *item; LIST_FOREACH(item, ipsets, next) { if (!LoadIpset(item->hfile)) return false; } return true; } bool IpsetsReloadCheckForProfile(const struct desync_profile *dp) { return IpsetsReloadCheck(&dp->ips_collection) && IpsetsReloadCheck(&dp->ips_collection_exclude); } static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ipset_collection_head *ips_exclude, const struct in_addr *ipv4, const struct in6_addr *ipv6) { struct ipset_item *item; if (!IpsetsReloadCheck(ips) || !IpsetsReloadCheck(ips_exclude)) return false; LIST_FOREACH(item, ips_exclude, next) { DLOG("[%s] exclude ",item->hfile->filename ? item->hfile->filename : "fixed"); if (SearchIpset(&item->hfile->ipset, ipv4, ipv6)) return false; } // old behavior compat: all include lists are empty means check passes if (!ipset_collection_is_empty(ips)) { LIST_FOREACH(item, ips, next) { DLOG("[%s] include ",item->hfile->filename ? item->hfile->filename : "fixed"); if (SearchIpset(&item->hfile->ipset, ipv4, ipv6)) return true; } return false; } return true; } bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6) { if (PROFILE_IPSETS_ABSENT(dp)) return true; DLOG("* ipset check for profile %d\n",dp->n); return IpsetCheck_(&dp->ips_collection,&dp->ips_collection_exclude,ipv4,ipv6); } static struct ipset_file *RegisterIpset_(struct ipset_files_head *ipsets, struct ipset_collection_head *ips_collection, const char *filename) { struct ipset_file *hfile; if (filename) { if (!(hfile=ipset_files_search(ipsets, filename))) if (!(hfile=ipset_files_add(ipsets, filename))) return NULL; if (!ipset_collection_search(ips_collection, filename)) if (!ipset_collection_add(ips_collection, hfile)) return NULL; } else { if (!(hfile=ipset_files_add(ipsets, NULL))) return NULL; if (!ipset_collection_add(ips_collection, hfile)) return NULL; } return hfile; } struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename) { if (filename && !file_mod_time(filename)) { DLOG_ERR("cannot access ipset file '%s'\n",filename); return NULL; } return RegisterIpset_( ¶ms.ipsets, bExclude ? &dp->ips_collection_exclude : &dp->ips_collection, filename); } static const char *dbg_ipset_fill(const ipset *ips) { if (ips->ips4) if (ips->ips6) return "ipv4+ipv6"; else return "ipv4"; else if (ips->ips6) return "ipv6"; else return "empty"; } void IpsetsDebug() { if (!params.debug) return; struct ipset_file *hfile; struct desync_profile_list *dpl; struct ipset_item *ips_item; LIST_FOREACH(hfile, ¶ms.ipsets, next) { if (hfile->filename) DLOG("ipset file %s (%s)\n",hfile->filename,dbg_ipset_fill(&hfile->ipset)); else DLOG("ipset fixed (%s)\n",dbg_ipset_fill(&hfile->ipset)); } LIST_FOREACH(dpl, ¶ms.desync_profiles, next) { LIST_FOREACH(ips_item, &dpl->dp.ips_collection, next) if (ips_item->hfile->filename) DLOG("profile %d include ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset)); else DLOG("profile %d include fixed ipset (%s)\n",dpl->dp.n,dbg_ipset_fill(&ips_item->hfile->ipset)); LIST_FOREACH(ips_item, &dpl->dp.ips_collection_exclude, next) if (ips_item->hfile->filename) DLOG("profile %d exclude ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset)); else DLOG("profile %d exclude fixed ipset (%s)\n",dpl->dp.n,dbg_ipset_fill(&ips_item->hfile->ipset)); } }