#include <sys_defs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
#include <msg.h>
#include <mymalloc.h>
#include <split_at.h>
#include <dict.h>
#include <match_list.h>
#include <stringops.h>
#include <cidr_match.h>
#define MATCH_DICTIONARY(pattern) \
((pattern)[0] != '[' && strchr((pattern), ':') != 0)
static int match_error(MATCH_LIST *list, const char *fmt,...)
{
VSTRING *buf = vstring_alloc(100);
va_list ap;
va_start(ap, fmt);
vstring_vsprintf(buf, fmt, ap);
va_end(ap);
if (list->flags & MATCH_FLAG_RETURN) {
msg_warn("%s", vstring_str(buf));
} else {
msg_fatal("%s", vstring_str(buf));
}
vstring_free(buf);
return (0);
}
int match_string(MATCH_LIST *list, const char *string, const char *pattern)
{
const char *myname = "match_string";
DICT *dict;
if (msg_verbose)
msg_info("%s: %s ~? %s", myname, string, pattern);
if (MATCH_DICTIONARY(pattern)) {
if ((dict = dict_handle(pattern)) == 0)
msg_panic("%s: unknown dictionary: %s", myname, pattern);
if (dict_get(dict, string) != 0)
return (1);
if ((list->error = dict->error) != 0)
return (match_error(list, "%s:%s: table lookup problem",
dict->type, dict->name));
return (0);
}
if (strcasecmp(string, pattern) == 0) {
return (1);
}
return (0);
}
int match_hostname(MATCH_LIST *list, const char *name, const char *pattern)
{
const char *myname = "match_hostname";
const char *pd;
const char *entry;
const char *next;
int match;
DICT *dict;
if (msg_verbose)
msg_info("%s: %s ~? %s", myname, name, pattern);
if (MATCH_DICTIONARY(pattern)) {
if ((dict = dict_handle(pattern)) == 0)
msg_panic("%s: unknown dictionary: %s", myname, pattern);
match = 0;
for (entry = name; *entry != 0; entry = next) {
if (entry == name || (dict->flags & DICT_FLAG_FIXED)) {
match = (dict_get(dict, entry) != 0);
if (msg_verbose > 1)
msg_info("%s: lookup %s:%s %s: %s",
myname, dict->type, dict->name, entry,
match ? "found" : "notfound");
if (match != 0)
break;
if ((list->error = dict->error) != 0)
return (match_error(list, "%s:%s: table lookup problem",
dict->type, dict->name));
}
if ((next = strchr(entry + 1, '.')) == 0)
break;
if (list->flags & MATCH_FLAG_PARENT)
next += 1;
}
return (match);
}
if (strcasecmp(name, pattern) == 0) {
return (1);
}
else {
if (list->flags & MATCH_FLAG_PARENT) {
pd = name + strlen(name) - strlen(pattern);
if (pd > name && pd[-1] == '.' && strcasecmp(pd, pattern) == 0)
return (1);
} else if (pattern[0] == '.') {
pd = name + strlen(name) - strlen(pattern);
if (pd > name && strcasecmp(pd, pattern) == 0)
return (1);
}
}
return (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);
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);
}
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);
}
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);
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);
}