dnsbl
changeset 196:ff6d14d75b1e
add missing files to cvs
| author | carl |
|---|---|
| date | Sat Feb 02 10:08:08 2008 -0800 (2008-02-02) |
| parents | 797299e9fffc |
| children | 3b69ee1ed10f |
| files | src/dccifd.cpp src/dccifd.h |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/dccifd.cpp Sat Feb 02 10:08:08 2008 -0800 1.3 @@ -0,0 +1,338 @@ 1.4 +/* 1.5 + 1.6 +Copyright (c) 2007 Carl Byington - 510 Software Group, released under 1.7 +the GPL version 3 or any later version at your choice available at 1.8 +http://www.gnu.org/licenses/gpl-3.0.txt 1.9 + 1.10 +*/ 1.11 + 1.12 +#include "includes.h" 1.13 +#include <errno.h> 1.14 +#include <fcntl.h> 1.15 +#include <poll.h> 1.16 +#include <signal.h> 1.17 +#include <string> 1.18 +#include <sys/types.h> 1.19 +#include <sys/wait.h> 1.20 +#include <unistd.h> 1.21 + 1.22 +// needed for socket io 1.23 +#include <sys/ioctl.h> 1.24 +#include <net/if.h> 1.25 +#include <arpa/inet.h> 1.26 +#include <netinet/in.h> 1.27 +#include <netinet/tcp.h> 1.28 +#include <netdb.h> 1.29 +#include <sys/socket.h> 1.30 +#include <sys/un.h> 1.31 + 1.32 + 1.33 + 1.34 +static const char Id[] = "$Id$"; 1.35 + 1.36 +const int maxlen = 1000; // used for snprintf buffers 1.37 +extern int NULL_SOCKET; 1.38 +const char *options = "header\n"; 1.39 + 1.40 + 1.41 +//////////////////////////////////////////////// 1.42 +// helper to convert syslog control chars 1.43 +// 1.44 +string escaper(string v); 1.45 +string escaper(string v) 1.46 +{ 1.47 + size_t n = v.length(); 1.48 + char buf[n+1]; 1.49 + strncpy(buf, v.c_str(), n); 1.50 + for (size_t i=0; i<n; i++) { 1.51 + if (buf[i] == '\r') buf[i] = 'r'; 1.52 + if (buf[i] == '\n') buf[i] = 'n'; 1.53 + if ((unsigned char)(buf[i]) < ' '){ 1.54 + buf[i] = '.'; 1.55 + } 1.56 + } 1.57 + return string(buf, n); 1.58 +} 1.59 + 1.60 + 1.61 +DccInterface::DccInterface(char *port_, mlfiPriv *priv_, int ip, char *helo_, char *from) 1.62 +{ 1.63 + err = false; 1.64 + first_recipient = true; 1.65 + first_header = true; 1.66 + priv = priv_; 1.67 + ip4 = ip; 1.68 + helo = helo_; 1.69 + envfrom = from; 1.70 + dccifd_port = port_; 1.71 + dccifd_socket = NULL_SOCKET; 1.72 +} 1.73 + 1.74 + 1.75 +DccInterface::~DccInterface() 1.76 +{ 1.77 + my_disconnect(); 1.78 +} 1.79 + 1.80 + 1.81 +void DccInterface::mlfi_envrcpt(SMFICTX *ctx, char *envrcpt, bool grey) 1.82 +{ 1.83 + if (first_recipient) { 1.84 + first_recipient = false; 1.85 + char adr[sizeof "255.255.255.255 "]; 1.86 + adr[0] = '\0'; 1.87 + inet_ntop(AF_INET, (const u_char *)&ip4, adr, sizeof(adr)); 1.88 + // Validated sending site's address 1.89 + char *rdns = getmacro(ctx, "_", ""); 1.90 + char buf[maxlen+1]; 1.91 + if (*rdns == '[') rdns = ""; 1.92 + else { 1.93 + int n = 0; 1.94 + while ((n < maxlen) && rdns[n] && (rdns[n] != ' ')) n++; 1.95 + strncpy(buf, rdns, n); 1.96 + buf[n] = '\0'; 1.97 + rdns = buf; 1.98 + } 1.99 + output(options); 1.100 + output(adr); output("\r"); 1.101 + output(rdns); output("\n"); 1.102 + //output("4.3.2.1\r\n"); // !! not local whitelisting 1.103 + output(helo); output("\n"); 1.104 + output(envfrom); output("\n"); 1.105 + } 1.106 + output(envrcpt); 1.107 + if (grey) output("\r\n"); 1.108 + else output("\rdnsblnogrey\n"); 1.109 +} 1.110 + 1.111 + 1.112 +void DccInterface::mlfi_header(SMFICTX *ctx, char* headerf, char* headerv) 1.113 +{ 1.114 + if (dccifd_socket == NULL_SOCKET) Connect(); 1.115 + if ((dccifd_socket != NULL_SOCKET) && (!dccifd_input.empty())) { 1.116 + output(dccifd_input); 1.117 + dccifd_input.clear(); 1.118 + } 1.119 + 1.120 + if (first_header) { 1.121 + output("\n"); 1.122 + first_header = false; 1.123 + } 1.124 + 1.125 + output(headerf); 1.126 + output(": "); 1.127 + output(headerv); 1.128 + output("\r\n"); 1.129 +} 1.130 + 1.131 + 1.132 +void DccInterface::mlfi_eoh() 1.133 +{ 1.134 + output("\r\n"); 1.135 +} 1.136 + 1.137 + 1.138 +void DccInterface::mlfi_body(u_char *bodyp, size_t bodylen) 1.139 +{ 1.140 + output((char *)bodyp, bodylen); 1.141 +} 1.142 + 1.143 + 1.144 +void DccInterface::mlfi_eom(bool &grey, int &bulk) 1.145 +{ 1.146 + // AnAnX-DCC-Rhyolite-Metrics: ns.five-ten-sg.com 104; Body=2 Fuz1=2nn 1.147 + 1.148 + close_output(); // signal EOF to DccInterface 1.149 + input(); // read what the dcc has to say about this message 1.150 + my_syslog(priv, "dcc returned " + escaper(dccifd_output)); 1.151 + grey = false; 1.152 + bulk = 0; 1.153 + const int n = dccifd_output.length(); 1.154 + char buf[n+1]; 1.155 + strncpy(buf, dccifd_output.c_str(), n); 1.156 + buf[n] = '\0'; 1.157 + 1.158 + int newlines = 0; 1.159 + int j, i = 0; 1.160 + while ((i<n) && (newlines < 2)) { 1.161 + switch (buf[i++]) { 1.162 + case 'G' : 1.163 + grey = true; 1.164 + break; 1.165 + case '\n' : 1.166 + newlines++; 1.167 + default : ; 1.168 + } 1.169 + } 1.170 + 1.171 + // skip up to and including ; 1.172 + while ((i<n) && (buf[i++] != ';')); 1.173 + 1.174 + // convert to lower, = to space, ctrl-chars to space 1.175 + for (j=i; j<n; j++) { 1.176 + buf[j] = tolower(buf[j]); 1.177 + if (buf[j] == '=') buf[j] = ' '; 1.178 + if (buf[j] < ' ') buf[j] = ' '; 1.179 + } 1.180 + 1.181 + while (i<n) { 1.182 + // skip leading blanks 1.183 + while ((i<n) && (buf[i] == ' ')) i++; 1.184 + 1.185 + // find blank terminator 1.186 + for (j=i; (j<n) && (buf[j] != ' '); j++); 1.187 + 1.188 + // find anything? 1.189 + if (j > i) { 1.190 + // process this token 1.191 + buf[j] = '\0'; 1.192 + //my_syslog(priv, string("dccifd token") + (buf+i)); 1.193 + if (strcmp(buf+i, "bulk") == 0) bulk = dccbulk; 1.194 + else if (strcmp(buf+i, "many") == 0) bulk = dccbulk; 1.195 + else if (strcmp(buf+i, "whitelist") == 0) bulk = 0; 1.196 + else if (isdigit(buf[i])) { 1.197 + int b = atoi(buf+i); 1.198 + if (b > bulk) bulk = b; 1.199 + } 1.200 + // skip this token 1.201 + i = j+1; 1.202 + } 1.203 + } 1.204 + char buff[maxlen]; 1.205 + snprintf(buff, sizeof(buff), "dccifd found grey %s bulk %d", ((grey) ? "yes" : "no"), bulk); 1.206 + //my_syslog(priv, buff); 1.207 +} 1.208 + 1.209 + 1.210 +void DccInterface::my_disconnect() 1.211 +{ 1.212 + if (dccifd_socket != NULL_SOCKET) { 1.213 + shutdown(dccifd_socket, SHUT_RDWR); 1.214 + close(dccifd_socket); 1.215 + dccifd_socket = NULL_SOCKET; 1.216 + } 1.217 +} 1.218 + 1.219 + 1.220 +void DccInterface::Connect() 1.221 +{ 1.222 + if (err) return; 1.223 + 1.224 + sockaddr_un server; 1.225 + memset(&server, '\0', sizeof(server)); 1.226 + server.sun_family = AF_UNIX; 1.227 + strncpy(server.sun_path, dccifd_port, sizeof(server.sun_path)-1); 1.228 + dccifd_socket = socket(AF_UNIX, SOCK_STREAM, 0); 1.229 + if (dccifd_socket != NULL_SOCKET) { 1.230 + bool rc = (connect(dccifd_socket, (sockaddr *)&server, sizeof(server)) == 0); 1.231 + if (!rc) { 1.232 + my_disconnect(); 1.233 + err = true; 1.234 + } 1.235 + } 1.236 +} 1.237 + 1.238 + 1.239 +size_t DccInterface::my_write(const char *buf, size_t len) { 1.240 + if (err) return 0; 1.241 + size_t rs = 0; 1.242 + while (len) { 1.243 + ssize_t ws = write(dccifd_socket, buf, len); 1.244 + if (ws > 0) { 1.245 + rs += ws; 1.246 + len -= ws; 1.247 + buf += ws; 1.248 + } 1.249 + else { 1.250 + // error or peer closed the socket! 1.251 + rs = 0; 1.252 + err = true; 1.253 + break; 1.254 + } 1.255 + } 1.256 + return rs; 1.257 +} 1.258 + 1.259 +size_t DccInterface::my_read(char *buf, size_t len) { 1.260 + if (err) return 0; 1.261 + size_t rs = 0; 1.262 + while (len) { 1.263 + ssize_t ws = read(dccifd_socket, buf, len); 1.264 + if (ws > 0) { 1.265 + rs += ws; 1.266 + len -= ws; 1.267 + buf += ws; 1.268 + } 1.269 + else if (ws < 0) { 1.270 + // read error 1.271 + rs = 0; 1.272 + err = true; 1.273 + break; 1.274 + } 1.275 + else { 1.276 + // peer closed the socket, end of file 1.277 + break; 1.278 + } 1.279 + } 1.280 + return rs; 1.281 +} 1.282 + 1.283 +void DccInterface::output(const char* buffer, size_t size) 1.284 +{ 1.285 + // if there are problems, fail. 1.286 + if (err) return; 1.287 + 1.288 + // buffer it if not connected yet 1.289 + if (dccifd_socket == NULL_SOCKET) { 1.290 + //my_syslog(priv, string("dcc buffered ") + escaper(string(buffer, size))); 1.291 + dccifd_input.append(buffer, size); 1.292 + return; 1.293 + } 1.294 + 1.295 + // write it if we are connected 1.296 + //my_syslog(priv, string("dcc write ") + escaper(string(buffer, size))); 1.297 + my_write(buffer, size); 1.298 +} 1.299 + 1.300 + 1.301 +void DccInterface::output(const char* buffer) 1.302 +{ 1.303 + output(buffer, strlen(buffer)); 1.304 +} 1.305 + 1.306 + 1.307 +void DccInterface::output(string buffer) 1.308 +{ 1.309 + output(buffer.c_str(), buffer.size()); 1.310 +} 1.311 + 1.312 + 1.313 +void DccInterface::close_output() 1.314 +{ 1.315 + if (dccifd_socket != NULL_SOCKET) { 1.316 + shutdown(dccifd_socket, SHUT_WR); 1.317 + } 1.318 +} 1.319 + 1.320 + 1.321 +void DccInterface::input() 1.322 +{ 1.323 + if ((dccifd_socket == NULL_SOCKET) || err) return; 1.324 + char buf[maxlen]; 1.325 + int rs; 1.326 + while (rs = my_read(buf, maxlen)) { 1.327 + //my_syslog(priv, string("dcc read ") + escaper(string(buf, rs))); 1.328 + dccifd_output.append(buf, rs); 1.329 + } 1.330 + my_disconnect(); 1.331 +} 1.332 + 1.333 + 1.334 +char *DccInterface::getmacro(SMFICTX *ctx, char *macro, char *def) 1.335 +{ 1.336 + char *rc = smfi_getsymval(ctx, macro); 1.337 + if (!rc) rc = def; 1.338 + return rc; 1.339 +} 1.340 + 1.341 +
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/src/dccifd.h Sat Feb 02 10:08:08 2008 -0800 2.3 @@ -0,0 +1,69 @@ 2.4 +/* 2.5 + 2.6 +Copyright (c) 2007 Carl Byington - 510 Software Group, released under 2.7 +the GPL version 3 or any later version at your choice available at 2.8 +http://www.gnu.org/licenses/gpl-3.0.txt 2.9 + 2.10 +*/ 2.11 + 2.12 +#ifndef _DCCIFD_H 2.13 +#define _DCCIFD_H 2.14 + 2.15 +extern "C" { 2.16 + #include <libmilter/mfapi.h> 2.17 +} 2.18 + 2.19 +#ifdef HAVE_CDEFS_H 2.20 +#include <sys/cdefs.h> 2.21 +#endif 2.22 + 2.23 +#include <list> 2.24 + 2.25 +using namespace std; 2.26 + 2.27 +class mlfiPriv; 2.28 + 2.29 +class DccInterface { 2.30 +public: 2.31 + DccInterface(char *port_, mlfiPriv *priv_, int ip, char *helo_, char *from); 2.32 + ~DccInterface(); 2.33 + 2.34 + void mlfi_envrcpt(SMFICTX *ctx, char *envrcpt, bool grey); 2.35 + void mlfi_header(SMFICTX *ctx, char* headerf, char* headerv); 2.36 + void mlfi_eoh(); 2.37 + void mlfi_body(u_char *bodyp, size_t bodylen); 2.38 + void mlfi_eom(bool &grey, int &bulk); 2.39 + 2.40 +private: 2.41 + void my_disconnect(); 2.42 + void Connect(); 2.43 + size_t my_write(const char *buf, size_t len); 2.44 + size_t my_read(char *buf, size_t len); 2.45 + void output(const char*buffer, size_t size); 2.46 + void output(const char*buffer); 2.47 + void output(string buffer); 2.48 + void close_output(); 2.49 + void input(); 2.50 + char *getmacro(SMFICTX *ctx, char *macro, char *def); 2.51 + 2.52 +public: 2.53 + bool err; // socket write error 2.54 + bool first_recipient; // have we not seen any recipients? 2.55 + bool first_header; // have we not seen any headers? 2.56 + 2.57 + // connection back to main dnsbl priv structure for logging 2.58 + mlfiPriv *priv; 2.59 + int ip4; // ip4 address of smtp client 2.60 + 2.61 + // strings owned by main dnsbl 2.62 + char *helo; // client helo value 2.63 + char *envfrom; // envelope from value for this message 2.64 + 2.65 + // Process handling variables 2.66 + int dccifd_socket; 2.67 + char *dccifd_port; 2.68 + string dccifd_output; // to dccifd socket 2.69 + string dccifd_input; // from dccifd socket 2.70 +}; 2.71 + 2.72 +#endif
