Mercurial > dnsbl
view 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 |
line wrap: on
line source
/* 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> 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(const char *port_, mlfiPriv *priv_, int ip, const char *helo_, const 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, const 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 const 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(helo); output("\n"); output(envfrom); output("\n"); } output(envrcpt); if (grey) output("\r\n"); else output("\rdnsblnogrey\n"); } void DccInterface::mlfi_header(SMFICTX *ctx, const char *headerf, const char *headerv) { if (dccifd_socket == NULL_SOCKET) Connect(); if (err) return; if ((dccifd_socket != NULL_SOCKET) && (!dccifd_input.empty())) { output(dccifd_input); dccifd_input = ""; } 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(const u_char *bodyp, size_t bodylen) { output((const 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 (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(); } const char *DccInterface::getmacro(SMFICTX *ctx, const char *macro, const char *def) { const char *rc = smfi_getsymval(ctx, (char*)macro); if (!rc) rc = def; return rc; }