Esempio n. 1
0
static DICT_CIDR_ENTRY *dict_cidr_parse_rule(char *p, VSTRING *why)
{
    DICT_CIDR_ENTRY *rule;
    char   *pattern;
    char   *value;
    CIDR_MATCH cidr_info;
    MAI_HOSTADDR_STR hostaddr;

    /*
     * Split the rule into key and value. We already eliminated leading
     * whitespace, comments, empty lines or lines with whitespace only. This
     * means a null key can't happen but we will handle this anyway.
     */
    pattern = p;
    while (*p && !ISSPACE(*p))			/* Skip over key */
	p++;
    if (*p)					/* Terminate key */
	*p++ = 0;
    while (*p && ISSPACE(*p))			/* Skip whitespace */
	p++;
    value = p;
    trimblanks(value, 0)[0] = 0;		/* Trim trailing blanks */
    if (*pattern == 0) {
	vstring_sprintf(why, "no address pattern");
	return (0);
    }
    if (*value == 0) {
	vstring_sprintf(why, "no lookup result");
	return (0);
    }

    /*
     * Parse the pattern, destroying it in the process.
     */
    if (cidr_match_parse(&cidr_info, pattern, why) != 0)
	return (0);

    /*
     * Bundle up the result.
     */
    rule = (DICT_CIDR_ENTRY *) mymalloc(sizeof(DICT_CIDR_ENTRY));
    rule->cidr_info = cidr_info;
    rule->value = mystrdup(value);

    if (msg_verbose) {
	if (inet_ntop(cidr_info.addr_family, cidr_info.net_bytes,
		      hostaddr.buf, sizeof(hostaddr.buf)) == 0)
	    msg_fatal("inet_ntop: %m");
	msg_info("dict_cidr_open: add %s/%d %s",
		 hostaddr.buf, cidr_info.mask_shift, rule->value);
    }
    return (rule);
}
Esempio n. 2
0
int     match_hostaddr(MATCH_LIST *list, const char *addr, const char *pattern)
{
    const char *myname = "match_hostaddr";
    char   *saved_patt;
    CIDR_MATCH match_info;
    DICT   *dict;
    VSTRING *err;
    int     rc;

    if (msg_verbose)
	msg_info("%s: %s ~? %s", myname, addr, pattern);

#define V4_ADDR_STRING_CHARS	"01234567890."
#define V6_ADDR_STRING_CHARS	V4_ADDR_STRING_CHARS "abcdefABCDEF:"

    if (addr[strspn(addr, V6_ADDR_STRING_CHARS)] != 0)
	return (0);

    /*
     * Try dictionary lookup. This can be case insensitive.
     */
    if (MATCH_DICTIONARY(pattern)) {
	if ((dict = dict_handle(pattern)) == 0)
	    msg_panic("%s: unknown dictionary: %s", myname, pattern);
	if (dict_get(dict, addr) != 0)
	    return (1);
	if ((list->error = dict->error) != 0)
	    return (match_error(list, "%s:%s: table lookup problem",
				dict->type, dict->name));
	return (0);
    }

    /*
     * Try an exact match with the host address.
     */
    if (pattern[0] != '[') {
	if (strcasecmp(addr, pattern) == 0)
	    return (1);
    } else {
	size_t  addr_len = strlen(addr);

	if (strncasecmp(addr, pattern + 1, addr_len) == 0
	    && strcmp(pattern + 1 + addr_len, "]") == 0)
	    return (1);
    }

    /*
     * Light-weight tests before we get into expensive operations.
     * 
     * - Don't bother matching IPv4 against IPv6. Postfix transforms
     * IPv4-in-IPv6 to native IPv4 form when IPv4 support is enabled in
     * Postfix; if not, then Postfix has no business dealing with IPv4
     * addresses anyway.
     * 
     * - Don't bother unless the pattern is either an IPv6 address or net/mask.
     * 
     * We can safely skip IPv4 address patterns because their form is
     * unambiguous and they did not match in the strcasecmp() calls above.
     * 
     * XXX We MUST skip (parent) domain names, which may appear in NAMADR_LIST
     * input, to avoid triggering false cidr_match_parse() errors.
     * 
     * The last two conditions below are for backwards compatibility with
     * earlier Postfix versions: don't abort with fatal errors on junk that
     * was silently ignored (principle of least astonishment).
     */
    if (!strchr(addr, ':') != !strchr(pattern, ':')
	|| pattern[strcspn(pattern, ":/")] == 0
	|| pattern[strspn(pattern, V4_ADDR_STRING_CHARS)] == 0
	|| pattern[strspn(pattern, V6_ADDR_STRING_CHARS "[]/")] != 0)
	return (0);

    /*
     * No escape from expensive operations: either we have a net/mask
     * pattern, or we have an address that can have multiple valid
     * representations (e.g., 0:0:0:0:0:0:0:1 versus ::1, etc.). The only way
     * to find out if the address matches the pattern is to transform
     * everything into to binary form, and to do the comparison there.
     */
    saved_patt = mystrdup(pattern);
    err = cidr_match_parse(&match_info, saved_patt, (VSTRING *) 0);
    myfree(saved_patt);
    if (err != 0) {
	list->error = DICT_ERR_RETRY;
	rc = match_error(list, "%s", vstring_str(err));
	vstring_free(err);
	return (rc);
    }
    return (cidr_match_execute(&match_info, addr) != 0);
}
Esempio n. 3
0
static DICT_CIDR_ENTRY *dict_cidr_parse_rule(char *p, int lineno, int nesting,
					             VSTRING *why)
{
    DICT_CIDR_ENTRY *rule;
    char   *pattern;
    char   *value;
    CIDR_MATCH cidr_info;
    MAI_HOSTADDR_STR hostaddr;
    int     match = 1;

    /*
     * IF must be followed by a pattern.
     */
    if (strncasecmp(p, "IF", 2) == 0 && !ISALNUM(p[2])) {
	p += 2;
	for (;;) {
	    if (*p == '!')
		match = !match;
	    else if (!ISSPACE(*p))
		break;
	    p++;
	}
	if (*p == 0) {
	    vstring_sprintf(why, "no address pattern");
	    return (0);
	}
	trimblanks(p, 0)[0] = 0;		/* Trim trailing blanks */
	if (cidr_match_parse_if(&cidr_info, p, match, why) != 0)
	    return (0);
	value = "";
    }

    /*
     * ENDIF must not be followed by other text.
     */
    else if (strncasecmp(p, "ENDIF", 5) == 0 && !ISALNUM(p[5])) {
	p += 5;
	while (*p && ISSPACE(*p))		/* Skip whitespace */
	    p++;
	if (*p != 0) {
	    vstring_sprintf(why, "garbage after ENDIF");
	    return (0);
	}
	if (nesting == 0) {
	    vstring_sprintf(why, "ENDIF without IF");
	    return (0);
	}
	cidr_match_endif(&cidr_info);
	value = "";
    }

    /*
     * An address pattern.
     */
    else {

	/*
	 * Process negation operators.
	 */
	for (;;) {
	    if (*p == '!')
		match = !match;
	    else if (!ISSPACE(*p))
		break;
	    p++;
	}

	/*
	 * Split the rule into key and value. We already eliminated leading
	 * whitespace, comments, empty lines or lines with whitespace only.
	 * This means a null key can't happen but we will handle this anyway.
	 */
	pattern = p;
	while (*p && !ISSPACE(*p))		/* Skip over key */
	    p++;
	if (*p)					/* Terminate key */
	    *p++ = 0;
	while (*p && ISSPACE(*p))		/* Skip whitespace */
	    p++;
	value = p;
	trimblanks(value, 0)[0] = 0;		/* Trim trailing blanks */
	if (*pattern == 0) {
	    vstring_sprintf(why, "no address pattern");
	    return (0);
	}

	/*
	 * Parse the pattern, destroying it in the process.
	 */
	if (cidr_match_parse(&cidr_info, pattern, match, why) != 0)
	    return (0);

	if (*value == 0) {
	    vstring_sprintf(why, "no lookup result");
	    return (0);
	}
    }

    /*
     * Bundle up the result.
     */
    rule = (DICT_CIDR_ENTRY *) mymalloc(sizeof(DICT_CIDR_ENTRY));
    rule->cidr_info = cidr_info;
    rule->value = mystrdup(value);
    rule->lineno = lineno;

    if (msg_verbose) {
	if (inet_ntop(cidr_info.addr_family, cidr_info.net_bytes,
		      hostaddr.buf, sizeof(hostaddr.buf)) == 0)
	    msg_fatal("inet_ntop: %m");
	msg_info("dict_cidr_open: add %s/%d %s",
		 hostaddr.buf, cidr_info.mask_shift, rule->value);
    }
    return (rule);
}