"Fossies" - the Fresh Open Source Software Archive

Member "postal-0.76/smtp.cpp" (30 Jun 2016, 9249 Bytes) of package /linux/privat/postal-0.76.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "smtp.cpp" see the Fossies "Dox" file reference documentation.

    1 #include "smtp.h"
    2 #include <unistd.h>
    3 #include <netdb.h>
    4 #include <arpa/inet.h>
    5 #include <sys/socket.h>
    6 #include <sys/time.h>
    7 #include <time.h>
    8 #include "userlist.h"
    9 #include "logit.h"
   10 #include "results.h"
   11 #include <cstring>
   12 
   13 smtpData::smtpData()
   14  : m_quit("QUIT\r\n")
   15  , m_randomLetters("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 `~!@#$%^&*()-_=+[]{};:'\"|/?<>,")
   16  , m_randomLen(strlen(m_randomLetters))
   17  , m_postalMsg("\r\nX-Postal: " VER_STR " - the mad postman.\r\n"
   18                "X-Postal: http://www.coker.com.au/postal/\r\n"
   19                "X-Postal: This is not a real email.\r\n\r\n")
   20  , m_dnsLock(true)
   21  , m_timeLastAction(time(NULL))
   22 {
   23   setRand(0);
   24 }
   25 
   26 const string *smtpData::getMailName(struct sockaddr_in &in)
   27 {
   28   Lock l(m_dnsLock);
   29   unsigned long ip = in.sin_addr.s_addr;
   30   string *name = m_names[ip];
   31   if(name != NULL)
   32     return name;
   33   struct hostent *h;
   34   h = gethostbyaddr((char *)&(in.sin_addr), sizeof(in.sin_addr), AF_INET);
   35   if(!h)
   36   {
   37     FILE *fp = fopen("/etc/mailname", "r");
   38     char buf[100];
   39     if(fp && fgets(buf, sizeof(buf), fp))
   40     {
   41       char *tmp = strchr(buf, '\n');
   42       if(tmp)
   43         *tmp = 0;
   44       name = new string(buf);
   45     }
   46     else
   47     { 
   48       name = new string(inet_ntoa(in.sin_addr));
   49     }
   50   }
   51   else
   52   {
   53     name = new string(h->h_name);
   54   }
   55   m_names[ip] = name;
   56   return name;
   57 }
   58 
   59 smtpData::~smtpData()
   60 {
   61 }
   62 
   63 void smtpData::setRand(int frequency)
   64 {
   65   if(time(NULL) - m_timeLastAction < frequency)
   66     return;
   67 
   68   for(int i = 0; i < MAP_SIZE; i++)
   69     m_randBuf[i] = m_randomLetters[random() % m_randomLen];
   70   m_timeLastAction = time(NULL);
   71 }
   72 
   73 void smtpData::randomString(char *buf, int len) const
   74 {
   75   if(len < 2)
   76     return;
   77   if(len > 2)
   78   {
   79     int offset = random() % (MAP_SIZE - (len - 2));
   80     memcpy(buf, &m_randBuf[offset], len - 2);
   81   }
   82   strcpy(buf + len - 2, "\r\n");
   83 }
   84 
   85 const int max_line_len = 79;
   86 
   87 void smtpData::randomBuf(char *buf, int len) const
   88 {
   89   while(len)
   90   {
   91     int line_len = random() % max_line_len;
   92     if(line_len < 2)
   93       line_len = 2;
   94     if(len - line_len < 2)
   95       line_len = len;
   96     randomString(buf, line_len);
   97     len -= line_len;
   98     buf += line_len;
   99   }
  100 }
  101 
  102 // Return a random date that may be as much as 60 seconds in the future or 600 seconds in the past.
  103 // buffer must be at least 34 bytes for "Day, dd Mon yyyy hh:mm:ss +zzzz\r\n"
  104 void smtpData::date(char *buf) const
  105 {
  106   time_t t = time(NULL);
  107   struct tm broken;
  108 
  109   t += 60 - random() % 600;
  110 
  111   if(!gmtime_r(&t, &broken) || !strftime(buf, 34, "%a, %d %b %Y %H:%M:%S %z\r\n", &broken))
  112     strcpy(buf, "Error making date");
  113 }
  114 
  115 const string smtpData::msgId(const char *sender, const unsigned threadNum) const
  116 {
  117   char msgId_buf[256];
  118   const unsigned int max_sender_len = sizeof(msgId_buf) - 35;
  119 
  120   if(strlen(sender) > max_sender_len)
  121     sender += strlen(sender) - max_sender_len;
  122   else if(*sender == '<')
  123     sender++;
  124 
  125   struct timeval tv;
  126   gettimeofday(&tv, NULL);
  127   snprintf(msgId_buf, sizeof(msgId_buf), "<%08X.%03X.%03X.%s\r\n", unsigned(tv.tv_sec), unsigned(tv.tv_usec % 2048), threadNum % 2048, sender);
  128   return string(msgId_buf);
  129 }
  130 
  131 Thread *smtp::newThread(int threadNum)
  132 {
  133   return new smtp(threadNum, this);
  134 }
  135 
  136 int smtp::action(PVOID)
  137 {
  138   while(1)
  139   {
  140     int rc = Connect();
  141     if(rc > 1)
  142       return 1;
  143     if(rc == 0)
  144     {
  145 #ifdef USE_SSL
  146       if(m_canTLS && CHECK_PERCENT(m_useTLS) )
  147       {
  148         rc = sendCommandString("STARTTLS\r\n");
  149         if(!rc)
  150           rc = ConnectTLS();
  151         if(!rc)
  152           rc = sendCommandString(m_helo);
  153         if(rc > 1)
  154           return rc;
  155         m_res->connect_ssl();
  156       }
  157 #endif
  158       int msgs;
  159       if(m_msgsPerConnection == 0)
  160         msgs = -1;
  161       else if(m_msgsPerConnection < 0)
  162         msgs = 0;
  163       else
  164         msgs = random() % m_msgsPerConnection + 1;
  165 
  166       if(rc)
  167         msgs = 0;
  168       for(int i = 0; i != msgs; i++)
  169       {
  170         if(*m_exitCount)
  171         {
  172           disconnect();
  173           return 1;
  174         }
  175         rc = sendMsg();
  176         if(rc > 1)
  177           return 1;
  178         if(rc)
  179           break;
  180       }
  181       if(!rc)
  182         rc = disconnect();
  183       if(rc > 1)
  184         return 1;
  185     }
  186     if(rc)
  187     {
  188       sleep(5);
  189     }
  190   }
  191 }
  192 
  193 smtp::smtp(int *exitCount, const char *addr, const char *ourAddr, UserList &ul
  194          , UserList *senderList, int minMsgSize, int maxMsgSize
  195          , int numMsgsPerConnection
  196          , int processes, Logit *log, TRISTATE netscape, bool useLMTP
  197 #ifdef USE_SSL
  198          , int ssl
  199 #endif
  200          , unsigned short port, Logit *debug)
  201  : tcp(exitCount, addr, port, log
  202 #ifdef USE_SSL
  203      , ssl
  204 #endif
  205      , ourAddr, debug)
  206  , m_ul(ul)
  207  , m_senderList(senderList ? senderList : &ul)
  208  , m_minMsgSize(minMsgSize * 1024)
  209  , m_maxMsgSize(maxMsgSize * 1024)
  210  , m_data(new smtpData())
  211  , m_msgsPerConnection(numMsgsPerConnection)
  212  , m_res(new results)
  213  , m_netscape(netscape)
  214  , m_nextPrint(time(NULL)/60*60+60)
  215  , m_useLMTP(useLMTP)
  216 {
  217   go(NULL, processes);
  218 }
  219 
  220 smtp::smtp(int threadNum, const smtp *parent)
  221  : tcp(threadNum, parent)
  222  , m_ul(parent->m_ul)
  223  , m_senderList(parent->m_senderList)
  224  , m_minMsgSize(parent->m_minMsgSize)
  225  , m_maxMsgSize(parent->m_maxMsgSize)
  226  , m_data(parent->m_data)
  227  , m_msgsPerConnection(parent->m_msgsPerConnection)
  228  , m_res(parent->m_res)
  229  , m_netscape(parent->m_netscape)
  230  , m_nextPrint(0)
  231  , m_useLMTP(parent->m_useLMTP)
  232 {
  233 }
  234 
  235 smtp::~smtp()
  236 {
  237   if(getThreadNum() < 1)
  238     delete m_data;
  239 }
  240 
  241 void smtp::sentData(int bytes)
  242 {
  243   m_res->dataBytes(bytes);
  244 }
  245 
  246 void smtp::receivedData(int)
  247 {
  248 }
  249 
  250 void smtp::error()
  251 {
  252   m_res->error();
  253   disconnect();
  254 }
  255 
  256 int smtp::Connect()
  257 {
  258   int rc = tcp::Connect();
  259   if(rc)
  260     return rc;
  261   m_res->connection();
  262   rc = readCommandResp();
  263   if(rc)
  264     return rc;
  265   const string *mailName = m_data->getMailName(m_connectionLocalAddr);
  266   if(m_useLMTP)
  267     m_helo = string("LHLO ") + *mailName + "\r\n";
  268   else
  269     m_helo = string("EHLO ") + *mailName + "\r\n";
  270   rc = sendCommandString(m_helo);
  271   if(rc)
  272     return rc;
  273   return 0;
  274 }
  275 
  276 int smtp::disconnect()
  277 {
  278   int rc = sendCommandString(m_data->quit());
  279   rc |= tcp::disconnect();
  280   return rc;
  281 }
  282 
  283 int smtp::sendMsg()
  284 {
  285   int rc;
  286   int size = 0;
  287   if(m_maxMsgSize > m_minMsgSize)
  288     size = random() % (m_maxMsgSize - m_minMsgSize) + m_minMsgSize;
  289   else
  290     size = m_maxMsgSize;
  291   m_md5.init();
  292   string logData;
  293   bool logAll = false;
  294   if(m_log && m_log->verbose())
  295     logAll = true;
  296 
  297   char aByte;
  298   rc = Read(&aByte, 1, 0);
  299   if(rc != 1)
  300     return 1;
  301 
  302   string sender = m_senderList->randomUser();
  303   string from = string("<") + sender + '>';
  304   string to = string("<") + m_ul.randomUser() + '>';
  305   rc = sendCommandString(string("MAIL FROM: ") + from + "\r\n");
  306   if(rc)
  307     return rc;
  308   rc = sendCommandString(string("RCPT TO: ") + to + "\r\n");
  309   if(rc)
  310     return rc;
  311   rc = sendCommandString("DATA\r\n");
  312   if(rc)
  313     return rc;
  314   string subject = string("Subject: ");
  315   if(m_netscape == eWONT)
  316     subject += "N";
  317   else if(m_netscape == eMUST)
  318     subject += " ";
  319   char subj_buf[61];
  320   // random string from 2 to buffer len
  321   int subj_len = random() % (sizeof(subj_buf) - 3) + 2;
  322   m_data->randomString(subj_buf, subj_len);
  323   subj_buf[subj_len] = 0;
  324   subject += subj_buf;
  325   char date[34];
  326   m_data->date(date);
  327   string msgId = m_data->msgId(from.c_str(), getThreadNum());
  328   string str = string("From: ") + from + "\r\nTo: " + to + "\r\n"
  329                 + subject + "Date: " + date + "Message-Id: " + msgId;
  330   m_md5.addData(str);
  331 
  332   char *sendbuf = (char *)malloc(size + 1);
  333   m_data->randomBuf(sendbuf, size);
  334   m_md5.addData(sendbuf, size);
  335   string sum = m_md5.getSum();
  336   str += "X-PostalHash: " + sum + m_data->postalMsg();
  337   rc = sendString(str);
  338   if(rc)
  339   {
  340     free(sendbuf);
  341     return rc;
  342   }
  343   if(logAll)
  344     logData = str;
  345 
  346   rc = sendData(sendbuf, size);
  347   if(rc)
  348     return rc;
  349   if(logAll)
  350     logData += sendbuf;
  351   free(sendbuf);
  352   str = ".\r\n";
  353   rc = sendCommandString(str);
  354   if(rc)
  355     return rc;
  356   m_res->message();
  357   if(logAll)
  358   {
  359     logData += str;
  360     m_log->Write(logData);
  361   }
  362   else if(m_log)
  363   {
  364     sum += " " + from + " " + to + "\n";
  365     m_log->Write(sum);
  366   }
  367   return 0;
  368 }
  369 
  370 ERROR_TYPE smtp::readCommandResp()
  371 {
  372   char recvBuf[1024];
  373   do
  374   {
  375     int rc = readLine(recvBuf, sizeof(recvBuf));
  376     if(rc < 0)
  377       return ERROR_TYPE(rc);
  378     if(recvBuf[0] != '2' && recvBuf[0] != '3')
  379     {
  380       fprintf(stderr, "Server error:%s.\n", recvBuf);
  381       error();
  382       return eServer;
  383     }
  384 #ifdef USE_SSL
  385     if(!m_canTLS)
  386     {
  387       if(!strncmp("250-STARTTLS", recvBuf, 12)
  388          || !strncmp("250 STARTTLS", recvBuf, 12))
  389       {
  390         m_canTLS = true;
  391       }
  392     }
  393 #endif
  394   }
  395   while(recvBuf[3] == '-');
  396   return eNoError;
  397 }
  398 
  399 int smtp::pollRead()
  400 {
  401   m_data->setRand(RAND_TIME);
  402   if(time(NULL) >= m_nextPrint)
  403   {
  404     m_res->print();
  405     m_nextPrint += 60;
  406   }
  407   return 0;
  408 }
  409 
  410 int smtp::WriteWork(PVOID buf, int size, int timeout)
  411 {
  412   int t1 = time(NULL);
  413   if(t1 + timeout > m_nextPrint)
  414     timeout = m_nextPrint - t1;
  415   if(timeout < 0)
  416     timeout = 0;
  417   int rc = Write(buf, size, timeout);
  418   int t2 = time(NULL);
  419   if(t2 < t1 + timeout)
  420   {
  421     struct timespec req;
  422     req.tv_sec = t1 + timeout - t2;
  423     req.tv_nsec = 0;
  424     nanosleep(&req, NULL);
  425   }
  426   return rc;
  427 }