├── COPYING ├── Makefile.am ├── Makefile.in ├── README ├── aclocal.m4 ├── autogen.sh ├── compile ├── conf-examples ├── nwsmtp-dbg.conf ├── nwsmtp.conf └── nwsmtp.conf-auth ├── config.guess ├── config.h.in ├── config.sub ├── configure ├── configure.in ├── debian ├── README.Debian ├── README.source ├── changelog ├── compat ├── control ├── copyright ├── docs ├── emacsen-install.ex ├── emacsen-remove.ex ├── emacsen-startup.ex ├── init.d.ex ├── manpage.1.ex ├── manpage.sgml.ex ├── manpage.xml.ex ├── menu.ex ├── nwsmtp.cron.d.ex ├── nwsmtp.default.ex ├── nwsmtp.doc-base.EX ├── patches │ ├── debian-changes-0.1-1 │ └── series ├── postinst.ex ├── postrm.ex ├── preinst.ex ├── prerm.ex ├── rules ├── source │ └── format └── watch.ex ├── depcomp ├── etc ├── Makefile.am ├── Makefile.in ├── greylisting.conf ├── ip_param.conf ├── nwsmtp.conf ├── remove_headers.conf └── virtual_alias_maps ├── install-sh ├── ltmain.sh ├── m4 ├── ac_boost_base.m4 ├── ac_boost_thread.m4 ├── acx_pthread.m4 ├── ax_boost_base.m4 ├── ax_boost_program_options.m4 ├── ax_boost_system.m4 ├── ax_boost_thread.m4 ├── ax_cxx_check_lib.m4 └── ax_lib_expat.m4 ├── missing ├── nwsmtp.cron.d ├── nwsmtp.init ├── nwsmtp.sysconfig └── src ├── .gdbinit ├── Makefile.am ├── Makefile.in ├── adkim.cpp ├── adkim.h ├── aliases.cpp ├── aliases.h ├── aspf.h ├── aspf_impl.h ├── atormoz.cpp ├── atormoz.h ├── auth.cpp ├── auth.h ├── avir_client.cpp ├── avir_client.h ├── bb_client.cpp ├── bb_client.h ├── bb_client_auth.cpp ├── bb_client_auth.h ├── bb_client_mailfrom.cpp ├── bb_client_mailfrom.h ├── bb_client_rcpt.cpp ├── bb_client_rcpt.h ├── bb_parser.cpp ├── bb_parser.h ├── buffer_iterator.h ├── buffers.h ├── check.h ├── coroutine.hpp ├── envelope.cpp ├── envelope.h ├── eom_parser.cpp ├── eom_parser.h ├── header_parser.cpp ├── header_parser.h ├── host_seq_resolver.h ├── http_client.cpp ├── http_client.h ├── ip_options.cpp ├── ip_options.h ├── log.cpp ├── log.h ├── main.cpp ├── net ├── basic_dns_resolver.hpp ├── basic_dns_resolver_service.hpp ├── dns.hpp ├── dns_resolver.hpp ├── impl │ └── dns_resolver_impl.hpp ├── network_array.hpp ├── resolver_iterator.hpp └── rfc1035_414.hpp ├── options.cpp ├── options.h ├── pa_stub.h ├── param_parser.cpp ├── param_parser.h ├── pidfile.cpp ├── pidfile.h ├── rbl.cpp ├── rbl.h ├── rc.proto ├── rc_check.h ├── rc_clients ├── basic_rc_client.cpp ├── basic_rc_client.h ├── greylisting.cpp ├── greylisting.h └── greylisting_options.h ├── rfc822date.c ├── rfc822date.h ├── rfc_date.cpp ├── rfc_date.h ├── server.cpp ├── server.h ├── smtp_client.cpp ├── smtp_client.h ├── smtp_connection.cpp ├── smtp_connection.h ├── smtp_connection_auth.cpp ├── smtp_connection_mailfrom.cpp ├── smtp_connection_manager.cpp ├── smtp_connection_manager.h ├── so_client.cpp ├── so_client.h ├── socket_pool_service.h ├── socket_pool_service_impl.h ├── spf_internal.h ├── switchcfg.cpp ├── switchcfg.h ├── tests ├── Makefile.am ├── Makefile.in ├── basic_test.h ├── bbproxy.cpp ├── buffers.cpp ├── client1.cpp ├── client2.cpp ├── client3.cpp ├── gr.cpp ├── resolv.cpp ├── spf.cpp ├── spool.cpp ├── tormoz.cpp ├── tormoz2.cpp ├── ylog.cpp └── ylog.h ├── timer.cpp ├── timer.h ├── uti.cpp ├── uti.h ├── yield.hpp └── yplatform └── base64.h /Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = foreign 2 | ACLOCAL_AMFLAGS = -I m4 3 | SUBDIRS = src src/tests etc 4 | 5 | libtool: $(LIBTOOL_DEPS) 6 | $(SHELL) ./config.status --recheck 7 | 8 | distclean-local: 9 | -$(RM) ./aminclude.am 10 | 11 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | GPL Licensed fully asynchronous SMTP proxy server for Linux used as a frontend proxy for Yandex.Mail. 2 | 3 | Features include but are not limited to: ssl support, rbl checks, spam filtering, virus filtering, spf checks, dkim checks. 4 | 5 | Prerequisites: 6 | Linux OS, 7 | boost >= 1.44.0-0 (see http://sourceforge.net/projects/boost/files/boost/1.44.0/ ) 8 | expat >= 1.95.8-8.3 (see http://sourceforge.net/projects/expat/ ) 9 | libspf2 >= 1.2.9 (see http://www.libspf2.org/) 10 | libopendkim >= 1.2.2-2 (see http://sourceforge.net/projects/opendkim/ ) 11 | 12 | To build: 13 | ./configure 14 | make 15 | make install 16 | 17 | A sample config file (nwsmtp.conf) is included in the distribution. To run: 18 | nwsmtp -c nwsmtp.conf 19 | 20 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | aclocal -I m4 3 | libtoolize --force -c 4 | automake --add-missing -c 5 | autoconf 6 | -------------------------------------------------------------------------------- /compile: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Wrapper for compilers which do not understand `-c -o'. 3 | 4 | scriptversion=2005-05-14.22 5 | 6 | # Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. 7 | # Written by Tom Tromey . 8 | # 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program; if not, write to the Free Software 21 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 | 23 | # As a special exception to the GNU General Public License, if you 24 | # distribute this file as part of a program that contains a 25 | # configuration script generated by Autoconf, you may include it under 26 | # the same distribution terms that you use for the rest of that program. 27 | 28 | # This file is maintained in Automake, please report 29 | # bugs to or send patches to 30 | # . 31 | 32 | case $1 in 33 | '') 34 | echo "$0: No command. Try \`$0 --help' for more information." 1>&2 35 | exit 1; 36 | ;; 37 | -h | --h*) 38 | cat <<\EOF 39 | Usage: compile [--help] [--version] PROGRAM [ARGS] 40 | 41 | Wrapper for compilers which do not understand `-c -o'. 42 | Remove `-o dest.o' from ARGS, run PROGRAM with the remaining 43 | arguments, and rename the output as expected. 44 | 45 | If you are trying to build a whole package this is not the 46 | right script to run: please start by reading the file `INSTALL'. 47 | 48 | Report bugs to . 49 | EOF 50 | exit $? 51 | ;; 52 | -v | --v*) 53 | echo "compile $scriptversion" 54 | exit $? 55 | ;; 56 | esac 57 | 58 | ofile= 59 | cfile= 60 | eat= 61 | 62 | for arg 63 | do 64 | if test -n "$eat"; then 65 | eat= 66 | else 67 | case $1 in 68 | -o) 69 | # configure might choose to run compile as `compile cc -o foo foo.c'. 70 | # So we strip `-o arg' only if arg is an object. 71 | eat=1 72 | case $2 in 73 | *.o | *.obj) 74 | ofile=$2 75 | ;; 76 | *) 77 | set x "$@" -o "$2" 78 | shift 79 | ;; 80 | esac 81 | ;; 82 | *.c) 83 | cfile=$1 84 | set x "$@" "$1" 85 | shift 86 | ;; 87 | *) 88 | set x "$@" "$1" 89 | shift 90 | ;; 91 | esac 92 | fi 93 | shift 94 | done 95 | 96 | if test -z "$ofile" || test -z "$cfile"; then 97 | # If no `-o' option was seen then we might have been invoked from a 98 | # pattern rule where we don't need one. That is ok -- this is a 99 | # normal compilation that the losing compiler can handle. If no 100 | # `.c' file was seen then we are probably linking. That is also 101 | # ok. 102 | exec "$@" 103 | fi 104 | 105 | # Name of file we expect compiler to create. 106 | cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` 107 | 108 | # Create the lock directory. 109 | # Note: use `[/.-]' here to ensure that we don't use the same name 110 | # that we are using for the .o file. Also, base the name on the expected 111 | # object file name, since that is what matters with a parallel build. 112 | lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d 113 | while true; do 114 | if mkdir "$lockdir" >/dev/null 2>&1; then 115 | break 116 | fi 117 | sleep 1 118 | done 119 | # FIXME: race condition here if user kills between mkdir and trap. 120 | trap "rmdir '$lockdir'; exit 1" 1 2 15 121 | 122 | # Run the compile. 123 | "$@" 124 | ret=$? 125 | 126 | if test -f "$cofile"; then 127 | mv "$cofile" "$ofile" 128 | elif test -f "${cofile}bj"; then 129 | mv "${cofile}bj" "$ofile" 130 | fi 131 | 132 | rmdir "$lockdir" 133 | exit $ret 134 | 135 | # Local Variables: 136 | # mode: shell-script 137 | # sh-indentation: 2 138 | # eval: (add-hook 'write-file-hooks 'time-stamp) 139 | # time-stamp-start: "scriptversion=" 140 | # time-stamp-format: "%:y-%02m-%02d.%02H" 141 | # time-stamp-end: "$" 142 | # End: 143 | -------------------------------------------------------------------------------- /conf-examples/nwsmtp-dbg.conf: -------------------------------------------------------------------------------- 1 | listen = 0.0.0.0:25 2 | #listen = 0.0.0.0:1668 3 | #ssl_listen = 0.0.0.0:1669 4 | workers = 4 5 | smtp_banner = (Want to use Yandex.Mail for your domain? Visit http://pdd.yandex.ru) 6 | 7 | rbl_check = yes 8 | rbl_hosts = spamsource.mail.yandex.net 9 | 10 | debug = 0 11 | 12 | bb_check = 1 13 | bb_try = 2 14 | bb_primary = http://blackbox-mimino.yandex.net/blackbox 15 | bb_secondary = http://blackbox-mimino.yandex.net/blackbox 16 | bb_fallback_time = 10 17 | bb_return_time = 10 18 | bb_timeout = 1 19 | 20 | bb_file_path=./bb-file.conf 21 | bb_port = 80 22 | 23 | 24 | aliases = /etc/aliases 25 | 26 | smtpd_recipient_limit = 25 27 | smtpd_client_connection_count_limit = 1000 28 | smtpd_connection_count_limit = 1000 29 | 30 | so_check = 0 31 | so_try = 2 32 | #so_primary = so-in-ugr.yandex.ru:2525 33 | #so_primary = so09-eto-ix-vlan640.yandex.ru:10025 34 | so_primary = 77.88.46.10:10025 35 | so_secondary = so-in.yandex.ru:2525 36 | so_fallback_time = 10 37 | so_return_time = 10 38 | so_connect_timeout = 3 39 | so_data_timeout = 3 40 | 41 | so_file_path=./so-file.conf 42 | so_port = 99 43 | 44 | av_check = 0 45 | av_try = 2 46 | av_primary = av-ugr.mail.yandex.net:3000 47 | av_secondary = av.mail.yandex.net:3000 48 | av_fallback_time = 10 49 | av_return_time = 10 50 | av_connect_timeout = 3 51 | av_data_timeout = 3 52 | 53 | smtpd_command_timeout = 75 54 | smtpd_data_timeout = 120 55 | 56 | relay_connect_timeout = 30 57 | relay_cmd_timeout = 75 58 | relay_data_timeout = 120 59 | 60 | fallback_relay_host = localhost:2525 61 | local_relay_host = localhost:1234 62 | use_local_relay = no 63 | 64 | spam_relay_host = spambacks.mail.yandex.net:25 65 | use_spam_relay = no 66 | 67 | allow_percent_hack=yes 68 | 69 | action_virus=1 70 | message_size_limit=2048 71 | 72 | remove_headers = 0 73 | remove_headers_file = ..//etc/remove_yandex_headers.conf 74 | 75 | rc_check = 0 76 | 77 | user=0 78 | group=0 79 | 80 | rc_host_list=../etc/rc-host.conf 81 | 82 | 83 | use_tls=yes 84 | 85 | tls_key_file=ssl/smtp.yandex.ru.key 86 | tls_cert_file=ssl/smtp.yandex.ru.crt 87 | tls_CAfile=ssl/smtp.yandex.ru.ca 88 | 89 | use_auth=yes -------------------------------------------------------------------------------- /conf-examples/nwsmtp.conf: -------------------------------------------------------------------------------- 1 | listen = 0.0.0.0:2667 2 | listen = 0.0.0.0:2668 3 | workers = 4 4 | smtp_banner = (Want to use Yandex.Mail for your domain? Visit http://pdd.yandex.ru) 5 | 6 | rbl_check = yes 7 | rbl_hosts = spamsource.mail.yandex.net 8 | 9 | debug = 0 10 | 11 | bb_check = 1 12 | bb_try = 2 13 | bb_primary = http://blackbox-mimino.yandex.net/blackbox 14 | bb_secondary = http://blackbox-mimino.yandex.net/blackbox 15 | bb_fallback_time = 10 16 | bb_return_time = 10 17 | bb_timeout = 1 18 | 19 | #bb_file_path=../etc/bb-file.conf 20 | bb_port = 99 21 | 22 | 23 | aliases = /etc/aliases 24 | 25 | smtpd_recipient_limit = 25 26 | smtpd_client_connection_count_limit = 1000 27 | smtpd_connection_count_limit = 1000 28 | 29 | so_check = 1 30 | so_try = 2 31 | #so_primary = so-in-ugr.yandex.ru:2525 32 | #so_primary = so09-eto-ix-vlan640.yandex.ru:10025 33 | so_primary = 77.88.46.10:10025 34 | so_secondary = so-in.yandex.ru:2525 35 | so_fallback_time = 10 36 | so_return_time = 10 37 | so_connect_timeout = 3 38 | so_data_timeout = 3 39 | 40 | so_file_path=./so-file.conf 41 | so_port = 99 42 | 43 | av_check = 0 44 | av_try = 2 45 | av_primary = av-ugr.mail.yandex.net:3000 46 | av_secondary = av.mail.yandex.net:3000 47 | av_fallback_time = 10 48 | av_return_time = 10 49 | av_connect_timeout = 3 50 | av_data_timeout = 3 51 | 52 | smtpd_command_timeout = 75 53 | smtpd_data_timeout = 120 54 | 55 | relay_connect_timeout = 30 56 | relay_cmd_timeout = 75 57 | relay_data_timeout = 120 58 | 59 | fallback_relay_host = localhost:2525 60 | local_relay_host = localhost:1234 61 | use_local_relay = no 62 | 63 | spam_relay_host = spambacks.mail.yandex.net:25 64 | use_spam_relay = no 65 | 66 | allow_percent_hack=yes 67 | 68 | action_virus=1 69 | message_size_limit=204800 70 | 71 | remove_headers = 0 72 | remove_headers_file = /etc/nwsmtp/remove_yandex_headers.conf 73 | 74 | #rc_check = 1 75 | 76 | user=0 77 | group=0 78 | 79 | rc_host_list=./rc-host.conf 80 | 81 | 82 | #use_tls=yes 83 | 84 | tls_key_file=../ssl/smtp.yandex.ru.key 85 | tls_cert_file=../ssl/smtp.yandex.ru.crt 86 | tls_CAfile=../ssl/smtp.yandex.ru.ca 87 | 88 | use_auth=yes -------------------------------------------------------------------------------- /conf-examples/nwsmtp.conf-auth: -------------------------------------------------------------------------------- 1 | debug = 0 2 | 3 | # daemon 4 | 5 | user=nwsmtp 6 | group=nwsmtp 7 | 8 | listen = 0.0.0.0:25 9 | listen = 0.0.0.0:587 10 | ssl_listen = 0.0.0.0:465 11 | workers = 16 12 | smtp_banner = (Want to use Yandex.Mail for your domain? Visit http://pdd.yandex.ru) 13 | 14 | 15 | #aliases = /etc/postfix/virtual_alias_maps 16 | 17 | smtpd_command_timeout = 75 18 | smtpd_data_timeout = 120 19 | smtpd_client_connection_count_limit = 50 20 | smtpd_connection_count_limit = 3000 21 | smtpd_hard_error_limit = 1024 22 | 23 | smtpd_recipient_limit = 25 24 | ip_config_file = /etc/nwsmtp/ip_param.conf 25 | 26 | #allow_percent_hack=yes 27 | 28 | message_size_limit=42991616 29 | 30 | remove_headers = 1 31 | remove_headers_list = /etc/nwsmtp/remove_headers.conf 32 | 33 | # services 34 | 35 | rbl_check = no 36 | rbl_hosts = spamsource.mail.yandex.net 37 | 38 | bb_check = 0 39 | bb_try = 2 40 | bb_file_path = /etc/yamail/blackbox_list.conf 41 | bb_primary = http://blackbox.yandex.net/blackbox 42 | bb_secondary = http://blackbox.yandex.net/blackbox 43 | bb_fallback_time = 1 44 | bb_return_time = 2 45 | bb_timeout = 1 46 | 47 | so_check = 1 48 | so_try = 2 49 | so_file_path = /etc/yamail/so_out_list.conf 50 | so_primary = so-out.yandex.ru:5252 51 | so_secondary = so-out.yandex.ru:5252 52 | so_fallback_time = 2 53 | so_return_time = 4 54 | so_connect_timeout = 3 55 | so_data_timeout = 30 56 | so_port = 5252 57 | so_trust_xyandexspam = 0 58 | 59 | av_check = 1 60 | av_try = 2 61 | av_primary = av.mail.yandex.net:3000 62 | av_secondary = av.mail.yandex.net:3000 63 | av_fallback_time = 10 64 | av_return_time = 10 65 | av_connect_timeout = 3 66 | av_data_timeout = 3 67 | 68 | rc_check = 0 69 | rc_verbose = 1 70 | rc_timeout = 1 71 | rc_host_list = /etc/yamail/rchost_list.conf 72 | 73 | # 0 - discard 74 | # 1 - reject 75 | action_virus = 0 76 | 77 | # relays 78 | 79 | relay_connect_timeout = 30 80 | relay_cmd_timeout = 75 81 | relay_data_timeout = 300 82 | 83 | use_local_relay = yes 84 | local_relay_host = smtp://127.0.0.1:26 85 | 86 | fallback_relay_host = smtp://127.0.0.1:26 87 | 88 | use_auth = 1 89 | 90 | use_tls = 1 91 | tls_key_file=/etc/nwsmtp/ssl/key.key 92 | tls_cert_file=/etc/nwsmtp/ssl/cert.crt 93 | 94 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.in by autoheader. */ 2 | 3 | /* Define if we want to use Blackbox for user authorization */ 4 | #undef ENABLE_AUTH_BLACKBOX 5 | 6 | /* Define to 1 if you have the `alarm' function. */ 7 | #undef HAVE_ALARM 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #undef HAVE_ARPA_INET_H 11 | 12 | /* define if the Boost library is available */ 13 | #undef HAVE_BOOST 14 | 15 | /* define if the Boost::PROGRAM_OPTIONS library is available */ 16 | #undef HAVE_BOOST_PROGRAM_OPTIONS 17 | 18 | /* define if the Boost::System library is available */ 19 | #undef HAVE_BOOST_SYSTEM 20 | 21 | /* define if the Boost::Thread library is available */ 22 | #undef HAVE_BOOST_THREAD 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_DLFCN_H 26 | 27 | /* Define to 1 if you have the `endgrent' function. */ 28 | #undef HAVE_ENDGRENT 29 | 30 | /* Define to 1 if you have the `endpwent' function. */ 31 | #undef HAVE_ENDPWENT 32 | 33 | /* Define to 1 if you have the `gethostname' function. */ 34 | #undef HAVE_GETHOSTNAME 35 | 36 | /* Define to 1 if you have the header file. */ 37 | #undef HAVE_HOSTSEARCH_HOSTSEARCH_H 38 | 39 | /* Define to 1 if you have the header file. */ 40 | #undef HAVE_INTTYPES_H 41 | 42 | /* Define to 1 if you have the `hostsearch' library (-lhostsearch). */ 43 | #undef HAVE_LIBHOSTSEARCH 44 | 45 | /* Define to 1 if you have the `opendkim' library (-lopendkim). */ 46 | #undef HAVE_LIBOPENDKIM 47 | 48 | /* Define to 1 if you have the `spf2' library (-lspf2). */ 49 | #undef HAVE_LIBSPF2 50 | 51 | /* Define to 1 if `lstat' has the bug that it succeeds when given the 52 | zero-length file name argument. */ 53 | #undef HAVE_LSTAT_EMPTY_STRING_BUG 54 | 55 | /* Define to 1 if your system has a GNU libc compatible `malloc' function, and 56 | to 0 otherwise. */ 57 | #undef HAVE_MALLOC 58 | 59 | /* Define to 1 if you have the header file. */ 60 | #undef HAVE_MEMORY_H 61 | 62 | /* Define to 1 if you have the `memset' function. */ 63 | #undef HAVE_MEMSET 64 | 65 | /* Define to 1 if you have the header file. */ 66 | #undef HAVE_NETDB_H 67 | 68 | /* Define to 1 if you have the header file. */ 69 | #undef HAVE_NETINET_IN_H 70 | 71 | /* Define to 1 if you have the header file. */ 72 | #undef HAVE_PA_ASYNC_H 73 | 74 | /* Define if you have POSIX threads libraries and header files. */ 75 | #undef HAVE_PTHREAD 76 | 77 | /* Define to 1 if you have the `socket' function. */ 78 | #undef HAVE_SOCKET 79 | 80 | /* Define to 1 if stdbool.h conforms to C99. */ 81 | #undef HAVE_STDBOOL_H 82 | 83 | /* Define to 1 if you have the header file. */ 84 | #undef HAVE_STDINT_H 85 | 86 | /* Define to 1 if you have the header file. */ 87 | #undef HAVE_STDLIB_H 88 | 89 | /* Define to 1 if you have the `strcasecmp' function. */ 90 | #undef HAVE_STRCASECMP 91 | 92 | /* Define to 1 if you have the `strchr' function. */ 93 | #undef HAVE_STRCHR 94 | 95 | /* Define to 1 if you have the `strdup' function. */ 96 | #undef HAVE_STRDUP 97 | 98 | /* Define to 1 if you have the `strerror' function. */ 99 | #undef HAVE_STRERROR 100 | 101 | /* Define to 1 if you have the `strftime' function. */ 102 | #undef HAVE_STRFTIME 103 | 104 | /* Define to 1 if you have the header file. */ 105 | #undef HAVE_STRINGS_H 106 | 107 | /* Define to 1 if you have the header file. */ 108 | #undef HAVE_STRING_H 109 | 110 | /* Define to 1 if you have the `strncasecmp' function. */ 111 | #undef HAVE_STRNCASECMP 112 | 113 | /* Define to 1 if you have the header file. */ 114 | #undef HAVE_SYSLOG_H 115 | 116 | /* Define to 1 if you have the header file. */ 117 | #undef HAVE_SYS_SOCKET_H 118 | 119 | /* Define to 1 if you have the header file. */ 120 | #undef HAVE_SYS_STAT_H 121 | 122 | /* Define to 1 if you have the header file. */ 123 | #undef HAVE_SYS_TIME_H 124 | 125 | /* Define to 1 if you have the header file. */ 126 | #undef HAVE_SYS_TYPES_H 127 | 128 | /* Define to 1 if you have the header file. */ 129 | #undef HAVE_UNISTD_H 130 | 131 | /* Define to 1 if the system has the type `_Bool'. */ 132 | #undef HAVE__BOOL 133 | 134 | /* Define to 1 if `lstat' dereferences a symlink specified with a trailing 135 | slash. */ 136 | #undef LSTAT_FOLLOWS_SLASHED_SYMLINK 137 | 138 | /* Name of package */ 139 | #undef PACKAGE 140 | 141 | /* Define to the address where bug reports for this package should be sent. */ 142 | #undef PACKAGE_BUGREPORT 143 | 144 | /* Define to the full name of this package. */ 145 | #undef PACKAGE_NAME 146 | 147 | /* Define to the full name and version of this package. */ 148 | #undef PACKAGE_STRING 149 | 150 | /* Define to the one symbol short name of this package. */ 151 | #undef PACKAGE_TARNAME 152 | 153 | /* Define to the version of this package. */ 154 | #undef PACKAGE_VERSION 155 | 156 | /* Define to necessary symbol if this constant uses a non-standard name on 157 | your system. */ 158 | #undef PTHREAD_CREATE_JOINABLE 159 | 160 | /* Define to 1 if you have the ANSI C header files. */ 161 | #undef STDC_HEADERS 162 | 163 | /* Define to 1 if you can safely include both and . */ 164 | #undef TIME_WITH_SYS_TIME 165 | 166 | /* Define to 1 if your declares `struct tm'. */ 167 | #undef TM_IN_SYS_TIME 168 | 169 | /* Version number of package */ 170 | #undef VERSION 171 | 172 | /* Define to empty if `const' does not conform to ANSI C. */ 173 | #undef const 174 | 175 | /* Define to rpl_malloc if the replacement function should be used. */ 176 | #undef malloc 177 | -------------------------------------------------------------------------------- /configure.in: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ(2.59) 5 | AC_INIT([nwsmtp],[0.0.1],[khanton@yandex.ru]) 6 | AM_INIT_AUTOMAKE 7 | AC_CONFIG_SRCDIR([src/main.cpp]) 8 | AC_CONFIG_HEADER([config.h]) 9 | 10 | AM_MAINTAINER_MODE 11 | 12 | m4_include([m4/acx_pthread.m4]) 13 | m4_include([m4/ax_cxx_check_lib.m4]) 14 | m4_include([m4/ax_boost_base.m4]) 15 | m4_include([m4/ax_boost_thread.m4]) 16 | m4_include([m4/ax_boost_system.m4]) 17 | m4_include([m4/ax_boost_program_options.m4]) 18 | m4_include([m4/ax_lib_expat.m4]) 19 | 20 | AC_ARG_ENABLE([blackbox], 21 | AS_HELP_STRING([--enable-blackbox], [use blackbox (default is disabled)]), 22 | [ 23 | if test "x$enable_blackbox" = "xno"; then 24 | want_blackbox="no" 25 | else 26 | want_blackbox="yes" 27 | fi 28 | ], 29 | [ 30 | want_blackbox="no" 31 | ] 32 | ) 33 | 34 | if test "$want_blackbox" = yes; then 35 | AC_MSG_NOTICE([will use Blackbox Auth]) 36 | AC_DEFINE([ENABLE_AUTH_BLACKBOX], [1], [Define if we want to use Blackbox for user authorization]) 37 | fi 38 | 39 | 40 | # Checks for programs. 41 | AC_PROG_LIBTOOL 42 | AC_PROG_CC 43 | AC_PROG_CXX 44 | AC_PROG_INSTALL 45 | AC_PROG_LN_S 46 | AC_PROG_MAKE_SET 47 | 48 | # Checks for libraries. 49 | AX_LIB_EXPAT 50 | ACX_PTHREAD 51 | AX_BOOST_BASE(1.42) 52 | AX_BOOST_SYSTEM 53 | AX_BOOST_THREAD 54 | AX_BOOST_PROGRAM_OPTIONS 55 | AC_CHECK_LIB([spf2], [SPF_realloc]) 56 | AC_CHECK_LIB(opendkim, dkim_set_key_lookup) 57 | 58 | PKG_CHECK_MODULES([protobuf], [protobuf]) 59 | 60 | # Checks for header files. 61 | AC_HEADER_STDC 62 | AC_CHECK_HEADERS([arpa/inet.h netinet/in.h stdlib.h sys/socket.h sys/time.h syslog.h unistd.h memory.h netdb.h stdlib.h string.h]) 63 | AC_FUNC_ERROR_AT_LINE 64 | AC_FUNC_MALLOC 65 | AC_CHECK_FUNCS([gethostname memset socket strcasecmp strdup strncasecmp]) 66 | 67 | AC_ARG_WITH([pa], 68 | AS_HELP_STRING([--with-pa], [use profile analyzer. Default: no])) 69 | 70 | AS_IF([test "x$with_pa" = "xyes"], 71 | [ 72 | AC_LANG_PUSH(C++) 73 | AC_CHECK_HEADERS([pa/async.h],[have_pa=yes],[have_pa=no]) 74 | AC_LANG_POP(C++) 75 | 76 | AS_IF([ test "x$have_pa" = "xno" ], 77 | [ 78 | AC_MSG_ERROR([performance analizer not found]) 79 | ] 80 | ) 81 | ] 82 | ) 83 | 84 | AC_ARG_WITH([hostsearch], 85 | AS_HELP_STRING([--with-hostsearch], [use libhostsearch analyzer. Default: no])) 86 | 87 | AS_IF([test "x$with_hostsearch" = "xyes"], 88 | [ 89 | AC_LANG_PUSH(C++) 90 | AC_CHECK_HEADERS([hostsearch/hostsearch.h],[have_hostsearch=yes],[have_hostsearch=no]) 91 | AC_LANG_POP(C++) 92 | AC_CHECK_LIB(hostsearch, bbUrls2) 93 | 94 | AS_IF([ test "x$have_hostsearch" = "xno" ], 95 | [ 96 | AC_MSG_ERROR([libhostsearch not found]) 97 | ] 98 | ) 99 | ] 100 | ) 101 | 102 | # Checks for typedefs, structures, and compiler characteristics. 103 | AC_HEADER_STDBOOL 104 | AC_C_CONST 105 | AC_STRUCT_TM 106 | 107 | # Checks for library functions. 108 | AC_FUNC_ERROR_AT_LINE 109 | AC_FUNC_LSTAT 110 | AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK 111 | AC_FUNC_MKTIME 112 | AC_FUNC_STRFTIME 113 | AC_CHECK_FUNCS([memset socket strcasecmp strdup strncasecmp endgrent endpwent memset socket strcasecmp strchr strerror strncasecmp]) 114 | 115 | AC_CONFIG_FILES([Makefile src/Makefile src/tests/Makefile etc/Makefile]) 116 | AC_OUTPUT 117 | -------------------------------------------------------------------------------- /debian/README.Debian: -------------------------------------------------------------------------------- 1 | nwsmtp for Debian 2 | ----------------- 3 | 4 | 5 | 6 | -- Alexei Moisseev Sat, 30 Jul 2011 14:03:22 +0400 7 | -------------------------------------------------------------------------------- /debian/README.source: -------------------------------------------------------------------------------- 1 | nwsmtp for Debian 2 | ----------------- 3 | 4 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | nwsmtp (0.1-1) unstable; urgency=low 2 | 3 | * Initial release (Closes: #nnnn) 4 | 5 | -- Alexei Moisseev Sat, 30 Jul 2011 14:03:22 +0400 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: nwsmtp 2 | Section: mail 3 | Priority: extra 4 | Maintainer: Alexei Moisseev 5 | Build-Depends: debhelper (>= 7.0.50~), libboost1.44-dev, libspf2-dev (>= 1.2.9~), libopendkim-dev (>= 1.2.2-2~), libprotobuf-dev, libexpat1-dev, protobuf-compiler, libssl-dev, libboost-regex1.44-dev 6 | Standards-Version: 3.9.1 7 | Homepage: https://github.com/alexeimoisseev/NwSMTP 8 | 9 | Package: nwsmtp 10 | Architecture: any 11 | Depends: libboost-program-options1.44.0 (>= 1.44.0-1), libboost-system1.44.0 (>= 1.44.0-1), libboost-thread1.44.0 (>= 1.44.0-1), libc6 (>= 2.8), libexpat1 (>= 1.95.8), libopendkim3, libprotobuf6, libspf2-2 (>= 1.2.9~), libssl0.9.8 (>= 0.9.8~), zlib1g (>= 1:1.1.4), opendkim (>= 1.2.2-2~), expat (>= 1.95.8-8.3) 12 | Description: Asynchronous SMTP proxy server 13 | GPL Licensed fully asynchronous SMTP proxy server for Linux used as a frontend proxy for Yandex.Mail. 14 | Features include but are not limited to: ssl support, rbl checks, spam filtering, virus filtering, spf checks, dkim checks. 15 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | README 2 | -------------------------------------------------------------------------------- /debian/emacsen-install.ex: -------------------------------------------------------------------------------- 1 | #! /bin/sh -e 2 | # /usr/lib/emacsen-common/packages/install/nwsmtp 3 | 4 | # Written by Jim Van Zandt , borrowing heavily 5 | # from the install scripts for gettext by Santiago Vila 6 | # and octave by Dirk Eddelbuettel . 7 | 8 | FLAVOR=$1 9 | PACKAGE=nwsmtp 10 | 11 | if [ ${FLAVOR} = emacs ]; then exit 0; fi 12 | 13 | echo install/${PACKAGE}: Handling install for emacsen flavor ${FLAVOR} 14 | 15 | #FLAVORTEST=`echo $FLAVOR | cut -c-6` 16 | #if [ ${FLAVORTEST} = xemacs ] ; then 17 | # SITEFLAG="-no-site-file" 18 | #else 19 | # SITEFLAG="--no-site-file" 20 | #fi 21 | FLAGS="${SITEFLAG} -q -batch -l path.el -f batch-byte-compile" 22 | 23 | ELDIR=/usr/share/emacs/site-lisp/${PACKAGE} 24 | ELCDIR=/usr/share/${FLAVOR}/site-lisp/${PACKAGE} 25 | 26 | # Install-info-altdir does not actually exist. 27 | # Maybe somebody will write it. 28 | if test -x /usr/sbin/install-info-altdir; then 29 | echo install/${PACKAGE}: install Info links for ${FLAVOR} 30 | install-info-altdir --quiet --section "" "" --dirname=${FLAVOR} /usr/share/info/${PACKAGE}.info.gz 31 | fi 32 | 33 | install -m 755 -d ${ELCDIR} 34 | cd ${ELDIR} 35 | FILES=`echo *.el` 36 | cp ${FILES} ${ELCDIR} 37 | cd ${ELCDIR} 38 | 39 | cat << EOF > path.el 40 | (setq load-path (cons "." load-path) byte-compile-warnings nil) 41 | EOF 42 | ${FLAVOR} ${FLAGS} ${FILES} 43 | rm -f *.el path.el 44 | 45 | exit 0 46 | -------------------------------------------------------------------------------- /debian/emacsen-remove.ex: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # /usr/lib/emacsen-common/packages/remove/nwsmtp 3 | 4 | FLAVOR=$1 5 | PACKAGE=nwsmtp 6 | 7 | if [ ${FLAVOR} != emacs ]; then 8 | if test -x /usr/sbin/install-info-altdir; then 9 | echo remove/${PACKAGE}: removing Info links for ${FLAVOR} 10 | install-info-altdir --quiet --remove --dirname=${FLAVOR} /usr/share/info/nwsmtp.info.gz 11 | fi 12 | 13 | echo remove/${PACKAGE}: purging byte-compiled files for ${FLAVOR} 14 | rm -rf /usr/share/${FLAVOR}/site-lisp/${PACKAGE} 15 | fi 16 | -------------------------------------------------------------------------------- /debian/emacsen-startup.ex: -------------------------------------------------------------------------------- 1 | ;; -*-emacs-lisp-*- 2 | ;; 3 | ;; Emacs startup file, e.g. /etc/emacs/site-start.d/50nwsmtp.el 4 | ;; for the Debian nwsmtp package 5 | ;; 6 | ;; Originally contributed by Nils Naumann 7 | ;; Modified by Dirk Eddelbuettel 8 | ;; Adapted for dh-make by Jim Van Zandt 9 | 10 | ;; The nwsmtp package follows the Debian/GNU Linux 'emacsen' policy and 11 | ;; byte-compiles its elisp files for each 'emacs flavor' (emacs19, 12 | ;; xemacs19, emacs20, xemacs20...). The compiled code is then 13 | ;; installed in a subdirectory of the respective site-lisp directory. 14 | ;; We have to add this to the load-path: 15 | (let ((package-dir (concat "/usr/share/" 16 | (symbol-name flavor) 17 | "/site-lisp/nwsmtp"))) 18 | ;; If package-dir does not exist, the nwsmtp package must have 19 | ;; removed but not purged, and we should skip the setup. 20 | (when (file-directory-p package-dir) 21 | (setq load-path (cons package-dir load-path)) 22 | (autoload 'nwsmtp-mode "nwsmtp-mode" 23 | "Major mode for editing nwsmtp files." t) 24 | (add-to-list 'auto-mode-alist '("\\.nwsmtp$" . nwsmtp-mode)))) 25 | 26 | -------------------------------------------------------------------------------- /debian/init.d.ex: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: nwsmtp 4 | # Required-Start: $network $local_fs 5 | # Required-Stop: 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: 9 | # Description: 10 | # <...> 11 | # <...> 12 | ### END INIT INFO 13 | 14 | # Author: Alexei Moisseev 15 | 16 | # PATH should only include /usr/* if it runs after the mountnfs.sh script 17 | PATH=/sbin:/usr/sbin:/bin:/usr/bin 18 | DESC=nwsmtp # Introduce a short description here 19 | NAME=nwsmtp # Introduce the short server's name here 20 | DAEMON=/usr/sbin/nwsmtp # Introduce the server's location here 21 | DAEMON_ARGS="" # Arguments to run the daemon with 22 | PIDFILE=/var/run/$NAME.pid 23 | SCRIPTNAME=/etc/init.d/$NAME 24 | 25 | # Exit if the package is not installed 26 | [ -x $DAEMON ] || exit 0 27 | 28 | # Read configuration variable file if it is present 29 | [ -r /etc/default/$NAME ] && . /etc/default/$NAME 30 | 31 | # Load the VERBOSE setting and other rcS variables 32 | . /lib/init/vars.sh 33 | 34 | # Define LSB log_* functions. 35 | # Depend on lsb-base (>= 3.0-6) to ensure that this file is present. 36 | . /lib/lsb/init-functions 37 | 38 | # 39 | # Function that starts the daemon/service 40 | # 41 | do_start() 42 | { 43 | # Return 44 | # 0 if daemon has been started 45 | # 1 if daemon was already running 46 | # 2 if daemon could not be started 47 | start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ 48 | || return 1 49 | start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ 50 | $DAEMON_ARGS \ 51 | || return 2 52 | # Add code here, if necessary, that waits for the process to be ready 53 | # to handle requests from services started subsequently which depend 54 | # on this one. As a last resort, sleep for some time. 55 | } 56 | 57 | # 58 | # Function that stops the daemon/service 59 | # 60 | do_stop() 61 | { 62 | # Return 63 | # 0 if daemon has been stopped 64 | # 1 if daemon was already stopped 65 | # 2 if daemon could not be stopped 66 | # other if a failure occurred 67 | start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME 68 | RETVAL="$?" 69 | [ "$RETVAL" = 2 ] && return 2 70 | # Wait for children to finish too if this is a daemon that forks 71 | # and if the daemon is only ever run from this initscript. 72 | # If the above conditions are not satisfied then add some other code 73 | # that waits for the process to drop all resources that could be 74 | # needed by services started subsequently. A last resort is to 75 | # sleep for some time. 76 | start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON 77 | [ "$?" = 2 ] && return 2 78 | # Many daemons don't delete their pidfiles when they exit. 79 | rm -f $PIDFILE 80 | return "$RETVAL" 81 | } 82 | 83 | # 84 | # Function that sends a SIGHUP to the daemon/service 85 | # 86 | do_reload() { 87 | # 88 | # If the daemon can reload its configuration without 89 | # restarting (for example, when it is sent a SIGHUP), 90 | # then implement that here. 91 | # 92 | start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME 93 | return 0 94 | } 95 | 96 | case "$1" in 97 | start) 98 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME" 99 | do_start 100 | case "$?" in 101 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 102 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 103 | esac 104 | ;; 105 | stop) 106 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" 107 | do_stop 108 | case "$?" in 109 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 110 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 111 | esac 112 | ;; 113 | status) 114 | status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? 115 | ;; 116 | #reload|force-reload) 117 | # 118 | # If do_reload() is not implemented then leave this commented out 119 | # and leave 'force-reload' as an alias for 'restart'. 120 | # 121 | #log_daemon_msg "Reloading $DESC" "$NAME" 122 | #do_reload 123 | #log_end_msg $? 124 | #;; 125 | restart|force-reload) 126 | # 127 | # If the "reload" option is implemented then remove the 128 | # 'force-reload' alias 129 | # 130 | log_daemon_msg "Restarting $DESC" "$NAME" 131 | do_stop 132 | case "$?" in 133 | 0|1) 134 | do_start 135 | case "$?" in 136 | 0) log_end_msg 0 ;; 137 | 1) log_end_msg 1 ;; # Old process is still running 138 | *) log_end_msg 1 ;; # Failed to start 139 | esac 140 | ;; 141 | *) 142 | # Failed to stop 143 | log_end_msg 1 144 | ;; 145 | esac 146 | ;; 147 | *) 148 | #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 149 | echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 150 | exit 3 151 | ;; 152 | esac 153 | 154 | : 155 | -------------------------------------------------------------------------------- /debian/manpage.1.ex: -------------------------------------------------------------------------------- 1 | .\" Hey, EMACS: -*- nroff -*- 2 | .\" First parameter, NAME, should be all caps 3 | .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection 4 | .\" other parameters are allowed: see man(7), man(1) 5 | .TH NWSMTP SECTION "July 30, 2011" 6 | .\" Please adjust this date whenever revising the manpage. 7 | .\" 8 | .\" Some roff macros, for reference: 9 | .\" .nh disable hyphenation 10 | .\" .hy enable hyphenation 11 | .\" .ad l left justify 12 | .\" .ad b justify to both left and right margins 13 | .\" .nf disable filling 14 | .\" .fi enable filling 15 | .\" .br insert line break 16 | .\" .sp insert n+1 empty lines 17 | .\" for manpage-specific macros, see man(7) 18 | .SH NAME 19 | nwsmtp \- program to do something 20 | .SH SYNOPSIS 21 | .B nwsmtp 22 | .RI [ options ] " files" ... 23 | .br 24 | .B bar 25 | .RI [ options ] " files" ... 26 | .SH DESCRIPTION 27 | This manual page documents briefly the 28 | .B nwsmtp 29 | and 30 | .B bar 31 | commands. 32 | .PP 33 | .\" TeX users may be more comfortable with the \fB\fP and 34 | .\" \fI\fP escape sequences to invode bold face and italics, 35 | .\" respectively. 36 | \fBnwsmtp\fP is a program that... 37 | .SH OPTIONS 38 | These programs follow the usual GNU command line syntax, with long 39 | options starting with two dashes (`-'). 40 | A summary of options is included below. 41 | For a complete description, see the Info files. 42 | .TP 43 | .B \-h, \-\-help 44 | Show summary of options. 45 | .TP 46 | .B \-v, \-\-version 47 | Show version of program. 48 | .SH SEE ALSO 49 | .BR bar (1), 50 | .BR baz (1). 51 | .br 52 | The programs are documented fully by 53 | .IR "The Rise and Fall of a Fooish Bar" , 54 | available via the Info system. 55 | .SH AUTHOR 56 | nwsmtp was written by . 57 | .PP 58 | This manual page was written by Alexei Moisseev , 59 | for the Debian project (and may be used by others). 60 | -------------------------------------------------------------------------------- /debian/manpage.sgml.ex: -------------------------------------------------------------------------------- 1 | manpage.1'. You may view 5 | the manual page with: `docbook-to-man manpage.sgml | nroff -man | 6 | less'. A typical entry in a Makefile or Makefile.am is: 7 | 8 | manpage.1: manpage.sgml 9 | docbook-to-man $< > $@ 10 | 11 | 12 | The docbook-to-man binary is found in the docbook-to-man package. 13 | Please remember that if you create the nroff version in one of the 14 | debian/rules file targets (such as build), you will need to include 15 | docbook-to-man in your Build-Depends control field. 16 | 17 | --> 18 | 19 | 20 | FIRSTNAME"> 21 | SURNAME"> 22 | 23 | July 30, 2011"> 24 | 26 | SECTION"> 27 | alexmois@ya.ru"> 28 | 29 | NWSMTP"> 30 | 31 | 32 | Debian"> 33 | GNU"> 34 | GPL"> 35 | ]> 36 | 37 | 38 | 39 |
40 | &dhemail; 41 |
42 | 43 | &dhfirstname; 44 | &dhsurname; 45 | 46 | 47 | 2003 48 | &dhusername; 49 | 50 | &dhdate; 51 |
52 | 53 | &dhucpackage; 54 | 55 | &dhsection; 56 | 57 | 58 | &dhpackage; 59 | 60 | program to do something 61 | 62 | 63 | 64 | &dhpackage; 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | DESCRIPTION 73 | 74 | This manual page documents briefly the 75 | &dhpackage; and bar 76 | commands. 77 | 78 | This manual page was written for the &debian; distribution 79 | because the original program does not have a manual page. 80 | Instead, it has documentation in the &gnu; 81 | Info format; see below. 82 | 83 | &dhpackage; is a program that... 84 | 85 | 86 | 87 | OPTIONS 88 | 89 | These programs follow the usual &gnu; command line syntax, 90 | with long options starting with two dashes (`-'). A summary of 91 | options is included below. For a complete description, see the 92 | Info files. 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | Show summary of options. 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | Show version of program. 109 | 110 | 111 | 112 | 113 | 114 | SEE ALSO 115 | 116 | bar (1), baz (1). 117 | 118 | The programs are documented fully by The Rise and 119 | Fall of a Fooish Bar available via the 120 | Info system. 121 | 122 | 123 | AUTHOR 124 | 125 | This manual page was written by &dhusername; &dhemail; for 126 | the &debian; system (and may be used by others). Permission is 127 | granted to copy, distribute and/or modify this document under 128 | the terms of the &gnu; General Public License, Version 2 any 129 | later version published by the Free Software Foundation. 130 | 131 | 132 | On Debian systems, the complete text of the GNU General Public 133 | License can be found in /usr/share/common-licenses/GPL. 134 | 135 | 136 | 137 |
138 | 139 | 155 | -------------------------------------------------------------------------------- /debian/menu.ex: -------------------------------------------------------------------------------- 1 | ?package(nwsmtp):needs="X11|text|vc|wm" section="Applications/see-menu-manual"\ 2 | title="nwsmtp" command="/usr/bin/nwsmtp" 3 | -------------------------------------------------------------------------------- /debian/nwsmtp.cron.d.ex: -------------------------------------------------------------------------------- 1 | # 2 | # Regular cron jobs for the nwsmtp package 3 | # 4 | 0 4 * * * root [ -x /usr/bin/nwsmtp_maintenance ] && /usr/bin/nwsmtp_maintenance 5 | -------------------------------------------------------------------------------- /debian/nwsmtp.default.ex: -------------------------------------------------------------------------------- 1 | # Defaults for nwsmtp initscript 2 | # sourced by /etc/init.d/nwsmtp 3 | # installed at /etc/default/nwsmtp by the maintainer scripts 4 | 5 | # 6 | # This is a POSIX shell fragment 7 | # 8 | 9 | # Additional options that are passed to the Daemon. 10 | DAEMON_OPTS="" 11 | -------------------------------------------------------------------------------- /debian/nwsmtp.doc-base.EX: -------------------------------------------------------------------------------- 1 | Document: nwsmtp 2 | Title: Debian nwsmtp Manual 3 | Author: 4 | Abstract: This manual describes what nwsmtp is 5 | and how it can be used to 6 | manage online manuals on Debian systems. 7 | Section: unknown 8 | 9 | Format: debiandoc-sgml 10 | Files: /usr/share/doc/nwsmtp/nwsmtp.sgml.gz 11 | 12 | Format: postscript 13 | Files: /usr/share/doc/nwsmtp/nwsmtp.ps.gz 14 | 15 | Format: text 16 | Files: /usr/share/doc/nwsmtp/nwsmtp.text.gz 17 | 18 | Format: HTML 19 | Index: /usr/share/doc/nwsmtp/html/index.html 20 | Files: /usr/share/doc/nwsmtp/html/*.html 21 | -------------------------------------------------------------------------------- /debian/patches/series: -------------------------------------------------------------------------------- 1 | debian-changes-0.1-1 2 | -------------------------------------------------------------------------------- /debian/postinst.ex: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # postinst script for nwsmtp 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # summary of how this script can be called: 9 | # * `configure' 10 | # * `abort-upgrade' 11 | # * `abort-remove' `in-favour' 12 | # 13 | # * `abort-remove' 14 | # * `abort-deconfigure' `in-favour' 15 | # `removing' 16 | # 17 | # for details, see http://www.debian.org/doc/debian-policy/ or 18 | # the debian-policy package 19 | 20 | 21 | case "$1" in 22 | configure) 23 | ;; 24 | 25 | abort-upgrade|abort-remove|abort-deconfigure) 26 | ;; 27 | 28 | *) 29 | echo "postinst called with unknown argument \`$1'" >&2 30 | exit 1 31 | ;; 32 | esac 33 | 34 | # dh_installdeb will replace this with shell code automatically 35 | # generated by other debhelper scripts. 36 | 37 | #DEBHELPER# 38 | 39 | exit 0 40 | -------------------------------------------------------------------------------- /debian/postrm.ex: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # postrm script for nwsmtp 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # summary of how this script can be called: 9 | # * `remove' 10 | # * `purge' 11 | # * `upgrade' 12 | # * `failed-upgrade' 13 | # * `abort-install' 14 | # * `abort-install' 15 | # * `abort-upgrade' 16 | # * `disappear' 17 | # 18 | # for details, see http://www.debian.org/doc/debian-policy/ or 19 | # the debian-policy package 20 | 21 | 22 | case "$1" in 23 | purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) 24 | ;; 25 | 26 | *) 27 | echo "postrm called with unknown argument \`$1'" >&2 28 | exit 1 29 | ;; 30 | esac 31 | 32 | # dh_installdeb will replace this with shell code automatically 33 | # generated by other debhelper scripts. 34 | 35 | #DEBHELPER# 36 | 37 | exit 0 38 | -------------------------------------------------------------------------------- /debian/preinst.ex: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # preinst script for nwsmtp 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # summary of how this script can be called: 9 | # * `install' 10 | # * `install' 11 | # * `upgrade' 12 | # * `abort-upgrade' 13 | # for details, see http://www.debian.org/doc/debian-policy/ or 14 | # the debian-policy package 15 | 16 | 17 | case "$1" in 18 | install|upgrade) 19 | ;; 20 | 21 | abort-upgrade) 22 | ;; 23 | 24 | *) 25 | echo "preinst called with unknown argument \`$1'" >&2 26 | exit 1 27 | ;; 28 | esac 29 | 30 | # dh_installdeb will replace this with shell code automatically 31 | # generated by other debhelper scripts. 32 | 33 | #DEBHELPER# 34 | 35 | exit 0 36 | -------------------------------------------------------------------------------- /debian/prerm.ex: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # prerm script for nwsmtp 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # summary of how this script can be called: 9 | # * `remove' 10 | # * `upgrade' 11 | # * `failed-upgrade' 12 | # * `remove' `in-favour' 13 | # * `deconfigure' `in-favour' 14 | # `removing' 15 | # 16 | # for details, see http://www.debian.org/doc/debian-policy/ or 17 | # the debian-policy package 18 | 19 | 20 | case "$1" in 21 | remove|upgrade|deconfigure) 22 | ;; 23 | 24 | failed-upgrade) 25 | ;; 26 | 27 | *) 28 | echo "prerm called with unknown argument \`$1'" >&2 29 | exit 1 30 | ;; 31 | esac 32 | 33 | # dh_installdeb will replace this with shell code automatically 34 | # generated by other debhelper scripts. 35 | 36 | #DEBHELPER# 37 | 38 | exit 0 39 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # This file was originally written by Joey Hess and Craig Small. 5 | # As a special exception, when this file is copied by dh-make into a 6 | # dh-make output file, you may use that output file without restriction. 7 | # This special exception was added by Craig Small in version 0.37 of dh-make. 8 | 9 | # Uncomment this to turn on verbose mode. 10 | #export DH_VERBOSE=1 11 | 12 | %: 13 | dh $@ 14 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/watch.ex: -------------------------------------------------------------------------------- 1 | # Example watch control file for uscan 2 | # Rename this file to "watch" and then you can run the "uscan" command 3 | # to check for upstream updates and more. 4 | # See uscan(1) for format 5 | 6 | # Compulsory line, this is a version 3 file 7 | version=3 8 | 9 | # Uncomment to examine a Webpage 10 | # 11 | #http://www.example.com/downloads.php nwsmtp-(.*)\.tar\.gz 12 | 13 | # Uncomment to examine a Webserver directory 14 | #http://www.example.com/pub/nwsmtp-(.*)\.tar\.gz 15 | 16 | # Uncommment to examine a FTP server 17 | #ftp://ftp.example.com/pub/nwsmtp-(.*)\.tar\.gz debian uupdate 18 | 19 | # Uncomment to find new files on sourceforge, for devscripts >= 2.9 20 | # http://sf.net/nwsmtp/nwsmtp-(.*)\.tar\.gz 21 | 22 | # Uncomment to find new files on GooglePages 23 | # http://example.googlepages.com/foo.html nwsmtp-(.*)\.tar\.gz 24 | -------------------------------------------------------------------------------- /etc/Makefile.am: -------------------------------------------------------------------------------- 1 | CONFS=ip_param.conf remove_headers.conf greylisting.conf 2 | 3 | install-data-am: 4 | $(INSTALL) -d $(DESTDIR)$(sysconfdir)/nwsmtp 5 | $(INSTALL_DATA) $(CONFS) $(DESTDIR)$(sysconfdir)/nwsmtp 6 | -------------------------------------------------------------------------------- /etc/greylisting.conf: -------------------------------------------------------------------------------- 1 | ns = gr 2 | use_ip = false 3 | use_envelope_from = true 4 | use_envelope_to = true 5 | use_header_from = true 6 | use_header_to = true 7 | use_header_messageid= false 8 | use_header_subject = true 9 | use_header_date = true 10 | use_body = false 11 | window_begin = 300 12 | window_end = 43200 13 | record_lifetime = 43200 14 | 15 | udp_timeout = 5 16 | udp_port = 8890 17 | 18 | host = tormoz1.mail.yandex.net 19 | host = tormoz2.mail.yandex.net 20 | host = tormoz3.mail.yandex.net 21 | host = tormoz4.mail.yandex.net 22 | 23 | -------------------------------------------------------------------------------- /etc/ip_param.conf: -------------------------------------------------------------------------------- 1 | # ip/mask rcpt_cnt 2 | 172.16.0.0/16 200 3 | -------------------------------------------------------------------------------- /etc/remove_headers.conf: -------------------------------------------------------------------------------- 1 | BCC 2 | X-Yandex-Spam 3 | X-Yandex-Insight 4 | X-Yandex-Folder 5 | X-Yandex-Hint 6 | X-Yandex-Service 7 | X-Yandex-Suid 8 | X-Yandex-Greylisting 9 | Authentication-Results 10 | Return-Path 11 | -------------------------------------------------------------------------------- /etc/virtual_alias_maps: -------------------------------------------------------------------------------- 1 | test-virtual-alias@yandex.ru test-virtual-alias%yandex.ru@mxbacks.yandex.ru,test-virtual-alias-get@yandex.ru 2 | khanton@yandex-team.ru khanton@yandex.ru -------------------------------------------------------------------------------- /m4/ac_boost_thread.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.nongnu.org/autoconf-archive/ax_boost_thread.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_BOOST_THREAD 8 | # 9 | # DESCRIPTION 10 | # 11 | # Test for Thread library from the Boost C++ libraries. The macro requires 12 | # a preceding call to AX_BOOST_BASE. Further documentation is available at 13 | # . 14 | # 15 | # This macro calls: 16 | # 17 | # AC_SUBST(BOOST_THREAD_LIB) 18 | # 19 | # And sets: 20 | # 21 | # HAVE_BOOST_THREAD 22 | # 23 | # LICENSE 24 | # 25 | # Copyright (c) 2009 Thomas Porschberg 26 | # Copyright (c) 2009 Michael Tindal 27 | # 28 | # Copying and distribution of this file, with or without modification, are 29 | # permitted in any medium without royalty provided the copyright notice 30 | # and this notice are preserved. 31 | 32 | AC_DEFUN([AX_BOOST_THREAD], 33 | [ 34 | AC_ARG_WITH([boost-thread], 35 | AS_HELP_STRING([--with-boost-thread@<:@=special-lib@:>@], 36 | [use the Thread library from boost - it is possible to specify a certain library for the linker 37 | e.g. --with-boost-thread=boost_thread-gcc-mt ]), 38 | [ 39 | if test "$withval" = "no"; then 40 | want_boost="no" 41 | elif test "$withval" = "yes"; then 42 | want_boost="yes" 43 | ax_boost_user_thread_lib="" 44 | else 45 | want_boost="yes" 46 | ax_boost_user_thread_lib="$withval" 47 | fi 48 | ], 49 | [want_boost="yes"] 50 | ) 51 | 52 | if test "x$want_boost" = "xyes"; then 53 | AC_REQUIRE([AC_PROG_CC]) 54 | AC_REQUIRE([AC_CANONICAL_BUILD]) 55 | CPPFLAGS_SAVED="$CPPFLAGS" 56 | CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" 57 | export CPPFLAGS 58 | 59 | LDFLAGS_SAVED="$LDFLAGS" 60 | LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" 61 | export LDFLAGS 62 | 63 | AC_CACHE_CHECK(whether the Boost::Thread library is available, 64 | ax_cv_boost_thread, 65 | [AC_LANG_PUSH([C++]) 66 | CXXFLAGS_SAVE=$CXXFLAGS 67 | 68 | if test "x$build_os" = "xsolaris" ; then 69 | CXXFLAGS="-pthreads $CXXFLAGS" 70 | elif test "x$build_os" = "xming32" ; then 71 | CXXFLAGS="-mthreads $CXXFLAGS" 72 | else 73 | CXXFLAGS="-pthread $CXXFLAGS" 74 | fi 75 | AC_COMPILE_IFELSE(AC_LANG_PROGRAM([[@%:@include ]], 76 | [[boost::thread_group thrds; 77 | return 0;]]), 78 | ax_cv_boost_thread=yes, ax_cv_boost_thread=no) 79 | CXXFLAGS=$CXXFLAGS_SAVE 80 | AC_LANG_POP([C++]) 81 | ]) 82 | if test "x$ax_cv_boost_thread" = "xyes"; then 83 | if test "x$build_os" = "xsolaris" ; then 84 | BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS" 85 | elif test "x$build_os" = "xming32" ; then 86 | BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS" 87 | else 88 | BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS" 89 | fi 90 | 91 | AC_SUBST(BOOST_CPPFLAGS) 92 | 93 | AC_DEFINE(HAVE_BOOST_THREAD,,[define if the Boost::Thread library is available]) 94 | BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` 95 | 96 | LDFLAGS_SAVE=$LDFLAGS 97 | case "x$build_os" in 98 | *bsd* ) 99 | LDFLAGS="-pthread $LDFLAGS" 100 | break; 101 | ;; 102 | esac 103 | if test "x$ax_boost_user_thread_lib" = "x"; then 104 | for libextension in `ls $BOOSTLIBDIR/libboost_thread*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_thread.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_thread*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_thread.*\)\.a*$;\1;'`; do 105 | ax_lib=${libextension} 106 | AC_CHECK_LIB($ax_lib, exit, 107 | [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], 108 | [link_thread="no"]) 109 | done 110 | if test "x$link_thread" != "xyes"; then 111 | for libextension in `ls $BOOSTLIBDIR/boost_thread*.dll* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_thread.*\)\.dll.*$;\1;'` `ls $BOOSTLIBDIR/boost_thread*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_thread.*\)\.a*$;\1;'` ; do 112 | ax_lib=${libextension} 113 | AC_CHECK_LIB($ax_lib, exit, 114 | [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], 115 | [link_thread="no"]) 116 | done 117 | fi 118 | 119 | else 120 | for ax_lib in $ax_boost_user_thread_lib boost_thread-$ax_boost_user_thread_lib; do 121 | AC_CHECK_LIB($ax_lib, exit, 122 | [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], 123 | [link_thread="no"]) 124 | done 125 | 126 | fi 127 | if test "x$link_thread" = "xno"; then 128 | AC_MSG_ERROR(Could not link against $ax_lib !) 129 | else 130 | case "x$build_os" in 131 | *bsd* ) 132 | BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS" 133 | break; 134 | ;; 135 | esac 136 | 137 | fi 138 | fi 139 | 140 | CPPFLAGS="$CPPFLAGS_SAVED" 141 | LDFLAGS="$LDFLAGS_SAVED" 142 | fi 143 | ]) 144 | -------------------------------------------------------------------------------- /m4/ax_boost_program_options.m4: -------------------------------------------------------------------------------- 1 | # ============================================================================ 2 | # http://www.gnu.org/software/autoconf-archive/ax_boost_program_options.html 3 | # ============================================================================ 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_BOOST_PROGRAM_OPTIONS 8 | # 9 | # DESCRIPTION 10 | # 11 | # Test for program options library from the Boost C++ libraries. The macro 12 | # requires a preceding call to AX_BOOST_BASE. Further documentation is 13 | # available at . 14 | # 15 | # This macro calls: 16 | # 17 | # AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) 18 | # 19 | # And sets: 20 | # 21 | # HAVE_BOOST_PROGRAM_OPTIONS 22 | # 23 | # LICENSE 24 | # 25 | # Copyright (c) 2009 Thomas Porschberg 26 | # 27 | # Copying and distribution of this file, with or without modification, are 28 | # permitted in any medium without royalty provided the copyright notice 29 | # and this notice are preserved. This file is offered as-is, without any 30 | # warranty. 31 | 32 | #serial 20 33 | 34 | AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], 35 | [ 36 | AC_ARG_WITH([boost-program-options], 37 | AS_HELP_STRING([--with-boost-program-options@<:@=special-lib@:>@], 38 | [use the program options library from boost - it is possible to specify a certain library for the linker 39 | e.g. --with-boost-program-options=boost_program_options-gcc-mt-1_33_1 ]), 40 | [ 41 | if test "$withval" = "no"; then 42 | want_boost="no" 43 | elif test "$withval" = "yes"; then 44 | want_boost="yes" 45 | ax_boost_user_program_options_lib="" 46 | else 47 | want_boost="yes" 48 | ax_boost_user_program_options_lib="$withval" 49 | fi 50 | ], 51 | [want_boost="yes"] 52 | ) 53 | 54 | if test "x$want_boost" = "xyes"; then 55 | AC_REQUIRE([AC_PROG_CC]) 56 | export want_boost 57 | CPPFLAGS_SAVED="$CPPFLAGS" 58 | CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" 59 | export CPPFLAGS 60 | LDFLAGS_SAVED="$LDFLAGS" 61 | LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" 62 | export LDFLAGS 63 | AC_CACHE_CHECK([whether the Boost::Program_Options library is available], 64 | ax_cv_boost_program_options, 65 | [AC_LANG_PUSH(C++) 66 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include 67 | ]], 68 | [[boost::program_options::options_description generic("Generic options"); 69 | return 0;]])], 70 | ax_cv_boost_program_options=yes, ax_cv_boost_program_options=no) 71 | AC_LANG_POP([C++]) 72 | ]) 73 | if test "$ax_cv_boost_program_options" = yes; then 74 | AC_DEFINE(HAVE_BOOST_PROGRAM_OPTIONS,,[define if the Boost::PROGRAM_OPTIONS library is available]) 75 | BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` 76 | if test "x$ax_boost_user_program_options_lib" = "x"; then 77 | for libextension in `ls $BOOSTLIBDIR/libboost_program_options*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.a*$;\1;'` ; do 78 | ax_lib=${libextension} 79 | AC_CHECK_LIB($ax_lib, exit, 80 | [BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break], 81 | [link_program_options="no"]) 82 | done 83 | if test "x$link_program_options" != "xyes"; then 84 | for libextension in `ls $BOOSTLIBDIR/boost_program_options*.dll* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.dll.*$;\1;'` `ls $BOOSTLIBDIR/boost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.a*$;\1;'` ; do 85 | ax_lib=${libextension} 86 | AC_CHECK_LIB($ax_lib, exit, 87 | [BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break], 88 | [link_program_options="no"]) 89 | done 90 | fi 91 | else 92 | for ax_lib in $ax_boost_user_program_options_lib boost_program_options-$ax_boost_user_program_options_lib; do 93 | AC_CHECK_LIB($ax_lib, main, 94 | [BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break], 95 | [link_program_options="no"]) 96 | done 97 | fi 98 | if test "x$ax_lib" = "x"; then 99 | AC_MSG_ERROR(Could not find a version of the library!) 100 | fi 101 | if test "x$link_program_options" != "xyes"; then 102 | AC_MSG_ERROR([Could not link against [$ax_lib] !]) 103 | fi 104 | fi 105 | CPPFLAGS="$CPPFLAGS_SAVED" 106 | LDFLAGS="$LDFLAGS_SAVED" 107 | fi 108 | ]) 109 | -------------------------------------------------------------------------------- /m4/ax_boost_system.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.nongnu.org/autoconf-archive/ax_boost_system.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_BOOST_SYSTEM 8 | # 9 | # DESCRIPTION 10 | # 11 | # Test for System library from the Boost C++ libraries. The macro requires 12 | # a preceding call to AX_BOOST_BASE. Further documentation is available at 13 | # . 14 | # 15 | # This macro calls: 16 | # 17 | # AC_SUBST(BOOST_SYSTEM_LIB) 18 | # 19 | # And sets: 20 | # 21 | # HAVE_BOOST_SYSTEM 22 | # 23 | # LICENSE 24 | # 25 | # Copyright (c) 2008 Thomas Porschberg 26 | # Copyright (c) 2008 Michael Tindal 27 | # Copyright (c) 2008 Daniel Casimiro 28 | # 29 | # Copying and distribution of this file, with or without modification, are 30 | # permitted in any medium without royalty provided the copyright notice 31 | # and this notice are preserved. This file is offered as-is, without any 32 | # warranty. 33 | 34 | #serial 6 35 | 36 | AC_DEFUN([AX_BOOST_SYSTEM], 37 | [ 38 | AC_ARG_WITH([boost-system], 39 | AS_HELP_STRING([--with-boost-system@<:@=special-lib@:>@], 40 | [use the System library from boost - it is possible to specify a certain library for the linker 41 | e.g. --with-boost-system=boost_system-gcc-mt ]), 42 | [ 43 | if test "$withval" = "no"; then 44 | want_boost="no" 45 | elif test "$withval" = "yes"; then 46 | want_boost="yes" 47 | ax_boost_user_system_lib="" 48 | else 49 | want_boost="yes" 50 | ax_boost_user_system_lib="$withval" 51 | fi 52 | ], 53 | [want_boost="yes"] 54 | ) 55 | 56 | if test "x$want_boost" = "xyes"; then 57 | AC_REQUIRE([AC_PROG_CC]) 58 | AC_REQUIRE([AC_CANONICAL_BUILD]) 59 | CPPFLAGS_SAVED="$CPPFLAGS" 60 | CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" 61 | export CPPFLAGS 62 | 63 | LDFLAGS_SAVED="$LDFLAGS" 64 | LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" 65 | export LDFLAGS 66 | 67 | AC_CACHE_CHECK(whether the Boost::System library is available, 68 | ax_cv_boost_system, 69 | [AC_LANG_PUSH([C++]) 70 | CXXFLAGS_SAVE=$CXXFLAGS 71 | 72 | AC_COMPILE_IFELSE(AC_LANG_PROGRAM([[@%:@include ]], 73 | [[boost::system::system_category]]), 74 | ax_cv_boost_system=yes, ax_cv_boost_system=no) 75 | CXXFLAGS=$CXXFLAGS_SAVE 76 | AC_LANG_POP([C++]) 77 | ]) 78 | if test "x$ax_cv_boost_system" = "xyes"; then 79 | AC_SUBST(BOOST_CPPFLAGS) 80 | 81 | AC_DEFINE(HAVE_BOOST_SYSTEM,,[define if the Boost::System library is available]) 82 | BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` 83 | 84 | LDFLAGS_SAVE=$LDFLAGS 85 | if test "x$ax_boost_user_system_lib" = "x"; then 86 | for libextension in `ls $BOOSTLIBDIR/libboost_system*.{so,a}* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_system.*\)\.so.*$;\1;' -e 's;^lib\(boost_system.*\)\.a*$;\1;'` ; do 87 | ax_lib=${libextension} 88 | AC_CHECK_LIB($ax_lib, exit, 89 | [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break], 90 | [link_system="no"]) 91 | done 92 | if test "x$link_system" != "xyes"; then 93 | for libextension in `ls $BOOSTLIBDIR/boost_system*.{dll,a}* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_system.*\)\.dll.*$;\1;' -e 's;^\(boost_system.*\)\.a*$;\1;'` ; do 94 | ax_lib=${libextension} 95 | AC_CHECK_LIB($ax_lib, exit, 96 | [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break], 97 | [link_system="no"]) 98 | done 99 | fi 100 | 101 | else 102 | for ax_lib in $ax_boost_user_system_lib boost_system-$ax_boost_user_system_lib; do 103 | AC_CHECK_LIB($ax_lib, exit, 104 | [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break], 105 | [link_system="no"]) 106 | done 107 | 108 | fi 109 | if test "x$link_system" = "xno"; then 110 | AC_MSG_ERROR(Could not link against $ax_lib !) 111 | fi 112 | fi 113 | 114 | CPPFLAGS="$CPPFLAGS_SAVED" 115 | LDFLAGS="$LDFLAGS_SAVED" 116 | fi 117 | ]) 118 | -------------------------------------------------------------------------------- /m4/ax_boost_thread.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_boost_thread.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_BOOST_THREAD 8 | # 9 | # DESCRIPTION 10 | # 11 | # Test for Thread library from the Boost C++ libraries. The macro requires 12 | # a preceding call to AX_BOOST_BASE. Further documentation is available at 13 | # . 14 | # 15 | # This macro calls: 16 | # 17 | # AC_SUBST(BOOST_THREAD_LIB) 18 | # 19 | # And sets: 20 | # 21 | # HAVE_BOOST_THREAD 22 | # 23 | # LICENSE 24 | # 25 | # Copyright (c) 2009 Thomas Porschberg 26 | # Copyright (c) 2009 Michael Tindal 27 | # 28 | # Copying and distribution of this file, with or without modification, are 29 | # permitted in any medium without royalty provided the copyright notice 30 | # and this notice are preserved. This file is offered as-is, without any 31 | # warranty. 32 | 33 | #serial 22 34 | 35 | AC_DEFUN([AX_BOOST_THREAD], 36 | [ 37 | AC_ARG_WITH([boost-thread], 38 | AS_HELP_STRING([--with-boost-thread@<:@=special-lib@:>@], 39 | [use the Thread library from boost - it is possible to specify a certain library for the linker 40 | e.g. --with-boost-thread=boost_thread-gcc-mt ]), 41 | [ 42 | if test "$withval" = "no"; then 43 | want_boost="no" 44 | elif test "$withval" = "yes"; then 45 | want_boost="yes" 46 | ax_boost_user_thread_lib="" 47 | else 48 | want_boost="yes" 49 | ax_boost_user_thread_lib="$withval" 50 | fi 51 | ], 52 | [want_boost="yes"] 53 | ) 54 | 55 | if test "x$want_boost" = "xyes"; then 56 | AC_REQUIRE([AC_PROG_CC]) 57 | AC_REQUIRE([AC_CANONICAL_BUILD]) 58 | CPPFLAGS_SAVED="$CPPFLAGS" 59 | CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" 60 | export CPPFLAGS 61 | 62 | LDFLAGS_SAVED="$LDFLAGS" 63 | LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" 64 | export LDFLAGS 65 | 66 | AC_CACHE_CHECK(whether the Boost::Thread library is available, 67 | ax_cv_boost_thread, 68 | [AC_LANG_PUSH([C++]) 69 | CXXFLAGS_SAVE=$CXXFLAGS 70 | 71 | if test "x$build_os" = "xsolaris" ; then 72 | CXXFLAGS="-pthreads $CXXFLAGS" 73 | elif test "x$build_os" = "xming32" ; then 74 | CXXFLAGS="-mthreads $CXXFLAGS" 75 | else 76 | CXXFLAGS="-pthread $CXXFLAGS" 77 | fi 78 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], 79 | [[boost::thread_group thrds; 80 | return 0;]])], 81 | ax_cv_boost_thread=yes, ax_cv_boost_thread=no) 82 | CXXFLAGS=$CXXFLAGS_SAVE 83 | AC_LANG_POP([C++]) 84 | ]) 85 | if test "x$ax_cv_boost_thread" = "xyes"; then 86 | if test "x$build_os" = "xsolaris" ; then 87 | BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS" 88 | elif test "x$build_os" = "xming32" ; then 89 | BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS" 90 | else 91 | BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS" 92 | fi 93 | 94 | AC_SUBST(BOOST_CPPFLAGS) 95 | 96 | AC_DEFINE(HAVE_BOOST_THREAD,,[define if the Boost::Thread library is available]) 97 | BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` 98 | 99 | LDFLAGS_SAVE=$LDFLAGS 100 | case "x$build_os" in 101 | *bsd* ) 102 | LDFLAGS="-pthread $LDFLAGS" 103 | break; 104 | ;; 105 | esac 106 | if test "x$ax_boost_user_thread_lib" = "x"; then 107 | for libextension in `ls $BOOSTLIBDIR/libboost_thread*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_thread.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_thread*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_thread.*\)\.a*$;\1;'`; do 108 | ax_lib=${libextension} 109 | AC_CHECK_LIB($ax_lib, exit, 110 | [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], 111 | [link_thread="no"]) 112 | done 113 | if test "x$link_thread" != "xyes"; then 114 | for libextension in `ls $BOOSTLIBDIR/boost_thread*.dll* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_thread.*\)\.dll.*$;\1;'` `ls $BOOSTLIBDIR/boost_thread*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_thread.*\)\.a*$;\1;'` ; do 115 | ax_lib=${libextension} 116 | AC_CHECK_LIB($ax_lib, exit, 117 | [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], 118 | [link_thread="no"]) 119 | done 120 | fi 121 | 122 | else 123 | for ax_lib in $ax_boost_user_thread_lib boost_thread-$ax_boost_user_thread_lib; do 124 | AC_CHECK_LIB($ax_lib, exit, 125 | [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], 126 | [link_thread="no"]) 127 | done 128 | 129 | fi 130 | if test "x$ax_lib" = "x"; then 131 | AC_MSG_ERROR(Could not find a version of the library!) 132 | fi 133 | if test "x$link_thread" = "xno"; then 134 | AC_MSG_ERROR(Could not link against $ax_lib !) 135 | else 136 | case "x$build_os" in 137 | *bsd* ) 138 | BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS" 139 | break; 140 | ;; 141 | esac 142 | 143 | fi 144 | fi 145 | 146 | CPPFLAGS="$CPPFLAGS_SAVED" 147 | LDFLAGS="$LDFLAGS_SAVED" 148 | fi 149 | ]) 150 | -------------------------------------------------------------------------------- /m4/ax_cxx_check_lib.m4: -------------------------------------------------------------------------------- 1 | dnl @synopsis AX_CXX_CHECK_LIB(libname, functioname, action-if, action-if-not) 2 | dnl 3 | dnl The standard AC_CHECK_LIB can not test functions in namespaces. 4 | dnl Therefore AC_CHECK_LIB(cgicc, cgicc::Cgicc::getVersion) will always 5 | dnl fail. We need to decompose the functionname into a series of namespaces 6 | dnl where it gets declared so that it can be used for a link test. 7 | dnl 8 | dnl In the first version I did allow namespace::functionname to be a 9 | dnl reference to a void-argument global functionname (just wrapped in a 10 | dnl namespace) like its C counterparts would be - but in reality such 11 | dnl thing does not exist. The only global / static functions are always 12 | dnl made const-functions which is an attribute mangled along into the 13 | dnl library function export name. 14 | dnl 15 | dnl The normal usage will ask for a test of a class-member function which 16 | dnl should be presented with a full function spec with arguments given in 17 | dnl parentheses following the function name - if the function to test for 18 | dnl does expect arguments then you should add default initial values in the 19 | dnl prototype (even if they do not exist originally, these are used only 20 | dnl locally to build a correct function call in the configure test script). 21 | dnl 22 | dnl In the current version if you do omit the parenthesis from the macro 23 | dnl argument then the macro will assume that you want to check for the 24 | dnl class name - which is really to check for default constructor being 25 | dnl exported from the given library name. 26 | dnl 27 | dnl EXAMPLE: 28 | dnl AX_CXX_CHECK_LIB(cgicc, [cgicc::HTTPCookie]) 29 | dnl AX_CXX_CHECK_LIB(cgicc, [cgicc::Cgicc::getVersion () const], 30 | dnl AX_CXX_CHECK_LIB(boost_regex, [boost::RegEx::Position (int i = 0) const]) 31 | dnl 32 | dnl Result: 33 | dnl Just as the usual AX_CXX_CHECK_LIB - defines HAVE_LIBCGICC 34 | dnl and adds the libraries to the default library path (and 35 | dnl uses internally the normal ac_check_lib cache symbol 36 | dnl like ac_cv_lib_cgicc_cgicc__Cgicc) 37 | dnl 38 | dnl Footnote: The C++ language is not good at creating stable library 39 | dnl interfaces at the binary level - a lot of functionality is usually being 40 | dnl given as inline functions plus there is hardly a chance to create opaque 41 | dnl types. Therefore most C++ library tests will only do compile tests using 42 | dnl the header files. Doing a check_lib is however good to check the link 43 | dnl dependency before hitting it as an error in the build later. 44 | dnl 45 | dnl @category C++ 46 | dnl @author Guido U. Draheim 47 | dnl @vesion 2006-12-18 48 | 49 | AC_DEFUN([AX_CXX_CHECK_LIB], 50 | [m4_ifval([$3], , [AH_CHECK_LIB([$1])])dnl 51 | AS_LITERAL_IF([$1], 52 | [AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1_$2])], 53 | [AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1''_$2])])dnl 54 | AC_CACHE_CHECK([for $2 in -l$1], ac_Lib, 55 | [ac_check_lib_save_LIBS=$LIBS 56 | LIBS="-l$1 $5 $LIBS" 57 | case "$2" 58 | in *::*::*\(*) 59 | AC_LINK_IFELSE([AC_LANG_PROGRAM([ 60 | namespace `echo "$2" | sed -e "s/::.*//"` 61 | { class `echo "$2" | sed -e "s/.*::\\(.*\\)::.*/\\1/" -e "s/(.*//"` 62 | { public: int `echo "$2" | sed -e "s/.*:://" -e "/(/!s/..*/&()/"`; 63 | }; 64 | } 65 | ],[`echo "$2" | sed -e "s/(.*//" -e "s/\\(.*\\)::\\(.*\\)/((\\1*)(0))->\\2/g"`()])], 66 | [AS_VAR_SET(ac_Lib, yes)], 67 | [AS_VAR_SET(ac_Lib, no)]) 68 | ;; *::*::*) 69 | AC_LINK_IFELSE([AC_LANG_PROGRAM([ 70 | namespace `echo "$2" | sed -e "s/::.*//"` 71 | { namespace `echo "$2" | sed -e "s/.*::\\(.*\\)::.*/\\1/"` 72 | { class `echo "$2" | sed -e "s/.*:://"` 73 | { public: `echo "$2" | sed -e "s/.*:://"` (); 74 | }; 75 | } 76 | } 77 | ],[new $2()])], 78 | [AS_VAR_SET(ac_Lib, yes)], 79 | [AS_VAR_SET(ac_Lib, no)]) 80 | ;; *::*\(*) 81 | AC_LINK_IFELSE([AC_LANG_PROGRAM([ 82 | class `echo "$2" | sed -e "s/\\(.*\\)::.*/\\1/" -e "s/(.*//"` 83 | { public: int `echo "$2" | sed -e "s/.*:://" -e "/(/!s/..*/&()/"`; 84 | }; 85 | ],[`echo "$2" | sed -e "s/(.*//" -e "s/\\(.*\\)::\\(.*\\)/((\\1*)(0))->\\2/g"`()])], 86 | [AS_VAR_SET(ac_Lib, yes)], 87 | [AS_VAR_SET(ac_Lib, no)]) 88 | ;; *::*) 89 | AC_LINK_IFELSE([AC_LANG_PROGRAM([ 90 | namespace `echo "$2" | sed -e "s/::.*//"` 91 | { class `echo "$2" | sed -e "s/.*:://"` 92 | { public: `echo "$2" | sed -e "s/.*:://"` (); 93 | }; 94 | } 95 | ],[new $2()])], 96 | [AS_VAR_SET(ac_Lib, yes)], 97 | [AS_VAR_SET(ac_Lib, no)]) 98 | ;; *) 99 | AC_LINK_IFELSE([AC_LANG_CALL([], [$2])], 100 | [AS_VAR_SET(ac_Lib, yes)], 101 | [AS_VAR_SET(ac_Lib, no)]) 102 | ;; esac 103 | LIBS=$ac_check_lib_save_LIBS]) 104 | AS_IF([test AS_VAR_GET(ac_Lib) = yes], 105 | [m4_default([$3], [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_LIB$1)) 106 | LIBS="-l$1 $LIBS" 107 | ])], 108 | [$4])dnl 109 | AS_VAR_POPDEF([ac_Lib])dnl 110 | ])# AC_CHECK_LIB 111 | -------------------------------------------------------------------------------- /nwsmtp.cron.d: -------------------------------------------------------------------------------- 1 | SHELL=/bin/sh 2 | PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin 3 | MAILTO=mail-root@yandex-team.ru 4 | 5 | */1 * * * * root nc -z -w 2 localhost 26 >/dev/null 2>&1; [ $? != "0" ] && (/etc/init.d/nwsmtp restart ; logger -p daemon.err "nwsmtp restarted") >/dev/null 2>&1 6 | -------------------------------------------------------------------------------- /nwsmtp.init: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # nwsmtp Start the nwsmtp daemon 4 | # 5 | # chkconfig: 345 98 05 6 | # description: nwsmtp 7 | # processname: nwsmtp 8 | # pidfile: /var/run/nwsmtp.pid 9 | 10 | 11 | # Source function library 12 | [ -f /etc/rc.d/init.d/functions ] && . /etc/rc.d/init.d/functions 13 | 14 | # pull in oracle's environment 15 | [ -f /etc/oraprofile ] && . /etc/oraprofile 16 | 17 | # pull in sysconfig settings 18 | [ -f /etc/sysconfig/nwsmtp ] && . /etc/sysconfig/nwsmtp 19 | 20 | ulimit -s 512 21 | ulimit -n 10240 22 | ulimit -c unlimited 23 | 24 | RETVAL=0 25 | DAEMON_COREFILE_LIMIT=unlimited 26 | 27 | PATH=/sbin:/bin:/usr/bin:/usr/sbin 28 | prog="/usr/sbin/nwsmtp" 29 | 30 | 31 | 32 | start() 33 | { 34 | echo -n $"Starting nwsmtp daemon: " 35 | if [ "$(pidofproc $prog)" = "" ]; then 36 | daemon $prog $OPTIONS 37 | echo 38 | else 39 | failure 40 | echo 41 | fi 42 | } 43 | 44 | stop() 45 | { 46 | echo -n $"Stopping nwsmtp daemon: " 47 | killproc $prog 48 | echo 49 | } 50 | 51 | case "$1" in 52 | start) 53 | start 54 | ;; 55 | 56 | stop) 57 | stop 58 | ;; 59 | status) 60 | status $prog 61 | ;; 62 | restart|reload) 63 | $0 stop 64 | $0 start 65 | ;; 66 | *) 67 | echo $"Usage: $0 {start|stop|status|restart|reload}" 68 | exit 1 69 | esac 70 | 71 | exit 0 72 | 73 | -------------------------------------------------------------------------------- /nwsmtp.sysconfig: -------------------------------------------------------------------------------- 1 | # Defaults for nwsmtp initscript 2 | # sourced by /etc/init.d/nwsmtp 3 | # installed at /etc/sysconfig/nwsmtp by the maintainer scripts 4 | 5 | # 6 | # This is a POSIX shell fragment 7 | # 8 | 9 | # Additional options that are passed to the Daemon. 10 | OPTIONS="-c /etc/nwsmtp/nwsmtp.conf -p /var/run/nwsmtp/nwsmtp.pid" 11 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS=-I$(top_srcdir) 2 | AM_CXXFLAGS=-Wall 3 | sbin_PROGRAMS = nwsmtp 4 | 5 | protocol_headers = rc.pb.h 6 | protocol_sources = rc.pb.cc 7 | 8 | nwsmtp_CFLAGS=@EXPAT_CFLAGS@ 9 | nwsmtp_CPPFLAGS=@BOOST_CPPFLAGS@ $(protobuf_CFLAGS) 10 | nwsmtp_LDFLAGS=@BOOST_LDFLAGS@ @EXPAT_LDFLAGS@ $(protobuf_LIBS) 11 | nwsmtp_LDADD=-lexpat -lopendkim @BOOST_PROGRAM_OPTIONS_LIB@\ 12 | @BOOST_THREAD_LIB@ @BOOST_SYSTEM_LIB@ 13 | nwsmtp_SOURCES = $(protocol_sources) main.cpp options.cpp server.cpp \ 14 | smtp_connection.cpp log.cpp switchcfg.cpp smtp_connection_manager.cpp\ 15 | rbl.cpp envelope.cpp rfc_date.cpp uti.cpp bb_client_rcpt.cpp http_client.cpp bb_parser.cpp\ 16 | so_client.cpp avir_client.cpp aliases.cpp smtp_client.cpp pidfile.cpp timer.cpp\ 17 | param_parser.cpp header_parser.cpp ip_options.cpp rfc822date.c atormoz.cpp adkim.cpp\ 18 | auth.cpp bb_client_auth.cpp smtp_connection_auth.cpp bb_client_mailfrom.cpp\ 19 | smtp_connection_mailfrom.cpp rc_clients/basic_rc_client.cpp\ 20 | rc_clients/greylisting.cpp 21 | 22 | CLEANFILES = $(protocol_headers) $(protocol_sources) 23 | 24 | .proto.pb.cc : 25 | $(AM_V_GEN)$(PROTOC) $(PROTOC_ARGS) $< 26 | 27 | .proto.pb.h : 28 | $(AM_V_GEN)$(PROTOC) $(PROTOC_ARGS) $< 29 | 30 | SUFFIXES = .proto .pb.cc 31 | 32 | PROTOC = protoc 33 | PROTOC_ARGS = -I. --cpp_out=. 34 | -------------------------------------------------------------------------------- /src/adkim.h: -------------------------------------------------------------------------------- 1 | #ifndef ADKIM_H 2 | #define ADKIM_H 3 | 4 | #include "buffers.h" 5 | #include 6 | #include 7 | 8 | struct dkim_parameters 9 | { 10 | typedef ybuffers_iterator yconst_buffers_iterator; 11 | 12 | yconst_buffers_iterator b; 13 | yconst_buffers_iterator bs; 14 | yconst_buffers_iterator e; 15 | 16 | dkim_parameters(const yconst_buffers_iterator& beg, 17 | const yconst_buffers_iterator& body_beg, const yconst_buffers_iterator& end) 18 | : b(beg), bs(body_beg), e(end) 19 | {} 20 | }; 21 | 22 | class dkim_check 23 | { 24 | public: 25 | struct dkim_check_impl; 26 | enum DKIM_STATUS 27 | { 28 | DKIM_PASS, 29 | DKIM_NEUTRAL, 30 | DKIM_FAIL, 31 | DKIM_NONE 32 | }; 33 | 34 | typedef boost::function< void (DKIM_STATUS, const std::string& indentity) > handler_t; 35 | 36 | dkim_check(); 37 | 38 | void start(boost::asio::io_service& ios, const dkim_parameters& p, handler_t handler); 39 | 40 | void stop(); 41 | 42 | bool is_inprogress() const; 43 | 44 | static const char* status(DKIM_STATUS s); 45 | 46 | private: 47 | boost::shared_ptr impl_; 48 | }; 49 | 50 | 51 | #endif // ADKIM_H 52 | -------------------------------------------------------------------------------- /src/aliases.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "aliases.h" 7 | #include "log.h" 8 | 9 | 10 | aliases g_aliases; 11 | 12 | aliases::aliases() 13 | { 14 | } 15 | 16 | bool aliases::load(const std::string &_file_name) 17 | { 18 | std::ifstream file(_file_name.c_str()); 19 | 20 | if (!file.good()) 21 | return false; 22 | 23 | std::map > new_aliases; 24 | 25 | std::string buffer; 26 | 27 | while(!std::getline(file, buffer).eof()) 28 | { 29 | 30 | std::string::size_type pos = buffer.find_first_of(" \t"); 31 | 32 | if (pos == std::string::npos) 33 | continue; 34 | 35 | std::string key = buffer.substr(0, pos); 36 | 37 | std::transform(key.begin(), key.end(), key.begin(), ::tolower); 38 | 39 | std::string al = buffer.substr(pos+1); 40 | 41 | std::list values; 42 | 43 | while (al.length() > 0) 44 | { 45 | 46 | std::string::size_type comma_pos = al.find(","); 47 | 48 | std::string next; 49 | 50 | if (comma_pos == std::string::npos) 51 | { 52 | next = al; 53 | al.clear(); 54 | } 55 | else 56 | { 57 | next = al.substr(0, comma_pos); 58 | al = al.substr(comma_pos + 1 ); 59 | } 60 | 61 | std::string::size_type start = next.find_first_not_of(" \t"); 62 | 63 | if (start == std::string::npos) 64 | { 65 | start = 0; 66 | } 67 | 68 | std::string::size_type end = next.find_last_not_of(" \t"); 69 | 70 | if (end == std::string::npos) 71 | { 72 | end = next.length(); 73 | } 74 | 75 | values.push_back(next.substr(start, (end-start)+1)); 76 | 77 | } 78 | 79 | new_aliases[key] = values; 80 | } 81 | 82 | boost::unique_lock lck(m_mutex); 83 | 84 | m_aliases.swap(new_aliases); 85 | 86 | return true; 87 | 88 | } 89 | 90 | bool aliases::process(const std::string &_rcpt, const long long unsigned _suid, boost::function< void (const std::string&, long long unsigned) > _func) 91 | { 92 | boost::shared_lock lck(m_mutex); 93 | 94 | std::string lrcpt(_rcpt); 95 | 96 | std::transform(lrcpt.begin(), lrcpt.end(), lrcpt.begin(), ::tolower); 97 | 98 | std::map >::iterator it= m_aliases.find(lrcpt); 99 | 100 | bool have_alias = (it != m_aliases.end()); 101 | 102 | if (have_alias) 103 | { 104 | for(std::list< std::string>::iterator lit = it->second.begin(); lit != it->second.end(); lit++) 105 | { 106 | _func(*lit, 0); // alias not user 107 | } 108 | } 109 | else 110 | { 111 | _func(_rcpt, _suid); 112 | } 113 | 114 | return have_alias; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /src/aliases.h: -------------------------------------------------------------------------------- 1 | #if !defined(_ALIASES_H_) 2 | #define _ALIASES_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class aliases 12 | { 13 | public: 14 | 15 | aliases(); 16 | 17 | bool load(const std::string &_file_name); 18 | 19 | bool process(const std::string &_rcpt, long long unsigned _suid, boost::function< void (const std::string &, long long unsigned) >); //true if have alias 20 | 21 | protected: 22 | 23 | std::map > m_aliases; 24 | 25 | boost::shared_mutex m_mutex; 26 | 27 | }; 28 | 29 | 30 | extern aliases g_aliases; 31 | 32 | #endif // _ALIASES_H_ 33 | -------------------------------------------------------------------------------- /src/aspf.h: -------------------------------------------------------------------------------- 1 | #ifndef ASPF_H 2 | #define ASPF_H 3 | 4 | #include 5 | #include 6 | 7 | struct spf_parameters 8 | { 9 | std::string ip; 10 | std::string domain; 11 | std::string from; 12 | }; 13 | 14 | template 15 | void async_check_SPF(boost::asio::io_service& ios, const spf_parameters& p, Handle handle); 16 | 17 | class spf_check 18 | { 19 | struct spf_check_impl; 20 | boost::shared_ptr impl_; 21 | 22 | public: 23 | spf_check(); 24 | 25 | template 26 | void start(boost::asio::io_service& ios, const spf_parameters& p, Handle handle); 27 | 28 | void stop(); 29 | 30 | bool is_inprogress() const; 31 | }; 32 | 33 | #include "aspf_impl.h" 34 | 35 | #endif //ASPF_H 36 | -------------------------------------------------------------------------------- /src/atormoz.cpp: -------------------------------------------------------------------------------- 1 | #include "atormoz.h" 2 | 3 | boost::optional parse_rc_response(const boost::asio::streambuf& buf) 4 | { 5 | typedef boost::asio::streambuf::const_buffers_type const_buffers_type; 6 | typedef boost::asio::buffers_iterator iterator; 7 | const_buffers_type buffers = buf.data(); 8 | iterator begin = iterator::begin(buffers); 9 | iterator end = iterator::end(buffers); 10 | 11 | // Look for the start of the body of the response 12 | boost::iterator_range delim = boost::as_literal("\r\n\r\n"); 13 | std::pair result = boost::asio::detail::partial_search( 14 | begin, end, delim.begin(), delim.end()); 15 | if (result.first != end && result.second) 16 | { 17 | iterator start = result.first + delim.size(); 18 | 19 | // Skip a line 20 | delim = boost::as_literal("\r\n"); 21 | result = boost::asio::detail::partial_search(start, end, 22 | delim.begin(), delim.end()); 23 | if (result.first != end && result.second) 24 | { 25 | // todo: we can optimise parsing here 26 | std::string d; 27 | start = result.first + delim.size(); 28 | std::copy(start, end, std::back_inserter(d)); 29 | 30 | rc_result res; 31 | try 32 | { 33 | std::istringstream iss(d); 34 | iss >> res.ok; 35 | iss >> res.sum1; 36 | iss >> res.sum2; 37 | iss >> res.sum3; 38 | iss >> res.sum4; 39 | } 40 | catch (...) 41 | { 42 | return boost::optional(); 43 | } 44 | 45 | return boost::optional(res); 46 | } 47 | } 48 | 49 | // No match. The response is invalid. 50 | return boost::optional(); 51 | } 52 | -------------------------------------------------------------------------------- /src/auth.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "auth.h" 5 | #include "yplatform/base64.h" 6 | 7 | auth::auth_status_t auth::initialize(const std::string &_ip) 8 | { 9 | ip_ = _ip; 10 | 11 | username_.clear(); 12 | password_.clear(); 13 | 14 | return AUTH_OK; 15 | } 16 | 17 | static void extract_base64_str(const std::string &_src, std::string &_dst) 18 | { 19 | _dst.reserve (_src.length() * 3 / 4); 20 | std::back_insert_iterator out_iter (_dst); 21 | 22 | yplatform::service::base64::decoder base64; 23 | base64.decode (_src.begin(), _src.end(), out_iter); 24 | } 25 | 26 | static bool extract_user_password(const std::string &_src, std::string &_user, std::string &_password) 27 | { 28 | std::string decoded; 29 | 30 | extract_base64_str(_src, decoded); 31 | 32 | std::string::size_type first_pos = decoded.find('\0'); 33 | 34 | if (first_pos != std::string::npos) 35 | { 36 | std::string::size_type second_pos = decoded.find('\0', first_pos + 1); 37 | 38 | if (second_pos != std::string::npos) 39 | { 40 | _user = decoded.substr(first_pos + 1, second_pos - first_pos - 1); 41 | _password = decoded.substr(second_pos + 1); // user and password, no extra steps 42 | 43 | return true; 44 | } 45 | else 46 | { 47 | _user = decoded.substr(second_pos + 1); 48 | _password.clear(); // only user no password need second SASL step 49 | return true; 50 | } 51 | 52 | } 53 | else // no start \0 fail 54 | { 55 | return false; 56 | } 57 | 58 | } 59 | 60 | auth::auth_status_t auth::first(const std::string &_method, const std::string &_init, std::string &_reply) 61 | { 62 | if (strcasecmp(_method.c_str(), "plain") == 0) 63 | { 64 | method_ = METHOD_PLAIN; 65 | 66 | if (_init.empty()) 67 | { 68 | _reply = "334 VXNlcm5hbWU6\r\n"; 69 | return AUTH_MORE; 70 | } 71 | 72 | if (extract_user_password(_init, username_, password_)) 73 | { 74 | return (username_.empty() || password_.empty()) ? AUTH_FORM : AUTH_DONE; 75 | } 76 | else 77 | { 78 | return AUTH_FORM; // Inavid base64 79 | } 80 | } 81 | else if (strcasecmp(_method.c_str(), "login") == 0) 82 | { 83 | method_ = METHOD_LOGIN; 84 | 85 | if (!_init.empty()) 86 | { 87 | extract_base64_str(_init, username_); 88 | 89 | _reply = "334 UGFzc3dvcmQ6\r\n"; 90 | 91 | return username_.empty() ? AUTH_FORM : AUTH_MORE; 92 | } 93 | else 94 | { 95 | _reply = "334 VXNlcm5hbWU6\r\n"; // username 96 | } 97 | 98 | return AUTH_MORE; 99 | } 100 | 101 | return AUTH_FORM; 102 | } 103 | 104 | auth::auth_status_t auth::next(const std::string &_response, std::string &_reply) 105 | { 106 | switch (method_) 107 | { 108 | case METHOD_PLAIN: 109 | 110 | if (extract_user_password(_response, username_, password_)) 111 | { 112 | 113 | return (username_.empty() || password_.empty()) ? AUTH_FORM : AUTH_DONE; 114 | } 115 | else 116 | { 117 | return AUTH_FORM; 118 | } 119 | 120 | break; 121 | 122 | case METHOD_LOGIN: 123 | 124 | if (username_.empty()) 125 | { 126 | extract_base64_str(_response, username_); 127 | _reply = "334 UGFzc3dvcmQ6\r\n"; 128 | return (username_.empty()) ? AUTH_FORM : AUTH_MORE; 129 | } 130 | else 131 | { 132 | extract_base64_str(_response, password_); 133 | return (password_.empty()) ? AUTH_FORM : AUTH_DONE; 134 | } 135 | 136 | break; 137 | 138 | case METHOD_INVALID: 139 | 140 | return AUTH_FORM; 141 | 142 | break; 143 | } 144 | return AUTH_OK; 145 | } 146 | 147 | auth::auth_status_t auth::get_session_params(std::string &_user, std::string &_password, std::string &_ip, std::string &_method) 148 | { 149 | _user = username_; 150 | _password = password_; 151 | _ip = ip_; 152 | 153 | switch (method_) 154 | { 155 | case METHOD_PLAIN: 156 | _method = "PLAIN"; 157 | break; 158 | 159 | case METHOD_LOGIN: 160 | _method = "LOGIN"; 161 | break; 162 | 163 | default: 164 | _method = "INVALID"; 165 | break; 166 | } 167 | 168 | return AUTH_OK; 169 | } 170 | 171 | std::string auth::get_methods() 172 | { 173 | return "LOGIN PLAIN"; 174 | } 175 | 176 | -------------------------------------------------------------------------------- /src/auth.h: -------------------------------------------------------------------------------- 1 | #if !defined(_AUTH_H_) 2 | #define _AUTH_H_ 3 | 4 | #include 5 | 6 | class auth 7 | { 8 | public: 9 | 10 | typedef enum 11 | { 12 | AUTH_OK = 1, // Operation succesed 13 | AUTH_MORE, // Auth need next stage 14 | AUTH_DONE, // Oparation done - can start BB Request 15 | AUTH_FORM // Invalid parametres 16 | } auth_status_t; 17 | 18 | typedef enum 19 | { 20 | METHOD_INVALID = 0, 21 | METHOD_PLAIN, 22 | METHOD_LOGIN 23 | } auth_method_t; 24 | 25 | auth_status_t initialize(const std::string &_ip); // set session ip 26 | 27 | auth_status_t first(const std::string &_method, const std::string &_response, std::string &_reply); // start auth operation 28 | 29 | auth_status_t next(const std::string &_response, std::string &_reply); // continue operation 30 | 31 | auth_status_t get_session_params(std::string &_user, std::string &_password, std::string &_ip, std::string &_method); // set session parameters 32 | 33 | std::string get_methods(); // return method parameters 34 | 35 | protected: 36 | 37 | auth_method_t method_; 38 | 39 | std::string username_; 40 | std::string password_; 41 | std::string ip_; 42 | }; 43 | 44 | 45 | #endif // _AUTH_H_ 46 | -------------------------------------------------------------------------------- /src/avir_client.h: -------------------------------------------------------------------------------- 1 | #if !defined(_AVIR_CLIENT_H_) 2 | #define _AVIR_CLIENT_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #if defined(HAVE_CONFIG_H) 12 | #include "../config.h" 13 | #endif 14 | #if defined(HAVE_PA_ASYNC_H) 15 | #include 16 | #endif 17 | 18 | #include "check.h" 19 | #include "switchcfg.h" 20 | #include "envelope.h" 21 | 22 | class avir_client: 23 | public boost::enable_shared_from_this, 24 | private boost::noncopyable 25 | { 26 | public: 27 | avir_client(boost::asio::io_service& io_service, switchcfg *_config); 28 | 29 | typedef boost::function < void () > complete_cb_t; 30 | 31 | void start(const check_data_t& _data, complete_cb_t complete_cb, envelope_ptr _envelope); 32 | 33 | void stop(); 34 | 35 | check_data_t check_data() const { return m_data; } 36 | 37 | protected: 38 | void do_stop(); 39 | 40 | void restart(); 41 | 42 | void handle_connect(const boost::system::error_code& ec, y::net::dns::resolver::iterator, int port); 43 | void handle_resolve(const boost::system::error_code& ec, y::net::dns::resolver::iterator, int port); 44 | void handle_write_prolog(const boost::system::error_code& _err); 45 | void handle_write_request(const boost::system::error_code &_err); 46 | void handle_read_status(const boost::system::error_code& _e, std::size_t _bytes_transferred); 47 | void handle_read_code(const boost::system::error_code& _e, std::size_t _bytes_transferred); 48 | 49 | void fault(const std::string &_log); 50 | void success(bool _infected); 51 | 52 | y::net::dns::resolver m_resolver; 53 | boost::asio::ip::tcp::socket m_socket; 54 | boost::asio::io_service::strand strand_; 55 | 56 | boost::asio::streambuf m_request; 57 | boost::array m_buffer; 58 | 59 | check_data_t m_data; 60 | envelope_ptr m_envelope; 61 | complete_cb_t m_complete; 62 | 63 | switchcfg *m_config; 64 | unsigned int m_try; 65 | std::size_t m_envelope_size; 66 | 67 | boost::asio::deadline_timer m_timer; 68 | 69 | unsigned int m_timer_value; 70 | 71 | void handle_timer( const boost::system::error_code &_error); 72 | void restart_timeout(); 73 | 74 | std::string m_log_host; 75 | bool m_log_connect; 76 | bool m_log_check; 77 | timer m_log_delay; 78 | 79 | void log_try(const std::string &_status, const std::string &_log); 80 | 81 | #if defined(HAVE_PA_ASYNC_H) 82 | pa::stimer_t m_pa_timer; 83 | #endif 84 | }; 85 | 86 | typedef boost::shared_ptr avir_client_ptr; 87 | 88 | #endif // _AVIR_CLIENT_H_ 89 | -------------------------------------------------------------------------------- /src/bb_client.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yandex/NwSMTP/c929fbb1bf4973ee6023efcef0fee55167a3bc53/src/bb_client.cpp -------------------------------------------------------------------------------- /src/bb_client.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yandex/NwSMTP/c929fbb1bf4973ee6023efcef0fee55167a3bc53/src/bb_client.h -------------------------------------------------------------------------------- /src/bb_client_auth.h: -------------------------------------------------------------------------------- 1 | #if !defined(_BB_CLIENT_AUTH_H_) 2 | #define _BB_CLIENT_AUTH_H_ 3 | 4 | #ifdef ENABLE_AUTH_BLACKBOX 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #if defined(HAVE_CONFIG_H) 13 | #include "../config.h" 14 | #endif 15 | #if defined(HAVE_PA_ASYNC_H) 16 | #include 17 | #endif 18 | 19 | #include "http_client.h" 20 | #include "switchcfg.h" 21 | #include "check.h" 22 | #include "envelope.h" 23 | #include "bb_parser.h" 24 | 25 | 26 | class black_box_client_auth: 27 | public boost::enable_shared_from_this, 28 | private boost::noncopyable 29 | 30 | { 31 | public: 32 | 33 | typedef struct 34 | { 35 | std::string login_; 36 | std::string password_; 37 | std::string ip_; 38 | std::string session_id_; 39 | std::string method_; 40 | } auth_info_t; 41 | 42 | black_box_client_auth(boost::asio::io_service& io_service, switchcfg *_switch_cfg); 43 | 44 | ~black_box_client_auth(); 45 | 46 | typedef boost::function< void (check::chk_status _status, long long unsigned _suid) > set_status_t; 47 | 48 | void start(const auth_info_t &_auth_info, set_status_t _status_cb); 49 | 50 | void stop(); 51 | 52 | check_rcpt_t check_rcpt() const; 53 | 54 | protected: 55 | 56 | void report(const check::chk_status _status, const std::string &_log,long long unsigned _suid=0, bool success = true); // end check process 57 | 58 | void do_stop(); 59 | void restart(); // new BB request 60 | void on_error (const boost::system::error_code& ec, const std::string& logemsg); 61 | void on_header_read(const std::string &_headers); 62 | void on_response_read(const std::string &_data, bool _eof); 63 | 64 | black_box_parser m_black_box_parser; 65 | 66 | http_client_ptr m_http_client; 67 | 68 | switchcfg *m_switch_cfg; 69 | 70 | unsigned int m_connect_count; 71 | 72 | boost::asio::io_service &m_io_service; 73 | 74 | set_status_t m_set_status; 75 | 76 | std::string m_log_host; 77 | 78 | timer m_log_delay; 79 | 80 | #if defined(HAVE_PA_ASYNC_H) 81 | pa::stimer_t m_pa_timer; 82 | #endif 83 | 84 | boost::asio::io_service::strand m_strand; 85 | 86 | std::string sasl_method_; 87 | 88 | auth_info_t auth_info_; 89 | }; 90 | 91 | typedef boost::shared_ptr black_box_client_auth_ptr; 92 | 93 | #endif // ENABLE_AUTH_BLACKBOX 94 | 95 | #endif //_BB_CLIENT_H_ 96 | -------------------------------------------------------------------------------- /src/bb_client_mailfrom.h: -------------------------------------------------------------------------------- 1 | #if !defined(_BB_CLIENT_MAILFROM_H_) 2 | #define _BB_CLIENT_MAILFROM_H_ 3 | 4 | #ifdef ENABLE_AUTH_BLACKBOX 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #if defined(HAVE_CONFIG_H) 13 | #include 14 | #endif 15 | #if defined(HAVE_PA_ASYNC_H) 16 | #include 17 | #endif 18 | 19 | #include "http_client.h" 20 | #include "switchcfg.h" 21 | #include "check.h" 22 | #include "bb_parser.h" 23 | #include "timer.h" 24 | 25 | class black_box_client_mailfrom: 26 | public boost::enable_shared_from_this, 27 | private boost::noncopyable 28 | 29 | { 30 | public: 31 | 32 | typedef struct 33 | { 34 | std::string session_id_; 35 | std::string mailfrom_; 36 | std::string ip_; 37 | } mailfrom_info_t; 38 | 39 | typedef struct 40 | { 41 | unsigned long long int suid_; 42 | int karma_; 43 | int karma_status_; 44 | time_t time_stamp_; 45 | std::string auth_addr_; 46 | } mailfrom_result_t; 47 | 48 | typedef boost::optional mailfrom_optional_result_t; 49 | 50 | black_box_client_mailfrom(boost::asio::io_service& io_service, switchcfg *_switch_cfg); 51 | 52 | ~black_box_client_mailfrom(); 53 | 54 | typedef boost::function< void (check::chk_status _status, mailfrom_result_t _auth_result) > set_status_t; 55 | 56 | void start(const mailfrom_info_t &_mailfrom_info, set_status_t _status_cb); 57 | 58 | void stop(); 59 | 60 | check_rcpt_t check_rcpt() const; 61 | 62 | protected: 63 | 64 | void report(check::chk_status _status, const std::string &_log, mailfrom_optional_result_t _result, bool _success = true); // end check process 65 | 66 | void do_stop(); 67 | void restart(); // new BB request 68 | void on_error (const boost::system::error_code& ec, const std::string& logemsg); 69 | void on_header_read(const std::string &_headers); 70 | void on_response_read(const std::string &_data, bool _eof); 71 | 72 | black_box_parser m_black_box_parser; 73 | 74 | http_client_ptr m_http_client; 75 | 76 | switchcfg *m_switch_cfg; 77 | 78 | unsigned int m_connect_count; 79 | 80 | boost::asio::io_service &m_io_service; 81 | 82 | set_status_t m_set_status; 83 | 84 | std::string m_log_host; 85 | 86 | timer m_log_delay; 87 | 88 | #if defined(HAVE_PA_ASYNC_H) 89 | pa::stimer_t m_pa_timer; 90 | #endif 91 | 92 | boost::asio::io_service::strand m_strand; 93 | 94 | mailfrom_info_t mailfrom_info_; 95 | }; 96 | 97 | typedef boost::shared_ptr black_box_client_mailfrom_ptr; 98 | 99 | #endif // ENABLE_AUTH_BLACKBOX 100 | 101 | #endif //_BB_CLIENT_MAILFROM_H_ 102 | -------------------------------------------------------------------------------- /src/bb_client_rcpt.h: -------------------------------------------------------------------------------- 1 | #if !defined(_BB_CLIENT_RCPT_H_) 2 | #define _BB_CLIENT_RCPT_H_ 3 | 4 | #ifdef ENABLE_AUTH_BLACKBOX 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #if defined(HAVE_CONFIG_H) 11 | #include 12 | #endif 13 | #if defined(HAVE_PA_ASYNC_H) 14 | #include 15 | #endif 16 | 17 | #include "http_client.h" 18 | #include "switchcfg.h" 19 | #include "check.h" 20 | #include "envelope.h" 21 | #include "bb_parser.h" 22 | 23 | class black_box_client_rcpt: 24 | public boost::enable_shared_from_this, 25 | private boost::noncopyable 26 | 27 | { 28 | public: 29 | 30 | black_box_client_rcpt(boost::asio::io_service& io_service, switchcfg *_switch_cfg); 31 | 32 | ~black_box_client_rcpt(); 33 | 34 | typedef boost::function< void () > set_rcpt_status_t; 35 | 36 | void start(const check_rcpt_t& _rcpt, set_rcpt_status_t _status_cb, envelope_ptr _envelope); 37 | 38 | void stop(); 39 | 40 | check_rcpt_t check_rcpt() const; 41 | 42 | protected: 43 | 44 | void report(const std::string &_response, const std::string &_log, bool success = true); // end check process 45 | 46 | void do_stop(); 47 | void restart(); // new BB request 48 | void on_error (const boost::system::error_code& ec, const std::string& logemsg); 49 | void on_header_read(const std::string &_headers); 50 | void on_response_read(const std::string &_data, bool _eof); 51 | 52 | black_box_parser m_black_box_parser; 53 | 54 | http_client_ptr m_http_client; 55 | 56 | check_rcpt_t m_check_rcpt; 57 | 58 | switchcfg *m_switch_cfg; 59 | 60 | unsigned int m_connect_count; 61 | 62 | boost::asio::io_service &m_io_service; 63 | 64 | set_rcpt_status_t m_set_rcpt_status; 65 | 66 | envelope_ptr m_envelope; 67 | 68 | std::string m_log_host; 69 | 70 | timer m_log_delay; 71 | 72 | #if defined(HAVE_PA_ASYNC_H) 73 | pa::stimer_t m_pa_timer; 74 | #endif 75 | 76 | boost::asio::io_service::strand m_strand; 77 | }; 78 | 79 | typedef boost::shared_ptr black_box_client_rcpt_ptr; 80 | 81 | #endif // ENABLE_AUTH_BLACKBOX 82 | 83 | #endif //_BB_CLIENT_H_ 84 | -------------------------------------------------------------------------------- /src/bb_parser.h: -------------------------------------------------------------------------------- 1 | #if !defined(_BB_PARSER_H_) 2 | #define _BB_PARSER_H_ 3 | 4 | #include 5 | 6 | #ifdef ENABLE_AUTH_BLACKBOX 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | const long long unsigned int g_no_spam_uid = 56218725; 13 | const int g_time_treshold = 10; 14 | 15 | class black_box_parser 16 | { 17 | public: 18 | 19 | typedef std::map field_map; 20 | 21 | typedef enum { 22 | METHOD_USER_INFO = 1, 23 | METHOD_USER_AUTH = 2 24 | } request_method; 25 | 26 | black_box_parser(); 27 | ~black_box_parser(); 28 | 29 | static std::string url_encode(const std::string &_str); 30 | 31 | static bool format_bb_request(request_method _method, 32 | const std::string &_url, 33 | const std::string &_login, 34 | const std::string &_sid, 35 | const std::string &_ip, 36 | const field_map &_req_field, 37 | bool _optimize, 38 | std::string &_request); 39 | 40 | void start_parse_request(const field_map &_map); 41 | 42 | bool parse_buffer(const std::string &_buffer, bool _done); // true if ok 43 | 44 | void start_element(const char* _name, const char** _atts); 45 | void end_element(const char* _name); 46 | void character_data_handler(const XML_Char* _str, int _len); 47 | bool get_attr(const char *_name, std::string &_value); 48 | 49 | int m_karma; 50 | int m_karma_status; 51 | time_t m_ban_time; 52 | std::string m_uid; 53 | field_map m_field_map; 54 | 55 | bool m_has_exception; 56 | unsigned int m_exception_code; 57 | std::string m_exception_name; 58 | std::string m_error_name; 59 | 60 | bool m_auth_success; 61 | 62 | protected: 63 | 64 | std::string m_collect_chars; 65 | const char **m_collect_attrs; 66 | 67 | XML_Parser m_parser; 68 | }; 69 | 70 | #endif // ENABLE_AUTH_BLACKBOX 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/check.h: -------------------------------------------------------------------------------- 1 | #if !defined(_CHECK_H_) 2 | #define _CHECK_H_ 3 | 4 | //#include 5 | 6 | struct check 7 | { 8 | typedef enum 9 | { 10 | CHK_ACCEPT = 0, 11 | CHK_REJECT, 12 | CHK_TEMPFAIL, 13 | CHK_DISCARD 14 | 15 | } chk_status; 16 | 17 | chk_status m_result; 18 | std::string m_answer; 19 | 20 | std::string m_session_id; 21 | std::string m_remote_ip; 22 | }; 23 | 24 | struct check_rcpt_t: 25 | public check 26 | { 27 | std::string m_rcpt; 28 | long long unsigned m_suid; 29 | std::string m_uid; 30 | }; 31 | 32 | struct check_data_t: 33 | public check 34 | { 35 | check_data_t() 36 | { 37 | } 38 | 39 | std::string m_remote_host; 40 | std::string m_helo_host; 41 | }; 42 | 43 | #endif // _CHECK_H_ 44 | -------------------------------------------------------------------------------- /src/coroutine.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // coroutine.hpp 3 | // ~~~~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #ifndef COROUTINE_HPP 12 | #define COROUTINE_HPP 13 | 14 | class coroutine 15 | { 16 | public: 17 | coroutine() : value_(0) {} 18 | bool is_child() const { return value_ < 0; } 19 | bool is_parent() const { return !is_child(); } 20 | bool is_complete() const { return value_ == -1; } 21 | private: 22 | friend class coroutine_ref; 23 | int value_; 24 | }; 25 | 26 | class coroutine_ref 27 | { 28 | public: 29 | coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {} 30 | coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {} 31 | ~coroutine_ref() { if (!modified_) value_ = -1; } 32 | operator int() const { return value_; } 33 | int& operator=(int v) { modified_ = true; return value_ = v; } 34 | private: 35 | void operator=(const coroutine_ref&); 36 | int& value_; 37 | bool modified_; 38 | }; 39 | 40 | #define CORO_REENTER(c) \ 41 | switch (coroutine_ref _coro_value = c) \ 42 | case -1: if (_coro_value) \ 43 | { \ 44 | goto terminate_coroutine; \ 45 | terminate_coroutine: \ 46 | _coro_value = -1; \ 47 | goto bail_out_of_coroutine; \ 48 | bail_out_of_coroutine: \ 49 | break; \ 50 | } \ 51 | else case 0: 52 | 53 | #define CORO_YIELD \ 54 | for (_coro_value = __LINE__;;) \ 55 | if (_coro_value == 0) \ 56 | { \ 57 | case __LINE__: ; \ 58 | break; \ 59 | } \ 60 | else \ 61 | switch (_coro_value ? 0 : 1) \ 62 | for (;;) \ 63 | case -1: if (_coro_value) \ 64 | goto terminate_coroutine; \ 65 | else for (;;) \ 66 | case 1: if (_coro_value) \ 67 | goto bail_out_of_coroutine; \ 68 | else case 0: 69 | 70 | #define CORO_FORK \ 71 | for (_coro_value = -__LINE__;; _coro_value = __LINE__) \ 72 | if (_coro_value == __LINE__) \ 73 | { \ 74 | case -__LINE__: ; \ 75 | break; \ 76 | } \ 77 | else 78 | 79 | #endif // COROUTINE_HPP 80 | -------------------------------------------------------------------------------- /src/envelope.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "envelope.h" 4 | 5 | envelope::envelope() 6 | : added_headers_(), 7 | orig_headers_(), 8 | altered_message_(), 9 | orig_message_(), 10 | orig_message_token_marker_size_(0), 11 | orig_message_body_beg_(), 12 | orig_message_size_(0), 13 | m_id(generate_new_id()), 14 | m_sender(), 15 | m_rcpt_list(), 16 | m_spam(false), 17 | m_no_local_relay(false), 18 | m_timer(), 19 | smtp_delivery_coro_() 20 | #ifdef ENABLE_AUTH_BLACKBOX 21 | ,karma_(0), 22 | karma_status_(0), 23 | time_stamp_(0), 24 | auth_mailfrom_(false) 25 | #endif 26 | 27 | { 28 | } 29 | 30 | struct rcpt_compare 31 | { 32 | long long unsigned m_suid; 33 | rcpt_compare(long long unsigned suid): m_suid(suid) 34 | { 35 | } 36 | 37 | bool operator () (const envelope::rcpt &_rcpt) 38 | { 39 | return _rcpt.m_suid == m_suid; 40 | } 41 | }; 42 | 43 | bool envelope::has_recipient(long long unsigned suid) 44 | { 45 | return m_rcpt_list.end() != 46 | std::find_if(m_rcpt_list.begin(), m_rcpt_list.end(), rcpt_compare(suid)); 47 | } 48 | 49 | envelope::rcpt_list_t::iterator envelope::add_recipient(const std::string &_rcpt, 50 | long long unsigned _suid, const std::string& _uid) 51 | { 52 | if (!_suid || !has_recipient(_suid)) 53 | { 54 | envelope::rcpt rcpt; 55 | 56 | rcpt.m_name = _rcpt; 57 | 58 | rcpt.m_suid = _suid; 59 | 60 | rcpt.m_uid = _uid; 61 | 62 | rcpt.m_spam_status = 0; 63 | 64 | m_rcpt_list.push_back(rcpt); 65 | 66 | return --m_rcpt_list.end(); 67 | } 68 | return m_rcpt_list.end(); 69 | } 70 | 71 | static char code_table[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx"; 72 | 73 | std::string envelope::generate_new_id() 74 | { 75 | 76 | std::string res; 77 | time_t now; 78 | 79 | struct tm *lt; 80 | 81 | int pid = getpid(); 82 | unsigned long tid = (unsigned long)pthread_self(); 83 | 84 | time( &now ); 85 | lt = localtime( &now ); 86 | 87 | res += code_table[ lt->tm_min ]; 88 | res += code_table[ lt->tm_sec ]; 89 | res += code_table[ pid % 60 ]; 90 | res += code_table[ tid % 60 ]; 91 | res += code_table[ rand() % 60 ]; 92 | res += code_table[ rand() % 60 ]; 93 | res += code_table[ rand() % 60 ]; 94 | res += code_table[ rand() % 60 ]; 95 | 96 | return res; 97 | } 98 | 99 | static bool pred(const envelope::rcpt_list_t::value_type &_t) 100 | { 101 | return _t.m_delivery_status == check::CHK_ACCEPT; 102 | } 103 | 104 | void envelope::remove_delivered_rcpt() 105 | { 106 | m_rcpt_list.erase(std::remove_if(m_rcpt_list.begin(), m_rcpt_list.end(), pred), m_rcpt_list.end()); 107 | } 108 | 109 | struct find_rcpt 110 | { 111 | find_rcpt(long long unsigned _suid) 112 | { 113 | m_suid = _suid; 114 | }; 115 | 116 | bool operator () (const envelope::rcpt_list_t::value_type &_rcpt) 117 | { 118 | return m_suid == _rcpt.m_suid; 119 | }; 120 | 121 | protected: 122 | 123 | long long unsigned m_suid; 124 | }; 125 | 126 | void envelope::set_personal_spam_status(long long unsigned _suid, unsigned int _status) 127 | { 128 | rcpt_list_t::iterator it = find_if(m_rcpt_list.begin(), m_rcpt_list.end(), find_rcpt(_suid)); 129 | 130 | if (it != m_rcpt_list.end()) 131 | { 132 | it->m_spam_status = _status; 133 | 134 | return; 135 | } 136 | } 137 | 138 | check::chk_status envelope::smtp_code_decode(unsigned int code) 139 | { 140 | if ((code >= 200) && (code < 300)) 141 | { 142 | return check::CHK_ACCEPT; 143 | } 144 | else if ((code >= 400) && (code < 500)) 145 | { 146 | return check::CHK_TEMPFAIL; 147 | } 148 | else if ((code >= 500) && (code < 600)) 149 | { 150 | return check::CHK_REJECT; 151 | } 152 | 153 | return check::CHK_TEMPFAIL; // Invalid 154 | } 155 | 156 | void envelope::cleanup_answers() 157 | { 158 | for(rcpt_list_t::iterator it = m_rcpt_list.begin(); it != m_rcpt_list.end(); it++) 159 | { 160 | it->m_remote_answer.clear(); 161 | } 162 | } 163 | 164 | 165 | -------------------------------------------------------------------------------- /src/envelope.h: -------------------------------------------------------------------------------- 1 | #if !defined(_ENVELOPE_H_) 2 | #define _ENVELOPE_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "buffers.h" 11 | #include "check.h" 12 | #include "timer.h" 13 | #include "rc_check.h" 14 | #include "rc_clients/greylisting.h" 15 | #include "coroutine.hpp" 16 | 17 | struct envelope 18 | : public boost::enable_shared_from_this, 19 | private boost::noncopyable 20 | 21 | { 22 | typedef ystreambuf::mutable_buffers_type ymutable_buffers; 23 | typedef ystreambuf::const_buffers_type yconst_buffers; 24 | typedef ybuffers_iterator yconst_buffers_iterator; 25 | 26 | struct rcpt 27 | { 28 | std::string m_name; 29 | 30 | long long unsigned m_suid; 31 | std::string m_uid; 32 | 33 | std::string m_remote_answer; 34 | 35 | check::chk_status m_delivery_status; 36 | 37 | unsigned int m_spam_status; 38 | 39 | boost::shared_ptr gr_check_; 40 | boost::shared_ptr rc_check_; 41 | 42 | bool operator == (struct rcpt &_rcpt) 43 | { 44 | return m_name == _rcpt.m_name; 45 | } 46 | 47 | rcpt() 48 | : m_suid(0), 49 | m_delivery_status(check::CHK_TEMPFAIL), 50 | m_spam_status(0) 51 | {} 52 | }; 53 | 54 | typedef std::list rcpt_list_t; 55 | 56 | envelope(); 57 | 58 | rcpt_list_t::iterator add_recipient(const std::string &_rcpt, 59 | long long unsigned _suid, const std::string& _uid); 60 | bool has_recipient(long long unsigned suid); 61 | 62 | void set_personal_spam_status(long long unsigned _suid, unsigned int _status); 63 | void set_karma_status(int _karma, int _karma_status, time_t _born_time); 64 | 65 | void remove_delivered_rcpt(); 66 | 67 | static std::string generate_new_id(); 68 | static check::chk_status smtp_code_decode(unsigned int code); 69 | 70 | void cleanup_answers(); 71 | 72 | yconst_buffers added_headers_; 73 | yconst_buffers orig_headers_; 74 | yconst_buffers altered_message_; 75 | yconst_buffers orig_message_; 76 | std::size_t orig_message_token_marker_size_; 77 | yconst_buffers_iterator orig_message_body_beg_; 78 | std::size_t orig_message_size_; 79 | 80 | std::string m_id; 81 | std::string m_sender; 82 | rcpt_list_t m_rcpt_list; 83 | bool m_spam; // envelope is spam 84 | bool m_no_local_relay; // no local relay if we have one or more aliases 85 | timer m_timer; 86 | coroutine smtp_delivery_coro_; 87 | 88 | #ifdef ENABLE_AUTH_BLACKBOX 89 | int karma_; 90 | int karma_status_; 91 | time_t time_stamp_; 92 | bool auth_mailfrom_; 93 | #endif 94 | 95 | }; 96 | 97 | typedef boost::shared_ptr envelope_ptr; 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /src/eom_parser.cpp: -------------------------------------------------------------------------------- 1 | #include "eom_parser.h" 2 | 3 | 4 | eom_parser::eom_parser() 5 | { 6 | m_state = STATE_0; 7 | } 8 | 9 | void eom_parser::reset() 10 | { 11 | m_state = STATE_0; 12 | } 13 | 14 | /* 15 | If the end of the message was found: 16 | returns true, 17 | eom, 18 | tail - the left over portion of the text directly past the parsed message 19 | 20 | Otherwise: 21 | returns false 22 | (needs more text) 23 | */ 24 | bool eom_parser::parse(const char* b, const char* e, const char*& eom, const char*& tail) 25 | { 26 | const char* p=b; 27 | const char* s=b; 28 | 29 | for (; p != e; ++p) 30 | { 31 | register char ch = *p; 32 | switch (m_state) 33 | { 34 | case STATE_0: // ^ 35 | if (ch == '.') 36 | m_state = STATE_1; // ^ -> ^. 37 | else if (ch == '\n') 38 | s = p+1; // ^ -> ^ 39 | else 40 | m_state = STATE_START; // ^ -> * 41 | break; 42 | 43 | case STATE_1: // ^. 44 | if (ch == '\n') 45 | { 46 | // message.write(b, s); 47 | tail = p+1; 48 | eom = s; 49 | //tail = string(p+1, e); 50 | m_state = STATE_0; 51 | return true; 52 | } 53 | else if (ch == '\r') 54 | m_state = STATE_2; // ^. -> ^.\r 55 | else 56 | { // need to get rid of '.' 57 | m_state = STATE_START; // ^. -> * 58 | // message.write(b, s); 59 | s = b = p; 60 | } 61 | break; 62 | 63 | case STATE_2: // ^.\r 64 | if (ch == '\n') 65 | { 66 | // message.write(b, s); 67 | tail = p+1; 68 | eom = s; 69 | //tail = string(p+1, e); 70 | m_state = STATE_0; 71 | return true; 72 | } 73 | else // ^.\r -> * 74 | { 75 | m_state = STATE_START; 76 | // const char* str = ".\r"; 77 | // message.write(str, str+2); 78 | b = p; 79 | } 80 | break; 81 | 82 | case STATE_START: // * 83 | if (ch == '\n') 84 | { 85 | m_state = STATE_0; // * -> ^ 86 | s = p+1; 87 | } 88 | break; 89 | } 90 | } 91 | 92 | // message.write(b, (m_state == STATE_START ? p : s) ); 93 | eom = (m_state == STATE_START ? p : s); 94 | return false; 95 | } 96 | -------------------------------------------------------------------------------- /src/header_parser.cpp: -------------------------------------------------------------------------------- 1 | #include "header_parser.h" 2 | 3 | header_iterator_range_t::iterator parse_header(header_iterator_range_t header, header_callback_t callback) 4 | { 5 | typedef header_iterator_range_t::iterator iterator; 6 | iterator beg = header.begin(); 7 | iterator end = header.end(); 8 | iterator pos = beg; 9 | 10 | while (pos != end) 11 | { 12 | register char c = *pos; 13 | 14 | // Check for end of headers (empty line): although RFC-822 recommends 15 | // to use CRLF for header/body separator (see 4.1 SYNTAX), here, we 16 | // also check for LF just in case... 17 | if (c == '\n') 18 | { 19 | ++pos; 20 | break; 21 | } 22 | else if (c == '\r' && pos + 1 != end && *(pos + 1) == '\n') 23 | { 24 | pos += 2; 25 | break; 26 | } 27 | 28 | // This line may be a field description 29 | if (!isspace(c)) 30 | { 31 | iterator nameStart = pos; // remember the start position of the line 32 | 33 | while (pos != end && (*pos != ':' && !isspace(*pos))) 34 | ++pos; 35 | 36 | iterator nameEnd = pos; 37 | 38 | while (pos != end && isspace(*pos)) 39 | ++pos; 40 | 41 | if (pos == end) 42 | break; 43 | 44 | if (*pos != ':') 45 | { 46 | // Humm...does not seem to be a valid header line. 47 | // Skip this error and advance to the next line 48 | pos = nameStart; 49 | 50 | while (pos != end && *pos++ != '\n') 51 | ; 52 | } 53 | else 54 | { 55 | // Extract the field name 56 | header_iterator_range_t name(nameStart, nameEnd); 57 | 58 | // Skip ':' character 59 | ++pos; 60 | 61 | // Skip spaces between ':' and the field contents 62 | while (pos != end && (*pos == ' ' || *pos == '\t')) 63 | ++pos; 64 | 65 | iterator ctsStart = pos; 66 | iterator ctsEnd = pos; 67 | 68 | while (pos != end) 69 | { 70 | ctsEnd = pos; 71 | 72 | while (pos != end) 73 | { 74 | c = *pos; 75 | 76 | // Check for end of line 77 | if (c == '\r' && pos + 1 != end && *(pos + 1) == '\n') 78 | { 79 | ctsEnd = pos; 80 | pos += 2; 81 | break; 82 | } 83 | else if (c == '\n') 84 | { 85 | ctsEnd = pos; 86 | ++pos; 87 | break; 88 | } 89 | 90 | ++pos; 91 | } 92 | 93 | if (pos == end) 94 | break; 95 | c = *pos; 96 | 97 | // Handle the case of folded lines 98 | if (c == ' ' || c == '\t') 99 | { 100 | // This is a folding white-space: we keep it as is and 101 | // we continue with contents parsing... 102 | } 103 | else 104 | { 105 | // End of this field 106 | break; 107 | } 108 | 109 | // Check for end of contents 110 | if (c == '\r' && pos + 1 != end && *(pos + 1) == '\n') 111 | { 112 | pos += 2; 113 | break; 114 | } 115 | else if (c == '\n') 116 | { 117 | ++pos; 118 | break; 119 | } 120 | } 121 | 122 | header_iterator_range_t val(ctsStart, ctsEnd); 123 | header_iterator_range_t h(nameStart, ctsEnd); 124 | 125 | callback(name, h, val); 126 | } 127 | } 128 | else 129 | { 130 | // Skip this error and advance to the next line 131 | while (pos != end && *pos++ != '\n') 132 | ; 133 | } 134 | } 135 | return pos; 136 | } 137 | -------------------------------------------------------------------------------- /src/header_parser.h: -------------------------------------------------------------------------------- 1 | #ifndef _HEADER_PARSER_H_ 2 | #define _HEADER_PARSER_H_ 3 | 4 | #include "envelope.h" 5 | #include 6 | #include 7 | 8 | typedef boost::iterator_range header_iterator_range_t; 9 | typedef boost::function< void (const header_iterator_range_t& name, const header_iterator_range_t& header, 10 | const header_iterator_range_t& value) > header_callback_t; 11 | 12 | header_iterator_range_t::iterator parse_header(header_iterator_range_t header, header_callback_t callback); 13 | 14 | #endif //_EOM_PARSER_H_ 15 | -------------------------------------------------------------------------------- /src/host_seq_resolver.h: -------------------------------------------------------------------------------- 1 | #ifndef NWSMTP_HOST_SEQ_RESOLVER_H 2 | #define NWSMTP_HOST_SEQ_RESOLVER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // Host resolver intented to check hosts in config options 11 | /* 12 | * Preconditions: 13 | * 1. Endpoint(std::string(), int()) should be a valid expression convertible to OutIter::value_type 14 | * 2. InIter models input iterator 15 | * 3. OutIter models output iterator (may be singular) 16 | * 4. OutIter::value_type should be default constructible 17 | */ 18 | template 19 | class host_sequence_resolver 20 | { 21 | boost::asio::io_service ios_; 22 | y::net::dns::resolver r_; 23 | boost::asio::io_service::strand strand_; 24 | 25 | typedef std::deque deque_t; 26 | class resolver 27 | { 28 | public: 29 | InIter src_; 30 | typename deque_t::iterator dst_; 31 | int port_; 32 | 33 | resolver(InIter src, typename deque_t::iterator dst, int port) 34 | : src_(src), 35 | dst_(dst), 36 | port_(port) 37 | { 38 | } 39 | 40 | void operator()(const boost::system::error_code& ec, 41 | y::net::dns::resolver::iterator it) 42 | { 43 | if (ec) 44 | throw std::runtime_error( str(boost::format("failed to resolve %1%") % *src_) ); 45 | 46 | if (const boost::shared_ptr ar = 47 | boost::dynamic_pointer_cast(*it)) 48 | { 49 | *dst_++ = Endpoint(ar->address(), port_); 50 | return; 51 | } 52 | } 53 | }; 54 | 55 | public: 56 | host_sequence_resolver() 57 | : ios_(), 58 | r_(ios_), 59 | strand_(ios_) 60 | { 61 | } 62 | 63 | void operator()(InIter ibeg, InIter iend, OutIter dst, int port) 64 | { 65 | deque_t d; 66 | for (; ibeg != iend; ++ibeg) 67 | { 68 | d.push_back(typename deque_t::value_type()); 69 | typename deque_t::iterator dst = --d.end(); 70 | try 71 | { 72 | // See if resolving is really needed 73 | Endpoint e(boost::asio::ip::address_v4::from_string(*ibeg), port); 74 | *dst++ = e; 75 | continue; 76 | } 77 | catch (...) {} 78 | 79 | r_.async_resolve(*ibeg, y::net::dns::type_a, 80 | strand_.wrap(resolver(ibeg, dst, port))); 81 | } 82 | 83 | ios_.run(); 84 | std::copy(d.begin(), d.end(), dst); 85 | } 86 | }; 87 | 88 | template 89 | void resolve_host_sequence(In ibeg, In iend, Out out, int port) 90 | { 91 | host_sequence_resolver r; 92 | r(ibeg, iend, out, port); 93 | } 94 | 95 | #endif // NWSMTP_HOST_SEQ_RESOLVER_H 96 | -------------------------------------------------------------------------------- /src/http_client.h: -------------------------------------------------------------------------------- 1 | #if !defined(_HTTP_CLIENT_H_) 2 | #define _HTTP_CLIENT_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | class http_client 13 | : public boost::enable_shared_from_this, 14 | private boost::noncopyable 15 | { 16 | public: 17 | 18 | typedef enum { http_method_get, http_method_put } http_method_t; 19 | 20 | http_client(boost::asio::io_service& io_service); 21 | 22 | typedef boost::function< void (const std::string _content) > report_cb; 23 | 24 | // body mast be url encoded 25 | void start(http_method_t _method, const std::string &_host, unsigned int _service, const std::string &_url, const std::string &_body, unsigned int _timeout); 26 | 27 | void set_callbacks(boost::function< void (const boost::system::error_code& ec, const std::string &_err) > _error, 28 | boost::function< void (const std::string &_headers) > _headers_read, 29 | boost::function< void (const std::string &_data, bool _eof) > _response_read); 30 | void stop(); 31 | 32 | boost::asio::ip::tcp::socket& socket(); 33 | 34 | protected: 35 | void do_stop(); 36 | void handle_connect(const boost::system::error_code& ec, y::net::dns::resolver::iterator, int port); 37 | void handle_resolve(const boost::system::error_code& ec, y::net::dns::resolver::iterator, int port); 38 | void handle_write_request(const boost::system::error_code &_err); 39 | void handle_read_status_line(const boost::system::error_code &_err); 40 | void handle_read_headers(const boost::system::error_code &_err); 41 | void handle_read_content(const boost::system::error_code &_err); 42 | void error(const boost::system::error_code& ec, const std::string &_what); 43 | 44 | y::net::dns::resolver m_resolver; 45 | boost::asio::ip::tcp::socket m_socket; 46 | 47 | boost::asio::streambuf m_request; 48 | boost::asio::streambuf m_response; 49 | 50 | boost::function< void (const boost::system::error_code& ec, const std::string &_logerrmessage) > on_error; // call if error occured 51 | boost::function< void (const std::string &_headers) > on_headers_read; // call if all headers read 52 | boost::function< void (const std::string &_data, bool _eof) > on_response_read; // call if response block read 53 | 54 | boost::asio::deadline_timer m_timer; 55 | boost::asio::io_service::strand strand_; 56 | 57 | unsigned int m_timer_value; 58 | 59 | void handle_timer( const boost::system::error_code &_error); 60 | void restart_timeout(); 61 | }; 62 | 63 | typedef boost::shared_ptr http_client_ptr; 64 | 65 | #endif // _HTTP_CLIENT_H_ 66 | -------------------------------------------------------------------------------- /src/ip_options.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "ip_options.h" 7 | 8 | 9 | ip_options_config g_ip_config; 10 | 11 | ip_options_config::ip_options_config() 12 | { 13 | } 14 | 15 | bool ip_options_config::load(const std::string _file) 16 | { 17 | 18 | std::ifstream file(_file.c_str()); 19 | 20 | if (!file.good()) 21 | return false; 22 | 23 | std::string buffer; 24 | 25 | while(!std::getline(file, buffer).eof()) 26 | { 27 | 28 | std::string::size_type pos = buffer.find_first_not_of(" \t"); 29 | 30 | if (pos == std::string::npos) 31 | continue; 32 | 33 | buffer = buffer.substr(pos); 34 | 35 | if ((!buffer.empty()) && (buffer[0] == '#')) 36 | continue; 37 | 38 | pos = buffer.find("/"); 39 | std::string::size_type pos2 = buffer.find_first_of(" \t"); 40 | 41 | if (pos2 == std::string::npos) // not space to end of line 42 | { 43 | continue; 44 | } 45 | 46 | std::string ip; 47 | std::string mask("32"); 48 | 49 | if (pos == std::string::npos) 50 | { 51 | ip = buffer.substr(0, pos2); // single ip from start of line 52 | buffer = buffer.substr(pos2); 53 | } 54 | else 55 | { 56 | ip = buffer.substr(0, pos); // ip/mask in CIDR 57 | mask = buffer.substr(pos+1, pos2 - pos); 58 | 59 | buffer = buffer.substr(pos2+1); 60 | } 61 | 62 | opt_store_t opt; 63 | 64 | try 65 | { 66 | opt.m_network = boost::asio::ip::address_v4::from_string(ip).to_ulong(); 67 | 68 | int cnt = atoi(mask.c_str()); 69 | 70 | if ((cnt < 0) || (cnt > 32)) 71 | { 72 | continue; 73 | } 74 | 75 | unsigned int msk = 0; 76 | 77 | for(int i = 1; i <= cnt; i++) 78 | { 79 | msk |= 1 << (32-i); 80 | } 81 | 82 | opt.m_mask = msk; 83 | } 84 | catch(...) 85 | { 86 | continue; 87 | } 88 | 89 | typedef boost::tokenizer > tokenizer; 90 | 91 | boost::char_separator sep(" \t"); 92 | tokenizer tokens(buffer, sep); 93 | 94 | if (std::distance(tokens.begin(), tokens.end()) < 1) 95 | { 96 | continue; 97 | } 98 | 99 | tokenizer::iterator tok_iter = tokens.begin(); 100 | 101 | opt.m_options.m_rcpt_count = atoi(tok_iter->c_str()); // rcpt count 102 | 103 | m_opt_list.push_back(opt); 104 | } 105 | 106 | return true; 107 | } 108 | 109 | struct pred 110 | { 111 | pred(const boost::asio::ip::address_v4 &_address) 112 | { 113 | m_address = _address; 114 | } 115 | 116 | bool operator () (const ip_options_config::opt_store_t &_opt) 117 | { 118 | 119 | /* unsigned int a = m_address.to_ulong(); 120 | unsigned int b = _opt.m_mask; 121 | unsigned int c = _opt.m_network; 122 | 123 | std::cout << std::hex << "a=" << a << " b=" << b << " c=" << c << " and=" << (a&b) << std::endl;*/ 124 | 125 | 126 | return ((m_address.to_ulong() & _opt.m_mask) == (_opt.m_network & _opt.m_mask)); 127 | } 128 | 129 | boost::asio::ip::address_v4 m_address; 130 | }; 131 | 132 | bool ip_options_config::check(const boost::asio::ip::address_v4 _address, ip_options_t &_options) 133 | { 134 | opt_store_list::iterator it = std::find_if(m_opt_list.begin(), m_opt_list.end(), pred(_address)); 135 | 136 | if (it != m_opt_list.end()) 137 | { 138 | _options = it->m_options; 139 | return true; 140 | } 141 | 142 | return false; 143 | } 144 | 145 | -------------------------------------------------------------------------------- /src/ip_options.h: -------------------------------------------------------------------------------- 1 | #if !defined(_IP_OPTIONS_H_) 2 | #define _IP_OPTIONS_H_ 3 | 4 | #include 5 | #include 6 | 7 | class ip_options_config 8 | { 9 | 10 | public: 11 | 12 | 13 | typedef struct 14 | { 15 | unsigned int m_rcpt_count; 16 | 17 | } ip_options_t; 18 | 19 | ip_options_config(); 20 | 21 | bool load(const std::string _file); 22 | 23 | bool check(const boost::asio::ip::address_v4 _address, ip_options_t &_options); 24 | 25 | typedef struct 26 | { 27 | unsigned int m_network; 28 | unsigned int m_mask; 29 | ip_options_t m_options; 30 | } opt_store_t; 31 | 32 | protected: 33 | 34 | typedef std::list opt_store_list; 35 | 36 | opt_store_list m_opt_list; 37 | }; 38 | 39 | extern ip_options_config g_ip_config; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/log.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "log.h" 3 | 4 | logger g_log; 5 | 6 | 7 | logger::logger() 8 | : m_exit(false), 9 | m_log_prio(0) 10 | { 11 | } 12 | 13 | void logger::initlog(const std::string &_info, int _log_prio) 14 | { 15 | openlog("nwsmtp", 0, LOG_MAIL); 16 | m_log_prio = _log_prio; 17 | 18 | } 19 | 20 | void logger::msg(int _prio, const std::string &_msg) 21 | { 22 | if (_prio < m_log_prio) 23 | { 24 | boost::mutex::scoped_lock lck(m_condition_mutex); 25 | m_queue.push(_msg); 26 | m_condition.notify_one(); 27 | } 28 | } 29 | 30 | void logger::msg(int _prio, const char *_msg) 31 | { 32 | msg(_prio, std::string(_msg)); 33 | } 34 | 35 | void logger::run() 36 | { 37 | std::string buffer; 38 | for (;;) 39 | { 40 | boost::mutex::scoped_lock lck(m_condition_mutex); 41 | while (m_queue.empty() && !m_exit) 42 | m_condition.wait(lck); 43 | 44 | if (!m_queue.empty()) 45 | { 46 | m_queue.front().swap(buffer); 47 | m_queue.pop(); 48 | 49 | lck.unlock(); 50 | syslog(LOG_INFO, "%s", buffer.c_str()); 51 | 52 | } 53 | else if (m_exit) 54 | break; 55 | } 56 | } 57 | 58 | void logger::stop() 59 | { 60 | m_exit = true; 61 | m_condition.notify_one(); 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | #if !defined(_LOG_H_) 2 | #define _LOG_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | const int MSG_NORMAL = 20; 12 | const int MSG_CRITICAL = 10; 13 | const int MSG_VERY_CRITICAL = 10; 14 | 15 | class logger 16 | { 17 | public: 18 | logger(); 19 | 20 | void initlog(const std::string &_info, int _log_prio); 21 | 22 | void msg(int _prio, const std::string &_msg); 23 | 24 | void msg(int _prio, const char *_msg); 25 | 26 | void run(); 27 | 28 | void stop(); 29 | 30 | protected: 31 | 32 | std::queue m_queue; 33 | 34 | boost::mutex m_condition_mutex; 35 | boost::condition m_condition; 36 | 37 | bool m_exit; 38 | int m_log_prio; 39 | 40 | }; 41 | 42 | extern logger g_log; 43 | 44 | #endif // _LOG_H_ 45 | 46 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #if defined(HAVE_PA_ASYNC_H) 12 | #include 13 | #endif 14 | 15 | #include "server.h" 16 | #include "options.h" 17 | #include "log.h" 18 | #include "aliases.h" 19 | #include "pidfile.h" 20 | #include "ip_options.h" 21 | 22 | namespace { 23 | void log_err(int prio, const std::string& what, bool copy_to_stderr) 24 | { 25 | g_log.msg(prio, what); 26 | if (copy_to_stderr) 27 | std::cerr << what << std::endl; 28 | } 29 | } 30 | 31 | int main(int argc, char* argv[]) 32 | { 33 | bool daemonized = false; 34 | if (!g_config.parse_config(argc, argv, std::cout)) 35 | { 36 | return 200; 37 | } 38 | 39 | g_log.initlog("nwsmtp", 9999); 40 | boost::thread log; 41 | 42 | #if defined(HAVE_HOSTSEARCH_HOSTSEARCH_H) 43 | if (g_config.m_so_check && !g_config.m_so_file_path.empty()) 44 | { 45 | g_log.msg(MSG_NORMAL,str(boost::format("Primary SO host: host='%1%:%2%'") % g_config.m_so_primary_host.m_host_name % g_config.m_so_primary_host.m_port)); 46 | } 47 | 48 | if (g_config.m_bb_check && !g_config.m_bb_file_path.empty()) 49 | { 50 | g_log.msg(MSG_NORMAL,str(boost::format("Primary black_box host: host='%1%:%2%%3%'") % g_config.m_bb_primary_host.m_host_name % g_config.m_bb_primary_host.m_port % g_config.m_bb_primary_host.m_url)); 51 | } 52 | #endif 53 | 54 | int rval = 0; 55 | try 56 | { 57 | g_bb_switch.initialize( g_config.m_bb_primary_host, g_config.m_bb_secondary_host); 58 | g_so_switch.initialize( g_config.m_so_primary_host, g_config.m_so_secondary_host); 59 | g_av_switch.initialize( g_config.m_av_primary_host, g_config.m_av_secondary_host); 60 | 61 | 62 | if (!g_config.m_aliases_file.empty()) 63 | { 64 | if (g_aliases.load(g_config.m_aliases_file)) 65 | { 66 | g_log.msg(MSG_NORMAL,str(boost::format("Load aliases file: name='%1%'") % g_config.m_aliases_file)); 67 | } 68 | else 69 | { 70 | throw std::logic_error(str(boost::format("Can't load aliases file: name='%1%'") % g_config.m_aliases_file)); 71 | } 72 | } 73 | 74 | if (!g_config.m_ip_config_file.empty()) 75 | { 76 | if (g_ip_config.load(g_config.m_ip_config_file)) 77 | { 78 | g_log.msg(MSG_NORMAL,str(boost::format("Load IP restriction file: name='%1%'") % g_config.m_ip_config_file)); 79 | } 80 | else 81 | { 82 | throw std::logic_error(str(boost::format("Can't load IP restriction file: name='%1%'") % g_config.m_ip_config_file)); 83 | } 84 | } 85 | 86 | g_log.msg(MSG_NORMAL, "Start process..."); 87 | 88 | sigset_t new_mask; 89 | sigfillset(&new_mask); 90 | sigset_t old_mask; 91 | pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask); 92 | 93 | server s(g_config.m_worker_count, g_config.m_uid, g_config.m_gid ); 94 | 95 | // Daemonize as late as possible, so as to be able to copy fatal error to stderr in case the server can't start 96 | if (!g_config.m_foreground) 97 | { 98 | if (daemon(0, 0) < 0) 99 | throw std::runtime_error("Failed to daemonize!"); 100 | daemonized = true; 101 | } 102 | 103 | #if defined(HAVE_PA_ASYNC_H) 104 | pa::async_profiler::init(1000000, 500); 105 | #endif 106 | 107 | // Start logging thread 108 | boost::thread(boost::bind(&logger::run, &g_log)).swap(log); 109 | 110 | s.run(); 111 | 112 | if (!g_pid_file.create(g_config.m_pid_file)) 113 | { 114 | log_err(MSG_NORMAL, str(boost::format("Can't write PID file: name='%1%', error='%2%'") % g_config.m_pid_file % strerror(errno)), 115 | !daemonized); 116 | } 117 | 118 | while(true) 119 | { 120 | pthread_sigmask(SIG_SETMASK, &old_mask, 0); 121 | 122 | sigset_t wait_mask; 123 | sigemptyset(&wait_mask); 124 | sigaddset(&wait_mask, SIGINT); 125 | sigaddset(&wait_mask, SIGQUIT); 126 | sigaddset(&wait_mask, SIGTERM); 127 | sigaddset(&wait_mask, SIGHUP); 128 | pthread_sigmask(SIG_BLOCK, &wait_mask, 0); 129 | int sig = 0; 130 | 131 | sigwait(&wait_mask, &sig); 132 | 133 | if (sig == SIGHUP) 134 | { 135 | if (g_aliases.load(g_config.m_aliases_file)) 136 | { 137 | g_log.msg(MSG_NORMAL,str(boost::format("Reload aliases file: name='%1%'") % g_config.m_aliases_file)); 138 | } 139 | else 140 | { 141 | log_err(MSG_VERY_CRITICAL,str(boost::format("Can't reload aliases file: name='%1%'") % g_config.m_aliases_file), 142 | !daemonized); 143 | } 144 | 145 | continue; 146 | } 147 | 148 | g_log.msg(MSG_NORMAL,str(boost::format("Received signal: %1%, exiting...") % sig)); 149 | 150 | break; 151 | } 152 | 153 | s.stop(); 154 | g_log.msg(MSG_NORMAL, "Normal end process..."); 155 | 156 | } 157 | catch (std::exception &e) 158 | { 159 | log_err(MSG_NORMAL, str(boost::format("Can't start server process: %1%") % e.what()), !daemonized); 160 | rval = 200; 161 | } 162 | 163 | g_pid_file.unlink(); 164 | 165 | // If an exception occured before the creation of the logging thread we need to create it here to log pending errors 166 | if (log.get_id() == boost::thread::id()) 167 | boost::thread(boost::bind(&logger::run, &g_log)).swap(log); 168 | 169 | g_log.stop(); 170 | log.join(); 171 | 172 | return rval; 173 | } 174 | -------------------------------------------------------------------------------- /src/net/basic_dns_resolver.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // basic_dns_resolver.hpp 3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2008 Andreas Haberstroh (andreas at ibusy dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | #ifndef BOOST_NET_BASIC_DNS_RESOLVER_HPP 11 | #define BOOST_NET_BASIC_DNS_RESOLVER_HPP 12 | 13 | #include 14 | 15 | namespace y { 16 | namespace net { 17 | namespace dns { 18 | 19 | template 20 | class basic_dns_resolver : public boost::asio::basic_io_object 21 | { 22 | public: 23 | 24 | typedef resolver_iterator iterator; 25 | 26 | explicit basic_dns_resolver(boost::asio::io_service &io_service) 27 | : boost::asio::basic_io_object(io_service) 28 | { 29 | } 30 | 31 | void add_nameserver(ip::address addr) 32 | { 33 | this->service.add_nameserver(this->implementation, addr); 34 | } 35 | 36 | void set_timeout(int seconds) 37 | { 38 | this->service.set_timeout(seconds); 39 | } 40 | 41 | void set_retries(int count) 42 | { 43 | this->service.set_retries(count); 44 | } 45 | 46 | template 47 | void async_resolve(const net::dns::question & question, Handler handler) 48 | { 49 | this->service.async_resolve(this->implementation, question, handler); 50 | } 51 | 52 | template 53 | void async_resolve(const string & domain, const net::dns::type_t rrtype, Handler handler) 54 | { 55 | this->service.async_resolve(this->implementation, domain, rrtype, handler); 56 | } 57 | 58 | void cancel() 59 | { 60 | this->service.cancel(this->implementation); 61 | } 62 | }; 63 | 64 | #if !defined(GENERATING_DOCUMENTATION) 65 | typedef basic_dns_resolver > resolver; 66 | #endif 67 | 68 | } // namespace dns 69 | } // namespace net 70 | } // namespace y 71 | 72 | #endif // BOOST_NET_BASIC_DNS_RESOLVER_HPP 73 | -------------------------------------------------------------------------------- /src/net/basic_dns_resolver_service.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // basic_dns_resolver_service.hpp 3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2008 Andreas Haberstroh (andreas at ibusy dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | #ifndef BOOST_NET_BASIC_DNS_RESOLVER_SERVICE_HPP 11 | #define BOOST_NET_BASIC_DNS_RESOLVER_SERVICE_HPP 12 | 13 | #include 14 | #include 15 | //#include 16 | 17 | namespace y { 18 | namespace net { 19 | namespace dns { 20 | 21 | template 22 | class basic_dns_resolver_service : public boost::asio::io_service::service 23 | { 24 | public: 25 | static boost::asio::io_service::id id; 26 | 27 | typedef resolver_iterator iterator; 28 | 29 | explicit basic_dns_resolver_service(boost::asio::io_service &io_service) 30 | : boost::asio::io_service::service(io_service) 31 | // work_(new boost::asio::io_service::work(work_io_service_)), 32 | // work_thread_(boost::bind(&boost::asio::io_service::run, &work_io_service_)) 33 | { 34 | } 35 | 36 | ~basic_dns_resolver_service() 37 | { 38 | // work_.reset(); 39 | // work_io_service_.stop(); 40 | // work_thread_.join(); 41 | } 42 | 43 | typedef boost::shared_ptr implementation_type; 44 | 45 | void construct(implementation_type &impl) 46 | { 47 | impl.reset(new DnsResolverImplementation(this->get_io_service())); 48 | } 49 | 50 | void destroy(implementation_type &impl) 51 | { 52 | if (impl) 53 | impl->destroy(); 54 | impl.reset(); 55 | } 56 | 57 | void cancel(implementation_type &impl) 58 | { 59 | if (impl) // ### ? 60 | impl->cancel(); 61 | } 62 | 63 | iterator resolve(implementation_type &impl, const net::dns::question & question) 64 | { 65 | return impl->resolve(question); 66 | } 67 | 68 | iterator resolve(implementation_type &impl, const string & domain, const net::dns::type_t rrtype) 69 | { 70 | return impl->resolve(domain, rrtype); 71 | } 72 | 73 | template 74 | void async_resolve(implementation_type &impl, const net::dns::question & question, Handler handler) 75 | { 76 | impl->async_resolve(question, handler); 77 | } 78 | 79 | template 80 | void async_resolve(implementation_type &impl, const string & domain, const net::dns::type_t rrtype, Handler handler) 81 | { 82 | net::dns::question question(domain, rrtype); 83 | impl->async_resolve(question, handler); 84 | } 85 | 86 | void add_nameserver(implementation_type &impl, ip::address addr) 87 | { 88 | impl->add_nameserver(addr); 89 | } 90 | 91 | void set_timeout(implementation_type &impl, int seconds) 92 | { 93 | impl->set_timeout(seconds); 94 | } 95 | 96 | void set_retries(implementation_type &impl, int count) 97 | { 98 | impl->set_retries(count); 99 | } 100 | 101 | 102 | private: 103 | void shutdown_service() 104 | { 105 | } 106 | 107 | // boost::asio::io_service work_io_service_; 108 | // boost::scoped_ptr work_; 109 | // boost::thread work_thread_; 110 | }; 111 | #if !defined(GENERATING_DOCUMENTATION) 112 | template 113 | boost::asio::io_service::id basic_dns_resolver_service::id; 114 | #endif 115 | } // namespace dns 116 | } // namespace net 117 | } // namespace y 118 | 119 | #endif // BOOST_NET_BASIC_DNS_RESOLVER_SERVICE_HPP 120 | -------------------------------------------------------------------------------- /src/net/dns_resolver.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // dns_resolver.hpp 3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2008 Andreas Haberstroh (andreas at ibusy dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | #ifndef BOOST_NET_DNS_RESOLVER_HPP 11 | #define BOOST_NET_DNS_RESOLVER_HPP 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #endif // BOOST_NET_DNS_RESOLVER_HPP 22 | -------------------------------------------------------------------------------- /src/net/resolver_iterator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RESOLVER_ITERATOR_H 2 | #define RESOLVER_ITERATOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace y { 10 | namespace net { 11 | namespace dns { 12 | 13 | class resolver_iterator 14 | : public boost::iterator_facade< 15 | resolver_iterator, 16 | const shared_resource_base_t, 17 | boost::forward_traversal_tag> 18 | { 19 | public: 20 | resolver_iterator() 21 | { 22 | } 23 | 24 | static resolver_iterator create( 25 | const rr_list_t& l, 26 | type_t t) 27 | { 28 | resolver_iterator iter; 29 | if (l.empty()) 30 | return iter; 31 | 32 | iter.values_.reset(new values_type); 33 | 34 | for (rr_list_t::const_iterator it=l.begin(); it!=l.end(); ++it) 35 | { 36 | if ((*it)->rtype() == t) 37 | iter.values_->push_back(*it); 38 | } 39 | 40 | if (iter.values_->size()) 41 | iter.iter_ = iter.values_->begin(); 42 | else 43 | iter.values_.reset(); 44 | 45 | return iter; 46 | } 47 | 48 | static resolver_iterator create( 49 | shared_resource_base_t r) 50 | { 51 | resolver_iterator iter; 52 | 53 | if (r) 54 | { 55 | iter.values_.reset(new values_type); 56 | iter.values_->push_back(r); 57 | iter.iter_ = iter.values_->begin(); 58 | } 59 | 60 | return iter; 61 | } 62 | 63 | 64 | private: 65 | friend class boost::iterator_core_access; 66 | 67 | void increment() 68 | { 69 | if (++*iter_ == values_->end()) 70 | { 71 | // Reset state to match a default constructed end iterator. 72 | values_.reset(); 73 | iter_.reset(); 74 | } 75 | } 76 | 77 | bool equal(const resolver_iterator& other) const 78 | { 79 | if (!values_ && !other.values_) 80 | return true; 81 | if (values_ != other.values_) 82 | return false; 83 | return *iter_ == *other.iter_; 84 | } 85 | 86 | const shared_resource_base_t& dereference() const 87 | { 88 | return **iter_; 89 | } 90 | 91 | typedef rr_list_t values_type; 92 | typedef rr_list_t::const_iterator values_iter_type; 93 | boost::shared_ptr values_; 94 | boost::optional iter_; 95 | }; 96 | 97 | } // namespace y 98 | } // namespace net 99 | } // namespace dns 100 | 101 | #endif //RESOLVER_ITERATOR_H 102 | 103 | -------------------------------------------------------------------------------- /src/options.h: -------------------------------------------------------------------------------- 1 | #if !defined(_CONFIG_H_) 2 | #define _CONFIG_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "rc_clients/greylisting.h" 12 | 13 | #if defined(HAVE_CONFIG_H) 14 | #include "../config.h" 15 | #endif 16 | 17 | struct uid_value 18 | { 19 | public: 20 | uid_value () : uid (0) {} 21 | uid_value (uid_t const& u) : uid (u) {} 22 | operator uid_t () const { return uid; } 23 | uid_t uid; 24 | }; 25 | 26 | struct gid_value 27 | { 28 | public: 29 | gid_value () : gid (0) {} 30 | gid_value (gid_t const& g) : gid (g) {} 31 | operator gid_t () const { return gid; } 32 | gid_t gid; 33 | }; 34 | 35 | struct server_parameters 36 | { 37 | 38 | struct remote_point 39 | { 40 | // [proto://]host_name[:port][/url] 41 | // [proto://]host_name[:port] 42 | std::string m_proto; 43 | std::string m_host_name; 44 | unsigned int m_port; 45 | std::string m_url; 46 | }; 47 | 48 | std::vector< std::string > m_listen_points; 49 | 50 | std::vector< std::string > m_ssl_listen_points; 51 | 52 | std::string m_smtp_banner; 53 | 54 | unsigned int m_worker_count; 55 | 56 | bool m_rbl_active; 57 | std::string m_rbl_hosts; 58 | 59 | unsigned int m_debug_level; 60 | 61 | // blackbox 62 | 63 | // time_t m_bb_fallback_time; 64 | // time_t m_bb_return_time; 65 | 66 | time_t m_bb_connect_timeout; 67 | time_t m_bb_timeout; 68 | 69 | remote_point m_bb_primary_host; 70 | remote_point m_bb_secondary_host; 71 | 72 | #if defined(HAVE_HOSTSEARCH_HOSTSEARCH_H) 73 | std::string m_bb_file_path; 74 | int m_bb_port; 75 | #endif 76 | 77 | std::string m_aliases_file; 78 | 79 | unsigned int m_max_rcpt_count; 80 | 81 | // SO 82 | 83 | // time_t m_so_fallback_time; 84 | // time_t m_so_return_time; 85 | 86 | time_t m_so_connect_timeout; 87 | time_t m_so_timeout; 88 | 89 | remote_point m_so_primary_host; 90 | remote_point m_so_secondary_host; 91 | 92 | #if defined(HAVE_HOSTSEARCH_HOSTSEARCH_H) 93 | int m_so_port; 94 | std::string m_so_file_path; 95 | #endif 96 | 97 | // AV 98 | 99 | // time_t m_av_fallback_time; 100 | // time_t m_av_return_time; 101 | 102 | time_t m_av_connect_timeout; 103 | time_t m_av_timeout; 104 | 105 | remote_point m_av_primary_host; 106 | remote_point m_av_secondary_host; 107 | 108 | // RC 109 | 110 | std::string m_rc_host_listconf; 111 | std::vector< std::pair > m_rc_host_list; 113 | int m_rc_port; 114 | int m_rc_timeout; 115 | int m_rc_verbose; 116 | int m_rc_check; 117 | 118 | // SPF 119 | 120 | time_t m_spf_timeout; 121 | 122 | // DKIM 123 | 124 | time_t m_dkim_timeout; 125 | 126 | time_t m_relay_connect_timeout; 127 | time_t m_relay_cmd_timeout; 128 | time_t m_relay_data_timeout; 129 | 130 | time_t m_smtpd_cmd_timeout; 131 | time_t m_smtpd_data_timeout; 132 | 133 | bool m_allow_percent_hack; 134 | 135 | remote_point m_relay_host; 136 | 137 | remote_point m_local_relay_host; 138 | bool m_use_local_relay; 139 | 140 | bool m_foreground; 141 | 142 | std::string m_pid_file; 143 | 144 | unsigned int m_client_connection_count_limit; 145 | unsigned int m_connection_count_limit; 146 | 147 | bool m_so_check; 148 | bool so_trust_xyandexspam_; 149 | 150 | bool m_av_check; 151 | int m_action_virus; 152 | 153 | bool m_bb_check; 154 | 155 | unsigned int m_so_try; 156 | unsigned int m_bb_try; 157 | unsigned int m_av_try; 158 | 159 | unsigned int m_message_size_limit; 160 | 161 | bool m_remove_headers; 162 | std::string m_remove_headers_list; 163 | boost::unordered_set< std::string > m_remove_headers_set; 164 | 165 | bool m_remove_extra_cr; 166 | 167 | uid_value m_uid; 168 | gid_value m_gid; 169 | 170 | std::string greylisting_config_file_; 171 | greylisting_options greylisting_; 172 | bool use_greylisting_; 173 | bool enable_so_after_greylisting_; 174 | bool add_xyg_after_greylisting_; 175 | 176 | std::string m_ip_config_file; 177 | std::string m_profiler_log; 178 | 179 | bool m_use_tls; 180 | 181 | std::string m_tls_key_file; 182 | std::string m_tls_cert_file; 183 | std::string m_tls_ca_file; 184 | 185 | bool m_use_auth; 186 | bool m_auth_after_tls; 187 | 188 | int m_hard_error_limit; 189 | 190 | bool parse_config(int _argc, char* _argv[], std::ostream& _out); 191 | }; 192 | 193 | extern server_parameters g_config; 194 | 195 | extern const char *temp_error; 196 | extern const char *temp_user_error; 197 | extern const char *perm_user__error; 198 | 199 | 200 | #endif //_CONFIG_H_ 201 | -------------------------------------------------------------------------------- /src/pa_stub.h: -------------------------------------------------------------------------------- 1 | #if defined(HAVE_CONFIG_H) 2 | 3 | #include "../config.h" 4 | 5 | #if defined(HAVE_PA_INTERFACE_H) 6 | 7 | #define HAVE_PA 8 | #else 9 | 10 | #undef HAVE_PA 11 | 12 | #endif 13 | #else 14 | 15 | #undef HAVE_PA 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/param_parser.cpp: -------------------------------------------------------------------------------- 1 | #include "param_parser.h" 2 | #include 3 | #include 4 | 5 | 6 | std::string extract_word(std::string &_str) 7 | { 8 | std::string::size_type begin = _str.find_first_not_of(" \r\n\r"); 9 | 10 | if (begin == std::string::npos) 11 | { 12 | _str.erase(0, begin); 13 | return ""; 14 | } 15 | 16 | std::string::size_type end = _str.find_first_of(" \t\r\n", begin); 17 | 18 | if (end == std::string::npos) 19 | { 20 | end = _str.length(); 21 | } 22 | 23 | std::string tmp = _str.substr(begin, end - begin); 24 | 25 | _str.erase(0, end); 26 | 27 | return tmp; 28 | } 29 | 30 | param_parser::params_map::value_type parse_one_parameter(const std::string &_buffer) 31 | { 32 | 33 | std::string::size_type pos = _buffer.find("="); 34 | 35 | if (pos == std::string::npos) 36 | { 37 | throw std::exception(); 38 | } 39 | 40 | std::string key = _buffer.substr(0, pos); 41 | std::string value = _buffer.substr(pos+1); 42 | 43 | std::transform(key.begin(), key.end(), key.begin(), ::tolower); 44 | 45 | return param_parser::params_map::value_type(key, value); 46 | } 47 | 48 | void param_parser::parse(const std::string &_src, std::string &_addr, params_map &_params) 49 | { 50 | std::string buffer(_src); 51 | 52 | _addr = extract_word(buffer); 53 | 54 | std::string param; 55 | 56 | while (!buffer.empty() && !(param = extract_word(buffer)).empty()) 57 | { 58 | try 59 | { 60 | _params.insert(parse_one_parameter(param)); 61 | } 62 | catch(...) 63 | { 64 | continue; 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/param_parser.h: -------------------------------------------------------------------------------- 1 | #if !defined(_PARAM_PARSER_H_) 2 | #define _PARAM_PARSER_H_ 3 | 4 | #include 5 | #include 6 | 7 | struct param_parser 8 | { 9 | typedef std::map params_map; 10 | 11 | static void parse(const std::string &_src, std::string &_addr, params_map &_params); 12 | }; 13 | #endif //_PARAM_PARSER_H_ 14 | 15 | -------------------------------------------------------------------------------- /src/pidfile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "pidfile.h" 8 | 9 | pid_file g_pid_file; 10 | 11 | bool pid_file::create(const std::string& _file_name) 12 | { 13 | 14 | if (_file_name.empty()) 15 | { 16 | return false; 17 | } 18 | 19 | m_pid_file_name = _file_name; 20 | 21 | std::ofstream s(m_pid_file_name.c_str()); 22 | 23 | s << getpid() << std::endl; 24 | 25 | return s.good(); 26 | } 27 | 28 | bool pid_file::unlink() 29 | { 30 | if (!m_pid_file_name.empty()) 31 | { 32 | return ::unlink(m_pid_file_name.c_str()); 33 | } 34 | 35 | return false; 36 | } 37 | -------------------------------------------------------------------------------- /src/pidfile.h: -------------------------------------------------------------------------------- 1 | #if !defined(_PIDFILE_H_) 2 | #define _PIDFILE_H_ 3 | 4 | #include 5 | 6 | struct pid_file 7 | { 8 | bool create(const std::string& _file_name); 9 | 10 | bool unlink(); 11 | 12 | std::string m_pid_file_name; 13 | }; 14 | 15 | extern pid_file g_pid_file; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/rbl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "uti.h" 6 | #include "rbl.h" 7 | 8 | using namespace y::net; 9 | 10 | 11 | rbl_check::rbl_check(boost::asio::io_service& _io_service): 12 | m_resolver(_io_service) 13 | { 14 | } 15 | 16 | void rbl_check::add_rbl_source(const std::string &_host_name) 17 | { 18 | m_source_list.push_back(_host_name); 19 | } 20 | 21 | void rbl_check::start(const boost::asio::ip::address_v4 &_address, complete_cb _callback) 22 | { 23 | m_complete = _callback; 24 | 25 | if (m_source_list.empty()) 26 | { 27 | m_message.clear(); 28 | m_resolver.get_io_service().post(m_complete); 29 | 30 | return; 31 | } 32 | 33 | m_current_source = m_source_list.begin(); 34 | 35 | m_address = _address; 36 | 37 | start_resolve(m_address, *m_current_source); 38 | } 39 | 40 | void rbl_check::start_resolve(const boost::asio::ip::address_v4& av4, const std::string& d) 41 | { 42 | m_resolver.async_resolve( 43 | rev_order_av4_str(av4, d), 44 | dns::type_a, 45 | boost::bind(&rbl_check::handle_resolve, 46 | shared_from_this(), _1, _2) 47 | ); 48 | } 49 | 50 | void rbl_check::handle_resolve(const boost::system::error_code& ec, dns::resolver::iterator) 51 | { 52 | if (!ec) 53 | { 54 | m_message = str(boost::format("554 5.7.1 Service unavailable; Client host [%1%] blocked using %2%; Blocked by spam statistics - see http://feedback.yandex.ru/?from=mail-rejects&subject=%3%\r\n") 55 | % m_address.to_string() % *m_current_source % m_address.to_string()); 56 | 57 | m_resolver.get_io_service().post(m_complete); 58 | m_complete.clear(); 59 | } 60 | else 61 | { 62 | m_current_source ++; 63 | 64 | if (m_current_source == m_source_list.end()) 65 | { 66 | m_message.clear(); 67 | m_resolver.get_io_service().post(m_complete); 68 | m_complete.clear(); 69 | } 70 | else 71 | { 72 | start_resolve(m_address, *m_current_source); 73 | } 74 | } 75 | } 76 | 77 | void rbl_check::stop() 78 | { 79 | m_resolver.cancel(); 80 | } 81 | 82 | bool rbl_check::get_status(std::string &_message) 83 | { 84 | _message = m_message; 85 | 86 | return !m_message.empty(); 87 | } 88 | -------------------------------------------------------------------------------- /src/rbl.h: -------------------------------------------------------------------------------- 1 | #if !defined(_RBL_H_) 2 | #define _RBL_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class rbl_check 12 | :public boost::enable_shared_from_this, 13 | private boost::noncopyable 14 | { 15 | public: 16 | 17 | rbl_check(boost::asio::io_service& io_service); 18 | 19 | void add_rbl_source(const std::string &_host_name); // Add rbl source host 20 | 21 | typedef boost::function< void ()> complete_cb; 22 | 23 | void start(const boost::asio::ip::address_v4 &_address, complete_cb _callback); // Start async check 24 | 25 | void stop(); // stop all active resolve 26 | 27 | bool get_status(std::string &_message); 28 | 29 | private: 30 | 31 | void handle_resolve(const boost::system::error_code& ec, y::net::dns::resolver::iterator it); 32 | 33 | void start_resolve(const boost::asio::ip::address_v4&, const std::string& d); 34 | 35 | std::list m_source_list; 36 | 37 | std::list::iterator m_current_source; 38 | 39 | y::net::dns::resolver m_resolver; 40 | 41 | boost::asio::ip::address_v4 m_address; 42 | 43 | complete_cb m_complete; 44 | 45 | std::string m_message; 46 | }; 47 | 48 | typedef boost::shared_ptr rbl_client_ptr; 49 | 50 | #endif // _RBL_H_ 51 | -------------------------------------------------------------------------------- /src/rc.proto: -------------------------------------------------------------------------------- 1 | option optimize_for = LITE_RUNTIME; 2 | 3 | message request_pb { 4 | enum Command { 5 | GET = 0; 6 | ADD = 1; 7 | } 8 | 9 | required uint64 id = 1; 10 | required Command command = 2; 11 | required string key_namespace = 3; 12 | required string key = 4; 13 | optional int64 ttl = 5; 14 | optional string comment = 6; 15 | repeated int32 param = 7; 16 | } 17 | 18 | message reply_pb { 19 | required uint64 id = 1; 20 | required string key_namespace = 2; 21 | required int64 age = 3; 22 | required bool key_exists = 5; 23 | repeated int32 result = 6; 24 | } 25 | -------------------------------------------------------------------------------- /src/rc_clients/basic_rc_client.cpp: -------------------------------------------------------------------------------- 1 | #include "basic_rc_client.h" 2 | 3 | class basic_rc_category_t : public boost::system::error_category 4 | { 5 | public: 6 | const char* name() const 7 | { 8 | return "nwsmtp.basic_rc"; 9 | } 10 | 11 | std::string message(int value) const 12 | { 13 | if (value == bad_response_id) 14 | return "Bad rcsrv reponse ID"; 15 | if (value == bad_response) 16 | return "Bad rcsrv response"; 17 | return "nwsmtp.basic_rc error"; 18 | } 19 | }; 20 | 21 | const boost::system::error_category& get_basic_rc_category() 22 | { 23 | static basic_rc_category_t instance; 24 | return instance; 25 | } 26 | -------------------------------------------------------------------------------- /src/rc_clients/greylisting.h: -------------------------------------------------------------------------------- 1 | #ifndef GREYLISTING_H 2 | #define GREYLISTING_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "buffers.h" 10 | #include "greylisting_options.h" 11 | #include "basic_rc_client.h" 12 | 13 | class greylisting_client 14 | : public boost::enable_shared_from_this 15 | { 16 | public: 17 | typedef ystreambuf::const_buffers_type yconst_buffers; 18 | typedef ybuffers_iterator yconst_buffers_iterator; 19 | typedef boost::iterator_range iter_range_t; 20 | typedef std::vector hostlist; 21 | 22 | enum errors 23 | { 24 | too_early = 1, 25 | too_late, 26 | logical_error 27 | }; 28 | 29 | struct headers 30 | { 31 | iter_range_t to; 32 | iter_range_t from; 33 | iter_range_t messageid; 34 | iter_range_t subject; 35 | iter_range_t date; 36 | }; 37 | struct key 38 | { 39 | boost::asio::ip::address client_ip; 40 | std::string envelope_from; 41 | std::string envelope_to; 42 | headers h; 43 | iter_range_t body; 44 | key( const boost::asio::ip::address& ip, const std::string& smtp_from, 45 | const std::string& smtp_to, const headers& hs, const iter_range_t& b) 46 | : client_ip(ip), 47 | envelope_from(smtp_from), 48 | envelope_to(smtp_to), 49 | h(hs), 50 | body(b) 51 | {} 52 | }; 53 | 54 | struct info_t // result of greylisting probing 55 | { 56 | std::size_t keyhash; 57 | boost::asio::ip::udp::endpoint host; 58 | std::string suid; 59 | long long int age; // age of the key 60 | int n; // total number of marks for the key specified 61 | int m; // number of successful marks for the key specified 62 | bool passed; // wether greylisting check passed 63 | bool valid; // wether contents of this struct make any sense (depends on the probe completion status) 64 | 65 | info_t() 66 | : keyhash(0), 67 | host(), 68 | suid(), 69 | age(0), 70 | n(0), 71 | m(0), 72 | passed(false), 73 | valid(false) 74 | { 75 | } 76 | }; 77 | 78 | greylisting_client(boost::asio::io_service& ios, 79 | const greylisting_options& opt, 80 | const hostlist& list); 81 | 82 | typedef boost::function< void(const boost::system::error_code&, hostlist::value_type) > handler_t; 83 | 84 | // Start asynchronous greylisting check; issues a 'get' request 85 | void probe(const key& i, const std::string& comment, handler_t handler); 86 | 87 | // Get the result of the last probe() compeletion 88 | const info_t& info() const { return i_; } 89 | 90 | // Issues an asynchronous 'add' request using the result of the last probe() completion 91 | void mark(const std::string& comment, handler_t handler); 92 | 93 | // Stop the last request 94 | void stop(); 95 | 96 | private: 97 | class request; 98 | typedef boost::function) > request_handler_t; 100 | 101 | void handle_probe(const boost::system::error_code& ec, boost::shared_ptr req); 102 | void handle_mark(const boost::system::error_code& ec, boost::shared_ptr req); 103 | 104 | const greylisting_options& opt_; 105 | const hostlist& l_; 106 | basic_rc_client cl_; 107 | info_t i_; 108 | }; 109 | 110 | const boost::system::error_category& get_gr_category(); 111 | 112 | static const boost::system::error_category& gr_category = get_gr_category(); 113 | 114 | inline boost::system::error_code make_error_code(greylisting_client::errors e) 115 | { 116 | return boost::system::error_code( 117 | static_cast(e), gr_category); 118 | } 119 | 120 | namespace boost { namespace system { 121 | template<> struct is_error_code_enum 122 | { 123 | static const bool value = true; 124 | }; 125 | }} 126 | 127 | #endif // GREYLISTING_H 128 | -------------------------------------------------------------------------------- /src/rc_clients/greylisting_options.h: -------------------------------------------------------------------------------- 1 | #ifndef GREYLISTING_OPTIONS_H 2 | #define GREYLISTING_OPTIONS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "host_seq_resolver.h" 9 | 10 | struct greylisting_options 11 | { 12 | std::string ns; 13 | bool use_ip; 14 | bool use_envelope_from; 15 | bool use_envelope_to; 16 | bool use_header_from; 17 | bool use_header_to; 18 | bool use_header_messageid; 19 | bool use_header_subject; 20 | bool use_header_date; 21 | bool use_body; 22 | int window_hit_threshold; 23 | ::time_t window_begin; 24 | ::time_t window_end; 25 | ::time_t record_lifetime; 26 | ::time_t udp_timeout; 27 | int udp_port; 28 | std::vector hosts; 29 | }; 30 | 31 | struct greylisting_options_parser 32 | { 33 | greylisting_options& p; 34 | greylisting_options_parser(greylisting_options& opt) 35 | : p(opt) 36 | {} 37 | 38 | void parse_from_file(const char* filename) 39 | { 40 | namespace bpo = boost::program_options; 41 | bpo::options_description descr("greylisting options"); 42 | bpo::variables_map vm; 43 | std::vector hosts; 44 | descr.add_options() 45 | ("ns", bpo::value(&p.ns)->default_value("gr"), "ns") 46 | ("use_ip", bpo::value(&p.use_ip)->default_value(false), "use client ip address (yes/no)") 47 | ("use_envelope_from", bpo::value(&p.use_envelope_from)->default_value(true), "use envelope from (yes/no)") 48 | ("use_envelope_to", bpo::value(&p.use_envelope_to)->default_value(true), "use envelope to (yes/no)") 49 | ("use_header_from", bpo::value(&p.use_header_from)->default_value(true), "use header from") 50 | ("use_header_to", bpo::value(&p.use_header_to)->default_value(true), "use header to") 51 | ("use_header_messageid", bpo::value(&p.use_header_messageid)->default_value(true), "use header messageid") 52 | ("use_header_subject", bpo::value(&p.use_header_subject)->default_value(true), "use header subject") 53 | ("use_header_date", bpo::value(&p.use_header_date)->default_value(true), "use header date") 54 | ("use_body", bpo::value(&p.use_body)->default_value(false), "use body") 55 | ("window_hit_threshold", bpo::value(&p.window_hit_threshold)->default_value(2), "window hit threshold") 56 | ("window_begin", bpo::value(&p.window_begin)->default_value(1200), "window begin") 57 | ("window_end", bpo::value(&p.window_end)->default_value(14400), "window end") 58 | ("record_lifetime", bpo::value(&p.record_lifetime)->default_value(604800), "record lifetime") 59 | ("udp_timeout", bpo::value(&p.udp_timeout)->default_value(5), "udp timeout") 60 | ("udp_port", bpo::value(&p.udp_port)->default_value(8890), "udp port") 61 | ("host", bpo::value >(&hosts)->required(), "rcsrv hosts") 62 | ; 63 | bpo::store(bpo::parse_config_file(filename, descr, false), vm); 64 | bpo::notify(vm); 65 | 66 | resolve_host_sequence(hosts.begin(), hosts.end(), 67 | std::back_inserter(p.hosts), p.udp_port); 68 | std::sort(p.hosts.begin(), p.hosts.end()); 69 | } 70 | }; 71 | 72 | #endif // GREYLISTING_OPTIONS_H 73 | -------------------------------------------------------------------------------- /src/rfc822date.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1990 by Rayan S. Zachariassen, all rights reserved. 3 | * This will be free software, but only when it is finished. 4 | * 5 | * Rewrite for GNU autoconf by Matti Aarnio 1996 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | static const char *weekday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; 13 | 14 | const char *monthname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 15 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 16 | 17 | char * 18 | rfc822tz(timep, ts, prettyname, zone_buf, zblen) 19 | time_t *timep; 20 | struct tm **ts; 21 | int prettyname; 22 | char* zone_buf; 23 | int zblen; 24 | { 25 | char *cp; 26 | int sign, offset; 27 | 28 | *ts = localtime(timep); 29 | offset = ((*ts)->tm_gmtoff) / 60; /* Offset in minutes */ 30 | 31 | sign = offset >= 0; 32 | if (offset < 0) 33 | offset = -offset; 34 | 35 | snprintf(zone_buf, zblen, "%c%02d%02d", 36 | sign ? '+' : '-', offset / 60, offset % 60); 37 | cp = zone_buf + strlen(zone_buf); 38 | 39 | if (prettyname) 40 | sprintf(cp," (%.19s)",(*ts)->tm_zone); 41 | 42 | return zone_buf; 43 | } 44 | 45 | /* Like ctime(), except returns RFC822 format (variable length!) date string */ 46 | 47 | char* rfc822date(time_t *unixtimep, char* buf, size_t blen, char* zone_buf, size_t zblen) 48 | { 49 | struct tm *ts; 50 | rfc822tz(unixtimep, &ts, 0, zone_buf, zblen); 51 | 52 | snprintf(buf, blen, "%s, %d %s %d %02d:%02d:%02d %s\r\n", 53 | weekday[ts->tm_wday], ts->tm_mday, 54 | monthname[ts->tm_mon], 1900 + ts->tm_year, 55 | ts->tm_hour, ts->tm_min, ts->tm_sec, zone_buf); 56 | return buf; 57 | } 58 | -------------------------------------------------------------------------------- /src/rfc822date.h: -------------------------------------------------------------------------------- 1 | #ifndef RFC822DATE_H 2 | #define RFC822DATE_H 3 | 4 | extern "C" char* rfc822date(time_t *unixtimep, char* buf, size_t blen, char* zone_buf, size_t zblen); 5 | 6 | #endif // RFC822DATE_H 7 | -------------------------------------------------------------------------------- /src/rfc_date.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "rfc_date.h" 8 | 9 | #define DAY_MIN (24 * HOUR_MIN) /* minutes in a day */ 10 | #define HOUR_MIN 60 /* minutes in an hour */ 11 | #define MIN_SEC 60 /* seconds in a minute */ 12 | 13 | #define STRFTIME_FMT "%a, %e %b %Y %H:%M:%S " 14 | 15 | std::string mail_date(time_t when) 16 | { 17 | std::string collect; 18 | 19 | struct tm *lt; 20 | struct tm gmt; 21 | int gmtoff; 22 | 23 | gmt = *gmtime(&when); 24 | lt = localtime(&when); 25 | 26 | gmtoff = (lt->tm_hour - gmt.tm_hour) * HOUR_MIN + lt->tm_min - gmt.tm_min; 27 | if (lt->tm_year < gmt.tm_year) 28 | gmtoff -= DAY_MIN; 29 | else if (lt->tm_year > gmt.tm_year) 30 | gmtoff += DAY_MIN; 31 | else if (lt->tm_yday < gmt.tm_yday) 32 | gmtoff -= DAY_MIN; 33 | else if (lt->tm_yday > gmt.tm_yday) 34 | gmtoff += DAY_MIN; 35 | if (lt->tm_sec <= gmt.tm_sec - MIN_SEC) 36 | gmtoff -= 1; 37 | else if (lt->tm_sec >= gmt.tm_sec + MIN_SEC) 38 | gmtoff += 1; 39 | 40 | 41 | char buffer[100]; 42 | 43 | memset(buffer, 0, sizeof(buffer)); 44 | 45 | strftime(buffer, sizeof(buffer)-1, STRFTIME_FMT, lt); 46 | 47 | collect = buffer; 48 | 49 | if (gmtoff < -DAY_MIN || gmtoff > DAY_MIN) 50 | { 51 | // error 52 | } 53 | 54 | memset(buffer, 0, sizeof(buffer)); 55 | 56 | snprintf(buffer, sizeof(buffer)-1, "%+03d%02d", (int) (gmtoff / HOUR_MIN), (int) (abs(gmtoff) % HOUR_MIN)); 57 | 58 | collect.append(buffer); 59 | 60 | memset(buffer, 0, sizeof(buffer)); 61 | 62 | strftime(buffer, sizeof(buffer)-1, " (%Z)", lt); 63 | 64 | return collect; 65 | } 66 | -------------------------------------------------------------------------------- /src/rfc_date.h: -------------------------------------------------------------------------------- 1 | #if !defined(_RFC_DATE_H_) 2 | #define _RFC_DATE_H_ 3 | 4 | #include 5 | 6 | std::string mail_date(time_t when); 7 | 8 | #endif // _RFC_DATE_H_ 9 | -------------------------------------------------------------------------------- /src/server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "server.h" 9 | #include "log.h" 10 | 11 | server::server(std::size_t _io_service_pool_size, uid_t _user, gid_t _group) 12 | : ssl_context_(m_io_service, boost::asio::ssl::context::sslv23), 13 | m_io_service_pool_size(_io_service_pool_size) 14 | { 15 | 16 | if (g_config.m_use_tls) 17 | { 18 | try 19 | { 20 | // ssl_context_.set_verify_mode (boost::asio::ssl::context::verify_peer | boost::asio::ssl::context::verify_client_once); 21 | ssl_context_.set_verify_mode (asio::ssl::context::verify_none); 22 | 23 | ssl_context_.set_options ( 24 | asio::ssl::context::default_workarounds 25 | | asio::ssl::context::no_sslv2 ); 26 | 27 | 28 | if (!g_config.m_tls_cert_file.empty()) 29 | { 30 | ssl_context_.use_certificate_chain_file(g_config.m_tls_cert_file); 31 | } 32 | if (!g_config.m_tls_key_file.empty()) 33 | { 34 | ssl_context_.use_private_key_file(g_config.m_tls_key_file, boost::asio::ssl::context::pem); 35 | } 36 | } 37 | catch (std::exception const& e) 38 | { 39 | throw std::runtime_error(str(boost::format("Can't load TLS key / certificate file: file='%1%', error='%2%'") % g_config.m_tls_key_file % e.what())); 40 | } 41 | } 42 | 43 | std::for_each(g_config.m_listen_points.begin(), g_config.m_listen_points.end(), 44 | boost::bind(&server::setup_acceptor, this, _1, false) 45 | ); 46 | 47 | if (g_config.m_use_tls) 48 | std::for_each(g_config.m_ssl_listen_points.begin(), g_config.m_ssl_listen_points.end(), 49 | boost::bind(&server::setup_acceptor, this, _1, true) 50 | ); 51 | 52 | if ( acceptors_.empty() ) 53 | { 54 | throw std::logic_error("No address to bind to!"); 55 | } 56 | 57 | if (_group && (setgid(_group) == -1)) 58 | { 59 | g_log.msg(MSG_CRITICAL, "Cannot change process group id !"); 60 | throw std::exception(); 61 | } 62 | 63 | if (_user && (setuid(_user) == -1)) 64 | { 65 | g_log.msg(MSG_CRITICAL, "Cannot change process user id !"); 66 | throw std::exception(); 67 | } 68 | 69 | } 70 | 71 | bool server::setup_acceptor(const std::string& address, bool ssl) 72 | { 73 | std::string::size_type pos = address.find(":"); 74 | 75 | if (pos == std::string::npos) 76 | return false; 77 | 78 | boost::asio::ip::tcp::resolver resolver(m_io_service); 79 | boost::asio::ip::tcp::resolver::query query(address.substr(0,pos), address.substr(pos+1)); 80 | boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); 81 | 82 | smtp_connection_ptr connection; 83 | connection.reset(new smtp_connection(m_io_service, m_connection_manager, ssl_context_)); 84 | 85 | boost::shared_ptr acceptor( new boost::asio::ip::tcp::acceptor(m_io_service) ); 86 | acceptors_.push_front(acceptor); 87 | 88 | acceptor->open(endpoint.protocol()); 89 | acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); 90 | acceptor->bind(endpoint); 91 | acceptor->listen(); 92 | 93 | acceptor->async_accept(connection->socket(), 94 | boost::bind(&server::handle_accept, this, acceptors_.begin(), connection, ssl, boost::asio::placeholders::error) 95 | ); 96 | return true; 97 | } 98 | 99 | 100 | void server::run() 101 | { 102 | for (std::size_t i = 0; i < m_io_service_pool_size; ++i) 103 | m_threads_pool.create_thread(boost::bind(&boost::asio::io_service::run, &m_io_service)); 104 | } 105 | 106 | void server::stop() 107 | { 108 | boost::mutex::scoped_lock lock(m_mutex); 109 | 110 | std::for_each(acceptors_.begin(), acceptors_.end(), boost::bind(&acceptor_ptr::value_type::close, _1)); 111 | 112 | lock.unlock(); 113 | 114 | m_threads_pool.join_all(); 115 | acceptors_.clear(); 116 | } 117 | 118 | void server::handle_accept(acceptor_list::iterator acceptor, smtp_connection_ptr _connection, bool _force_ssl, const boost::system::error_code& e) 119 | { 120 | boost::mutex::scoped_lock lock(m_mutex); 121 | 122 | if (e == boost::asio::error::operation_aborted) 123 | return; 124 | 125 | if (!e) 126 | { 127 | try 128 | { 129 | _connection->start( _force_ssl ); 130 | 131 | } 132 | catch(boost::system::system_error &e) 133 | { 134 | if (e.code() != boost::asio::error::not_connected) 135 | { 136 | g_log.msg(MSG_NORMAL, str(boost::format("Accept exception: %1%") % e.what())); 137 | } 138 | } 139 | _connection.reset(new smtp_connection(m_io_service, m_connection_manager, ssl_context_)); 140 | } 141 | else 142 | { 143 | if (e != boost::asio::error::not_connected) 144 | g_log.msg(MSG_NORMAL, str(boost::format("Accept error: %1%") % e.message())); 145 | } 146 | 147 | (*acceptor)->async_accept(_connection->socket(), 148 | boost::bind(&server::handle_accept, this, acceptor, _connection, _force_ssl, boost::asio::placeholders::error) 149 | ); 150 | } 151 | -------------------------------------------------------------------------------- /src/server.h: -------------------------------------------------------------------------------- 1 | #if !defined(_SERVER_H_) 2 | #define _SERVER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "smtp_connection.h" 12 | #include "smtp_connection_manager.h" 13 | #include "options.h" 14 | 15 | class server 16 | : private boost::noncopyable 17 | { 18 | public: 19 | 20 | explicit server(std::size_t _io_service_pool_size, uid_t _user = 0, gid_t _group = 0); 21 | 22 | void run(); 23 | 24 | void stop(); 25 | 26 | private: 27 | typedef boost::shared_ptr acceptor_ptr; 28 | typedef std::list acceptor_list; 29 | 30 | bool setup_acceptor(const std::string& address, bool ssl); 31 | void handle_accept(acceptor_list::iterator acceptor, smtp_connection_ptr _connection, bool force_ssl, const boost::system::error_code& e); 32 | 33 | boost::asio::io_service m_io_service; 34 | 35 | acceptor_list acceptors_; 36 | 37 | boost::asio::ssl::context ssl_context_; 38 | 39 | smtp_connection_manager m_connection_manager; 40 | 41 | std::size_t m_io_service_pool_size; 42 | 43 | boost::thread_group m_threads_pool; 44 | 45 | boost::mutex m_mutex; 46 | }; 47 | 48 | #endif // _SERVER_H_ 49 | -------------------------------------------------------------------------------- /src/smtp_client.h: -------------------------------------------------------------------------------- 1 | #if !defined(_SMTP_CLIENT_H_) 2 | #define _SMTP_CLIENT_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #if defined(HAVE_CONFIG_H) 12 | #include "../config.h" 13 | #endif 14 | #if defined(HAVE_PA_ASYNC_H) 15 | #include 16 | #endif 17 | 18 | #include "envelope.h" 19 | #include "check.h" 20 | #include "options.h" 21 | 22 | class smtp_client: 23 | public boost::enable_shared_from_this, 24 | private boost::noncopyable 25 | { 26 | public: 27 | 28 | explicit smtp_client(boost::asio::io_service& _io_service); 29 | 30 | typedef boost::function < void () > complete_cb_t; 31 | 32 | void start(const check_data_t& _data, 33 | complete_cb_t _complete, 34 | envelope_ptr _envelope, 35 | const server_parameters::remote_point &_remote, 36 | const char *_proto_name ); 37 | 38 | void stop(); 39 | 40 | check_data_t check_data() const { return m_data; } 41 | 42 | protected: 43 | 44 | bool m_lmtp; 45 | 46 | bool m_use_pipelining; 47 | 48 | std::string m_read_buffer; 49 | 50 | complete_cb_t m_complete; 51 | 52 | envelope_ptr m_envelope; 53 | 54 | typedef enum { 55 | STATE_START = 0, 56 | STATE_HELLO, 57 | STATE_AFTER_MAIL, 58 | STATE_AFTER_RCPT, 59 | STATE_AFTER_DATA, 60 | STATE_AFTER_DOT, 61 | STATE_AFTER_QUIT, 62 | STATE_ERROR 63 | } proto_state_t; 64 | 65 | proto_state_t m_proto_state; 66 | check_data_t m_data; 67 | 68 | std::string m_proto_name; 69 | 70 | boost::asio::ip::tcp::socket m_socket; 71 | boost::asio::io_service::strand strand_; 72 | 73 | boost::asio::streambuf m_request; 74 | boost::asio::streambuf m_response; 75 | 76 | void do_stop(); 77 | 78 | void start_read_line(); 79 | 80 | void handle_read_smtp_line(const boost::system::error_code& _err); 81 | 82 | bool process_answer(std::istream &_stream); 83 | 84 | void handle_connect(const boost::system::error_code& ec, y::net::dns::resolver::iterator); 85 | 86 | void handle_resolve(const boost::system::error_code& ec, y::net::dns::resolver::iterator); 87 | 88 | void handle_write_request(const boost::system::error_code& _err, size_t sz, const std::string& s); 89 | 90 | void handle_write_data_request(const boost::system::error_code& _err, size_t sz); 91 | 92 | y::net::dns::resolver m_resolver; 93 | 94 | void fault(const std::string &_log, const std::string &_remote); 95 | 96 | void success(); 97 | 98 | envelope::rcpt_list_t::iterator m_current_rcpt; 99 | 100 | boost::asio::deadline_timer m_timer; 101 | 102 | unsigned int m_timer_value; 103 | 104 | void handle_timer( const boost::system::error_code &_error); 105 | 106 | void restart_timeout(); 107 | 108 | check::chk_status report_rcpt(bool _success, const std::string &_log, const std::string &_remote); 109 | 110 | std::string m_line_buffer; 111 | 112 | std::string m_relay_name; 113 | std::string m_relay_ip; 114 | int m_relay_port; 115 | 116 | boost::asio::ip::tcp::endpoint m_endpoint; 117 | void handle_simple_connect(const boost::system::error_code& error); 118 | 119 | #if defined(HAVE_PA_ASYNC_H) 120 | pa::stimer_t m_pa_timer; 121 | #endif 122 | 123 | }; 124 | 125 | typedef boost::shared_ptr smtp_client_ptr; 126 | 127 | #endif // _SMTP_CLIENT_H_ 128 | -------------------------------------------------------------------------------- /src/smtp_connection_auth.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef ENABLE_AUTH_BLACKBOX 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "smtp_connection.h" 15 | #include "smtp_connection_manager.h" 16 | #include "log.h" 17 | #include "options.h" 18 | #include "uti.h" 19 | #include "ip_options.h" 20 | 21 | const char *auth_error = "535 5.7.8 Error: authentication failed:%1%\r\n"; 22 | 23 | bool smtp_connection::continue_smtp_auth ( const std::string& _cmd, std::ostream &_response ) 24 | { 25 | m_proto_state = STATE_HELLO; 26 | 27 | std::string response; 28 | black_box_client_auth::auth_info_t info; 29 | 30 | switch (auth_.next(_cmd, response)) 31 | { 32 | case auth::AUTH_OK: 33 | _response << "235 2.7.0 Authentication successful"; // Inpossible case 34 | 35 | break; 36 | 37 | case auth::AUTH_DONE: // got all params start BB Auth 38 | 39 | auth_.get_session_params(info.login_, info.password_, info.ip_, info.method_); 40 | 41 | info.session_id_ = m_session_id; 42 | 43 | m_proto_state = STATE_CHECK_AUTH; 44 | 45 | start_passport_auth(info); 46 | 47 | break; 48 | 49 | case auth::AUTH_MORE: 50 | 51 | m_proto_state = STATE_AUTH_MORE; 52 | 53 | _response << response; 54 | 55 | break; 56 | 57 | case auth::AUTH_FORM: 58 | _response << str(boost::format(auth_error) % "Invalid format."); 59 | 60 | break; 61 | } 62 | 63 | return true; 64 | } 65 | 66 | bool smtp_connection::smtp_auth ( const std::string& _cmd, std::ostream &_response ) 67 | { 68 | if (m_proto_state == STATE_START) 69 | { 70 | _response << "503 5.5.1 Error: send HELO/EHLO first\r\n"; 71 | return true; 72 | } 73 | 74 | if (authenticated_) 75 | { 76 | _response << "503 5.5.1 Error: already authenticated\r\n"; 77 | return true; 78 | } 79 | 80 | std::string::size_type pos = _cmd.find( ' ' ); 81 | 82 | std::string command; 83 | std::string param; 84 | 85 | if ( pos != std::string::npos ) // Split line into command and argument parts 86 | { 87 | command = _cmd.substr( 0, pos ); 88 | param = _cmd.substr( pos + 1 ); 89 | } 90 | else 91 | { 92 | command = _cmd; 93 | } 94 | 95 | std::string response; 96 | 97 | black_box_client_auth::auth_info_t info; 98 | 99 | switch (auth_.first(command, param, response)) 100 | { 101 | case auth::AUTH_OK: 102 | _response << "235 2.7.0 Authentication successful"; // Inpossible case 103 | 104 | break; 105 | 106 | case auth::AUTH_DONE: // got all params start BB Auth 107 | 108 | auth_.get_session_params(info.login_, info.password_, info.ip_, info.method_); 109 | 110 | info.session_id_ = m_session_id; 111 | 112 | m_proto_state = STATE_CHECK_AUTH; 113 | 114 | start_passport_auth(info); 115 | 116 | break; 117 | 118 | case auth::AUTH_MORE: 119 | 120 | m_proto_state = STATE_AUTH_MORE; 121 | 122 | _response << response; 123 | 124 | break; 125 | 126 | case auth::AUTH_FORM: 127 | _response << str(boost::format(auth_error) % "Invalid format."); 128 | 129 | break; 130 | } 131 | 132 | return true; 133 | } 134 | 135 | void smtp_connection::start_passport_auth(const black_box_client_auth::auth_info_t &_info) 136 | { 137 | if (m_bb_check_auth) 138 | m_bb_check_auth->stop(); 139 | 140 | m_bb_check_auth.reset( new black_box_client_auth(io_service_, &g_bb_switch) ); 141 | m_bb_check_auth->start( _info, strand_.wrap(bind(&smtp_connection::handle_bb_auth_result, shared_from_this(), _1, _2)) ); 142 | } 143 | 144 | void smtp_connection::handle_bb_auth_result_helper(check::chk_status _status, unsigned long long _suid) 145 | { 146 | m_proto_state = STATE_HELLO; 147 | std::ostream response_stream(&m_response); 148 | 149 | switch (_status) 150 | { 151 | case check::CHK_ACCEPT: 152 | authenticated_ = true; 153 | response_stream << "235 2.7.0 Authentication successful.\r\n"; 154 | 155 | m_suid = _suid; 156 | 157 | break; 158 | 159 | case check::CHK_DISCARD: 160 | case check::CHK_REJECT: 161 | response_stream << "535 5.7.8 Error: authentication failed: Invalid user or password!\r\n"; 162 | break; 163 | 164 | case check::CHK_TEMPFAIL: 165 | response_stream << "454 4.3.0 Try again later\r\n"; 166 | break; 167 | } 168 | 169 | if (ssl_state_ == ssl_active) 170 | { 171 | boost::asio::async_write(m_ssl_socket, m_response, 172 | strand_.wrap(boost::bind(&smtp_connection::handle_write_request, shared_from_this(), 173 | boost::asio::placeholders::error))); 174 | 175 | } 176 | else 177 | { 178 | boost::asio::async_write(socket(), m_response, 179 | strand_.wrap(boost::bind(&smtp_connection::handle_write_request, shared_from_this(), 180 | boost::asio::placeholders::error))); 181 | } 182 | } 183 | 184 | 185 | void smtp_connection::handle_bb_auth_result(check::chk_status _check, unsigned long long _suid) 186 | { 187 | if (!m_bb_check_auth) 188 | return; 189 | 190 | if (m_bb_check_auth) 191 | m_bb_check_auth->stop(); 192 | 193 | m_bb_check_auth.reset(); 194 | 195 | handle_bb_auth_result_helper(_check, _suid); 196 | } 197 | 198 | #endif // ENABLE_AUTH_BLACKBOX 199 | -------------------------------------------------------------------------------- /src/smtp_connection_mailfrom.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef ENABLE_AUTH_BLACKBOX 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "smtp_connection.h" 16 | #include "smtp_connection_manager.h" 17 | #include "log.h" 18 | #include "options.h" 19 | #include "uti.h" 20 | #include "ip_options.h" 21 | 22 | void smtp_connection::handle_bb_mailfrom_helper(check::chk_status _status, black_box_client_mailfrom::mailfrom_result_t _result) 23 | { 24 | m_proto_state = STATE_HELLO; 25 | 26 | m_envelope->karma_ = _result.karma_; 27 | m_envelope->karma_status_ = _result.karma_status_; 28 | m_envelope->time_stamp_ = _result.time_stamp_; // born data 29 | m_envelope->auth_mailfrom_ = true; 30 | 31 | if (authenticated_ && m_suid) 32 | { 33 | if (m_suid != _result.suid_) 34 | { 35 | _status = check::CHK_REJECT; 36 | } 37 | } 38 | 39 | switch (_status) 40 | { 41 | case check::CHK_ACCEPT: 42 | authenticated_ = true; 43 | 44 | end_mail_from_command(false, true, _result.auth_addr_, ""); 45 | 46 | break; 47 | 48 | case check::CHK_DISCARD: 49 | case check::CHK_REJECT: 50 | 51 | end_mail_from_command(false, true, _result.auth_addr_, "553 5.7.1 Sender address rejected: not owned by auth user."); 52 | 53 | break; 54 | 55 | case check::CHK_TEMPFAIL: 56 | 57 | end_mail_from_command(false, true, _result.auth_addr_, "454 4.3.0 Try again later"); 58 | 59 | break; 60 | } 61 | 62 | } 63 | 64 | 65 | void smtp_connection::handle_bb_mailfrom_result(check::chk_status _check, black_box_client_mailfrom::mailfrom_result_t _result) 66 | { 67 | if (!m_bb_check_mailfrom) 68 | return; 69 | 70 | if (m_bb_check_mailfrom) 71 | m_bb_check_mailfrom->stop(); 72 | 73 | m_bb_check_mailfrom.reset(); 74 | 75 | handle_bb_mailfrom_helper(_check, _result); 76 | } 77 | 78 | #endif // ENABLE_AUTH_BLACKBOX 79 | -------------------------------------------------------------------------------- /src/smtp_connection_manager.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "log.h" 6 | 7 | #include "smtp_connection_manager.h" 8 | 9 | bool smtp_connection_manager::start(smtp_connection_ptr _session, unsigned int _max_sessions_per_ip, unsigned int _max_sessions, std::string &_msg) 10 | { 11 | boost::mutex::scoped_lock lck(m_mutex); 12 | 13 | if (m_sessions.size() >= _max_sessions) 14 | { 15 | _msg = str(boost::format("421 4.7.0 %1% Error: too many connections.\r\n") % boost::asio::ip::host_name()); 16 | return false; 17 | } 18 | 19 | if (get_ip_session(_session->remote_address()) >= _max_sessions_per_ip) 20 | { 21 | _msg = str(boost::format("421 4.7.0 %1% Error: too many connections from %2%\r\n") % boost::asio::ip::host_name() % _session->remote_address().to_string()); 22 | return false; 23 | } 24 | 25 | m_sessions.insert(_session); 26 | // int sess_sz = m_sessions.size(); 27 | 28 | ip_inc(_session->remote_address()); 29 | 30 | // lck.unlock(); 31 | // g_log.msg(MSG_NORMAL, str(boost::format("(start) Connection size:%1%") % sess_sz)); 32 | 33 | return true; 34 | } 35 | 36 | void smtp_connection_manager::stop(smtp_connection_ptr _session) 37 | { 38 | boost::mutex::scoped_lock lck(m_mutex); 39 | 40 | std::set::iterator sessit = m_sessions.find(_session); 41 | if (sessit != m_sessions.end()) 42 | { 43 | m_sessions.erase(sessit); 44 | // int sess_sz = m_sessions.size(); // ### 45 | 46 | ip_dec(_session->remote_address()); 47 | lck.unlock(); 48 | 49 | // g_log.msg(MSG_NORMAL, str(boost::format("(stop) Connection size:%1%") % sess_sz)); // ### 50 | } 51 | _session->stop(); 52 | } 53 | 54 | void smtp_connection_manager::stop_all() 55 | { 56 | std::for_each(m_sessions.begin(), m_sessions.end(), 57 | boost::bind(&smtp_connection::stop, _1)); 58 | 59 | m_sessions.clear(); 60 | } 61 | 62 | unsigned int smtp_connection_manager::ip_inc(const boost::asio::ip::address _address) 63 | { 64 | per_ip_session_t::iterator it = m_ip_count.find(_address.to_v4().to_ulong()); 65 | 66 | if (it == m_ip_count.end()) 67 | { 68 | m_ip_count.insert(per_ip_session_t::value_type(_address.to_v4().to_ulong(), 1)); 69 | return 1; 70 | } 71 | 72 | (it->second)++; 73 | 74 | return it->second; 75 | } 76 | 77 | unsigned int smtp_connection_manager::ip_dec(const boost::asio::ip::address _address) 78 | { 79 | per_ip_session_t::iterator it = m_ip_count.find(_address.to_v4().to_ulong()); 80 | 81 | if (it != m_ip_count.end()) 82 | { 83 | if (it->second > 0) 84 | { 85 | it->second--; 86 | return it->second; 87 | } 88 | else 89 | { 90 | m_ip_count.erase(it); 91 | } 92 | } 93 | 94 | return 0; 95 | } 96 | 97 | unsigned int smtp_connection_manager::get_ip_session(const boost::asio::ip::address _address) 98 | { 99 | per_ip_session_t::const_iterator it = m_ip_count.find(_address.to_v4().to_ulong()); 100 | 101 | if (it == m_ip_count.end()) 102 | { 103 | return 0; 104 | } 105 | else 106 | { 107 | return it->second; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/smtp_connection_manager.h: -------------------------------------------------------------------------------- 1 | #if !defined(_SMTP_CONNECTION_MANAGER_H_) 2 | #define _SMTP_CONNECTION_MANAGER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "smtp_connection.h" 10 | 11 | class smtp_connection_manager 12 | : private boost::noncopyable 13 | { 14 | public: 15 | 16 | bool start(smtp_connection_ptr _session, unsigned int _max_sessions_per_ip, unsigned int _max_sessions, std::string &_msg); 17 | 18 | void stop(smtp_connection_ptr _session); 19 | 20 | void stop_all(); 21 | 22 | protected: 23 | 24 | std::set m_sessions; 25 | 26 | typedef boost::unordered_map < unsigned long, unsigned int> per_ip_session_t; 27 | 28 | per_ip_session_t m_ip_count; 29 | 30 | unsigned int ip_inc(const boost::asio::ip::address _address); 31 | unsigned int ip_dec(const boost::asio::ip::address _address); 32 | unsigned int get_ip_session(const boost::asio::ip::address _address); 33 | 34 | boost::mutex m_mutex; 35 | }; 36 | 37 | #endif // _SMTP_CONNECTION_MANAGER_H_ 38 | -------------------------------------------------------------------------------- /src/so_client.h: -------------------------------------------------------------------------------- 1 | #if !defined(_SO_CLIENT_H_) 2 | #define _SO_CLIENT_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #if defined(HAVE_CONFIG_H) 12 | #include "../config.h" 13 | #endif 14 | #if defined(HAVE_PA_ASYNC_H) 15 | #include 16 | #endif 17 | 18 | #include "envelope.h" 19 | #include "check.h" 20 | #include "switchcfg.h" 21 | #include "timer.h" 22 | 23 | class so_client: 24 | public boost::enable_shared_from_this, 25 | private boost::noncopyable 26 | { 27 | public: 28 | 29 | typedef enum { 30 | SO_UNKNOWN = 0, 31 | SO_SKIP = 0, // Use SO_SKIP instead SO_UNKNOWN 32 | SO_HAM = 1, 33 | SO_DELIVERY = 2, 34 | SO_SPAM = 4, 35 | SO_MALICIOUS = 256, 36 | SO_FAULT = -1 37 | } spam_status_t; 38 | 39 | explicit so_client(boost::asio::io_service& _io_service, switchcfg *_so_config); 40 | 41 | typedef boost::function < void () > complete_cb_t; 42 | 43 | void start(const check_data_t& _data, complete_cb_t _complete, envelope_ptr _envelope, 44 | std::string spf_from, boost::optional spf_result, boost::optional spf_expl); 45 | 46 | void stop(); 47 | 48 | check_data_t check_data() const { return m_data; } 49 | 50 | protected: 51 | 52 | void restart(); 53 | 54 | std::string m_read_buffer; 55 | 56 | complete_cb_t m_complete; 57 | 58 | envelope_ptr m_envelope; 59 | 60 | unsigned int m_envelope_size; 61 | 62 | typedef enum { 63 | STATE_START = 0, 64 | STATE_AFTER_CONNECT, 65 | STATE_AFTER_HELO, 66 | STATE_AFTER_MAILFROM, 67 | STATE_AFTER_RCPTTO, 68 | STATE_AFTER_DATA, 69 | STATE_AFTER_DOT, 70 | STATE_ERROR 71 | } proto_state_t; 72 | 73 | proto_state_t m_proto_state; 74 | 75 | check_data_t m_data; 76 | 77 | unsigned int m_so_try; 78 | 79 | boost::asio::ip::tcp::socket m_socket; 80 | boost::asio::io_service::strand strand_; 81 | 82 | boost::asio::streambuf m_request; 83 | boost::asio::streambuf m_response; 84 | 85 | void do_stop(); 86 | 87 | void start_read_line(); 88 | 89 | void write_extra_headers(); 90 | void handle_write_extra_headers(const boost::system::error_code& ec); 91 | 92 | void handle_read_so_line(const boost::system::error_code& _err); 93 | 94 | bool process_answer(std::istream &_stream); 95 | 96 | void handle_connect(const boost::system::error_code& ec, y::net::dns::resolver::iterator, int port); 97 | 98 | void handle_resolve(const boost::system::error_code& ec, y::net::dns::resolver::iterator, int port); 99 | 100 | void handle_write_request(const boost::system::error_code& _err); 101 | 102 | y::net::dns::resolver m_resolver; 103 | 104 | void fault(const std::string &_log); 105 | 106 | void success(spam_status_t _status); 107 | 108 | envelope::rcpt_list_t::iterator m_current_rcpt; 109 | 110 | boost::asio::deadline_timer m_timer; 111 | 112 | unsigned int m_timer_value; 113 | 114 | void handle_timer( const boost::system::error_code &_error); 115 | 116 | void restart_timeout(); 117 | 118 | switchcfg *m_config; 119 | 120 | std::string m_log_host; 121 | timer m_log_delay; 122 | unsigned int m_so_connect_try; 123 | 124 | std::string extra_headers_; 125 | 126 | void log_finish(so_client::spam_status_t _code); 127 | 128 | boost::asio::ip::tcp::endpoint m_endpoint; 129 | void handle_simple_connect(const boost::system::error_code& error); 130 | 131 | #if defined(HAVE_PA_ASYNC_H) 132 | pa::stimer_t m_pa_timer; 133 | #endif 134 | }; 135 | 136 | typedef boost::shared_ptr so_client_ptr; 137 | 138 | #endif // _SO_CLIENT_H_ 139 | -------------------------------------------------------------------------------- /src/switchcfg.cpp: -------------------------------------------------------------------------------- 1 | #include "switchcfg.h" 2 | 3 | switchcfg g_bb_switch; 4 | 5 | switchcfg g_so_switch; 6 | 7 | switchcfg g_av_switch; 8 | 9 | switchcfg::switchcfg() 10 | { 11 | } 12 | 13 | 14 | void switchcfg::initialize( const server_parameters::remote_point &_primary, const server_parameters::remote_point &_secondary) 15 | { 16 | boost::mutex::scoped_lock lck(m_config_mutex); 17 | 18 | m_primary = _primary; 19 | m_secondary = _secondary; 20 | } 21 | 22 | server_parameters::remote_point switchcfg::get_primary() 23 | { 24 | boost::mutex::scoped_lock lck(m_config_mutex); 25 | 26 | return m_primary; 27 | } 28 | 29 | server_parameters::remote_point switchcfg::get_secondary() 30 | { 31 | boost::mutex::scoped_lock lck(m_config_mutex); 32 | 33 | return m_secondary; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/switchcfg.h: -------------------------------------------------------------------------------- 1 | #if !defined(_SWITCHCFG_H_) 2 | #define _SWITCHCFG_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include "options.h" 8 | 9 | class switchcfg 10 | { 11 | public: 12 | 13 | switchcfg(); 14 | 15 | void initialize(const server_parameters::remote_point &_primary, const server_parameters::remote_point &_secondary); 16 | 17 | server_parameters::remote_point get_primary(); 18 | 19 | server_parameters::remote_point get_secondary(); 20 | 21 | protected: 22 | 23 | server_parameters::remote_point m_primary; 24 | server_parameters::remote_point m_secondary; 25 | 26 | boost::mutex m_config_mutex; 27 | }; 28 | 29 | extern switchcfg g_bb_switch; 30 | extern switchcfg g_so_switch; 31 | extern switchcfg g_av_switch; 32 | 33 | #endif // _SWITCHCFG_H_ 34 | 35 | -------------------------------------------------------------------------------- /src/tests/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I../ -I../rc_clients 2 | AM_CXXFLAGS = -Wall 3 | 4 | noinst_PROGRAMS = resolv spf spool client1 client2 client3 tormoz tormoz2 bbproxy buffers gr 5 | 6 | resolv_SOURCES = resolv.cpp ylog.cpp 7 | resolv_LDADD = @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_THREAD_LIB@ @BOOST_SYSTEM_LIB@ 8 | 9 | spf_SOURCES = spf.cpp ../uti.cpp 10 | spf_LDADD = @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_THREAD_LIB@ @BOOST_SYSTEM_LIB@ 11 | 12 | spool_SOURCES = spool.cpp ylog.cpp 13 | spool_LDADD = @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_THREAD_LIB@ @BOOST_SYSTEM_LIB@ 14 | 15 | client1_SOURCES = client1.cpp ylog.cpp 16 | client1_LDADD = @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_THREAD_LIB@ @BOOST_SYSTEM_LIB@ 17 | 18 | client2_SOURCES = client2.cpp ylog.cpp 19 | client2_LDADD = @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_THREAD_LIB@ @BOOST_SYSTEM_LIB@ 20 | 21 | client3_SOURCES = client3.cpp ylog.cpp 22 | client3_LDADD = @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_THREAD_LIB@ @BOOST_SYSTEM_LIB@ 23 | 24 | tormoz_SOURCES = tormoz.cpp ../atormoz.cpp ylog.cpp 25 | tormoz_LDADD = @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_THREAD_LIB@ @BOOST_SYSTEM_LIB@ 26 | 27 | tormoz2_SOURCES = tormoz2.cpp ../atormoz.cpp ../uti.cpp ylog.cpp 28 | tormoz2_LDADD = @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_THREAD_LIB@ @BOOST_SYSTEM_LIB@ -lboost_regex 29 | 30 | bbproxy_SOURCES = bbproxy.cpp ylog.cpp 31 | bbproxy_LDADD = @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_THREAD_LIB@ @BOOST_SYSTEM_LIB@ -lboost_regex 32 | 33 | buffers_SOURCES = buffers.cpp 34 | buffers_LDADD = @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_THREAD_LIB@ @BOOST_SYSTEM_LIB@ 35 | 36 | gr_SOURCES = gr.cpp ../rc_clients/greylisting.cpp ../rc_clients/basic_rc_client.cpp \ 37 | ../rc.pb.cc ../header_parser.cpp 38 | gr_LDADD = @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_THREAD_LIB@ @BOOST_SYSTEM_LIB@ $(protobuf_LIBS) -------------------------------------------------------------------------------- /src/tests/spf.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "aspf.h" 10 | 11 | void handle_spf_check(spf_parameters p, boost::optional result, boost::optional expl) 12 | { 13 | std::cout << "---" << p.domain << "---" << endl; 14 | if (result) 15 | cout << *result << endl; 16 | else 17 | cout << "(skip)" << endl; 18 | if (expl) 19 | cout << *expl << endl; 20 | } 21 | 22 | int main(int argc, char** argv) 23 | { 24 | 25 | boost::asio::io_service ios; 26 | boost::shared_ptr work(new boost::asio::io_service::work(ios)); 27 | 28 | spf_parameters p; 29 | 30 | boost::program_options::options_description cmd_opt("cmd line options"); 31 | cmd_opt.add_options() 32 | ("help,h", "produce help message") 33 | ("ip,i", boost::program_options::value(&p.ip)->default_value("8.8.8.8"), "user ip") 34 | ("from,f", boost::program_options::value(&p.from), "smtp from") 35 | ("domain,d", boost::program_options::value(&p.domain), "smtp hello") 36 | ; 37 | boost::program_options::variables_map vm; 38 | try 39 | { 40 | boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(cmd_opt).run(), vm); 41 | boost::program_options::notify(vm); 42 | if (vm.count("help") /*|| !vm.count("domain") */) 43 | { 44 | cout << cmd_opt << endl; 45 | return 1; 46 | } 47 | } 48 | catch (const std::exception& e) 49 | { 50 | cerr << "bad options: " << e.what() << endl; 51 | return -1; 52 | } 53 | 54 | boost::thread thread1(boost::bind(&boost::asio::io_service::run, &ios)); 55 | boost::thread thread2(boost::bind(&boost::asio::io_service::run, &ios)); 56 | 57 | boost::posix_time::ptime tm = boost::posix_time::microsec_clock::local_time(); 58 | 59 | if (vm.count("domain") || vm.count("from")) 60 | async_check_SPF(ios, p, boost::protect(boost::bind(handle_spf_check, p, _1, _2))); 61 | else 62 | { 63 | string host; 64 | while (getline(cin, host)) 65 | { 66 | if (!host.empty()) 67 | { 68 | p.domain = host; 69 | async_check_SPF(ios, p, boost::protect(boost::bind(handle_spf_check, p, _1, _2))); 70 | } 71 | } 72 | } 73 | work.reset(); 74 | 75 | thread1.join(); 76 | thread2.join(); 77 | 78 | cout << "time elapsed: " << boost::posix_time::microsec_clock::local_time()-tm << endl; 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /src/tests/ylog.cpp: -------------------------------------------------------------------------------- 1 | #include "ylog.h" 2 | 3 | ylog::ylog_t ylog::ycout(std::cout); 4 | ylog::ylog_t ylog::ycerr(std::cerr); 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/tests/ylog.h: -------------------------------------------------------------------------------- 1 | #ifndef YLOG_H_ 2 | #define YLOG_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace ylog 9 | { 10 | using namespace std; 11 | 12 | /// Helper class to allow output to cout with multiple threads 13 | //--- 14 | struct ylog_t : private boost::noncopyable 15 | { 16 | struct helper 17 | { 18 | ylog_t* q_; 19 | 20 | template 21 | helper& operator<< (const T& t) 22 | { 23 | q_->os_ << t; 24 | return *this; 25 | } 26 | 27 | helper(helper& rh) 28 | : q_(rh.q_) 29 | { 30 | rh.q_ = 0; 31 | } 32 | 33 | ~helper() 34 | { 35 | if (q_) { 36 | q_->os_ << endl; 37 | q_->m_.unlock(); 38 | } 39 | } 40 | 41 | private: 42 | helper (ylog_t* y) 43 | : q_(y) 44 | { 45 | q_->m_.lock(); 46 | } 47 | friend struct ylog_t; 48 | }; 49 | 50 | std::ostream& os_; 51 | boost::mutex m_; 52 | 53 | explicit ylog_t(std::ostream& os) 54 | : os_(os) 55 | { 56 | } 57 | 58 | template 59 | ylog_t::helper operator<< (T t) 60 | { 61 | helper h (this); 62 | os_ << t; 63 | return h; 64 | } 65 | }; 66 | 67 | extern ylog_t ycout; 68 | extern ylog_t ycerr; 69 | 70 | //--- 71 | 72 | } // namespace ylog 73 | 74 | #endif // YLOG_H_ 75 | 76 | -------------------------------------------------------------------------------- /src/timer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "timer.h" 4 | 5 | using namespace std; 6 | 7 | timer::timer() 8 | { 9 | time(&m_time); 10 | } 11 | 12 | 13 | void timer::start() 14 | { 15 | time(&m_time); 16 | } 17 | 18 | time_t timer::restart(bool _diff) 19 | { 20 | time_t ret = mark(_diff); 21 | 22 | time(&m_time); 23 | 24 | return ret; 25 | } 26 | 27 | time_t timer::mark(bool _diff) 28 | { 29 | if (m_time == 0) 30 | return 0; 31 | 32 | time_t mark; 33 | 34 | time(&mark); 35 | 36 | return _diff ? mark - m_time : mark ; 37 | } 38 | 39 | string timer::format_time(time_t _time) 40 | { 41 | int accu = _time; 42 | 43 | int hours = _time / (60*60); 44 | 45 | accu -= hours * (60*60); 46 | 47 | int min = accu / 60; 48 | int sec = accu % 60; 49 | 50 | char buffer[200]; 51 | 52 | snprintf(buffer, 199, "%02d:%02d:%02d", hours, min, sec); 53 | 54 | return buffer; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /src/timer.h: -------------------------------------------------------------------------------- 1 | #if !defined(_TIMER_H_) 2 | #define _TIMER_H_ 3 | 4 | #include 5 | 6 | class timer 7 | { 8 | public: 9 | timer(); 10 | 11 | void start(); 12 | 13 | time_t mark(bool _diff=true); 14 | time_t restart(bool _diff=true); 15 | 16 | static std::string format_time(time_t _time); 17 | 18 | protected: 19 | time_t m_time; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/uti.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "uti.h" 8 | 9 | static std::string conv_cr_lf(char _ch) 10 | { 11 | switch (_ch) 12 | { 13 | case '\r': 14 | return ""; 15 | case '\n': 16 | return "^M"; 17 | default: 18 | return std::string(&_ch, 1); 19 | } 20 | } 21 | 22 | std::string cleanup_str(const std::string &_str) 23 | { 24 | std::string buffer(_str); 25 | 26 | std::string::size_type pos = buffer.find_last_not_of("\r\n"); 27 | 28 | if (pos != std::string::npos) 29 | { 30 | buffer.erase(pos+1); 31 | } 32 | 33 | std::ostringstream remote_filt; 34 | 35 | std::transform(buffer.begin(), buffer.end(), std::ostream_iterator(remote_filt), conv_cr_lf); 36 | 37 | return remote_filt.str(); 38 | } 39 | 40 | 41 | std::string rev_order_av4_str(const boost::asio::ip::address_v4& a, const std::string& d) 42 | { 43 | return str(boost::format("%1%.%2%.%3%.%4%.%5%") 44 | % static_cast(a.to_bytes()[3]) 45 | % static_cast(a.to_bytes()[2]) 46 | % static_cast(a.to_bytes()[1]) 47 | % static_cast(a.to_bytes()[0]) 48 | % d 49 | ); 50 | } 51 | 52 | std::string unfqdn(const std::string& fqdn) 53 | { 54 | std::size_t sz = fqdn.size(); 55 | if (sz && fqdn[sz-1] == '.') 56 | return std::string(fqdn.begin(), fqdn.begin()+sz-1); 57 | return fqdn; 58 | } 59 | 60 | unsigned long djb2_hash(const unsigned char* str, size_t size) 61 | { 62 | unsigned long hash = 5381; 63 | const unsigned char* p, *se = str + size; 64 | for (p=str; p!=se; ++p) 65 | hash = ((hash << 5) + hash) ^ *p; 66 | return hash; 67 | } 68 | -------------------------------------------------------------------------------- /src/uti.h: -------------------------------------------------------------------------------- 1 | #if !defined(_UTI_H_) 2 | #define _UTI_H_ 3 | 4 | #include 5 | #include 6 | 7 | std::string trim(const std::string &_str); // smtp_connection.cpp 8 | 9 | std::string cleanup_str(const std::string &_str); 10 | 11 | std::string rev_order_av4_str(const boost::asio::ip::address_v4&, const std::string& domain); 12 | 13 | std::string unfqdn(const std::string& fqdn); // remove last dot from fqdn, if any 14 | 15 | unsigned long djb2_hash(const unsigned char* str, size_t size); 16 | 17 | inline bool parse_email(const std::string& email, std::string& name, std::string& domain) 18 | { 19 | if (const char* at = strchr(email.c_str(), '@')) 20 | { 21 | name = std::string(email.c_str(), at); 22 | domain = std::string(at+1, email.c_str() + email.size()); 23 | return true; 24 | } 25 | return false; 26 | } 27 | 28 | #endif //_UTI_H_ 29 | -------------------------------------------------------------------------------- /src/yield.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // yield.hpp 3 | // ~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #include "coroutine.hpp" 12 | 13 | #ifndef reenter 14 | # define reenter(c) CORO_REENTER(c) 15 | #endif 16 | 17 | #ifndef yield 18 | # define yield CORO_YIELD 19 | #endif 20 | 21 | #ifndef fork 22 | # define fork CORO_FORK 23 | #endif 24 | --------------------------------------------------------------------------------