Mercurial > dnsbl
annotate src/dccifd.cpp @ 407:29d54e7028f6 stable-6-0-54
document dmarc vs dnsbl dkim/spf; switch to . rather than " " for dkim impossible signer
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 30 Mar 2017 10:26:30 -0700 |
parents | df7dc6b2b153 |
children | 5209e92b4885 |
rev | line source |
---|---|
196 | 1 /* |
2 | |
3 Copyright (c) 2007 Carl Byington - 510 Software Group, released under | |
4 the GPL version 3 or any later version at your choice available at | |
5 http://www.gnu.org/licenses/gpl-3.0.txt | |
6 | |
7 */ | |
8 | |
9 #include "includes.h" | |
10 #include <errno.h> | |
11 #include <fcntl.h> | |
12 #include <poll.h> | |
13 #include <signal.h> | |
14 #include <string> | |
15 #include <sys/types.h> | |
16 #include <sys/wait.h> | |
17 #include <unistd.h> | |
18 | |
19 // needed for socket io | |
20 #include <sys/ioctl.h> | |
21 #include <net/if.h> | |
22 #include <arpa/inet.h> | |
23 #include <netinet/in.h> | |
24 #include <netinet/tcp.h> | |
25 #include <netdb.h> | |
26 #include <sys/socket.h> | |
27 #include <sys/un.h> | |
28 | |
29 | |
30 const int maxlen = 1000; // used for snprintf buffers | |
31 extern int NULL_SOCKET; | |
32 const char *options = "header\n"; | |
33 | |
34 | |
35 //////////////////////////////////////////////// | |
36 // helper to convert syslog control chars | |
37 // | |
38 string escaper(string v); | |
39 string escaper(string v) | |
40 { | |
41 size_t n = v.length(); | |
42 char buf[n+1]; | |
43 strncpy(buf, v.c_str(), n); | |
44 for (size_t i=0; i<n; i++) { | |
45 if (buf[i] == '\r') buf[i] = 'r'; | |
46 if (buf[i] == '\n') buf[i] = 'n'; | |
47 if ((unsigned char)(buf[i]) < ' '){ | |
48 buf[i] = '.'; | |
49 } | |
50 } | |
51 return string(buf, n); | |
52 } | |
53 | |
54 | |
214
82886d4dd71f
Fixes to compile on Fedora 9 and for const correctness.
Carl Byington <carl@five-ten-sg.com>
parents:
203
diff
changeset
|
55 DccInterface::DccInterface(const char *port_, mlfiPriv *priv_, int ip, const char *helo_, const char *from) |
196 | 56 { |
57 err = false; | |
58 first_recipient = true; | |
59 first_header = true; | |
60 priv = priv_; | |
61 ip4 = ip; | |
62 helo = helo_; | |
63 envfrom = from; | |
64 dccifd_port = port_; | |
65 dccifd_socket = NULL_SOCKET; | |
66 } | |
67 | |
68 | |
69 DccInterface::~DccInterface() | |
70 { | |
71 my_disconnect(); | |
72 } | |
73 | |
74 | |
214
82886d4dd71f
Fixes to compile on Fedora 9 and for const correctness.
Carl Byington <carl@five-ten-sg.com>
parents:
203
diff
changeset
|
75 void DccInterface::mlfi_envrcpt(SMFICTX *ctx, const char *envrcpt, bool grey) |
196 | 76 { |
77 if (first_recipient) { | |
78 first_recipient = false; | |
79 char adr[sizeof "255.255.255.255 "]; | |
80 adr[0] = '\0'; | |
81 inet_ntop(AF_INET, (const u_char *)&ip4, adr, sizeof(adr)); | |
82 // Validated sending site's address | |
214
82886d4dd71f
Fixes to compile on Fedora 9 and for const correctness.
Carl Byington <carl@five-ten-sg.com>
parents:
203
diff
changeset
|
83 const char *rdns = getmacro(ctx, "_", ""); |
196 | 84 char buf[maxlen+1]; |
85 if (*rdns == '[') rdns = ""; | |
86 else { | |
87 int n = 0; | |
88 while ((n < maxlen) && rdns[n] && (rdns[n] != ' ')) n++; | |
89 strncpy(buf, rdns, n); | |
90 buf[n] = '\0'; | |
91 rdns = buf; | |
92 } | |
93 output(options); | |
94 output(adr); output("\r"); | |
95 output(rdns); output("\n"); | |
96 output(helo); output("\n"); | |
97 output(envfrom); output("\n"); | |
98 } | |
99 output(envrcpt); | |
100 if (grey) output("\r\n"); | |
101 else output("\rdnsblnogrey\n"); | |
102 } | |
103 | |
104 | |
214
82886d4dd71f
Fixes to compile on Fedora 9 and for const correctness.
Carl Byington <carl@five-ten-sg.com>
parents:
203
diff
changeset
|
105 void DccInterface::mlfi_header(SMFICTX *ctx, const char *headerf, const char *headerv) |
196 | 106 { |
107 if (dccifd_socket == NULL_SOCKET) Connect(); | |
371
df7dc6b2b153
install dnsblnogrey/whiteclnt for dccifd
Carl Byington <carl@five-ten-sg.com>
parents:
227
diff
changeset
|
108 if (err) return; |
196 | 109 if ((dccifd_socket != NULL_SOCKET) && (!dccifd_input.empty())) { |
110 output(dccifd_input); | |
227
3fee608becbc
Fixes to compile on old systems without memrchr or string::clear().
Carl Byington <carl@five-ten-sg.com>
parents:
214
diff
changeset
|
111 dccifd_input = ""; |
196 | 112 } |
113 | |
114 if (first_header) { | |
115 output("\n"); | |
116 first_header = false; | |
117 } | |
118 | |
119 output(headerf); | |
120 output(": "); | |
121 output(headerv); | |
122 output("\r\n"); | |
123 } | |
124 | |
125 | |
126 void DccInterface::mlfi_eoh() | |
127 { | |
128 output("\r\n"); | |
129 } | |
130 | |
131 | |
214
82886d4dd71f
Fixes to compile on Fedora 9 and for const correctness.
Carl Byington <carl@five-ten-sg.com>
parents:
203
diff
changeset
|
132 void DccInterface::mlfi_body(const u_char *bodyp, size_t bodylen) |
196 | 133 { |
214
82886d4dd71f
Fixes to compile on Fedora 9 and for const correctness.
Carl Byington <carl@five-ten-sg.com>
parents:
203
diff
changeset
|
134 output((const char *)bodyp, bodylen); |
196 | 135 } |
136 | |
137 | |
138 void DccInterface::mlfi_eom(bool &grey, int &bulk) | |
139 { | |
140 // AnAnX-DCC-Rhyolite-Metrics: ns.five-ten-sg.com 104; Body=2 Fuz1=2nn | |
141 | |
142 close_output(); // signal EOF to DccInterface | |
143 input(); // read what the dcc has to say about this message | |
144 my_syslog(priv, "dcc returned " + escaper(dccifd_output)); | |
145 grey = false; | |
146 bulk = 0; | |
147 const int n = dccifd_output.length(); | |
148 char buf[n+1]; | |
149 strncpy(buf, dccifd_output.c_str(), n); | |
150 buf[n] = '\0'; | |
151 | |
152 int newlines = 0; | |
153 int j, i = 0; | |
154 while ((i<n) && (newlines < 2)) { | |
155 switch (buf[i++]) { | |
156 case 'G' : | |
157 grey = true; | |
158 break; | |
159 case '\n' : | |
160 newlines++; | |
161 default : ; | |
162 } | |
163 } | |
164 | |
165 // skip up to and including ; | |
166 while ((i<n) && (buf[i++] != ';')); | |
167 | |
168 // convert to lower, = to space, ctrl-chars to space | |
169 for (j=i; j<n; j++) { | |
170 buf[j] = tolower(buf[j]); | |
171 if (buf[j] == '=') buf[j] = ' '; | |
172 if (buf[j] < ' ') buf[j] = ' '; | |
173 } | |
174 | |
175 while (i<n) { | |
176 // skip leading blanks | |
177 while ((i<n) && (buf[i] == ' ')) i++; | |
178 | |
179 // find blank terminator | |
180 for (j=i; (j<n) && (buf[j] != ' '); j++); | |
181 | |
182 // find anything? | |
183 if (j > i) { | |
184 // process this token | |
185 buf[j] = '\0'; | |
186 //my_syslog(priv, string("dccifd token") + (buf+i)); | |
187 if (strcmp(buf+i, "bulk") == 0) bulk = dccbulk; | |
188 else if (strcmp(buf+i, "many") == 0) bulk = dccbulk; | |
189 else if (strcmp(buf+i, "whitelist") == 0) bulk = 0; | |
190 else if (isdigit(buf[i])) { | |
191 int b = atoi(buf+i); | |
192 if (b > bulk) bulk = b; | |
193 } | |
194 // skip this token | |
195 i = j+1; | |
196 } | |
197 } | |
227
3fee608becbc
Fixes to compile on old systems without memrchr or string::clear().
Carl Byington <carl@five-ten-sg.com>
parents:
214
diff
changeset
|
198 //char buff[maxlen]; |
3fee608becbc
Fixes to compile on old systems without memrchr or string::clear().
Carl Byington <carl@five-ten-sg.com>
parents:
214
diff
changeset
|
199 //snprintf(buff, sizeof(buff), "dccifd found grey %s bulk %d", ((grey) ? "yes" : "no"), bulk); |
196 | 200 //my_syslog(priv, buff); |
201 } | |
202 | |
203 | |
204 void DccInterface::my_disconnect() | |
205 { | |
206 if (dccifd_socket != NULL_SOCKET) { | |
207 shutdown(dccifd_socket, SHUT_RDWR); | |
208 close(dccifd_socket); | |
209 dccifd_socket = NULL_SOCKET; | |
210 } | |
211 } | |
212 | |
213 | |
214 void DccInterface::Connect() | |
215 { | |
216 if (err) return; | |
217 | |
218 sockaddr_un server; | |
219 memset(&server, '\0', sizeof(server)); | |
220 server.sun_family = AF_UNIX; | |
221 strncpy(server.sun_path, dccifd_port, sizeof(server.sun_path)-1); | |
222 dccifd_socket = socket(AF_UNIX, SOCK_STREAM, 0); | |
223 if (dccifd_socket != NULL_SOCKET) { | |
224 bool rc = (connect(dccifd_socket, (sockaddr *)&server, sizeof(server)) == 0); | |
225 if (!rc) { | |
226 my_disconnect(); | |
227 err = true; | |
228 } | |
229 } | |
230 } | |
231 | |
232 | |
233 size_t DccInterface::my_write(const char *buf, size_t len) { | |
234 if (err) return 0; | |
371
df7dc6b2b153
install dnsblnogrey/whiteclnt for dccifd
Carl Byington <carl@five-ten-sg.com>
parents:
227
diff
changeset
|
235 |
196 | 236 size_t rs = 0; |
237 while (len) { | |
238 ssize_t ws = write(dccifd_socket, buf, len); | |
239 if (ws > 0) { | |
240 rs += ws; | |
241 len -= ws; | |
242 buf += ws; | |
243 } | |
244 else { | |
245 // error or peer closed the socket! | |
246 rs = 0; | |
247 err = true; | |
248 break; | |
249 } | |
250 } | |
251 return rs; | |
252 } | |
253 | |
254 size_t DccInterface::my_read(char *buf, size_t len) { | |
255 if (err) return 0; | |
371
df7dc6b2b153
install dnsblnogrey/whiteclnt for dccifd
Carl Byington <carl@five-ten-sg.com>
parents:
227
diff
changeset
|
256 |
196 | 257 size_t rs = 0; |
258 while (len) { | |
259 ssize_t ws = read(dccifd_socket, buf, len); | |
260 if (ws > 0) { | |
261 rs += ws; | |
262 len -= ws; | |
263 buf += ws; | |
264 } | |
265 else if (ws < 0) { | |
266 // read error | |
267 rs = 0; | |
268 err = true; | |
269 break; | |
270 } | |
271 else { | |
272 // peer closed the socket, end of file | |
273 break; | |
274 } | |
275 } | |
276 return rs; | |
277 } | |
278 | |
279 void DccInterface::output(const char* buffer, size_t size) | |
280 { | |
281 if (err) return; | |
282 | |
283 // buffer it if not connected yet | |
284 if (dccifd_socket == NULL_SOCKET) { | |
285 //my_syslog(priv, string("dcc buffered ") + escaper(string(buffer, size))); | |
286 dccifd_input.append(buffer, size); | |
287 return; | |
288 } | |
289 | |
290 // write it if we are connected | |
291 //my_syslog(priv, string("dcc write ") + escaper(string(buffer, size))); | |
292 my_write(buffer, size); | |
293 } | |
294 | |
295 | |
296 void DccInterface::output(const char* buffer) | |
297 { | |
298 output(buffer, strlen(buffer)); | |
299 } | |
300 | |
301 | |
302 void DccInterface::output(string buffer) | |
303 { | |
304 output(buffer.c_str(), buffer.size()); | |
305 } | |
306 | |
307 | |
308 void DccInterface::close_output() | |
309 { | |
310 if (dccifd_socket != NULL_SOCKET) { | |
311 shutdown(dccifd_socket, SHUT_WR); | |
312 } | |
313 } | |
314 | |
315 | |
316 void DccInterface::input() | |
317 { | |
318 if ((dccifd_socket == NULL_SOCKET) || err) return; | |
319 char buf[maxlen]; | |
320 int rs; | |
214
82886d4dd71f
Fixes to compile on Fedora 9 and for const correctness.
Carl Byington <carl@five-ten-sg.com>
parents:
203
diff
changeset
|
321 while ((rs = my_read(buf, maxlen))) { |
196 | 322 //my_syslog(priv, string("dcc read ") + escaper(string(buf, rs))); |
323 dccifd_output.append(buf, rs); | |
324 } | |
325 my_disconnect(); | |
326 } | |
327 | |
328 | |
214
82886d4dd71f
Fixes to compile on Fedora 9 and for const correctness.
Carl Byington <carl@five-ten-sg.com>
parents:
203
diff
changeset
|
329 const char *DccInterface::getmacro(SMFICTX *ctx, const char *macro, const char *def) |
196 | 330 { |
214
82886d4dd71f
Fixes to compile on Fedora 9 and for const correctness.
Carl Byington <carl@five-ten-sg.com>
parents:
203
diff
changeset
|
331 const char *rc = smfi_getsymval(ctx, (char*)macro); |
196 | 332 if (!rc) rc = def; |
333 return rc; | |
334 } | |
335 | |
336 |