Mercurial > dnsbl
annotate src/dccifd.cpp @ 240:536d59c3a7b8
pollnval might be triggered on the last pollin data chunk
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Tue, 30 Mar 2010 10:05:35 -0700 |
parents | 3fee608becbc |
children | df7dc6b2b153 |
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(); | |
108 if ((dccifd_socket != NULL_SOCKET) && (!dccifd_input.empty())) { | |
109 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
|
110 dccifd_input = ""; |
196 | 111 } |
112 | |
113 if (first_header) { | |
114 output("\n"); | |
115 first_header = false; | |
116 } | |
117 | |
118 output(headerf); | |
119 output(": "); | |
120 output(headerv); | |
121 output("\r\n"); | |
122 } | |
123 | |
124 | |
125 void DccInterface::mlfi_eoh() | |
126 { | |
127 output("\r\n"); | |
128 } | |
129 | |
130 | |
214
82886d4dd71f
Fixes to compile on Fedora 9 and for const correctness.
Carl Byington <carl@five-ten-sg.com>
parents:
203
diff
changeset
|
131 void DccInterface::mlfi_body(const u_char *bodyp, size_t bodylen) |
196 | 132 { |
214
82886d4dd71f
Fixes to compile on Fedora 9 and for const correctness.
Carl Byington <carl@five-ten-sg.com>
parents:
203
diff
changeset
|
133 output((const char *)bodyp, bodylen); |
196 | 134 } |
135 | |
136 | |
137 void DccInterface::mlfi_eom(bool &grey, int &bulk) | |
138 { | |
139 // AnAnX-DCC-Rhyolite-Metrics: ns.five-ten-sg.com 104; Body=2 Fuz1=2nn | |
140 | |
141 close_output(); // signal EOF to DccInterface | |
142 input(); // read what the dcc has to say about this message | |
143 my_syslog(priv, "dcc returned " + escaper(dccifd_output)); | |
144 grey = false; | |
145 bulk = 0; | |
146 const int n = dccifd_output.length(); | |
147 char buf[n+1]; | |
148 strncpy(buf, dccifd_output.c_str(), n); | |
149 buf[n] = '\0'; | |
150 | |
151 int newlines = 0; | |
152 int j, i = 0; | |
153 while ((i<n) && (newlines < 2)) { | |
154 switch (buf[i++]) { | |
155 case 'G' : | |
156 grey = true; | |
157 break; | |
158 case '\n' : | |
159 newlines++; | |
160 default : ; | |
161 } | |
162 } | |
163 | |
164 // skip up to and including ; | |
165 while ((i<n) && (buf[i++] != ';')); | |
166 | |
167 // convert to lower, = to space, ctrl-chars to space | |
168 for (j=i; j<n; j++) { | |
169 buf[j] = tolower(buf[j]); | |
170 if (buf[j] == '=') buf[j] = ' '; | |
171 if (buf[j] < ' ') buf[j] = ' '; | |
172 } | |
173 | |
174 while (i<n) { | |
175 // skip leading blanks | |
176 while ((i<n) && (buf[i] == ' ')) i++; | |
177 | |
178 // find blank terminator | |
179 for (j=i; (j<n) && (buf[j] != ' '); j++); | |
180 | |
181 // find anything? | |
182 if (j > i) { | |
183 // process this token | |
184 buf[j] = '\0'; | |
185 //my_syslog(priv, string("dccifd token") + (buf+i)); | |
186 if (strcmp(buf+i, "bulk") == 0) bulk = dccbulk; | |
187 else if (strcmp(buf+i, "many") == 0) bulk = dccbulk; | |
188 else if (strcmp(buf+i, "whitelist") == 0) bulk = 0; | |
189 else if (isdigit(buf[i])) { | |
190 int b = atoi(buf+i); | |
191 if (b > bulk) bulk = b; | |
192 } | |
193 // skip this token | |
194 i = j+1; | |
195 } | |
196 } | |
227
3fee608becbc
Fixes to compile on old systems without memrchr or string::clear().
Carl Byington <carl@five-ten-sg.com>
parents:
214
diff
changeset
|
197 //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
|
198 //snprintf(buff, sizeof(buff), "dccifd found grey %s bulk %d", ((grey) ? "yes" : "no"), bulk); |
196 | 199 //my_syslog(priv, buff); |
200 } | |
201 | |
202 | |
203 void DccInterface::my_disconnect() | |
204 { | |
205 if (dccifd_socket != NULL_SOCKET) { | |
206 shutdown(dccifd_socket, SHUT_RDWR); | |
207 close(dccifd_socket); | |
208 dccifd_socket = NULL_SOCKET; | |
209 } | |
210 } | |
211 | |
212 | |
213 void DccInterface::Connect() | |
214 { | |
215 if (err) return; | |
216 | |
217 sockaddr_un server; | |
218 memset(&server, '\0', sizeof(server)); | |
219 server.sun_family = AF_UNIX; | |
220 strncpy(server.sun_path, dccifd_port, sizeof(server.sun_path)-1); | |
221 dccifd_socket = socket(AF_UNIX, SOCK_STREAM, 0); | |
222 if (dccifd_socket != NULL_SOCKET) { | |
223 bool rc = (connect(dccifd_socket, (sockaddr *)&server, sizeof(server)) == 0); | |
224 if (!rc) { | |
225 my_disconnect(); | |
226 err = true; | |
227 } | |
228 } | |
229 } | |
230 | |
231 | |
232 size_t DccInterface::my_write(const char *buf, size_t len) { | |
233 if (err) return 0; | |
234 size_t rs = 0; | |
235 while (len) { | |
236 ssize_t ws = write(dccifd_socket, buf, len); | |
237 if (ws > 0) { | |
238 rs += ws; | |
239 len -= ws; | |
240 buf += ws; | |
241 } | |
242 else { | |
243 // error or peer closed the socket! | |
244 rs = 0; | |
245 err = true; | |
246 break; | |
247 } | |
248 } | |
249 return rs; | |
250 } | |
251 | |
252 size_t DccInterface::my_read(char *buf, size_t len) { | |
253 if (err) return 0; | |
254 size_t rs = 0; | |
255 while (len) { | |
256 ssize_t ws = read(dccifd_socket, buf, len); | |
257 if (ws > 0) { | |
258 rs += ws; | |
259 len -= ws; | |
260 buf += ws; | |
261 } | |
262 else if (ws < 0) { | |
263 // read error | |
264 rs = 0; | |
265 err = true; | |
266 break; | |
267 } | |
268 else { | |
269 // peer closed the socket, end of file | |
270 break; | |
271 } | |
272 } | |
273 return rs; | |
274 } | |
275 | |
276 void DccInterface::output(const char* buffer, size_t size) | |
277 { | |
278 // if there are problems, fail. | |
279 if (err) return; | |
280 | |
281 // buffer it if not connected yet | |
282 if (dccifd_socket == NULL_SOCKET) { | |
283 //my_syslog(priv, string("dcc buffered ") + escaper(string(buffer, size))); | |
284 dccifd_input.append(buffer, size); | |
285 return; | |
286 } | |
287 | |
288 // write it if we are connected | |
289 //my_syslog(priv, string("dcc write ") + escaper(string(buffer, size))); | |
290 my_write(buffer, size); | |
291 } | |
292 | |
293 | |
294 void DccInterface::output(const char* buffer) | |
295 { | |
296 output(buffer, strlen(buffer)); | |
297 } | |
298 | |
299 | |
300 void DccInterface::output(string buffer) | |
301 { | |
302 output(buffer.c_str(), buffer.size()); | |
303 } | |
304 | |
305 | |
306 void DccInterface::close_output() | |
307 { | |
308 if (dccifd_socket != NULL_SOCKET) { | |
309 shutdown(dccifd_socket, SHUT_WR); | |
310 } | |
311 } | |
312 | |
313 | |
314 void DccInterface::input() | |
315 { | |
316 if ((dccifd_socket == NULL_SOCKET) || err) return; | |
317 char buf[maxlen]; | |
318 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
|
319 while ((rs = my_read(buf, maxlen))) { |
196 | 320 //my_syslog(priv, string("dcc read ") + escaper(string(buf, rs))); |
321 dccifd_output.append(buf, rs); | |
322 } | |
323 my_disconnect(); | |
324 } | |
325 | |
326 | |
214
82886d4dd71f
Fixes to compile on Fedora 9 and for const correctness.
Carl Byington <carl@five-ten-sg.com>
parents:
203
diff
changeset
|
327 const char *DccInterface::getmacro(SMFICTX *ctx, const char *macro, const char *def) |
196 | 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 *rc = smfi_getsymval(ctx, (char*)macro); |
196 | 330 if (!rc) rc = def; |
331 return rc; | |
332 } | |
333 | |
334 |