"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 }