From: Baptiste Daroussin Date: Fri, 17 Feb 2023 13:12:48 +0000 (+0100) Subject: fakesmtpd: add a program to fake a smtpd server for testing purpose X-Git-Tag: RELEASE_1_4_0b1~114 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=60d0c4db3f584c4a4bf0edb6127c81fa350c8204;p=thirdparty%2Fmlmmj.git fakesmtpd: add a program to fake a smtpd server for testing purpose --- diff --git a/tests/Makefile.am b/tests/Makefile.am index 4ee5e359..d00cf3b7 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,9 +1,12 @@ AUTOMAKE_OPTIONS = foreign -check_PROGRAMS = mlmmj +check_PROGRAMS = mlmmj fakesmtpd mlmmj_SOURCES = mlmmj.c \ mlmmj_tests.c + +fakesmtpd_SOURCES= fakesmtpd.c + EXTRA_DIST = *.sh *.h CLEANFILES= $(test_scripts:.sh=) diff --git a/tests/fakesmtpd.c b/tests/fakesmtpd.c new file mode 100644 index 00000000..824f1b06 --- /dev/null +++ b/tests/fakesmtpd.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2023 Baptiste Daroussin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifndef NELEM +#define NELEM(array) (sizeof(array) / sizeof((array)[0])) +#endif + +static struct replies { + const char *cmd; + const char *reply; +} reps [] = { + { "EHLO", "250-hostname.net\n250 CHUNKING\n" }, + { "QUIT", "221 2.0.0 bye\n" }, + { "MAIL FROM", "250 2.1.0 Ok\n"}, + { "RCPT TO", "250 2.1.0 Ok\n" }, + { "DATA", "354 End data with .\n" }, +}; + +int +main(void) +{ + int s, c; + FILE *f; + socklen_t clsize = 0; + struct sockaddr_in me, cl; + char *line = NULL; + size_t linecap = 0; + int mailnum = 0; + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + exit(1); + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &(int) { 1 }, sizeof(int)) != 0) + exit(2); + memset(&me, 0, sizeof(me)); + me.sin_family = AF_INET; + me.sin_addr.s_addr = inet_addr("127.0.0.1"); + /* specific interface */ + me.sin_port = htons(25678); + if (bind(s, (struct sockaddr *) &me, sizeof(me)) == -1) + exit(EXIT_FAILURE); + if (listen(s, 1) == -1) + exit(EXIT_FAILURE); + + if (daemon(1, 0) != 0) + err(EXIT_FAILURE, "daemon"); + f = fopen("fakesmtp.pid", "w+"); + fprintf(f, "%d\n", getpid()); + fclose(f); + for (;;) { + char *mail; + FILE *fp, *fp2; + c = accept(s, (struct sockaddr *) &cl, &clsize); + if (c == -1) + exit(EXIT_FAILURE); + + mailnum++; + asprintf(&mail, "mail-%d.txt", mailnum); + fp = fopen(mail, "w+"); + fp2 = fopen("debugmail.txt", "w+"); + free(mail); + f = fdopen(c, "rb"); + dprintf(c, "220 me fake smtp\n"); + fprintf(fp2, "==>: 220 me fake smtp\n"); + bool data = false; + while (getline(&line, &linecap, f) > 0) { + fprintf(fp, "%s", line); + fprintf(fp2, "<==: %s", line); + if (!data) { + for (size_t i = 0; i < NELEM(reps); i++) { + if (strncmp(reps[i].cmd, line, strlen(reps[i].cmd)) == 0) { + fprintf(fp2, "==>: %s", reps[i].reply); + dprintf(c, "%s", reps[i].reply); + if (strcmp(reps[i].cmd, "DATA") == 0) + data = true; + if (strcmp(reps[i].cmd, "QUIT") == 0) + goto next; + goto nextline; + } + } + fprintf(fp2, "==>: %s", "500 5.5.2 Error\n"); + dprintf(c, "500 5.5.2 Error: command not recognized\n"); + } +nextline: + if (data && (strcmp(line, ".\r\n") == 0 || strcmp(line, ".\n") == 0)) { + data = false; + fprintf(fp2, "==>: %s", "250 2.1.0 Ok\n"); + dprintf(c, "250 2.1.0 Ok\n"); + } + } +next: + fclose(fp); + fclose(fp2); + fclose(f); + } + + return (EXIT_SUCCESS); + +}