7 /* Dictionary interface for CIDR data
9 /* #include <dict_cidr.h>
11 /* DICT *dict_cidr_open(name, open_flags, dict_flags)
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.
20 /* dict(3) generic dictionary manager
23 /* kadlec@blackhole.kfki.hu
24 /* KFKI Research Institute for Particle and Nuclear Physics
26 /* 1525 Budapest, Hungary
29 /* IBM T.J. Watson Research
31 /* Yorktown Heights, NY 10598, USA
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
45 /* Utility library. */
51 #include <stringops.h>
52 #include <readlline.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 */
69 DICT dict
; /* generic members */
70 DICT_CIDR_ENTRY
*head
; /* first entry */
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
;
81 msg_info("dict_cidr_lookup: %s: %s", dict
->name
, key
);
85 if ((entry
= (DICT_CIDR_ENTRY
*)
86 cidr_match_execute(&(dict_cidr
->head
->cidr_info
), key
)) != 0)
87 return (entry
->value
);
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
);
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
;
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.
123 while (*p
&& !ISSPACE(*p
)) /* Skip over key */
125 if (*p
) /* Terminate key */
127 while (*p
&& ISSPACE(*p
)) /* Skip whitespace */
130 trimblanks(value
, 0)[0] = 0; /* Trim trailing blanks */
132 vstring_sprintf(why
, "no address pattern");
136 vstring_sprintf(why
, "no lookup result");
141 * Parse the pattern, destroying it in the process.
143 if (cidr_match_parse(&cidr_info
, pattern
, why
) != 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
);
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
);
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
;
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;
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
,
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
;
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
);
199 msg_warn("cidr map %s, line %d: %s: skipping this rule",
200 mapname
, lineno
, vstring_str(why
));
204 dict_cidr
->head
= rule
;
206 last_rule
->cidr_info
.next
= &(rule
->cidr_info
);
213 if (vstream_fclose(map_fp
))
214 msg_fatal("cidr map %s: read error: %m", mapname
);
215 vstring_free(line_buffer
);
218 return (DICT_DEBUG (&dict_cidr
->dict
));