0
|
1 /* Distributed Checksum Clearinghouse |
|
2 * |
|
3 * parse a named checksum |
|
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_ck.h" |
|
43 #include "dcc_xhdr.h" |
|
44 #ifndef DCC_WIN32 |
|
45 #include <arpa/inet.h> |
|
46 #endif |
|
47 |
|
48 #define MAX_SERVER_CIDR_BITS 16 /* fix dcc.8 if this changes */ |
|
49 |
|
50 |
|
51 static int /* -1=fatal 0=problem */ |
|
52 dcc_host2ck(DCC_EMSG emsg, DCC_WF *wf, |
|
53 const char *ck, /* this string of an IP address */ |
|
54 DCC_TGTS tgts, /* # of targets */ |
|
55 DCC_PARSED_CK_FNC fnc, /* do something with each checksum */ |
|
56 DCC_PARSED_CK_CIDR_FNC cidr_fnc) |
|
57 { |
|
58 int error; |
|
59 DCC_FNM_LNO_BUF fnm_buf; |
|
60 struct in6_addr addr6, mask6, *addr6p; |
|
61 DCC_SUM sum; |
|
62 DCC_SOCKU *sup; |
|
63 int i, j, bits; |
|
64 |
|
65 /* recognize xxx.xxx.xxx.xxx/y for IP address blocks |
|
66 * as well as simple IP addresses */ |
|
67 bits = dcc_str2cidr(emsg, &addr6, &mask6, 0, ck, |
|
68 wf_fnm(wf, wf->fno), wf->lno); |
|
69 if (bits < 0) |
|
70 return 0; |
|
71 |
|
72 if (bits > 0) { |
|
73 /* use client CIDR blocks if possible */ |
|
74 if (cidr_fnc) |
|
75 return cidr_fnc(emsg, wf, bits, &addr6, &mask6, tgts); |
|
76 |
|
77 /* This is for a server whitelist, because client whitelists |
|
78 * come here with non-null cidr_fnc |
|
79 * Allow only class-B sized blocks, because server whitelist |
|
80 * entries for a CIDR block consist of one checksum per IP |
|
81 * address in the CIDR block. A line in a whitelist file |
|
82 * specifying a class-B block requires the addition of 65,536 |
|
83 * checksums to the server database. Instead, use whiteclnt |
|
84 * entries. */ |
|
85 if (128-bits > MAX_SERVER_CIDR_BITS) { |
|
86 dcc_pemsg(EX_NOHOST, emsg, |
|
87 "CIDR block length in %s too large%s", |
|
88 ck, wf_fnm_lno(&fnm_buf, wf)); |
|
89 return 0; |
|
90 } |
|
91 |
|
92 for (i = 1 << (128-bits); i > 0; --i) { |
|
93 dcc_ck_ipv6(sum, &addr6); |
|
94 j = fnc(emsg, wf, DCC_CK_IP, sum, tgts); |
|
95 if (j <= 0) |
|
96 return j; |
|
97 addr6.s6_addr32[3] = ntohl(addr6.s6_addr32[3]); |
|
98 ++addr6.s6_addr32[3]; |
|
99 addr6.s6_addr32[3] = htonl(addr6.s6_addr32[3]); |
|
100 } |
|
101 return 1; |
|
102 } |
|
103 |
|
104 /* we appear to have a host name, |
|
105 * which is not allowed in a per-user whitelist */ |
|
106 if (wf->wf_flags & DCC_WF_PER_USER) { |
|
107 dcc_pemsg(EX_NOHOST, emsg, |
|
108 "hostname checksum illegal in per-user whitelist%s", |
|
109 wf_fnm_lno(&fnm_buf, wf)); |
|
110 return 0; |
|
111 } |
|
112 |
|
113 if (wf->wtbl) /* need future host name resolutions */ |
|
114 wf->wtbl->hdr.flags |= DCC_WHITE_FG_HOSTNAMES; |
|
115 |
|
116 memset(&addr6, 0, sizeof(addr6)); |
|
117 dcc_host_lock(); |
|
118 /* don't use SOCKS host name resolution because the host names that |
|
119 * most need whitelisting are inside the SOCKS firewall and may not |
|
120 * be known to outside DNS servers. */ |
|
121 if (!dcc_get_host(ck, 2, &error)) { |
|
122 dcc_pemsg(EX_NOHOST, emsg, |
|
123 "hostname \"%s\": %s%s", |
|
124 ck, DCC_HSTRERROR(error), |
|
125 wf_fnm_lno(&fnm_buf, wf)); |
|
126 dcc_host_unlock(); |
|
127 return 0; |
|
128 } |
|
129 |
|
130 for (sup = dcc_hostaddrs; sup < dcc_hostaddrs_end; ++sup) { |
|
131 if (sup->sa.sa_family == AF_INET6) { |
|
132 addr6p = &sup->ipv6.sin6_addr; |
|
133 } else { |
|
134 dcc_ipv4toipv6(&addr6, sup->ipv4.sin_addr); |
|
135 addr6p = &addr6; |
|
136 } |
|
137 if (cidr_fnc) { |
|
138 bits = 128; |
|
139 dcc_bits2mask(&mask6, bits); |
|
140 j = cidr_fnc(emsg, wf, bits, addr6p, &mask6, tgts); |
|
141 } else { |
|
142 dcc_ck_ipv6(sum, addr6p); |
|
143 j = fnc(emsg, wf, DCC_CK_IP, sum, tgts); |
|
144 } |
|
145 if (j <= 0) { |
|
146 dcc_host_unlock(); |
|
147 return j; |
|
148 } |
|
149 } |
|
150 dcc_host_unlock(); |
|
151 return 1; |
|
152 } |
|
153 |
|
154 |
|
155 |
|
156 /* generate checksum value from the name of the checksum and a string */ |
|
157 int /* 1=ok 0=problem -1=fatal */ |
|
158 dcc_parse_ck(DCC_EMSG emsg, /* failure message here */ |
|
159 DCC_WF *wf, |
|
160 const char *type_nm, |
|
161 DCC_CK_TYPES type, |
|
162 const char *str, /* ASCII string to generate checksum */ |
|
163 DCC_TGTS tgts, /* # of targets */ |
|
164 DCC_PARSED_CK_FNC add_fnc, /* do something with the checksum */ |
|
165 DCC_PARSED_CK_CIDR_FNC cidr_fnc) |
|
166 { |
|
167 DCC_FNM_LNO_BUF fnm_buf; |
|
168 char *phdr, c, hdr_buf[80]; |
|
169 DCC_SUM sum; |
|
170 const char *pstr; |
|
171 |
|
172 /* compute the checksum */ |
|
173 switch (type) { |
|
174 case DCC_CK_IP: |
|
175 return dcc_host2ck(emsg, wf, str, tgts, add_fnc, cidr_fnc); |
|
176 |
|
177 case DCC_CK_ENV_FROM: |
|
178 case DCC_CK_FROM: |
|
179 case DCC_CK_MESSAGE_ID: |
|
180 case DCC_CK_RECEIVED: |
|
181 case DCC_CK_ENV_TO: |
|
182 dcc_str2ck(sum, 0, 0, str); |
|
183 return add_fnc(emsg, wf, type, sum, tgts); |
|
184 |
|
185 case DCC_CK_SUB: |
|
186 str += strspn(str, DCC_WHITESPACE); |
|
187 pstr = str; |
|
188 phdr = hdr_buf; |
|
189 for (;;) { |
|
190 c = *pstr++; |
|
191 if (c == '\0' || c == ':' |
|
192 || DCC_IS_WHITE(c)) |
|
193 break; |
|
194 c = DCC_TO_LOWER(c); |
|
195 *phdr++ = c; |
|
196 if (phdr >= &hdr_buf[sizeof(hdr_buf)]) { |
|
197 dcc_pemsg(EX_DATAERR, emsg, |
|
198 " imposible substitute header name" |
|
199 " in \"%s\"%s", |
|
200 str, wf_fnm_lno(&fnm_buf, wf)); |
|
201 return 0; |
|
202 } |
|
203 } |
|
204 pstr += strspn(pstr, DCC_WHITESPACE); |
|
205 if (*pstr == '\0' || phdr == hdr_buf) { |
|
206 dcc_pemsg(EX_DATAERR, emsg, |
|
207 " substitute header name absent in \"%s\"%s", |
|
208 str, wf_fnm_lno(&fnm_buf, wf)); |
|
209 return 0; |
|
210 } |
|
211 dcc_str2ck(sum, hdr_buf, phdr-hdr_buf, pstr); |
|
212 return add_fnc(emsg, wf, type, sum, tgts); |
|
213 |
|
214 case DCC_CK_INVALID: |
|
215 case DCC_CK_BODY: |
|
216 case DCC_CK_FUZ1: |
|
217 case DCC_CK_FUZ2: |
|
218 case DCC_CK_G_MSG_R_TOTAL: |
|
219 case DCC_CK_G_TRIPLE_R_BULK: |
|
220 case DCC_CK_SRVR_ID: |
|
221 break; |
|
222 } |
|
223 |
|
224 dcc_pemsg(EX_DATAERR, emsg, "unrecognized checksum type \"%s\"%s", |
|
225 type_nm, wf_fnm_lno(&fnm_buf, wf)); |
|
226 return 0; |
|
227 } |
|
228 |
|
229 |
|
230 |
|
231 /* generate checksum value from the name of the checksum and hex values */ |
|
232 int /* 1=ok 0=syntax -1=fatal */ |
|
233 dcc_parse_hex_ck(DCC_EMSG emsg, /* failure message here */ |
|
234 DCC_WF *wf, |
|
235 const char *type_nm, |
|
236 DCC_CK_TYPES type, |
|
237 const char *str, /* ASCII string to generate checksum */ |
|
238 DCC_TGTS tgts, /* # of targets */ |
|
239 DCC_PARSED_CK_FNC add_fnc) /* do something with the checksum */ |
|
240 { |
|
241 union { |
|
242 u_int32_t n[4]; |
|
243 DCC_SUM sum; |
|
244 } u; |
|
245 DCC_FNM_LNO_BUF fnm_buf; |
|
246 int id; |
|
247 |
|
248 if (type == DCC_CK_INVALID) { |
|
249 dcc_pemsg(EX_DATAERR, emsg, |
|
250 "unrecognized checksum type \"%s\"%s", |
|
251 type_nm, wf_fnm_lno(&fnm_buf, wf)); |
|
252 return 0; |
|
253 } |
|
254 |
|
255 if (4 == sscanf(str, DCC_CKSUM_HEX_PAT"\n", |
|
256 &u.n[0], &u.n[1], &u.n[2], &u.n[3]) |
|
257 || (type == DCC_CK_SUB |
|
258 && 4 == sscanf(str, "%*s "DCC_CKSUM_HEX_PAT"\n", |
|
259 &u.n[0], &u.n[1], &u.n[2], &u.n[3]))) { |
|
260 /* recognize simple hex checksums */ |
|
261 u.n[0] = htonl(u.n[0]); |
|
262 u.n[1] = htonl(u.n[1]); |
|
263 u.n[2] = htonl(u.n[2]); |
|
264 u.n[3] = htonl(u.n[3]); |
|
265 |
|
266 } else if (1 == sscanf(str, DCC_XHDR_ID_SIMPLE" at %d", &id) |
|
267 || 1 == sscanf(str, DCC_XHDR_ID_REP_OK" at %d", &id) |
|
268 || 1 == sscanf(str, DCC_XHDR_ID_IGNORE" at %d", &id) |
|
269 || 1 == sscanf(str, DCC_XHDR_ID_ROGUE" at %d", &id)) { |
|
270 /* parse server-ID declarations */ |
|
271 memset(&u, 0, sizeof(u)); |
|
272 u.sum[0] = DCC_CK_SRVR_ID; |
|
273 u.sum[1] = id >> 8; |
|
274 u.sum[2] = id; |
|
275 |
|
276 } else { |
|
277 dcc_pemsg(EX_DATAERR, emsg, |
|
278 "unrecognized checksum value \"%s\"%s", |
|
279 str, wf_fnm_lno(&fnm_buf, wf)); |
|
280 return 0; |
|
281 } |
|
282 |
|
283 /* apply the function to the checksum */ |
|
284 return add_fnc(emsg, wf, type, u.sum, tgts); |
|
285 } |