#include <sys_defs.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <mymalloc.h>
#include <msg.h>
#include <vstream.h>
#include <vstring.h>
#include <stringops.h>
#include <readlline.h>
#include <dict.h>
#include <myaddrinfo.h>
#include <cidr_match.h>
#include <dict_cidr.h>
typedef struct DICT_CIDR_ENTRY {
CIDR_MATCH cidr_info;
char *value;
} DICT_CIDR_ENTRY;
typedef struct {
DICT dict;
DICT_CIDR_ENTRY *head;
} DICT_CIDR;
static const char *dict_cidr_lookup(DICT *dict, const char *key)
{
DICT_CIDR *dict_cidr = (DICT_CIDR *) dict;
DICT_CIDR_ENTRY *entry;
if (msg_verbose)
msg_info("dict_cidr_lookup: %s: %s", dict->name, key);
dict_errno = 0;
if ((entry = (DICT_CIDR_ENTRY *)
cidr_match_execute(&(dict_cidr->head->cidr_info), key)) != 0)
return (entry->value);
return (0);
}
static void dict_cidr_close(DICT *dict)
{
DICT_CIDR *dict_cidr = (DICT_CIDR *) dict;
DICT_CIDR_ENTRY *entry;
DICT_CIDR_ENTRY *next;
for (entry = dict_cidr->head; entry; entry = next) {
next = (DICT_CIDR_ENTRY *) entry->cidr_info.next;
myfree(entry->value);
myfree((char *) entry);
}
dict_free(dict);
}
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;
pattern = p;
while (*p && !ISSPACE(*p))
p++;
if (*p)
*p++ = 0;
while (*p && ISSPACE(*p))
p++;
value = p;
trimblanks(value, 0)[0] = 0;
if (*pattern == 0) {
vstring_sprintf(why, "no address pattern");
return (0);
}
if (*value == 0) {
vstring_sprintf(why, "no lookup result");
return (0);
}
if (cidr_match_parse(&cidr_info, pattern, why) != 0)
return (0);
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);
}
DICT *dict_cidr_open(const char *mapname, int open_flags, int dict_flags)
{
DICT_CIDR *dict_cidr;
VSTREAM *map_fp;
VSTRING *line_buffer = vstring_alloc(100);
VSTRING *why = vstring_alloc(100);
DICT_CIDR_ENTRY *rule;
DICT_CIDR_ENTRY *last_rule = 0;
int lineno = 0;
if (open_flags != O_RDONLY)
msg_fatal("%s:%s map requires O_RDONLY access mode",
DICT_TYPE_CIDR, mapname);
dict_cidr = (DICT_CIDR *) dict_alloc(DICT_TYPE_CIDR, mapname,
sizeof(*dict_cidr));
dict_cidr->dict.lookup = dict_cidr_lookup;
dict_cidr->dict.close = dict_cidr_close;
dict_cidr->dict.flags = dict_flags | DICT_FLAG_PATTERN;
dict_cidr->head = 0;
if ((map_fp = vstream_fopen(mapname, O_RDONLY, 0)) == 0)
msg_fatal("open %s: %m", mapname);
while (readlline(line_buffer, map_fp, &lineno)) {
rule = dict_cidr_parse_rule(vstring_str(line_buffer), why);
if (rule == 0) {
msg_warn("cidr map %s, line %d: %s: skipping this rule",
mapname, lineno, vstring_str(why));
continue;
}
if (last_rule == 0)
dict_cidr->head = rule;
else
last_rule->cidr_info.next = &(rule->cidr_info);
last_rule = rule;
}
if (vstream_fclose(map_fp))
msg_fatal("cidr map %s: read error: %m", mapname);
vstring_free(line_buffer);
vstring_free(why);
return (DICT_DEBUG (&dict_cidr->dict));
}