static int _check_psl(const psl_ctx_t *psl) { int it, pos, err = 0; /* check if plain suffix also appears in exceptions */ for (it = 0; it < psl->suffixes->cur; it++) { _psl_entry_t *e = _vector_get(psl->suffixes, it); if (!e->wildcard && _vector_find(psl->suffix_exceptions, e) >= 0) { fprintf(stderr, "Found entry '%s' also in exceptions\n", e->label); err = 1; } } /* check if exception also appears in suffix list as plain entry */ for (it = 0; it < psl->suffix_exceptions->cur; it++) { _psl_entry_t *e2, *e = _vector_get(psl->suffix_exceptions, it); if ((e2 = _vector_get(psl->suffixes, pos = _vector_find(psl->suffixes, e)))) { if (!e2->wildcard) { fprintf(stderr, "Found exception '!%s' also as suffix\n", e->label); err = 1; } /* Two same domains in a row are allowed: wildcard and non-wildcard. * Binary search find either of them, so also check previous and next entry. */ else if (pos > 0 && _suffix_compare(e, e2 = _vector_get(psl->suffixes, pos - 1)) == 0 && !e2->wildcard) { fprintf(stderr, "Found exception '!%s' also as suffix\n", e->label); err = 1; } else if (pos < psl->suffixes->cur - 1 && _suffix_compare(e, e2 = _vector_get(psl->suffixes, pos + 1)) == 0 && !e2->wildcard) { fprintf(stderr, "Found exception '!%s' also as suffix\n", e->label); err = 1; } } } /* check if non-wildcard entry is already covered by wildcard entry */ for (it = 0; it < psl->suffixes->cur; it++) { const char *p; _psl_entry_t *e = _vector_get(psl->suffixes, it); if (e->nlabels > 1 && !e->wildcard && (p = strchr(e->label, '.'))) { _psl_entry_t *e2, *e3, suffix; suffix.label = p + 1; suffix.length = strlen(p + 1); suffix.nlabels = e->nlabels - 1; e2 = _vector_get(psl->suffixes, pos = _vector_find(psl->suffixes, &suffix)); if (e2) { if (e2->wildcard) { fprintf(stderr, "Found superfluous '%s' already covered by '*.%s'\n", e->label, e2->label); err = 1; } /* Two same domains in a row are allowed: wildcard and non-wildcard. * Binary search find either of them, so also check previous and next entry. */ else if (pos > 0 && _suffix_compare(e2, e3 = _vector_get(psl->suffixes, pos - 1)) == 0 && e3->wildcard) { fprintf(stderr, "Found superfluous '%s' already covered by '*.%s'\n", e->label, e2->label); err = 1; } else if (pos < psl->suffixes->cur - 1 && _suffix_compare(e2, e3 = _vector_get(psl->suffixes, pos + 1)) == 0 && e3->wildcard) { fprintf(stderr, "Found superfluous '%s' already covered by '*.%s'\n", e->label, e2->label); err = 1; } } } } return err; }
static int _psl_is_public_suffix(const psl_ctx_t *psl, const char *domain) { _psl_entry_t suffix, *rule; const char *p, *label_bak; unsigned short length_bak; /* this function should be called without leading dots, just make sure */ suffix.label = domain + (*domain == '.'); suffix.length = strlen(suffix.label); suffix.wildcard = 0; suffix.nlabels = 1; for (p = suffix.label; *p; p++) if (*p == '.') suffix.nlabels++; /* if domain has enough labels, it is public */ if (psl == &_builtin_psl) rule = &suffixes[0]; else rule = _vector_get(psl->suffixes, 0); if (!rule || rule->nlabels < suffix.nlabels - 1) return 0; if (psl == &_builtin_psl) rule = bsearch(&suffix, suffixes, countof(suffixes), sizeof(suffixes[0]), (int(*)(const void *, const void *))_suffix_compare); else rule = _vector_get(psl->suffixes, _vector_find(psl->suffixes, &suffix)); if (rule) { /* definitely a match, no matter if the found rule is a wildcard or not */ return 1; } else if (suffix.nlabels == 1) { /* unknown TLD, this is the prevailing '*' match */ return 1; } label_bak = suffix.label; length_bak = suffix.length; if ((suffix.label = strchr(suffix.label, '.'))) { suffix.label++; suffix.length = strlen(suffix.label); suffix.nlabels--; if (psl == &_builtin_psl) rule = bsearch(&suffix, suffixes, countof(suffixes), sizeof(suffixes[0]), (int(*)(const void *, const void *))_suffix_compare); else rule = _vector_get(psl->suffixes, _vector_find(psl->suffixes, &suffix)); if (rule) { if (rule->wildcard) { /* now that we matched a wildcard, we have to check for an exception */ suffix.label = label_bak; suffix.length = length_bak; suffix.nlabels++; if (psl == &_builtin_psl) { if (bsearch(&suffix, suffix_exceptions, countof(suffix_exceptions), sizeof(suffix_exceptions[0]), (int(*)(const void *, const void *))_suffix_compare)) return 0; /* found an exception, so 'domain' is not a public suffix */ } else { if (_vector_get(psl->suffix_exceptions, _vector_find(psl->suffix_exceptions, &suffix)) != 0) return 0; /* found an exception, so 'domain' is not a public suffix */ } return 1; } } } return 0; }