Mercurial > dnsbl
diff src/dccifd.cpp @ 196:ff6d14d75b1e
add missing files to cvs
author | carl |
---|---|
date | Sat, 02 Feb 2008 10:08:08 -0800 |
parents | |
children | 92a5c866bdfa |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dccifd.cpp Sat Feb 02 10:08:08 2008 -0800 @@ -0,0 +1,338 @@ +/* + +Copyright (c) 2007 Carl Byington - 510 Software Group, released under +the GPL version 3 or any later version at your choice available at +http://www.gnu.org/licenses/gpl-3.0.txt + +*/ + +#include "includes.h" +#include <errno.h> +#include <fcntl.h> +#include <poll.h> +#include <signal.h> +#include <string> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +// needed for socket io +#include <sys/ioctl.h> +#include <net/if.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netdb.h> +#include <sys/socket.h> +#include <sys/un.h> + + + +static const char Id[] = "$Id$"; + +const int maxlen = 1000; // used for snprintf buffers +extern int NULL_SOCKET; +const char *options = "header\n"; + + +//////////////////////////////////////////////// +// helper to convert syslog control chars +// +string escaper(string v); +string escaper(string v) +{ + size_t n = v.length(); + char buf[n+1]; + strncpy(buf, v.c_str(), n); + for (size_t i=0; i<n; i++) { + if (buf[i] == '\r') buf[i] = 'r'; + if (buf[i] == '\n') buf[i] = 'n'; + if ((unsigned char)(buf[i]) < ' '){ + buf[i] = '.'; + } + } + return string(buf, n); +} + + +DccInterface::DccInterface(char *port_, mlfiPriv *priv_, int ip, char *helo_, char *from) +{ + err = false; + first_recipient = true; + first_header = true; + priv = priv_; + ip4 = ip; + helo = helo_; + envfrom = from; + dccifd_port = port_; + dccifd_socket = NULL_SOCKET; +} + + +DccInterface::~DccInterface() +{ + my_disconnect(); +} + + +void DccInterface::mlfi_envrcpt(SMFICTX *ctx, char *envrcpt, bool grey) +{ + if (first_recipient) { + first_recipient = false; + char adr[sizeof "255.255.255.255 "]; + adr[0] = '\0'; + inet_ntop(AF_INET, (const u_char *)&ip4, adr, sizeof(adr)); + // Validated sending site's address + char *rdns = getmacro(ctx, "_", ""); + char buf[maxlen+1]; + if (*rdns == '[') rdns = ""; + else { + int n = 0; + while ((n < maxlen) && rdns[n] && (rdns[n] != ' ')) n++; + strncpy(buf, rdns, n); + buf[n] = '\0'; + rdns = buf; + } + output(options); + output(adr); output("\r"); + output(rdns); output("\n"); + //output("4.3.2.1\r\n"); // !! not local whitelisting + output(helo); output("\n"); + output(envfrom); output("\n"); + } + output(envrcpt); + if (grey) output("\r\n"); + else output("\rdnsblnogrey\n"); +} + + +void DccInterface::mlfi_header(SMFICTX *ctx, char* headerf, char* headerv) +{ + if (dccifd_socket == NULL_SOCKET) Connect(); + if ((dccifd_socket != NULL_SOCKET) && (!dccifd_input.empty())) { + output(dccifd_input); + dccifd_input.clear(); + } + + if (first_header) { + output("\n"); + first_header = false; + } + + output(headerf); + output(": "); + output(headerv); + output("\r\n"); +} + + +void DccInterface::mlfi_eoh() +{ + output("\r\n"); +} + + +void DccInterface::mlfi_body(u_char *bodyp, size_t bodylen) +{ + output((char *)bodyp, bodylen); +} + + +void DccInterface::mlfi_eom(bool &grey, int &bulk) +{ + // AnAnX-DCC-Rhyolite-Metrics: ns.five-ten-sg.com 104; Body=2 Fuz1=2nn + + close_output(); // signal EOF to DccInterface + input(); // read what the dcc has to say about this message + my_syslog(priv, "dcc returned " + escaper(dccifd_output)); + grey = false; + bulk = 0; + const int n = dccifd_output.length(); + char buf[n+1]; + strncpy(buf, dccifd_output.c_str(), n); + buf[n] = '\0'; + + int newlines = 0; + int j, i = 0; + while ((i<n) && (newlines < 2)) { + switch (buf[i++]) { + case 'G' : + grey = true; + break; + case '\n' : + newlines++; + default : ; + } + } + + // skip up to and including ; + while ((i<n) && (buf[i++] != ';')); + + // convert to lower, = to space, ctrl-chars to space + for (j=i; j<n; j++) { + buf[j] = tolower(buf[j]); + if (buf[j] == '=') buf[j] = ' '; + if (buf[j] < ' ') buf[j] = ' '; + } + + while (i<n) { + // skip leading blanks + while ((i<n) && (buf[i] == ' ')) i++; + + // find blank terminator + for (j=i; (j<n) && (buf[j] != ' '); j++); + + // find anything? + if (j > i) { + // process this token + buf[j] = '\0'; + //my_syslog(priv, string("dccifd token") + (buf+i)); + if (strcmp(buf+i, "bulk") == 0) bulk = dccbulk; + else if (strcmp(buf+i, "many") == 0) bulk = dccbulk; + else if (strcmp(buf+i, "whitelist") == 0) bulk = 0; + else if (isdigit(buf[i])) { + int b = atoi(buf+i); + if (b > bulk) bulk = b; + } + // skip this token + i = j+1; + } + } + char buff[maxlen]; + snprintf(buff, sizeof(buff), "dccifd found grey %s bulk %d", ((grey) ? "yes" : "no"), bulk); + //my_syslog(priv, buff); +} + + +void DccInterface::my_disconnect() +{ + if (dccifd_socket != NULL_SOCKET) { + shutdown(dccifd_socket, SHUT_RDWR); + close(dccifd_socket); + dccifd_socket = NULL_SOCKET; + } +} + + +void DccInterface::Connect() +{ + if (err) return; + + sockaddr_un server; + memset(&server, '\0', sizeof(server)); + server.sun_family = AF_UNIX; + strncpy(server.sun_path, dccifd_port, sizeof(server.sun_path)-1); + dccifd_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (dccifd_socket != NULL_SOCKET) { + bool rc = (connect(dccifd_socket, (sockaddr *)&server, sizeof(server)) == 0); + if (!rc) { + my_disconnect(); + err = true; + } + } +} + + +size_t DccInterface::my_write(const char *buf, size_t len) { + if (err) return 0; + size_t rs = 0; + while (len) { + ssize_t ws = write(dccifd_socket, buf, len); + if (ws > 0) { + rs += ws; + len -= ws; + buf += ws; + } + else { + // error or peer closed the socket! + rs = 0; + err = true; + break; + } + } + return rs; +} + +size_t DccInterface::my_read(char *buf, size_t len) { + if (err) return 0; + size_t rs = 0; + while (len) { + ssize_t ws = read(dccifd_socket, buf, len); + if (ws > 0) { + rs += ws; + len -= ws; + buf += ws; + } + else if (ws < 0) { + // read error + rs = 0; + err = true; + break; + } + else { + // peer closed the socket, end of file + break; + } + } + return rs; +} + +void DccInterface::output(const char* buffer, size_t size) +{ + // if there are problems, fail. + if (err) return; + + // buffer it if not connected yet + if (dccifd_socket == NULL_SOCKET) { + //my_syslog(priv, string("dcc buffered ") + escaper(string(buffer, size))); + dccifd_input.append(buffer, size); + return; + } + + // write it if we are connected + //my_syslog(priv, string("dcc write ") + escaper(string(buffer, size))); + my_write(buffer, size); +} + + +void DccInterface::output(const char* buffer) +{ + output(buffer, strlen(buffer)); +} + + +void DccInterface::output(string buffer) +{ + output(buffer.c_str(), buffer.size()); +} + + +void DccInterface::close_output() +{ + if (dccifd_socket != NULL_SOCKET) { + shutdown(dccifd_socket, SHUT_WR); + } +} + + +void DccInterface::input() +{ + if ((dccifd_socket == NULL_SOCKET) || err) return; + char buf[maxlen]; + int rs; + while (rs = my_read(buf, maxlen)) { + //my_syslog(priv, string("dcc read ") + escaper(string(buf, rs))); + dccifd_output.append(buf, rs); + } + my_disconnect(); +} + + +char *DccInterface::getmacro(SMFICTX *ctx, char *macro, char *def) +{ + char *rc = smfi_getsymval(ctx, macro); + if (!rc) rc = def; + return rc; +} + +