0
|
1 /* Distributed Checksum Clearinghouse |
|
2 * |
|
3 * whitelist lister |
|
4 * |
|
5 * Copyright (c) 2008 by Rhyolite Software, LLC |
|
6 * |
|
7 * This agreement is not applicable to any entity which sells anti-spam |
|
8 * solutions to others or provides an anti-spam solution as part of a |
|
9 * security solution sold to other entities, or to a private network |
|
10 * which employs the DCC or uses data provided by operation of the DCC |
|
11 * but does not provide corresponding data to other users. |
|
12 * |
|
13 * Permission to use, copy, modify, and distribute this software without |
|
14 * changes for any purpose with or without fee is hereby granted, provided |
|
15 * that the above copyright notice and this permission notice appear in all |
|
16 * copies and any distributed versions or copies are either unchanged |
|
17 * or not called anything similar to "DCC" or "Distributed Checksum |
|
18 * Clearinghouse". |
|
19 * |
|
20 * Parties not eligible to receive a license under this agreement can |
|
21 * obtain a commercial license to use DCC by contacting Rhyolite Software |
|
22 * at sales@rhyolite.com. |
|
23 * |
|
24 * A commercial license would be for Distributed Checksum and Reputation |
|
25 * Clearinghouse software. That software includes additional features. This |
|
26 * free license for Distributed ChecksumClearinghouse Software does not in any |
|
27 * way grant permision to use Distributed Checksum and Reputation Clearinghouse |
|
28 * software |
|
29 * |
|
30 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL |
|
31 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES |
|
32 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC |
|
33 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES |
|
34 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
35 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
|
36 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
37 * SOFTWARE. |
|
38 * |
|
39 * Rhyolite Software DCC 1.3.103-1.67 $Revision$ |
|
40 */ |
|
41 |
|
42 #include "dcc_defs.h" |
|
43 #include "dcc_ck.h" |
|
44 #include <arpa/inet.h> |
|
45 |
|
46 static DCC_EMSG dcc_emsg; |
|
47 static const char *homedir; |
|
48 |
|
49 static u_char quiet; |
|
50 |
|
51 static const char *ts2buf(time_t); |
|
52 |
|
53 |
|
54 static void NRATTRIB |
|
55 usage(void) |
|
56 { |
|
57 dcc_logbad(EX_USAGE, "usage: [-VPQ] [-h homedir] [-t env_to] file"); |
|
58 } |
|
59 |
|
60 |
|
61 |
|
62 int |
|
63 main(int argc, char **argv) |
|
64 { |
|
65 const char *to = 0; |
|
66 u_char print_version = 0; |
|
67 u_char first; |
|
68 DCC_WHITE_INX inx, inx2; |
|
69 const char *nm; |
|
70 DCC_SUM sum; |
|
71 struct stat ht_sb, ascii_sb, inc_sb; |
|
72 char tgts_buf[20]; |
|
73 int col; |
|
74 u_char heading; |
|
75 DCC_TGTS tgts; |
|
76 DCC_WHITE_LISTING listing; |
|
77 DCC_CK_TYPES type; |
|
78 int i; |
|
79 |
|
80 dcc_syslog_init(0, argv[0], 0); |
|
81 dcc_clnt_debug = 99; |
|
82 |
|
83 dup2(1, 2); /* put error messages in context */ |
|
84 |
|
85 dcc_wf_init(&cmn_wf, DCC_WF_WLIST | DCC_WF_EITHER); |
|
86 |
|
87 while ((i = getopt(argc, argv, "VPQqh:t:")) != EOF) { |
|
88 switch (i) { |
|
89 case 'V': |
|
90 fprintf(stderr, DCC_VERSION"\n"); |
|
91 print_version = 1; |
|
92 break; |
|
93 |
|
94 case 'P': /* parse or rebuild hash table */ |
|
95 cmn_wf.wf_flags &= ~DCC_WF_WLIST_RO; |
|
96 cmn_wf.wf_flags |= DCC_WF_WLIST_RW; |
|
97 break; |
|
98 |
|
99 case 'Q': /* query; don't rebuild hash table */ |
|
100 cmn_wf.wf_flags &= ~DCC_WF_WLIST_RW; |
|
101 cmn_wf.wf_flags |= DCC_WF_WLIST_RO; |
|
102 break; |
|
103 |
|
104 case 'q': |
|
105 quiet = 1; |
|
106 break; |
|
107 |
|
108 case 'h': |
|
109 homedir = optarg; |
|
110 break; |
|
111 |
|
112 case 't': |
|
113 to = optarg; |
|
114 break; |
|
115 |
|
116 default: |
|
117 usage(); |
|
118 } |
|
119 } |
|
120 argc -= optind; |
|
121 argv += optind; |
|
122 if (argc == 0) { |
|
123 if (print_version) |
|
124 exit(EX_OK); |
|
125 usage(); |
|
126 } |
|
127 |
|
128 dcc_cdhome(0, homedir, 1); |
|
129 |
|
130 first = 1; |
|
131 while ((nm = *argv++) != 0) { |
|
132 if (first) { |
|
133 first = 0; |
|
134 } else { |
|
135 printf("\n\n--------------------------------\n"); |
|
136 } |
|
137 if (cmn_wf.wf_flags & DCC_WF_WLIST_RO) |
|
138 cmn_wf.wf_flags |= DCC_WF_RO; |
|
139 else |
|
140 cmn_wf.wf_flags &= ~DCC_WF_RO; |
|
141 if (!dcc_new_white_nm(dcc_emsg, &cmn_wf, nm)) { |
|
142 dcc_error_msg("%s", dcc_emsg); |
|
143 exit(EX_DATAERR); |
|
144 } |
|
145 printf("%s\n", cmn_wf.ascii_nm); |
|
146 |
|
147 switch (dcc_rdy_white(dcc_emsg, &cmn_wf, &cmn_tmp_wf)) { |
|
148 case DCC_WHITE_OK: |
|
149 break; |
|
150 case DCC_WHITE_NOFILE: |
|
151 dcc_error_msg("does %s exist?", nm); |
|
152 exit(EX_DATAERR); |
|
153 case DCC_WHITE_CONTINUE: |
|
154 dcc_error_msg("%s", dcc_emsg); |
|
155 break; |
|
156 case DCC_WHITE_SILENT: |
|
157 case DCC_WHITE_COMPLAIN: |
|
158 dcc_error_msg("%s", dcc_emsg); |
|
159 exit(EX_DATAERR); |
|
160 break; |
|
161 } |
|
162 printf("%s\n", cmn_wf.wtbl->magic); |
|
163 |
|
164 if (to) { |
|
165 dcc_str2ck(sum, 0, 0, to); |
|
166 printf("%s\n%8s %s\t", |
|
167 to, |
|
168 dcc_type2str_err(DCC_CK_ENV_TO, 0, 0, 0), |
|
169 dcc_ck2str_err(DCC_CK_ENV_TO, sum, 0)); |
|
170 if (DCC_WHITE_OK != dcc_white_sum(dcc_emsg, &cmn_wf, |
|
171 DCC_CK_ENV_TO, sum, |
|
172 &tgts, &listing)) { |
|
173 dcc_error_msg("%s", dcc_emsg); |
|
174 } |
|
175 if (listing == DCC_WHITE_UNLISTED) { |
|
176 printf("unlisted\n"); |
|
177 } else { |
|
178 printf("%s\n", |
|
179 dcc_tgts2str(tgts_buf, sizeof(tgts_buf), |
|
180 tgts, 0)); |
|
181 } |
|
182 continue; |
|
183 } |
|
184 |
|
185 printf(" %s whitelist %d entries\n", |
|
186 (cmn_wf.wtbl_flags & DCC_WHITE_FG_PER_USER) |
|
187 ? "per-user" : "global", |
|
188 cmn_wf.wtbl->hdr.entries); |
|
189 |
|
190 if (0 > fstat(cmn_wf.ht_fd, &ht_sb)) { |
|
191 dcc_error_msg("stat(%s): %s", |
|
192 cmn_wf.ht_nm, ERROR_STR()); |
|
193 exit(EX_DATAERR); |
|
194 } |
|
195 |
|
196 if (0 > stat(cmn_wf.ascii_nm, &ascii_sb)) { |
|
197 dcc_error_msg("stat(%s): %s", |
|
198 cmn_wf.ascii_nm, ERROR_STR()); |
|
199 } else if (ht_sb.st_mtime < ascii_sb.st_mtime) { |
|
200 printf(" %s is older than %s\n", |
|
201 cmn_wf.ht_nm, cmn_wf.ascii_nm); |
|
202 } |
|
203 |
|
204 if (cmn_wf.wtbl->hdr.ascii_mtime == 0) { |
|
205 printf(" %s broken\n", cmn_wf.ht_nm); |
|
206 } else if (cmn_wf.wtbl->hdr.ascii_mtime != ascii_sb.st_mtime) { |
|
207 printf(" %s has timestamp %s\n" |
|
208 "\tfor %s which has mtime %s\n", |
|
209 cmn_wf.ht_nm, |
|
210 ts2buf(cmn_wf.wtbl->hdr.ascii_mtime), |
|
211 cmn_wf.ascii_nm, |
|
212 ts2buf(ascii_sb.st_mtime)); |
|
213 } |
|
214 |
|
215 if (cmn_wf.wtbl->hdr.broken != 0) |
|
216 printf(" %s broken until %s\n", |
|
217 cmn_wf.ht_nm, |
|
218 ts2buf(cmn_wf.wtbl->hdr.broken)); |
|
219 if (cmn_wf.wtbl->hdr.reparse != 0) |
|
220 printf(" re-parse %s for errors after %s\n", |
|
221 cmn_wf.ascii_nm, |
|
222 ts2buf(cmn_wf.wtbl->hdr.reparse)); |
|
223 |
|
224 if (cmn_wf.wtbl->hdr.flags & DCC_WHITE_FG_HOSTNAMES) { |
|
225 printf(" resolve hostnames after %s\n", |
|
226 ts2buf(ht_sb.st_mtime + DCC_WHITECLNT_RESOLVE)); |
|
227 } else if (!(cmn_wf.wtbl->hdr.flags & DCC_WHITE_FG_PER_USER)) { |
|
228 printf(" contains no hostnames\n"); |
|
229 } |
|
230 |
|
231 for (i = 0; i < DIM(cmn_wf.wtbl->hdr.white_incs); ++i) { |
|
232 if (cmn_wf.wtbl->hdr.white_incs[i].nm[0] == '\0') |
|
233 break; |
|
234 if (!i) |
|
235 printf(" includes\n"); |
|
236 printf(" %s\n", |
|
237 fnm2abs_err(0, |
|
238 cmn_wf.wtbl->hdr.white_incs[i].nm)); |
|
239 if (0 > stat(cmn_wf.wtbl->hdr.white_incs[i].nm, |
|
240 &inc_sb)) { |
|
241 dcc_error_msg("stat(%s): %s", |
|
242 cmn_wf.ascii_nm, ERROR_STR()); |
|
243 } else if (ht_sb.st_mtime < inc_sb.st_mtime) { |
|
244 printf(" %s is older than %s" |
|
245 " and needs rebuilding\n", |
|
246 cmn_wf.ht_nm, |
|
247 path2fnm(cmn_wf.wtbl->hdr.white_incs[i |
|
248 ].nm)); |
|
249 } |
|
250 } |
|
251 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_DCC_ON) |
|
252 printf(" option DCC-on\n"); |
|
253 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_DCC_OFF) |
|
254 printf(" option DCC-off\n"); |
|
255 |
|
256 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_REP_ON) |
|
257 printf(" option dcc-rep-on\n"); |
|
258 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_REP_OFF) |
|
259 printf(" option dcc-rep-off\n"); |
|
260 |
|
261 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_GREY_ON) |
|
262 printf(" option greylist-on\n"); |
|
263 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_GREY_OFF) |
|
264 printf(" option greylist-off\n"); |
|
265 |
|
266 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_LOG_ALL) |
|
267 printf(" option log-all\n"); |
|
268 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_LOG_NORMAL) |
|
269 printf(" option log-normal\n"); |
|
270 |
|
271 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_LOG_D) |
|
272 printf(" option log-subdirectory-day\n"); |
|
273 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_LOG_H) |
|
274 printf(" option log-subdirectory-hour\n"); |
|
275 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_LOG_M) |
|
276 printf(" option log-subdirectory-minute\n"); |
|
277 |
|
278 |
|
279 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_GREY_LOG_ON) |
|
280 printf(" option greylist-log-on\n"); |
|
281 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_GREY_LOG_OFF) |
|
282 printf(" option greylist-log-off\n"); |
|
283 |
|
284 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_MTA_FIRST) |
|
285 printf(" option MTA-first\n"); |
|
286 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_MTA_LAST) |
|
287 printf(" option MTA-last\n"); |
|
288 |
|
289 for (i = 0; i < MAX_DNSBL_GROUPS; ++i) { |
|
290 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_DNSBL_ON(i)) |
|
291 printf(" option DNSBL%d-on\n", i+1); |
|
292 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_DNSBL_OFF(i)) |
|
293 printf(" option DNSBL%d-off\n", i+1); |
|
294 } |
|
295 |
|
296 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_DISCARD_OK) |
|
297 printf(" option forced-discard-ok\n"); |
|
298 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_NO_DISCARD) |
|
299 printf(" option no-forced-discard\n"); |
|
300 |
|
301 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_TRAP_ACC) |
|
302 printf(" option spam-trap-accept\n"); |
|
303 if (cmn_wf.wtbl_flags & DCC_WHITE_FG_TRAP_REJ) |
|
304 printf(" option spam-trap_rej\n"); |
|
305 |
|
306 for (type = DCC_CK_TYPE_FIRST; |
|
307 type <= DCC_CK_TYPE_LAST; |
|
308 ++type) { |
|
309 tgts = cmn_wf.wtbl->hdr.tholds_rej[type]; |
|
310 if (tgts == DCC_THOLD_UNSET) |
|
311 continue; |
|
312 printf(" option threshold %s,%s\n", |
|
313 dcc_type2str_err(type, 0, 0, 0), |
|
314 dcc_thold2str(tgts_buf, sizeof(tgts_buf), |
|
315 type, tgts)); |
|
316 } |
|
317 |
|
318 printf("\n file checksum %s\n", |
|
319 dcc_ck2str_err(0, cmn_wf.wtbl->hdr.ck_sum, 0)); |
|
320 |
|
321 if (quiet) |
|
322 continue; |
|
323 |
|
324 heading = 0; |
|
325 for (i = 0; i < cmn_wf.wtbl->hdr.cidr.len; ++i) { |
|
326 struct in_addr addr4; |
|
327 char cidr_buf[INET6_ADDRSTRLEN]; |
|
328 |
|
329 DCC_WHITE_CIDR_ENTRY *e=&cmn_wf.wtbl->hdr.cidr.e[i]; |
|
330 if (!heading) { |
|
331 heading = 1; |
|
332 fputs("\n CIDR blocks\n", stdout); |
|
333 } |
|
334 printf("%6s %s/%d\n", |
|
335 dcc_tgts2str(tgts_buf, sizeof(tgts_buf), |
|
336 e->tgts,0), |
|
337 dcc_ipv6tostr2(cidr_buf, sizeof(cidr_buf), |
|
338 &e->addr), |
|
339 dcc_ipv6toipv4(&addr4, &e->addr) |
|
340 ? e->bits-96 : e->bits); |
|
341 } |
|
342 if (heading) |
|
343 putchar('\n'); |
|
344 |
|
345 /* first the hash table */ |
|
346 fputs("\n hash table\n", stdout); |
|
347 col = 0; |
|
348 for (inx = 0; inx < DIM(cmn_wf.wtbl->bins); ++inx) { |
|
349 if (!cmn_wf.wtbl->bins[inx] |
|
350 && col == 0 |
|
351 && inx != 0) { |
|
352 inx2 = inx; |
|
353 while (inx2 < DIM(cmn_wf.wtbl->bins) |
|
354 && !cmn_wf.wtbl->bins[inx2]) |
|
355 ++inx2; |
|
356 i = inx2 - inx; |
|
357 i -= i % 4; |
|
358 if (i != 0) { |
|
359 printf(" ...\n"); |
|
360 inx += i; |
|
361 } |
|
362 } |
|
363 printf("%4d:", inx); |
|
364 if (cmn_wf.wtbl->bins[inx]) { |
|
365 printf("%-4d", cmn_wf.wtbl->bins[inx]); |
|
366 } else { |
|
367 printf(" "); |
|
368 } |
|
369 col = (col + 1) % 4; |
|
370 putchar(col == 0 ? '\n' : '\t'); |
|
371 } |
|
372 |
|
373 /* then the entries */ |
|
374 printf("\n\n%4s->%-4s %12s %6s\n", |
|
375 "slot", "next", "type", "count"); |
|
376 for (inx = 0; inx < cmn_wf.wtbl_entries; ++inx) { |
|
377 DCC_WHITE_ENTRY *e = &cmn_wf.wtbl->tbl[inx]; |
|
378 if (e->type == DCC_CK_INVALID) |
|
379 continue; |
|
380 printf("%4d->%-4d %12s %6s %s\n", |
|
381 inx, e->fwd, |
|
382 dcc_type2str_err(e->type, 0, 0, 0), |
|
383 dcc_tgts2str(tgts_buf, sizeof(tgts_buf), |
|
384 e->tgts, 0), |
|
385 dcc_ck2str_err(e->type, e->sum, 0)); |
|
386 } |
|
387 } |
|
388 exit(EX_OK); |
|
389 } |
|
390 |
|
391 |
|
392 |
|
393 static const char * |
|
394 ts2buf(time_t ts) |
|
395 { |
|
396 static struct { |
|
397 char buf[26]; |
|
398 } times[4]; |
|
399 static int nbuf; |
|
400 |
|
401 nbuf = (nbuf+1) % DIM(times); |
|
402 return dcc_time2str(times[nbuf].buf, sizeof(times[nbuf].buf), |
|
403 "%b %d %X %Z", |
|
404 ts); |
|
405 } |