#include <stdio.h> #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<end && *p && *p!='\r' && *p != '\n'; p++); // comment line if (!(**s == '#' || **s == ';' || **s == '/' || **s == '\r' || **s == '\n' )) { l = p-*s; if (l>=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; } (*ct)++; } else if (parse_cidr6(cidr,&c6)) { if (!ipset6AddCidr(&ips->ips6, &c6)) { ipsetDestroy(ips); return false; } (*ct)++; } else DLOG_ERR("bad ip or subnet : %s\n",cidr); } // advance to the next line for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++); *s = p; return true; } static bool AppendIpset(ipset *ips, const char *filename) { char *p, *e, s[256], *zbuf; size_t zsize; int ct = 0; FILE *F; int r; DLOG_CONDUP("Loading ipset %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(ips,&p,e,&ct)) { DLOG_ERR("Not enough memory to store ipset : %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)-1, F)) { p = s; if (!addpool(ips,&p,p+strlen(p),&ct)) { DLOG_ERR("Not enough memory to store ipset : %s\n", filename); fclose(F); return false; } } fclose(F); } DLOG_CONDUP("Loaded %d ip/subnets from %s\n", ct, filename); return true; } static bool LoadIpsets(ipset *ips, struct str_list_head *file_list) { struct str_list *file; ipsetDestroy(ips); LIST_FOREACH(file, file_list, next) { if (!AppendIpset(ips, file->str)) return false; } return true; } bool LoadIncludeIpsets() { struct desync_profile_list *dpl; LIST_FOREACH(dpl, ¶ms.desync_profiles, next) if (!LoadIpsets(&dpl->dp.ips, &dpl->dp.ipset_files)) return false; return true; } bool LoadExcludeIpsets() { struct desync_profile_list *dpl; LIST_FOREACH(dpl, ¶ms.desync_profiles, next) if (!LoadIpsets(&dpl->dp.ips_exclude, &dpl->dp.ipset_exclude_files)) return false; return true; } 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); } VPRINT("ipset check for %s : %s\n", s_ip, bInSet ? "positive" : "negative"); } else // ipv4 and ipv6 are both empty or non-empty VPRINT("ipset check error !!!!!!!! ipv4=%p ipv6=%p\n",ipv4,ipv6); return bInSet; } static bool IpsetCheck_(const ipset *ips, const ipset *ips_exclude, const struct in_addr *ipv4, const struct in6_addr *ipv6) { if (!IPSET_EMPTY(ips_exclude)) { VPRINT("exclude "); if (SearchIpset(ips_exclude, ipv4, ipv6)) return false; } if (!IPSET_EMPTY(ips)) { VPRINT("include "); return SearchIpset(ips, ipv4, ipv6); } return true; } bool IpsetCheck(struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6) { if (!PROFILE_IPSETS_EMPTY(dp)) VPRINT("* ipset check for profile %d\n",dp->n); return IpsetCheck_(&dp->ips,&dp->ips_exclude,ipv4,ipv6); }