Postfix3.3.1
smtp-source.c
[詳解]
1 /*++
2 /* NAME
3 /* smtp-source 1
4 /* SUMMARY
5 /* parallelized SMTP/LMTP test generator
6 /* SYNOPSIS
7 /* .fi
8 /* \fBsmtp-source\fR [\fIoptions\fR] [\fBinet:\fR]\fIhost\fR[:\fIport\fR]
9 /*
10 /* \fBsmtp-source\fR [\fIoptions\fR] \fBunix:\fIpathname\fR
11 /* DESCRIPTION
12 /* \fBsmtp-source\fR connects to the named \fIhost\fR and TCP \fIport\fR
13 /* (default: port 25)
14 /* and sends one or more messages to it, either sequentially
15 /* or in parallel. The program speaks either SMTP (default) or
16 /* LMTP.
17 /* Connections can be made to UNIX-domain and IPv4 or IPv6 servers.
18 /* IPv4 and IPv6 are the default.
19 /*
20 /* Note: this is an unsupported test program. No attempt is made
21 /* to maintain compatibility between successive versions.
22 /*
23 /* Arguments:
24 /* .IP \fB-4\fR
25 /* Connect to the server with IPv4. This option has no effect when
26 /* Postfix is built without IPv6 support.
27 /* .IP \fB-6\fR
28 /* Connect to the server with IPv6. This option is not available when
29 /* Postfix is built without IPv6 support.
30 /* .IP "\fB-A\fR"
31 /* Don't abort when the server sends something other than the
32 /* expected positive reply code.
33 /* .IP \fB-c\fR
34 /* Display a running counter that is incremented each time
35 /* an SMTP DATA command completes.
36 /* .IP "\fB-C \fIcount\fR"
37 /* When a host sends RESET instead of SYN|ACK, try \fIcount\fR times
38 /* before giving up. The default count is 1. Specify a larger count in
39 /* order to work around a problem with TCP/IP stacks that send RESET
40 /* when the listen queue is full.
41 /* .IP \fB-d\fR
42 /* Don't disconnect after sending a message; send the next
43 /* message over the same connection.
44 /* .IP "\fB-f \fIfrom\fR"
45 /* Use the specified sender address (default: <foo@myhostname>).
46 /* .IP "\fB-F \fIfile\fR"
47 /* Send the pre-formatted message header and body in the
48 /* specified \fIfile\fR, while prepending '.' before lines that
49 /* begin with '.', and while appending CRLF after each line.
50 /* .IP "\fB-l \fIlength\fR"
51 /* Send \fIlength\fR bytes as message payload. The length does not
52 /* include message headers.
53 /* .IP \fB-L\fR
54 /* Speak LMTP rather than SMTP.
55 /* .IP "\fB-m \fImessage_count\fR"
56 /* Send the specified number of messages (default: 1).
57 /* .IP "\fB-M \fImyhostname\fR"
58 /* Use the specified hostname or [address] in the HELO command
59 /* and in the default sender and recipient addresses, instead
60 /* of the machine hostname.
61 /* .IP "\fB-N\fR"
62 /* Prepend a non-repeating sequence number to each recipient
63 /* address. This avoids the artificial 100% hit rate in the
64 /* resolve and rewrite client caches and exercises the
65 /* trivial-rewrite daemon, better approximating Postfix
66 /* performance under real-life work-loads.
67 /* .IP \fB-o\fR
68 /* Old mode: don't send HELO, and don't send message headers.
69 /* .IP "\fB-r \fIrecipient_count\fR"
70 /* Send the specified number of recipients per transaction (default: 1).
71 /* Recipient names are generated by prepending a number to the
72 /* recipient address.
73 /* .IP "\fB-R \fIinterval\fR"
74 /* Wait for a random period of time 0 <= n <= interval between messages.
75 /* Suspending one thread does not affect other delivery threads.
76 /* .IP "\fB-s \fIsession_count\fR"
77 /* Run the specified number of SMTP sessions in parallel (default: 1).
78 /* .IP "\fB-S \fIsubject\fR"
79 /* Send mail with the named subject line (default: none).
80 /* .IP "\fB-t \fIto\fR"
81 /* Use the specified recipient address (default: <foo@myhostname>).
82 /* .IP "\fB-T \fIwindowsize\fR"
83 /* Override the default TCP window size. To work around
84 /* broken TCP window scaling implementations, specify a
85 /* value > 0 and < 65536.
86 /* .IP \fB-v\fR
87 /* Make the program more verbose, for debugging purposes.
88 /* .IP "\fB-w \fIinterval\fR"
89 /* Wait a fixed time between messages.
90 /* Suspending one thread does not affect other delivery threads.
91 /* .IP [\fBinet:\fR]\fIhost\fR[:\fIport\fR]
92 /* Connect via TCP to host \fIhost\fR, port \fIport\fR. The default
93 /* port is \fBsmtp\fR.
94 /* .IP \fBunix:\fIpathname\fR
95 /* Connect to the UNIX-domain socket at \fIpathname\fR.
96 /* BUGS
97 /* No SMTP command pipelining support.
98 /* SEE ALSO
99 /* smtp-sink(1), SMTP/LMTP message dump
100 /* LICENSE
101 /* .ad
102 /* .fi
103 /* The Secure Mailer license must be distributed with this software.
104 /* AUTHOR(S)
105 /* Wietse Venema
106 /* IBM T.J. Watson Research
107 /* P.O. Box 704
108 /* Yorktown Heights, NY 10598, USA
109 /*
110 /* Wietse Venema
111 /* Google, Inc.
112 /* 111 8th Avenue
113 /* New York, NY 10011, USA
114 /*--*/
115 
116 /* System library. */
117 
118 #include <sys_defs.h>
119 #include <sys/socket.h>
120 #include <sys/wait.h>
121 #include <netinet/in.h>
122 #include <sys/un.h>
123 #include <stdarg.h>
124 #include <string.h>
125 #include <ctype.h>
126 #include <stdlib.h>
127 #include <unistd.h>
128 #include <signal.h>
129 #include <fcntl.h>
130 #include <errno.h>
131 
132 /* Utility library. */
133 
134 #include <msg.h>
135 #include <msg_vstream.h>
136 #include <vstring.h>
137 #include <vstream.h>
138 #include <vstring_vstream.h>
139 #include <get_hostname.h>
140 #include <split_at.h>
141 #include <connect.h>
142 #include <mymalloc.h>
143 #include <events.h>
144 #include <iostuff.h>
145 #include <sane_connect.h>
146 #include <host_port.h>
147 #include <myaddrinfo.h>
148 #include <inet_proto.h>
149 #include <valid_hostname.h>
150 #include <valid_mailhost_addr.h>
151 #include <compat_va_copy.h>
152 
153 /* Global library. */
154 
155 #include <smtp_stream.h>
156 #include <mail_date.h>
157 #include <mail_version.h>
158 
159 /* Application-specific. */
160 
161  /*
162  * Per-session data structure with state.
163  *
164  * This software can maintain multiple parallel connections to the same SMTP
165  * server. However, it makes no more than one connection request at a time
166  * to avoid overwhelming the server with SYN packets and having to back off.
167  * Back-off would screw up the benchmark. Pending connection requests are
168  * kept in a linear list.
169  */
170 typedef struct SESSION {
171  int xfer_count; /* # of xfers in session */
172  int rcpt_done; /* # of recipients done */
173  int rcpt_count; /* # of recipients to go */
174  int rcpt_accepted; /* # of recipients accepted */
175  VSTREAM *stream; /* open connection */
176  int connect_count; /* # of connect()s to retry */
177  struct SESSION *next; /* connect() queue linkage */
178 } SESSION;
179 
180 static SESSION *last_session; /* connect() queue tail */
181 
182  /*
183  * Structure with broken-up SMTP server response.
184  */
185 typedef struct { /* server response */
186  int code; /* status */
187  char *str; /* text */
188  VSTRING *buf; /* origin of text */
189 } RESPONSE;
190 
191 static VSTRING *buffer;
192 static int var_line_limit = 10240;
193 static int var_timeout = 300;
194 static const char *var_myhostname;
195 static int session_count;
196 static int message_count = 1;
197 static struct sockaddr_storage ss;
198 
199 #undef sun
200 static struct sockaddr_un sun;
201 static struct sockaddr *sa;
202 static int sa_length;
203 static int recipients = 1;
204 static char *defaddr;
205 static char *recipient;
206 static char *sender;
207 static char *message_data;
208 static int message_length;
209 static int disconnect = 1;
210 static int count = 0;
211 static int counter = 0;
212 static int send_helo_first = 1;
213 static int send_headers = 1;
214 static int connect_count = 1;
215 static int random_delay = 0;
216 static int fixed_delay = 0;
217 static int talk_lmtp = 0;
218 static char *subject = 0;
219 static int number_rcpts = 0;
220 static int allow_reject = 0;
221 
222 static void enqueue_connect(SESSION *);
223 static void start_connect(SESSION *);
224 static void connect_done(int, void *);
225 static void read_banner(int, void *);
226 static void send_helo(SESSION *);
227 static void helo_done(int, void *);
228 static void send_mail(SESSION *);
229 static void mail_done(int, void *);
230 static void send_rcpt(int, void *);
231 static void rcpt_done(int, void *);
232 static void send_data(int, void *);
233 static void data_done(int, void *);
234 static void dot_done(int, void *);
235 static void send_rset(int, void *);
236 static void rset_done(int, void *);
237 static void send_quit(SESSION *);
238 static void quit_done(int, void *);
239 static void close_session(SESSION *);
240 
241 /* random_interval - generate a random value in 0 .. (small) interval */
242 
243 static int random_interval(int interval)
244 {
245  return (rand() % (interval + 1));
246 }
247 
248 /* command - send an SMTP command */
249 
250 static void command(VSTREAM *stream, char *fmt,...)
251 {
252  va_list ap;
253 
254  va_start(ap, fmt);
255 
256  /*
257  * Optionally, log the command before actually sending, so we can see
258  * what the program is trying to do.
259  */
260  if (msg_verbose) {
261  va_list ap2;
262 
263  VA_COPY(ap2, ap);
264  vmsg_info(fmt, ap2);
265  va_end(ap2);
266  }
267  smtp_vprintf(stream, fmt, ap);
268  va_end(ap);
269  smtp_flush(stream);
270 }
271 
272 /* socket_error - look up and reset the last socket error */
273 
274 static int socket_error(int sock)
275 {
276  int error;
277  SOCKOPT_SIZE error_len;
278 
279  /*
280  * Some Solaris 2 versions have getsockopt() itself return the error,
281  * instead of returning it via the parameter list.
282  */
283  error = 0;
284  error_len = sizeof(error);
285  if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *) &error, &error_len) < 0)
286  return (-1);
287  if (error) {
288  errno = error;
289  return (-1);
290  }
291 
292  /*
293  * No problems.
294  */
295  return (0);
296 }
297 
298 /* response - read and process SMTP server response */
299 
300 static RESPONSE *response(VSTREAM *stream, VSTRING *buf)
301 {
302  static RESPONSE rdata;
303  int more;
304  char *cp;
305 
306  /*
307  * Initialize the response data buffer. Defend against a denial of
308  * service attack by limiting the amount of multi-line text that we are
309  * willing to store.
310  */
311  if (rdata.buf == 0) {
312  rdata.buf = vstring_alloc(100);
313  vstring_ctl(rdata.buf, CA_VSTRING_CTL_MAXLEN(var_line_limit), 0);
314  }
315 
316  /*
317  * Censor out non-printable characters in server responses. Concatenate
318  * multi-line server responses. Separate the status code from the text.
319  * Leave further parsing up to the application.
320  */
321 #define BUF ((char *) vstring_str(buf))
322  VSTRING_RESET(rdata.buf);
323  for (;;) {
324  smtp_get(buf, stream, var_line_limit, SMTP_GET_FLAG_SKIP);
325  for (cp = BUF; *cp != 0; cp++)
326  if (!ISPRINT(*cp) && !ISSPACE(*cp))
327  *cp = '?';
328  cp = BUF;
329  if (msg_verbose)
330  msg_info("<<< %s", cp);
331  while (ISDIGIT(*cp))
332  cp++;
333  rdata.code = (cp - BUF == 3 ? atoi(BUF) : 0);
334  if ((more = (*cp == '-')) != 0)
335  cp++;
336  while (ISSPACE(*cp))
337  cp++;
338  vstring_strcat(rdata.buf, cp);
339  if (more == 0)
340  break;
341  VSTRING_ADDCH(rdata.buf, '\n');
342  }
343  VSTRING_TERMINATE(rdata.buf);
344  rdata.str = vstring_str(rdata.buf);
345  return (&rdata);
346 }
347 
348 /* exception_text - translate exceptions from the smtp_stream module */
349 
350 static char *exception_text(int except)
351 {
352  switch (except) {
353  case SMTP_ERR_EOF:
354  return ("lost connection");
355  case SMTP_ERR_TIME:
356  return ("timeout");
357  default:
358  msg_panic("exception_text: unknown exception %d", except);
359  }
360  /* NOTREACHED */
361 }
362 
363 /* startup - connect to server but do not wait */
364 
365 static void startup(SESSION *session)
366 {
367  if (message_count-- <= 0) {
368  myfree((void *) session);
369  session_count--;
370  return;
371  }
372  if (session->stream == 0) {
373  enqueue_connect(session);
374  } else {
375  send_mail(session);
376  }
377 }
378 
379 /* start_event - invoke startup from timer context */
380 
381 static void start_event(int unused_event, void *context)
382 {
383  SESSION *session = (SESSION *) context;
384 
385  startup(session);
386 }
387 
388 /* start_another - start another session */
389 
390 static void start_another(SESSION *session)
391 {
392  if (random_delay > 0) {
393  event_request_timer(start_event, (void *) session,
394  random_interval(random_delay));
395  } else if (fixed_delay > 0) {
396  event_request_timer(start_event, (void *) session, fixed_delay);
397  } else {
398  startup(session);
399  }
400 }
401 
402 /* enqueue_connect - queue a connection request */
403 
404 static void enqueue_connect(SESSION *session)
405 {
406  session->next = 0;
407  if (last_session == 0) {
408  last_session = session;
409  start_connect(session);
410  } else {
411  last_session->next = session;
412  last_session = session;
413  }
414 }
415 
416 /* dequeue_connect - connection request completed */
417 
418 static void dequeue_connect(SESSION *session)
419 {
420  if (session == last_session) {
421  if (session->next != 0)
422  msg_panic("dequeue_connect: queue ends after last");
423  last_session = 0;
424  } else {
425  if (session->next == 0)
426  msg_panic("dequeue_connect: queue ends before last");
427  start_connect(session->next);
428  }
429 }
430 
431 /* fail_connect - handle failed startup */
432 
433 static void fail_connect(SESSION *session)
434 {
435  if (session->connect_count-- == 1)
436  msg_fatal("connect: %m");
437  msg_warn("connect: %m");
439  vstream_fclose(session->stream);
440  session->stream = 0;
441 #ifdef MISSING_USLEEP
442  doze(10);
443 #else
444  usleep(10);
445 #endif
446  start_connect(session);
447 }
448 
449 /* start_connect - start TCP handshake */
450 
451 static void start_connect(SESSION *session)
452 {
453  int fd;
454  struct linger linger;
455 
456  /*
457  * Some systems don't set the socket error when connect() fails early
458  * (loopback) so we must deal with the error immediately, rather than
459  * retrieving it later with getsockopt(). We can't use MSG_PEEK to
460  * distinguish between server disconnect and connection refused.
461  */
462  if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
463  msg_fatal("socket: %m");
464  (void) non_blocking(fd, NON_BLOCKING);
465  linger.l_onoff = 1;
466  linger.l_linger = 0;
467  if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *) &linger,
468  sizeof(linger)) < 0)
469  msg_warn("setsockopt SO_LINGER %d: %m", linger.l_linger);
470  session->stream = vstream_fdopen(fd, O_RDWR);
471  event_enable_write(fd, connect_done, (void *) session);
472  smtp_timeout_setup(session->stream, var_timeout);
473  if (inet_windowsize > 0)
475  if (sane_connect(fd, sa, sa_length) < 0 && errno != EINPROGRESS)
476  fail_connect(session);
477 }
478 
479 /* connect_done - send message sender info */
480 
481 static void connect_done(int unused_event, void *context)
482 {
483  SESSION *session = (SESSION *) context;
484  int fd = vstream_fileno(session->stream);
485 
486  /*
487  * Try again after some delay when the connection failed, in case they
488  * run a Mickey Mouse protocol stack.
489  */
490  if (socket_error(fd) < 0) {
491  fail_connect(session);
492  } else {
493  non_blocking(fd, BLOCKING);
494  /* Disable write events. */
496  event_enable_read(fd, read_banner, (void *) session);
497  dequeue_connect(session);
498  /* Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE. */
499  if (sa->sa_family == AF_INET
500 #ifdef AF_INET6
501  || sa->sa_family == AF_INET6
502 #endif
503  )
504  vstream_tweak_tcp(session->stream);
505  }
506 }
507 
508 /* read_banner - receive SMTP server greeting */
509 
510 static void read_banner(int unused_event, void *context)
511 {
512  SESSION *session = (SESSION *) context;
513  RESPONSE *resp;
514  int except;
515 
516  /*
517  * Prepare for disaster.
518  */
519  if ((except = vstream_setjmp(session->stream)) != 0)
520  msg_fatal("%s while reading server greeting", exception_text(except));
521 
522  /*
523  * Read and parse the server's SMTP greeting banner.
524  */
525  if (((resp = response(session->stream, buffer))->code / 100) == 2) {
526  /* void */ ;
527  } else if (allow_reject) {
528  msg_warn("rejected at server banner: %d %s", resp->code, resp->str);
529  } else {
530  msg_fatal("rejected at server banner: %d %s", resp->code, resp->str);
531  }
532 
533  /*
534  * Send helo or send the envelope sender address.
535  */
536  if (send_helo_first)
537  send_helo(session);
538  else
539  send_mail(session);
540 }
541 
542 /* send_helo - send hostname */
543 
544 static void send_helo(SESSION *session)
545 {
546  int except;
547  const char *NOCLOBBER protocol = (talk_lmtp ? "LHLO" : "HELO");
548 
549  /*
550  * Send the standard greeting with our hostname
551  */
552  if ((except = vstream_setjmp(session->stream)) != 0)
553  msg_fatal("%s while sending %s", exception_text(except), protocol);
554 
555  command(session->stream, "%s %s", protocol, var_myhostname);
556 
557  /*
558  * Prepare for the next event.
559  */
560  event_enable_read(vstream_fileno(session->stream), helo_done, (void *) session);
561 }
562 
563 /* helo_done - handle HELO response */
564 
565 static void helo_done(int unused_event, void *context)
566 {
567  SESSION *session = (SESSION *) context;
568  RESPONSE *resp;
569  int except;
570  const char *protocol = (talk_lmtp ? "LHLO" : "HELO");
571 
572  /*
573  * Get response to HELO command.
574  */
575  if ((except = vstream_setjmp(session->stream)) != 0)
576  msg_fatal("%s while sending %s", exception_text(except), protocol);
577 
578  if ((resp = response(session->stream, buffer))->code / 100 == 2) {
579  /* void */ ;
580  } else if (allow_reject) {
581  msg_warn("%s rejected: %d %s", protocol, resp->code, resp->str);
582  if (resp->code == 421 || resp->code == 521) {
583  close_session(session);
584  return;
585  }
586  } else {
587  msg_fatal("%s rejected: %d %s", protocol, resp->code, resp->str);
588  }
589 
590  send_mail(session);
591 }
592 
593 /* send_mail - send envelope sender */
594 
595 static void send_mail(SESSION *session)
596 {
597  int except;
598 
599  /*
600  * Send the envelope sender address.
601  */
602  if ((except = vstream_setjmp(session->stream)) != 0)
603  msg_fatal("%s while sending sender", exception_text(except));
604 
605  command(session->stream, "MAIL FROM:<%s>", sender);
606 
607  /*
608  * Prepare for the next event.
609  */
610  event_enable_read(vstream_fileno(session->stream), mail_done, (void *) session);
611 }
612 
613 /* mail_done - handle MAIL response */
614 
615 static void mail_done(int unused, void *context)
616 {
617  SESSION *session = (SESSION *) context;
618  RESPONSE *resp;
619  int except;
620 
621  /*
622  * Get response to MAIL command.
623  */
624  if ((except = vstream_setjmp(session->stream)) != 0)
625  msg_fatal("%s while sending sender", exception_text(except));
626 
627  if ((resp = response(session->stream, buffer))->code / 100 == 2) {
628  session->rcpt_count = recipients;
629  session->rcpt_done = 0;
630  session->rcpt_accepted = 0;
631  send_rcpt(unused, context);
632  } else if (allow_reject) {
633  msg_warn("sender rejected: %d %s", resp->code, resp->str);
634  if (resp->code == 421 || resp->code == 521) {
635  close_session(session);
636  return;
637  }
638  send_rset(unused, context);
639  } else {
640  msg_fatal("sender rejected: %d %s", resp->code, resp->str);
641  }
642 }
643 
644 /* send_rcpt - send recipient address */
645 
646 static void send_rcpt(int unused_event, void *context)
647 {
648  SESSION *session = (SESSION *) context;
649  int except;
650 
651  /*
652  * Send envelope recipient address.
653  */
654  if ((except = vstream_setjmp(session->stream)) != 0)
655  msg_fatal("%s while sending recipient", exception_text(except));
656 
657  if (session->rcpt_count > 1 || number_rcpts > 0)
658  command(session->stream, "RCPT TO:<%d%s>",
659  number_rcpts ? number_rcpts++ : session->rcpt_count,
660  recipient);
661  else
662  command(session->stream, "RCPT TO:<%s>", recipient);
663  session->rcpt_count--;
664  session->rcpt_done++;
665 
666  /*
667  * Prepare for the next event.
668  */
669  event_enable_read(vstream_fileno(session->stream), rcpt_done, (void *) session);
670 }
671 
672 /* rcpt_done - handle RCPT completion */
673 
674 static void rcpt_done(int unused, void *context)
675 {
676  SESSION *session = (SESSION *) context;
677  RESPONSE *resp;
678  int except;
679 
680  /*
681  * Get response to RCPT command.
682  */
683  if ((except = vstream_setjmp(session->stream)) != 0)
684  msg_fatal("%s while sending recipient", exception_text(except));
685 
686  if ((resp = response(session->stream, buffer))->code / 100 == 2) {
687  session->rcpt_accepted++;
688  } else if (allow_reject) {
689  msg_warn("recipient rejected: %d %s", resp->code, resp->str);
690  if (resp->code == 421 || resp->code == 521) {
691  close_session(session);
692  return;
693  }
694  } else {
695  msg_fatal("recipient rejected: %d %s", resp->code, resp->str);
696  }
697 
698  /*
699  * Send another RCPT command or send DATA.
700  */
701  if (session->rcpt_count > 0)
702  send_rcpt(unused, context);
703  else if (session->rcpt_accepted > 0)
704  send_data(unused, context);
705  else
706  send_rset(unused, context);
707 }
708 
709 /* send_data - send DATA command */
710 
711 static void send_data(int unused_event, void *context)
712 {
713  SESSION *session = (SESSION *) context;
714  int except;
715 
716  /*
717  * Request data transmission.
718  */
719  if ((except = vstream_setjmp(session->stream)) != 0)
720  msg_fatal("%s while sending DATA command", exception_text(except));
721  command(session->stream, "DATA");
722 
723  /*
724  * Prepare for the next event.
725  */
726  event_enable_read(vstream_fileno(session->stream), data_done, (void *) session);
727 }
728 
729 /* data_done - send message content */
730 
731 static void data_done(int unused, void *context)
732 {
733  SESSION *session = (SESSION *) context;
734  RESPONSE *resp;
735  int except;
736  static const char *mydate;
737  static int mypid;
738 
739  /*
740  * Get response to DATA command.
741  */
742  if ((except = vstream_setjmp(session->stream)) != 0)
743  msg_fatal("%s while sending DATA command", exception_text(except));
744  if ((resp = response(session->stream, buffer))->code == 354) {
745  /* see below */ ;
746  } else if (allow_reject) {
747  msg_warn("data rejected: %d %s", resp->code, resp->str);
748  if (resp->code == 421 || resp->code == 521) {
749  close_session(session);
750  return;
751  }
752  send_rset(unused, context);
753  return;
754  } else {
755  msg_fatal("data rejected: %d %s", resp->code, resp->str);
756  }
757 
758  /*
759  * Send basic header to keep mailers that bother to examine them happy.
760  */
761  if (send_headers) {
762  if (mydate == 0) {
763  mydate = mail_date(time((time_t *) 0));
764  mypid = getpid();
765  }
766  smtp_printf(session->stream, "From: <%s>", sender);
767  smtp_printf(session->stream, "To: <%s>", recipient);
768  smtp_printf(session->stream, "Date: %s", mydate);
769  smtp_printf(session->stream, "Message-Id: <%04x.%04x.%04x@%s>",
770  mypid, vstream_fileno(session->stream), message_count, var_myhostname);
771  if (subject)
772  smtp_printf(session->stream, "Subject: %s", subject);
773  smtp_fputs("", 0, session->stream);
774  }
775 
776  /*
777  * Send some garbage.
778  */
779  if ((except = vstream_setjmp(session->stream)) != 0)
780  msg_fatal("%s while sending message", exception_text(except));
781  if (message_length == 0) {
782  smtp_fputs("La de da de da 1.", 17, session->stream);
783  smtp_fputs("La de da de da 2.", 17, session->stream);
784  smtp_fputs("La de da de da 3.", 17, session->stream);
785  smtp_fputs("La de da de da 4.", 17, session->stream);
786  } else {
787 
788  /*
789  * XXX This may cause the process to block with message content
790  * larger than VSTREAM_BUFIZ bytes.
791  */
792  smtp_fputs(message_data, message_length, session->stream);
793  }
794 
795  /*
796  * Send end of message and process the server response.
797  */
798  command(session->stream, ".");
799 
800  /*
801  * Update the running counter.
802  */
803  if (count) {
804  counter++;
805  vstream_printf("%d\r", counter);
807  }
808 
809  /*
810  * Prepare for the next event.
811  */
812  event_enable_read(vstream_fileno(session->stream), dot_done, (void *) session);
813 }
814 
815 /* dot_done - send QUIT or start another transaction */
816 
817 static void dot_done(int unused_event, void *context)
818 {
819  SESSION *session = (SESSION *) context;
820  RESPONSE *resp;
821  int except;
822 
823  /*
824  * Get response to "." command.
825  */
826  if ((except = vstream_setjmp(session->stream)) != 0)
827  msg_fatal("%s while sending message", exception_text(except));
828  do { /* XXX this could block */
829  if ((resp = response(session->stream, buffer))->code / 100 == 2) {
830  /* void */ ;
831  } else if (allow_reject) {
832  msg_warn("end of data rejected: %d %s", resp->code, resp->str);
833  if (resp->code == 421 || resp->code == 521) {
834  close_session(session);
835  return;
836  }
837  } else {
838  msg_fatal("end of data rejected: %d %s", resp->code, resp->str);
839  }
840  } while (talk_lmtp && --session->rcpt_done > 0);
841  session->xfer_count++;
842 
843  /*
844  * Say goodbye or send the next message.
845  */
846  if (disconnect || message_count < 1) {
847  send_quit(session);
848  } else {
850  start_another(session);
851  }
852 }
853 
854 /* send_rset - send RSET command */
855 
856 static void send_rset(int unused_event, void *context)
857 {
858  SESSION *session = (SESSION *) context;
859 
860  command(session->stream, "RSET");
861  event_enable_read(vstream_fileno(session->stream), rset_done, (void *) session);
862 }
863 
864 /* rset_done - handle RSET reply */
865 
866 static void rset_done(int unused_event, void *context)
867 {
868  SESSION *session = (SESSION *) context;
869  RESPONSE *resp;
870  int except;
871 
872  /*
873  * Get response to RSET command.
874  */
875  if ((except = vstream_setjmp(session->stream)) != 0)
876  msg_fatal("%s while sending message", exception_text(except));
877  if ((resp = response(session->stream, buffer))->code / 100 == 2) {
878  /* void */
879  } else if (allow_reject) {
880  msg_warn("rset rejected: %d %s", resp->code, resp->str);
881  if (resp->code == 421 || resp->code == 521) {
882  close_session(session);
883  return;
884  }
885  } else {
886  msg_fatal("rset rejected: %d %s", resp->code, resp->str);
887  }
888 
889  /*
890  * Say goodbye or send the next message.
891  */
892  if (disconnect || message_count < 1) {
893  send_quit(session);
894  } else {
896  start_another(session);
897  }
898 }
899 
900 /* send_quit - send QUIT command */
901 
902 static void send_quit(SESSION *session)
903 {
904  command(session->stream, "QUIT");
905  event_enable_read(vstream_fileno(session->stream), quit_done, (void *) session);
906 }
907 
908 /* quit_done - disconnect */
909 
910 static void quit_done(int unused_event, void *context)
911 {
912  SESSION *session = (SESSION *) context;
913 
914  (void) response(session->stream, buffer);
916  vstream_fclose(session->stream);
917  session->stream = 0;
918  start_another(session);
919 }
920 
921 /* close_session - disconnect, for example after 421 or 521 reply */
922 
923 static void close_session(SESSION *session)
924 {
926  vstream_fclose(session->stream);
927  session->stream = 0;
928  start_another(session);
929 }
930 
931 /* usage - explain */
932 
933 static void usage(char *myname)
934 {
935  msg_fatal("usage: %s -cdLNov -s sess -l msglen -m msgs -C count -M myhostname -f from -t to -r rcptcount -R delay -w delay host[:port]", myname);
936 }
937 
939 
940 /* main - parse JCL and start the machine */
941 
942 int main(int argc, char **argv)
943 {
944  SESSION *session;
945  char *host;
946  char *port;
947  char *path;
948  int path_len;
949  int sessions = 1;
950  int ch;
951  int i;
952  char *buf;
953  const char *parse_err;
954  struct addrinfo *res;
955  int aierr;
956  const char *protocols = INET_PROTO_NAME_ALL;
957  char *message_file = 0;
958 
959  /*
960  * Fingerprint executables and core dumps.
961  */
963 
964  signal(SIGPIPE, SIG_IGN);
965  msg_vstream_init(argv[0], VSTREAM_ERR);
966 
967  /*
968  * Parse JCL.
969  */
970  while ((ch = GETOPT(argc, argv, "46AcC:df:F:l:Lm:M:Nor:R:s:S:t:T:vw:")) > 0) {
971  switch (ch) {
972  case '4':
973  protocols = INET_PROTO_NAME_IPV4;
974  break;
975  case '6':
976  protocols = INET_PROTO_NAME_IPV6;
977  break;
978  case 'A':
979  allow_reject = 1;
980  break;
981  case 'c':
982  count++;
983  break;
984  case 'C':
985  if ((connect_count = atoi(optarg)) <= 0)
986  msg_fatal("bad connection count: %s", optarg);
987  break;
988  case 'd':
989  disconnect = 0;
990  break;
991  case 'f':
992  sender = optarg;
993  break;
994  case 'F':
995  if (message_file == 0 && message_length > 0)
996  msg_fatal("-l option cannot be used with -F");
997  message_file = optarg;
998  break;
999  case 'l':
1000  if (message_file != 0)
1001  msg_fatal("-l option cannot be used with -F");
1002  if ((message_length = atoi(optarg)) <= 0)
1003  msg_fatal("bad message length: %s", optarg);
1004  break;
1005  case 'L':
1006  talk_lmtp = 1;
1007  break;
1008  case 'm':
1009  if ((message_count = atoi(optarg)) <= 0)
1010  msg_fatal("bad message count: %s", optarg);
1011  break;
1012  case 'M':
1013  if (*optarg == '[') {
1014  if (!valid_mailhost_literal(optarg, DO_GRIPE))
1015  msg_fatal("bad address literal: %s", optarg);
1016  } else {
1017  if (!valid_hostname(optarg, DO_GRIPE))
1018  msg_fatal("bad hostname: %s", optarg);
1019  }
1020  var_myhostname = optarg;
1021  break;
1022  case 'N':
1023  number_rcpts = 1;
1024  break;
1025  case 'o':
1026  send_helo_first = 0;
1027  send_headers = 0;
1028  break;
1029  case 'r':
1030  if ((recipients = atoi(optarg)) <= 0)
1031  msg_fatal("bad recipient count: %s", optarg);
1032  break;
1033  case 'R':
1034  if (fixed_delay > 0)
1035  msg_fatal("do not use -w and -R options at the same time");
1036  if ((random_delay = atoi(optarg)) <= 0)
1037  msg_fatal("bad random delay: %s", optarg);
1038  break;
1039  case 's':
1040  if ((sessions = atoi(optarg)) <= 0)
1041  msg_fatal("bad session count: %s", optarg);
1042  break;
1043  case 'S':
1044  subject = optarg;
1045  break;
1046  case 't':
1047  recipient = optarg;
1048  break;
1049  case 'T':
1050  if ((inet_windowsize = atoi(optarg)) <= 0)
1051  msg_fatal("bad TCP window size: %s", optarg);
1052  break;
1053  case 'v':
1054  msg_verbose++;
1055  break;
1056  case 'w':
1057  if (random_delay > 0)
1058  msg_fatal("do not use -w and -R options at the same time");
1059  if ((fixed_delay = atoi(optarg)) <= 0)
1060  msg_fatal("bad fixed delay: %s", optarg);
1061  break;
1062  default:
1063  usage(argv[0]);
1064  }
1065  }
1066  if (argc - optind != 1)
1067  usage(argv[0]);
1068 
1069  if (random_delay > 0)
1070  srand(getpid());
1071 
1072  /*
1073  * Initialize the message content, SMTP encoded. smtp_fputs() will append
1074  * another \r\n but we don't care.
1075  */
1076  if (message_file != 0) {
1077  VSTREAM *fp;
1078  VSTRING *buf = vstring_alloc(100);
1079  VSTRING *msg = vstring_alloc(100);
1080 
1081  if ((fp = vstream_fopen(message_file, O_RDONLY, 0)) == 0)
1082  msg_fatal("open %s: %m", message_file);
1083  while (vstring_get_nonl(buf, fp) != VSTREAM_EOF) {
1084  if (*vstring_str(buf) == '.')
1085  VSTRING_ADDCH(msg, '.');
1086  vstring_memcat(msg, vstring_str(buf), VSTRING_LEN(buf));
1087  vstring_memcat(msg, "\r\n", 2);
1088  }
1089  if (vstream_ferror(fp))
1090  msg_fatal("read %s: %m", message_file);
1091  vstream_fclose(fp);
1092  vstring_free(buf);
1093  message_length = VSTRING_LEN(msg);
1094  message_data = vstring_export(msg);
1095  send_headers = 0;
1096  } else if (message_length > 0) {
1097  message_data = mymalloc(message_length);
1098  memset(message_data, 'X', message_length);
1099  for (i = 80; i < message_length; i += 80) {
1100  message_data[i - 80] = "0123456789"[(i / 80) % 10];
1101  message_data[i - 2] = '\r';
1102  message_data[i - 1] = '\n';
1103  }
1104  }
1105 
1106  /*
1107  * Translate endpoint address to internal form.
1108  */
1109  (void) inet_proto_init("protocols", protocols);
1110  if (strncmp(argv[optind], "unix:", 5) == 0) {
1111  path = argv[optind] + 5;
1112  path_len = strlen(path);
1113  if (path_len >= (int) sizeof(sun.sun_path))
1114  msg_fatal("unix-domain name too long: %s", path);
1115  memset((void *) &sun, 0, sizeof(sun));
1116  sun.sun_family = AF_UNIX;
1117 #ifdef HAS_SUN_LEN
1118  sun.sun_len = path_len + 1;
1119 #endif
1120  memcpy(sun.sun_path, path, path_len);
1121  sa = (struct sockaddr *) &sun;
1122  sa_length = sizeof(sun);
1123  } else {
1124  if (strncmp(argv[optind], "inet:", 5) == 0)
1125  argv[optind] += 5;
1126  buf = mystrdup(argv[optind]);
1127  if ((parse_err = host_port(buf, &host, (char *) 0, &port, "smtp")) != 0)
1128  msg_fatal("%s: %s", argv[optind], parse_err);
1129  if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res)) != 0)
1130  msg_fatal("%s: %s", argv[optind], MAI_STRERROR(aierr));
1131  myfree(buf);
1132  sa = (struct sockaddr *) &ss;
1133  if (res->ai_addrlen > sizeof(ss))
1134  msg_fatal("address length %d > buffer length %d",
1135  (int) res->ai_addrlen, (int) sizeof(ss));
1136  memcpy((void *) sa, res->ai_addr, res->ai_addrlen);
1137  sa_length = res->ai_addrlen;
1138 #ifdef HAS_SA_LEN
1139  sa->sa_len = sa_length;
1140 #endif
1141  freeaddrinfo(res);
1142  }
1143 
1144  /*
1145  * Make sure the SMTP server cannot run us out of memory by sending
1146  * never-ending lines of text.
1147  */
1148  if (buffer == 0) {
1149  buffer = vstring_alloc(100);
1151  }
1152 
1153  /*
1154  * Make sure we have sender and recipient addresses.
1155  */
1156  if (var_myhostname == 0)
1158  if (sender == 0 || recipient == 0) {
1159  vstring_sprintf(buffer, "foo@%s", var_myhostname);
1160  defaddr = mystrdup(vstring_str(buffer));
1161  if (sender == 0)
1162  sender = defaddr;
1163  if (recipient == 0)
1164  recipient = defaddr;
1165  }
1166 
1167  /*
1168  * Start sessions.
1169  */
1170  while (sessions-- > 0) {
1171  session = (SESSION *) mymalloc(sizeof(*session));
1172  session->stream = 0;
1173  session->xfer_count = 0;
1174  session->connect_count = connect_count;
1175  session->next = 0;
1176  session_count++;
1177  startup(session);
1178  }
1179  for (;;) {
1180  event_loop(-1);
1181  if (session_count <= 0 && message_count <= 0) {
1182  if (count) {
1183  VSTREAM_PUTC('\n', VSTREAM_OUT);
1185  }
1186  exit(0);
1187  }
1188  }
1189 }
int msg_verbose
Definition: msg.c:177
void event_enable_read(int fd, EVENT_NOTIFY_RDWR_FN callback, void *context)
Definition: events.c:729
#define VSTREAM_EOF
Definition: vstream.h:110
void myfree(void *ptr)
Definition: mymalloc.c:207
void freeaddrinfo(struct addrinfo *ai)
Definition: myaddrinfo.c:742
#define NOCLOBBER
Definition: sys_defs.h:1670
char * mystrdup(const char *str)
Definition: mymalloc.c:225
int vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
const char * mail_date(time_t when)
Definition: mail_date.c:54
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define vstring_str(vp)
Definition: vstring.h:71
#define VSTREAM_OUT
Definition: vstream.h:67
int sane_connect(int sock, struct sockaddr *sa, SOCKADDR_SIZE len)
Definition: sane_connect.c:44
#define SMTP_ERR_TIME
Definition: smtp_stream.h:31
INET_PROTO_INFO * inet_proto_init(const char *context, const char *protocols)
Definition: inet_proto.c:180
#define hostname_to_sockaddr(host, serv, sock, res)
Definition: myaddrinfo.h:171
#define CA_VSTRING_CTL_MAXLEN(val)
Definition: vstring.h:61
#define INET_PROTO_NAME_ALL
Definition: mail_params.h:992
int smtp_get(VSTRING *vp, VSTREAM *stream, ssize_t bound, int flags)
Definition: smtp_stream.c:305
void event_enable_write(int fd, EVENT_NOTIFY_RDWR_FN callback, void *context)
Definition: events.c:784
#define vstream_setjmp(stream)
Definition: vstream.h:248
int xfer_count
Definition: qmqp-source.c:132
#define VSTRING_LEN(vp)
Definition: vstring.h:72
void set_inet_windowsize(int sock, int windowsize)
#define VA_COPY(dest, src)
void vstring_ctl(VSTRING *vp,...)
Definition: vstring.c:390
VSTREAM * vstream_fopen(const char *path, int flags, mode_t mode)
Definition: vstream.c:1241
#define VSTRING_TERMINATE(vp)
Definition: vstring.h:74
int const char * fmt
int main(int argc, char **argv)
Definition: smtp-source.c:942
void smtp_vprintf(VSTREAM *stream, const char *fmt, va_list ap)
Definition: smtp_stream.c:249
int valid_hostname(const char *name, int gripe)
#define VSTRING_ADDCH(vp, ch)
Definition: vstring.h:81
#define SOCKOPT_SIZE
Definition: sys_defs.h:1415
#define SMTP_ERR_EOF
Definition: smtp_stream.h:30
int valid_mailhost_literal(const char *addr, int gripe)
#define ISDIGIT(c)
Definition: sys_defs.h:1748
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
void event_loop(int delay)
Definition: events.c:998
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
#define VSTRING_RESET(vp)
Definition: vstring.h:77
struct SESSION SESSION
int inet_windowsize
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define BUF
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
void smtp_fputs(const char *cp, ssize_t todo, VSTREAM *stream)
Definition: smtp_stream.c:383
#define smtp_timeout_setup(stream, timeout)
Definition: smtp_stream.h:47
#define MAIL_VERSION_STAMP_ALLOCATE
Definition: mail_version.h:67
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
void smtp_printf(VSTREAM *stream, const char *fmt,...)
Definition: smtp_stream.c:272
int rcpt_done
Definition: qmqp-source.c:133
VSTRING * buf
VSTREAM * stream
Definition: qmqp-source.c:135
void doze(unsigned delay)
Definition: doze.c:44
#define INET_PROTO_NAME_IPV6
Definition: mail_params.h:991
int var_line_limit
Definition: mail_params.c:263
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
int rcpt_accepted
Definition: smtp-source.c:174
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
void smtp_flush(VSTREAM *stream)
Definition: smtp_stream.c:228
int rcpt_count
Definition: qmqp-source.c:134
VSTRING * vstring_memcat(VSTRING *vp, const char *src, ssize_t len)
Definition: vstring.c:495
#define GETOPT(argc, argv, str)
Definition: sys_defs.h:1313
int vstream_tweak_tcp(VSTREAM *)
Definition: vstream_tweak.c:86
#define NON_BLOCKING
Definition: iostuff.h:49
int int
Definition: smtpd_proxy.h:21
#define ISPRINT(c)
Definition: sys_defs.h:1751
int non_blocking(int, int)
Definition: non_blocking.c:55
const char * host_port(char *buf, char **host, char *def_host, char **port, char *def_service)
Definition: host_port.c:115
void vmsg_info(const char *fmt, va_list ap)
Definition: msg.c:208
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
Definition: events.c:894
struct SESSION * next
Definition: qmqp-source.c:137
#define DO_GRIPE
Definition: haproxy_srvr.h:30
#define vstream_fileno(vp)
Definition: vstream.h:115
#define MAI_STRERROR(e)
Definition: myaddrinfo.h:169
void msg_vstream_init(const char *name, VSTREAM *vp)
Definition: msg_vstream.c:77
int connect_count
Definition: qmqp-source.c:136
#define ISSPACE(c)
Definition: sys_defs.h:1753
#define VSTREAM_PUTC(ch, vp)
Definition: vstream.h:107
#define SMTP_GET_FLAG_SKIP
Definition: smtp_stream.h:51
char * str
const char * get_hostname(void)
Definition: get_hostname.c:55
char * var_myhostname
Definition: mail_params.c:223
void event_disable_readwrite(int fd)
Definition: events.c:839
#define vstream_ferror(vp)
Definition: vstream.h:120
#define INET_PROTO_NAME_IPV4
Definition: mail_params.h:990
#define BLOCKING
Definition: iostuff.h:48
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
Definition: vstring.c:459
char * vstring_export(VSTRING *vp)
Definition: vstring.c:569
#define VSTREAM_ERR
Definition: vstream.h:68
VSTREAM * vstream_fdopen(int fd, int flags)
Definition: vstream.c:1204
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
void msg_info(const char *fmt,...)
Definition: msg.c:199
MAIL_VERSION_STAMP_DECLARE
Definition: smtp-source.c:938