Mercurial > dnsbl
comparison src/dccifd.cpp @ 196:ff6d14d75b1e
add missing files to cvs
author | carl |
---|---|
date | Sat, 02 Feb 2008 10:08:08 -0800 |
parents | |
children | 92a5c866bdfa |
comparison
equal
deleted
inserted
replaced
195:797299e9fffc | 196:ff6d14d75b1e |
---|---|
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 | |
31 static const char Id[] = "$Id$"; | |
32 | |
33 const int maxlen = 1000; // used for snprintf buffers | |
34 extern int NULL_SOCKET; | |
35 const char *options = "header\n"; | |
36 | |
37 | |
38 //////////////////////////////////////////////// | |
39 // helper to convert syslog control chars | |
40 // | |
41 string escaper(string v); | |
42 string escaper(string v) | |
43 { | |
44 size_t n = v.length(); | |
45 char buf[n+1]; | |
46 strncpy(buf, v.c_str(), n); | |
47 for (size_t i=0; i<n; i++) { | |
48 if (buf[i] == '\r') buf[i] = 'r'; | |
49 if (buf[i] == '\n') buf[i] = 'n'; | |
50 if ((unsigned char)(buf[i]) < ' '){ | |
51 buf[i] = '.'; | |
52 } | |
53 } | |
54 return string(buf, n); | |
55 } | |
56 | |
57 | |
58 DccInterface::DccInterface(char *port_, mlfiPriv *priv_, int ip, char *helo_, char *from) | |
59 { | |
60 err = false; | |
61 first_recipient = true; | |
62 first_header = true; | |
63 priv = priv_; | |
64 ip4 = ip; | |
65 helo = helo_; | |
66 envfrom = from; | |
67 dccifd_port = port_; | |
68 dccifd_socket = NULL_SOCKET; | |
69 } | |
70 | |
71 | |
72 DccInterface::~DccInterface() | |
73 { | |
74 my_disconnect(); | |
75 } | |
76 | |
77 | |
78 void DccInterface::mlfi_envrcpt(SMFICTX *ctx, char *envrcpt, bool grey) | |
79 { | |
80 if (first_recipient) { | |
81 first_recipient = false; | |
82 char adr[sizeof "255.255.255.255 "]; | |
83 adr[0] = '\0'; | |
84 inet_ntop(AF_INET, (const u_char *)&ip4, adr, sizeof(adr)); | |
85 // Validated sending site's address | |
86 char *rdns = getmacro(ctx, "_", ""); | |
87 char buf[maxlen+1]; | |
88 if (*rdns == '[') rdns = ""; | |
89 else { | |
90 int n = 0; | |
91 while ((n < maxlen) && rdns[n] && (rdns[n] != ' ')) n++; | |
92 strncpy(buf, rdns, n); | |
93 buf[n] = '\0'; | |
94 rdns = buf; | |
95 } | |
96 output(options); | |
97 output(adr); output("\r"); | |
98 output(rdns); output("\n"); | |
99 //output("4.3.2.1\r\n"); // !! not local whitelisting | |
100 output(helo); output("\n"); | |
101 output(envfrom); output("\n"); | |
102 } | |
103 output(envrcpt); | |
104 if (grey) output("\r\n"); | |
105 else output("\rdnsblnogrey\n"); | |
106 } | |
107 | |
108 | |
109 void DccInterface::mlfi_header(SMFICTX *ctx, char* headerf, char* headerv) | |
110 { | |
111 if (dccifd_socket == NULL_SOCKET) Connect(); | |
112 if ((dccifd_socket != NULL_SOCKET) && (!dccifd_input.empty())) { | |
113 output(dccifd_input); | |
114 dccifd_input.clear(); | |
115 } | |
116 | |
117 if (first_header) { | |
118 output("\n"); | |
119 first_header = false; | |
120 } | |
121 | |
122 output(headerf); | |
123 output(": "); | |
124 output(headerv); | |
125 output("\r\n"); | |
126 } | |
127 | |
128 | |
129 void DccInterface::mlfi_eoh() | |
130 { | |
131 output("\r\n"); | |
132 } | |
133 | |
134 | |
135 void DccInterface::mlfi_body(u_char *bodyp, size_t bodylen) | |
136 { | |
137 output((char *)bodyp, bodylen); | |
138 } | |
139 | |
140 | |
141 void DccInterface::mlfi_eom(bool &grey, int &bulk) | |
142 { | |
143 // AnAnX-DCC-Rhyolite-Metrics: ns.five-ten-sg.com 104; Body=2 Fuz1=2nn | |
144 | |
145 close_output(); // signal EOF to DccInterface | |
146 input(); // read what the dcc has to say about this message | |
147 my_syslog(priv, "dcc returned " + escaper(dccifd_output)); | |
148 grey = false; | |
149 bulk = 0; | |
150 const int n = dccifd_output.length(); | |
151 char buf[n+1]; | |
152 strncpy(buf, dccifd_output.c_str(), n); | |
153 buf[n] = '\0'; | |
154 | |
155 int newlines = 0; | |
156 int j, i = 0; | |
157 while ((i<n) && (newlines < 2)) { | |
158 switch (buf[i++]) { | |
159 case 'G' : | |
160 grey = true; | |
161 break; | |
162 case '\n' : | |
163 newlines++; | |
164 default : ; | |
165 } | |
166 } | |
167 | |
168 // skip up to and including ; | |
169 while ((i<n) && (buf[i++] != ';')); | |
170 | |
171 // convert to lower, = to space, ctrl-chars to space | |
172 for (j=i; j<n; j++) { | |
173 buf[j] = tolower(buf[j]); | |
174 if (buf[j] == '=') buf[j] = ' '; | |
175 if (buf[j] < ' ') buf[j] = ' '; | |
176 } | |
177 | |
178 while (i<n) { | |
179 // skip leading blanks | |
180 while ((i<n) && (buf[i] == ' ')) i++; | |
181 | |
182 // find blank terminator | |
183 for (j=i; (j<n) && (buf[j] != ' '); j++); | |
184 | |
185 // find anything? | |
186 if (j > i) { | |
187 // process this token | |
188 buf[j] = '\0'; | |
189 //my_syslog(priv, string("dccifd token") + (buf+i)); | |
190 if (strcmp(buf+i, "bulk") == 0) bulk = dccbulk; | |
191 else if (strcmp(buf+i, "many") == 0) bulk = dccbulk; | |
192 else if (strcmp(buf+i, "whitelist") == 0) bulk = 0; | |
193 else if (isdigit(buf[i])) { | |
194 int b = atoi(buf+i); | |
195 if (b > bulk) bulk = b; | |
196 } | |
197 // skip this token | |
198 i = j+1; | |
199 } | |
200 } | |
201 char buff[maxlen]; | |
202 snprintf(buff, sizeof(buff), "dccifd found grey %s bulk %d", ((grey) ? "yes" : "no"), bulk); | |
203 //my_syslog(priv, buff); | |
204 } | |
205 | |
206 | |
207 void DccInterface::my_disconnect() | |
208 { | |
209 if (dccifd_socket != NULL_SOCKET) { | |
210 shutdown(dccifd_socket, SHUT_RDWR); | |
211 close(dccifd_socket); | |
212 dccifd_socket = NULL_SOCKET; | |
213 } | |
214 } | |
215 | |
216 | |
217 void DccInterface::Connect() | |
218 { | |
219 if (err) return; | |
220 | |
221 sockaddr_un server; | |
222 memset(&server, '\0', sizeof(server)); | |
223 server.sun_family = AF_UNIX; | |
224 strncpy(server.sun_path, dccifd_port, sizeof(server.sun_path)-1); | |
225 dccifd_socket = socket(AF_UNIX, SOCK_STREAM, 0); | |
226 if (dccifd_socket != NULL_SOCKET) { | |
227 bool rc = (connect(dccifd_socket, (sockaddr *)&server, sizeof(server)) == 0); | |
228 if (!rc) { | |
229 my_disconnect(); | |
230 err = true; | |
231 } | |
232 } | |
233 } | |
234 | |
235 | |
236 size_t DccInterface::my_write(const char *buf, size_t len) { | |
237 if (err) return 0; | |
238 size_t rs = 0; | |
239 while (len) { | |
240 ssize_t ws = write(dccifd_socket, buf, len); | |
241 if (ws > 0) { | |
242 rs += ws; | |
243 len -= ws; | |
244 buf += ws; | |
245 } | |
246 else { | |
247 // error or peer closed the socket! | |
248 rs = 0; | |
249 err = true; | |
250 break; | |
251 } | |
252 } | |
253 return rs; | |
254 } | |
255 | |
256 size_t DccInterface::my_read(char *buf, size_t len) { | |
257 if (err) return 0; | |
258 size_t rs = 0; | |
259 while (len) { | |
260 ssize_t ws = read(dccifd_socket, buf, len); | |
261 if (ws > 0) { | |
262 rs += ws; | |
263 len -= ws; | |
264 buf += ws; | |
265 } | |
266 else if (ws < 0) { | |
267 // read error | |
268 rs = 0; | |
269 err = true; | |
270 break; | |
271 } | |
272 else { | |
273 // peer closed the socket, end of file | |
274 break; | |
275 } | |
276 } | |
277 return rs; | |
278 } | |
279 | |
280 void DccInterface::output(const char* buffer, size_t size) | |
281 { | |
282 // if there are problems, fail. | |
283 if (err) return; | |
284 | |
285 // buffer it if not connected yet | |
286 if (dccifd_socket == NULL_SOCKET) { | |
287 //my_syslog(priv, string("dcc buffered ") + escaper(string(buffer, size))); | |
288 dccifd_input.append(buffer, size); | |
289 return; | |
290 } | |
291 | |
292 // write it if we are connected | |
293 //my_syslog(priv, string("dcc write ") + escaper(string(buffer, size))); | |
294 my_write(buffer, size); | |
295 } | |
296 | |
297 | |
298 void DccInterface::output(const char* buffer) | |
299 { | |
300 output(buffer, strlen(buffer)); | |
301 } | |
302 | |
303 | |
304 void DccInterface::output(string buffer) | |
305 { | |
306 output(buffer.c_str(), buffer.size()); | |
307 } | |
308 | |
309 | |
310 void DccInterface::close_output() | |
311 { | |
312 if (dccifd_socket != NULL_SOCKET) { | |
313 shutdown(dccifd_socket, SHUT_WR); | |
314 } | |
315 } | |
316 | |
317 | |
318 void DccInterface::input() | |
319 { | |
320 if ((dccifd_socket == NULL_SOCKET) || err) return; | |
321 char buf[maxlen]; | |
322 int rs; | |
323 while (rs = my_read(buf, maxlen)) { | |
324 //my_syslog(priv, string("dcc read ") + escaper(string(buf, rs))); | |
325 dccifd_output.append(buf, rs); | |
326 } | |
327 my_disconnect(); | |
328 } | |
329 | |
330 | |
331 char *DccInterface::getmacro(SMFICTX *ctx, char *macro, char *def) | |
332 { | |
333 char *rc = smfi_getsymval(ctx, macro); | |
334 if (!rc) rc = def; | |
335 return rc; | |
336 } | |
337 | |
338 |