/* * Inject a large amount of e-mail to stress-test mailprocd. * Public domain. */ #include #include #include #include #include #include #include #include char *host = NULL; char *port = NULL; static int SMTP_Expect(FILE *f, const char *code) { char *buf, *lbuf = NULL; size_t len; int rv = 0; if ((buf = fgetln(f, &len)) == NULL) { fprintf(stderr, "EOF from server\n"); return (0); } if (buf[len-1] == '\n') { buf[len-1] = '\0'; } else { if ((lbuf = malloc(len+1)) == NULL) { fprintf(stderr, "malloc linebuf\n"); return (0); } memcpy(lbuf, buf, len); lbuf[len] = '\0'; buf = lbuf; } if (code[0] != buf[0]) { fprintf(stderr, "Server returned \"%s\" (was expecting %s)\n", buf, code); rv = 0; } if (lbuf != NULL) { free(lbuf); } return (1); } /* Inject via SMTP */ static int InjectSMTP(const char *msg, size_t msgLen, const char *from, const char *rcpt) { struct addrinfo hints, *res, *res0; const char *cause = NULL; int rv, s; FILE *f; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((rv = getaddrinfo(host, port, &hints, &res0)) != 0) { fprintf(stderr, "%s:%s: %s\n", host, port, gai_strerror(rv)); return (-1); } for (s = -1, res = res0; res != NULL; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { cause = "socket"; continue; } if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { cause = "connect"; close(s); s = -1; continue; } break; } if (s == -1) { fprintf(stderr, "%s: %s\n", cause, strerror(errno)); goto fail_addr; } if ((f = fdopen(s, "w+")) == NULL) { fprintf(stderr, "fdopen: %s\n", strerror(errno)); goto fail; } if (setvbuf(f, NULL, _IOLBF, 0) == EOF) { printf("setvbuf failed\n"); } if (!SMTP_Expect(f, "220")) { goto fail; } fputs("HELO [127.0.0.1]\n", f); if (!SMTP_Expect(f, "250")) { goto fail; } fputs("MAIL FROM:<", f); fputs(from, f); fputs(">\n", f); if (!SMTP_Expect(f, "250")) { goto fail; } fputs("RCPT TO:<", f); fputs(rcpt, f); fputs(">\n", f); if (!SMTP_Expect(f, "250")) { goto fail; } fputs("DATA\n", f); if (!SMTP_Expect(f, "354")) { goto fail; } fputs(msg, f); fputs("\r\n.\r\n", f); if (!SMTP_Expect(f, "250")) { goto fail; } close(s); freeaddrinfo(res0); return (0); fail: close(s); fail_addr: freeaddrinfo(res0); return (-1); } static void printusage(void) { extern char *__progname; printf("Usage: %s [-h host] [-p port] [-c count] [-f from] [-r rcpt]\n", __progname); } int main(int argc, char *argv[]) { extern char *optarg; char *from = NULL; char *rcpt = NULL; char *nonspam, *spam; size_t nonspam_len = 0; size_t spam_len = 0; int c; FILE *f; int i, count = 5; if ((f = fopen("spam1.txt", "r")) == NULL) { fprintf(stderr, "spam1.txt: %s\n", strerror(errno)); exit(1); } fseek(f, 0, SEEK_END); spam_len = (size_t)ftell(f); fseek(f, 0, SEEK_SET); printf("spam message = %d bytes\n", (int)spam_len); spam = malloc(spam_len); fread(spam, spam_len, 1, f); fclose(f); if ((f = fopen("nonspam1.txt", "r")) == NULL) { fprintf(stderr, "nonspam1.txt: %s\n", strerror(errno)); exit(1); } fseek(f, 0, SEEK_END); nonspam_len = (size_t)ftell(f); fseek(f, 0, SEEK_SET); printf("non-spam message = %d bytes\n", (int)nonspam_len); nonspam = malloc(nonspam_len); fread(nonspam, nonspam_len, 1, f); fclose(f); while ((c = getopt(argc, argv, "h:p:c:f:r:")) != -1) { switch (c) { case 'h': host = optarg; break; case 'p': port = optarg; break; case 'c': count = atoi(optarg); break; case 'f': from = optarg; break; case 'r': rcpt = optarg; break; default: printusage(); exit(1); } } if (from == NULL || rcpt == NULL || port == NULL || host == NULL) { printusage(); exit(1); } #if 0 printf("Sending %d spam messages to %s via [%s:%s]\n", count, rcpt, host, port); for (i = 0; i < count; i++) { InjectSMTP(spam, spam_len, from, rcpt); } #endif printf("Sending %d nonspam messages to %s via [%s:%s]\n", count, rcpt, host, port); for (i = 0; i < count; i++) { InjectSMTP(nonspam, nonspam_len, from, rcpt); } return (0); }