Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / dict_cidr.c
bloba802ea9805dd13191350c9fa1ce184164b7371f6
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* dict_cidr 3
6 /* SUMMARY
7 /* Dictionary interface for CIDR data
8 /* SYNOPSIS
9 /* #include <dict_cidr.h>
11 /* DICT *dict_cidr_open(name, open_flags, dict_flags)
12 /* const char *name;
13 /* int open_flags;
14 /* int dict_flags;
15 /* DESCRIPTION
16 /* dict_cidr_open() opens the named file and stores
17 /* the key/value pairs where the key must be either a
18 /* "naked" IP address or a netblock in CIDR notation.
19 /* SEE ALSO
20 /* dict(3) generic dictionary manager
21 /* AUTHOR(S)
22 /* Jozsef Kadlecsik
23 /* kadlec@blackhole.kfki.hu
24 /* KFKI Research Institute for Particle and Nuclear Physics
25 /* POB. 49
26 /* 1525 Budapest, Hungary
28 /* Wietse Venema
29 /* IBM T.J. Watson Research
30 /* P.O. Box 704
31 /* Yorktown Heights, NY 10598, USA
32 /*--*/
34 /* System library. */
36 #include <sys_defs.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
45 /* Utility library. */
47 #include <mymalloc.h>
48 #include <msg.h>
49 #include <vstream.h>
50 #include <vstring.h>
51 #include <stringops.h>
52 #include <readlline.h>
53 #include <dict.h>
54 #include <myaddrinfo.h>
55 #include <cidr_match.h>
56 #include <dict_cidr.h>
58 /* Application-specific. */
61 * Each rule in a CIDR table is parsed and stored in a linked list.
63 typedef struct DICT_CIDR_ENTRY {
64 CIDR_MATCH cidr_info; /* must be first */
65 char *value; /* lookup result */
66 } DICT_CIDR_ENTRY;
68 typedef struct {
69 DICT dict; /* generic members */
70 DICT_CIDR_ENTRY *head; /* first entry */
71 } DICT_CIDR;
73 /* dict_cidr_lookup - CIDR table lookup */
75 static const char *dict_cidr_lookup(DICT *dict, const char *key)
77 DICT_CIDR *dict_cidr = (DICT_CIDR *) dict;
78 DICT_CIDR_ENTRY *entry;
80 if (msg_verbose)
81 msg_info("dict_cidr_lookup: %s: %s", dict->name, key);
83 dict_errno = 0;
85 if ((entry = (DICT_CIDR_ENTRY *)
86 cidr_match_execute(&(dict_cidr->head->cidr_info), key)) != 0)
87 return (entry->value);
88 return (0);
91 /* dict_cidr_close - close the CIDR table */
93 static void dict_cidr_close(DICT *dict)
95 DICT_CIDR *dict_cidr = (DICT_CIDR *) dict;
96 DICT_CIDR_ENTRY *entry;
97 DICT_CIDR_ENTRY *next;
99 for (entry = dict_cidr->head; entry; entry = next) {
100 next = (DICT_CIDR_ENTRY *) entry->cidr_info.next;
101 myfree(entry->value);
102 myfree((char *) entry);
104 dict_free(dict);
107 /* dict_cidr_parse_rule - parse CIDR table rule into network, mask and value */
109 static DICT_CIDR_ENTRY *dict_cidr_parse_rule(char *p, VSTRING *why)
111 DICT_CIDR_ENTRY *rule;
112 char *pattern;
113 char *value;
114 CIDR_MATCH cidr_info;
115 MAI_HOSTADDR_STR hostaddr;
118 * Split the rule into key and value. We already eliminated leading
119 * whitespace, comments, empty lines or lines with whitespace only. This
120 * means a null key can't happen but we will handle this anyway.
122 pattern = p;
123 while (*p && !ISSPACE(*p)) /* Skip over key */
124 p++;
125 if (*p) /* Terminate key */
126 *p++ = 0;
127 while (*p && ISSPACE(*p)) /* Skip whitespace */
128 p++;
129 value = p;
130 trimblanks(value, 0)[0] = 0; /* Trim trailing blanks */
131 if (*pattern == 0) {
132 vstring_sprintf(why, "no address pattern");
133 return (0);
135 if (*value == 0) {
136 vstring_sprintf(why, "no lookup result");
137 return (0);
141 * Parse the pattern, destroying it in the process.
143 if (cidr_match_parse(&cidr_info, pattern, why) != 0)
144 return (0);
147 * Bundle up the result.
149 rule = (DICT_CIDR_ENTRY *) mymalloc(sizeof(DICT_CIDR_ENTRY));
150 rule->cidr_info = cidr_info;
151 rule->value = mystrdup(value);
153 if (msg_verbose) {
154 if (inet_ntop(cidr_info.addr_family, cidr_info.net_bytes,
155 hostaddr.buf, sizeof(hostaddr.buf)) == 0)
156 msg_fatal("inet_ntop: %m");
157 msg_info("dict_cidr_open: add %s/%d %s",
158 hostaddr.buf, cidr_info.mask_shift, rule->value);
160 return (rule);
163 /* dict_cidr_open - parse CIDR table */
165 DICT *dict_cidr_open(const char *mapname, int open_flags, int dict_flags)
167 DICT_CIDR *dict_cidr;
168 VSTREAM *map_fp;
169 VSTRING *line_buffer = vstring_alloc(100);
170 VSTRING *why = vstring_alloc(100);
171 DICT_CIDR_ENTRY *rule;
172 DICT_CIDR_ENTRY *last_rule = 0;
173 int lineno = 0;
176 * Sanity checks.
178 if (open_flags != O_RDONLY)
179 msg_fatal("%s:%s map requires O_RDONLY access mode",
180 DICT_TYPE_CIDR, mapname);
183 * XXX Eliminate unnecessary queries by setting a flag that says "this
184 * map matches network addresses only".
186 dict_cidr = (DICT_CIDR *) dict_alloc(DICT_TYPE_CIDR, mapname,
187 sizeof(*dict_cidr));
188 dict_cidr->dict.lookup = dict_cidr_lookup;
189 dict_cidr->dict.close = dict_cidr_close;
190 dict_cidr->dict.flags = dict_flags | DICT_FLAG_PATTERN;
191 dict_cidr->head = 0;
193 if ((map_fp = vstream_fopen(mapname, O_RDONLY, 0)) == 0)
194 msg_fatal("open %s: %m", mapname);
196 while (readlline(line_buffer, map_fp, &lineno)) {
197 rule = dict_cidr_parse_rule(vstring_str(line_buffer), why);
198 if (rule == 0) {
199 msg_warn("cidr map %s, line %d: %s: skipping this rule",
200 mapname, lineno, vstring_str(why));
201 continue;
203 if (last_rule == 0)
204 dict_cidr->head = rule;
205 else
206 last_rule->cidr_info.next = &(rule->cidr_info);
207 last_rule = rule;
211 * Clean up.
213 if (vstream_fclose(map_fp))
214 msg_fatal("cidr map %s: read error: %m", mapname);
215 vstring_free(line_buffer);
216 vstring_free(why);
218 return (DICT_DEBUG (&dict_cidr->dict));