midi-smtp-server 3.0.3 → 3.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -6
- data/MIT-LICENSE.txt +1 -1
- data/README.md +32 -18
- data/lib/midi-smtp-server/exceptions.rb +2 -2
- data/lib/midi-smtp-server/tls-transport.rb +3 -3
- data/lib/midi-smtp-server/version.rb +3 -3
- data/lib/midi-smtp-server.rb +252 -62
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2376ca7f3510ebe230523b2fd5629dc39a5c44f3415ce3980d1e27d156ac3397
|
4
|
+
data.tar.gz: eaeb5ae1fe8dd868b772d9dfa267665e2b0e8b6f63c4761cab2d861cac412499
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da5d3c16c081cd3c34be74d1f745bcc015e5c1fa9bbcdf6d55552e1e2c30df831ad63c025c86e4ffda078dc37b1c7bcf16d14fe512dbb91bbabb54dd9b2ca944
|
7
|
+
data.tar.gz: acbdac6c519f20758e9af7922094032ce3d3bc67e4874d8b37bac283e408ca303cd3fc47ae51b360e3ef9d1bfddc68bc620f5a105e4a68ca4a3d0ca3fef73ef6
|
data/CHANGELOG.md
CHANGED
@@ -4,9 +4,30 @@ We suggest everybody using MidiSmtpServer to switch at least to latest 2.3.y. or
|
|
4
4
|
|
5
5
|
For upgrades from previous versions or outdated _MiniSmtpServer_ gem you may follow the guides at [Appendix Upgrade](https://midi-smtp-server.readthedocs.io/appendix_upgrade/) to get your code ready for the latest releases.
|
6
6
|
|
7
|
+
|
8
|
+
#### 3.2.1 (2023-08-15)
|
9
|
+
|
10
|
+
1. New feature [proxy](https://midi-smtp-server.readthedocs.io/feature_proxy) ([check issue 49](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/49))
|
11
|
+
2. mkdocs update for readthedocs
|
12
|
+
|
13
|
+
|
14
|
+
#### 3.1.2 (2023-05-06)
|
15
|
+
|
16
|
+
1. Minor fix for backwards compatibility to method `start` when not using pre_fork options.
|
17
|
+
|
18
|
+
|
19
|
+
#### 3.1.1 (2023-02-26)
|
20
|
+
|
21
|
+
1. Add option to additional activate [pre-forking workers](https://midi-smtp-server.readthedocs.io/feature_load_balancing/#pre-forking) (beta) ([check issue 42](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/42))
|
22
|
+
2. Adjust sleep idle time while in command and data loop to speedup processing ([check issue 47](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/47))
|
23
|
+
3. Mark the current default value `0.1` for `io_waitreadable_sleep` as deprecated, will become `0.03` in a future version.
|
24
|
+
4. Modify github workflow and apply testing of ruby 3.1 and ruby 3.2
|
25
|
+
5. Generate updated openssl test certificates for TLS tests
|
26
|
+
|
27
|
+
|
7
28
|
#### 3.0.3 (2022-02-12)
|
8
29
|
|
9
|
-
1. Critical fix for thread safety ([check issue
|
30
|
+
1. Critical fix for thread safety ([check issue 39](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/39))
|
10
31
|
2. Fix tests using net/smtp '>= 0.3.1'
|
11
32
|
|
12
33
|
|
@@ -29,14 +50,13 @@ For upgrades from previous versions or outdated _MiniSmtpServer_ gem you may fol
|
|
29
50
|
10. Dropped deprecated empty wildcard `""` support on initialize - please use specific hostnames and / or ip-addresses or star wildcard `"*"` only
|
30
51
|
11. Align tests with Rubocop style and coding enforcements
|
31
52
|
12. Added `rake` tasks for testing and linting, checkout `bundle exec rake -T`
|
32
|
-
13. Re-defined arguments of methods `new`, `join`, `stop` as keyword arguments, check [minor
|
53
|
+
13. Re-defined arguments of methods `new`, `join`, `stop` as keyword arguments, check [minor incompatibility: upgrade to 3.x](https://midi-smtp-server.readthedocs.io/appendix_upgrade/#upgrade-to-3x)
|
33
54
|
14. Enhance the slack recipe in cookbook for [Docker usage](https://github.com/4commerce-technologies-AG/midi-smtp-server/tree/master/cookbook/recipe-slack)
|
34
55
|
|
35
56
|
|
36
57
|
#### 2.3.3 (2022-02-12)
|
37
58
|
|
38
|
-
1. Critical fix for thread safety ([check issue
|
39
|
-
2. Fix tests using net/smtp '>= 0.3.1'
|
59
|
+
1. Critical fix for thread safety ([check issue 39](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/39))
|
40
60
|
|
41
61
|
|
42
62
|
#### 2.3.2 (2020-01-21)
|
@@ -61,7 +81,7 @@ For upgrades from previous versions or outdated _MiniSmtpServer_ gem you may fol
|
|
61
81
|
|
62
82
|
1. Support [IPv4 and IPv6 (documentation)](https://midi-smtp-server.readthedocs.io/instantiate/#ipv4-and-ipv6-ready)
|
63
83
|
2. Support binding of [multiple ports and hosts / ip addresses](https://midi-smtp-server.readthedocs.io/instantiate/#ports-and-addresses)
|
64
|
-
3. Handle [utilization of connections and processings](https://midi-smtp-server.readthedocs.io/
|
84
|
+
3. Handle [utilization of connections and processings](https://midi-smtp-server.readthedocs.io/feature_load_balancing/)
|
65
85
|
4. Support of RFC(2)822 [CR LF modes](https://midi-smtp-server.readthedocs.io/feature_cr_lf_modes/)
|
66
86
|
5. Support (optionally) SMTP [PIPELINING](https://tools.ietf.org/html/rfc2920) extension
|
67
87
|
6. Support (optionally) SMTP [8BITMIME](https://midi-smtp-server.readthedocs.io/feature_8bitmime_smtputf8/) extension
|
@@ -104,7 +124,7 @@ For upgrades from previous versions or outdated _MiniSmtpServer_ gem you may fol
|
|
104
124
|
|
105
125
|
#### 2.x
|
106
126
|
|
107
|
-
1.
|
127
|
+
1. Modularized
|
108
128
|
2. Removed dependency to GServer
|
109
129
|
3. Additional events to interact with
|
110
130
|
4. Use logger to log several messages from severity :debug up to :fatal
|
data/MIT-LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2014 -
|
3
|
+
Copyright (c) 2014 - 2023 Tom Freudenberg
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -19,7 +19,7 @@ MidiSmtpServer is the highly customizable ruby SMTP-Server and SMTP-Service libr
|
|
19
19
|
|
20
20
|
As a library it is mainly designed to be integrated into your projects as serving a SMTP-Server service. The lib will do nothing with your mail and you have to create your own event functions to handle and operate on incoming mails. We are using this in conjunction with [Mikel Lindsaar](https://github.com/mikel) great Mail component (https://github.com/mikel/mail). Time to run your own SMTP-Server service.
|
21
21
|
|
22
|
-
Checkout all the features and improvements (3.0.1 Logging enhancement, 2.3.x Multiple ports and addresses, 2.2.x Encryption [StartTLS], 2.1.0 Authentication [AUTH], 2.1.1 significant speed improvement, etc.) and get more details from section [changes and updates](https://github.com/4commerce-technologies-AG/midi-smtp-server#changes-and-updates).
|
22
|
+
Checkout all the features and improvements (3.1.1 Process parallelization, 3.0.1 Logging enhancement, 2.3.x Multiple ports and addresses, 2.2.x Encryption [StartTLS], 2.1.0 Authentication [AUTH], 2.1.1 significant speed improvement, etc.) and get more details from section [changes and updates](https://github.com/4commerce-technologies-AG/midi-smtp-server#changes-and-updates).
|
23
23
|
|
24
24
|
MidiSmtpServer is an extremely flexible library and almost any aspect of SMTP communications can be handled by deriving its events and using its configuration options.
|
25
25
|
|
@@ -40,10 +40,10 @@ class MySmtpd < MidiSmtpServer::Smtpd
|
|
40
40
|
logger.debug("[#{ctx[:envelope][:from]}] for recipient(s): [#{ctx[:envelope][:to]}]...")
|
41
41
|
|
42
42
|
# Just decode message once to make sure, that this message ist readable
|
43
|
-
|
43
|
+
mail = Mail.read_from_string(ctx[:message][:data])
|
44
44
|
|
45
45
|
# handle incoming mail, just show the message subject
|
46
|
-
logger.debug(
|
46
|
+
logger.debug(mail.subject)
|
47
47
|
end
|
48
48
|
|
49
49
|
end
|
@@ -64,10 +64,10 @@ This source code shows the example to receive messages via SMTP and store them t
|
|
64
64
|
# get each message after DATA <message> .
|
65
65
|
def on_message_data_event(ctx)
|
66
66
|
# Just decode message once to make sure, that this message ist readable
|
67
|
-
|
67
|
+
mail = Mail.read_from_string(ctx[:message])
|
68
68
|
|
69
69
|
# Publish to rabbit
|
70
|
-
@bunny_exchange.publish(
|
70
|
+
@bunny_exchange.publish(mail.to_s, :headers => { 'x-smtp' => mail.header.to_s }, :routing_key => "to_queue")
|
71
71
|
end
|
72
72
|
```
|
73
73
|
|
@@ -76,7 +76,11 @@ This source code shows the example to receive messages via SMTP and store them t
|
|
76
76
|
|
77
77
|
## Installation
|
78
78
|
|
79
|
-
MidiSmtpServer is packaged as a RubyGem
|
79
|
+
MidiSmtpServer is packaged as a RubyGem and hosted on rubygems.
|
80
|
+
|
81
|
+
#### CLI
|
82
|
+
|
83
|
+
You can easily install the package by entering following at your command line:
|
80
84
|
|
81
85
|
`gem install midi-smtp-server`
|
82
86
|
|
@@ -84,6 +88,14 @@ Use the component in your project sources by:
|
|
84
88
|
|
85
89
|
`require 'midi-smtp-server'`
|
86
90
|
|
91
|
+
#### Gemfile
|
92
|
+
|
93
|
+
When a `Gemfile` handles your dependencies, please consider to use the [pessimistic operator](https://thoughtbot.com/blog/rubys-pessimistic-operator) at least:
|
94
|
+
|
95
|
+
`gem 'midi-smtp-server', '~> 3.1.2''`
|
96
|
+
|
97
|
+
All changes by PATCH versions are always functional and compatible with no issues on update!
|
98
|
+
|
87
99
|
<br>
|
88
100
|
|
89
101
|
|
@@ -96,35 +108,35 @@ Read the [MidiSmtpServer Documentation](https://midi-smtp-server.readthedocs.io/
|
|
96
108
|
|
97
109
|
## Reliable code
|
98
110
|
|
99
|
-
Since version 2.3 implementation and integration tests by minitest framework are added to this repository. While the implementation tests are mostly checking the components, the integration tests try to verify the correct exchange of messages for different scenarios. In
|
111
|
+
Since version 2.3 implementation and integration tests by minitest framework are added to this repository. While the implementation tests are mostly checking the components, the integration tests try to verify the correct exchange of messages for different scenarios. Last but not least the stress tests do catch some rare conditions to make sure that no information is leaving its thread and process. In addition all sources are checked by rubocop to ensure they fit to the style guides.
|
100
112
|
|
101
113
|
You may run all rubocop tests through the `rake` helper:
|
102
114
|
|
103
|
-
```
|
115
|
+
```bash
|
104
116
|
bundle exec rake rubocop
|
105
117
|
```
|
106
118
|
|
107
119
|
You may also run all tests through the `rake` helper:
|
108
120
|
|
109
|
-
```
|
121
|
+
```bash
|
110
122
|
bundle exec rake test:all
|
111
123
|
```
|
112
124
|
|
113
125
|
or with more verbose output:
|
114
126
|
|
115
|
-
```
|
127
|
+
```bash
|
116
128
|
bundle exec rake test:all v=1
|
117
129
|
```
|
118
130
|
|
119
|
-
To just run just a part of the tests, you may select the `specs`, `unit` or `
|
131
|
+
To just run just a part of the tests, you may select the `specs`, `unit`, `integration` or `stress` tests:
|
120
132
|
|
121
|
-
```
|
133
|
+
```bash
|
122
134
|
bundle exec rake test:specs
|
123
135
|
```
|
124
136
|
|
125
137
|
To just run some selected (by regular expression) tests, you may use the `T=filter` option. The example will run only the tests and specs containing the word _connections_ in their method_name or describe_text:
|
126
138
|
|
127
|
-
```
|
139
|
+
```bash
|
128
140
|
bundle exec rake test:all v=1 T=connections
|
129
141
|
```
|
130
142
|
|
@@ -146,10 +158,11 @@ We suggest everybody using MidiSmtpServer to switch at least to latest 2.3.y. or
|
|
146
158
|
|
147
159
|
For upgrades from previous versions or outdated _MiniSmtpServer_ gem you may follow the guides (see appendix) how to change your existing code to be compatible with the latest releases.
|
148
160
|
|
149
|
-
#### Latest release: 3.0.3 (2022-02-12)
|
150
161
|
|
151
|
-
|
152
|
-
|
162
|
+
#### Latest release: 3.2.1 (2023-08-15)
|
163
|
+
|
164
|
+
1. New feature [proxy](https://midi-smtp-server.readthedocs.io/feature_proxy) ([check issue 49](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/49))
|
165
|
+
2. mkdocs update for readthedocs
|
153
166
|
|
154
167
|
|
155
168
|
#### Changelog history
|
@@ -171,6 +184,7 @@ Checkout the [Appendix Upgrade](https://midi-smtp-server.readthedocs.io/appendix
|
|
171
184
|
You may find, use and download the gem package on [RubyGems.org](http://rubygems.org/gems/midi-smtp-server).
|
172
185
|
|
173
186
|
[![Gem Version](https://badge.fury.io/rb/midi-smtp-server.svg)](http://badge.fury.io/rb/midi-smtp-server)
|
187
|
+
[![Ruby](https://github.com/4commerce-technologies-AG/midi-smtp-server/actions/workflows/push-and-pr-testing-ruby-ci.yml/badge.svg)](https://github.com/4commerce-technologies-AG/midi-smtp-server/actions/workflows/push-and-pr-testing-ruby-ci.yml)
|
174
188
|
|
175
189
|
<br>
|
176
190
|
|
@@ -189,6 +203,6 @@ You may find, use and download the gem package on [RubyGems.org](http://rubygems
|
|
189
203
|
|
190
204
|
Author: [Tom Freudenberg](http://about.me/tom.freudenberg)
|
191
205
|
|
192
|
-
[MidiSmtpServer Class](https://github.com/4commerce-technologies-AG/midi-smtp-server/) is inspired from [MiniSmtpServer Class](https://github.com/aarongough/mini-smtp-server) and code written by [Aaron Gough](https://github.com/aarongough) and [Peter Cooper](
|
206
|
+
[MidiSmtpServer Class](https://github.com/4commerce-technologies-AG/midi-smtp-server/) is inspired from [MiniSmtpServer Class](https://github.com/aarongough/mini-smtp-server) and code written by [Aaron Gough](https://github.com/aarongough) and [Peter Cooper](https://github.com/4commerce-technologies-AG/midi-smtp-server#author--credits)
|
193
207
|
|
194
|
-
Copyright (c) 2014-
|
208
|
+
Copyright (c) 2014-2023 [Tom Freudenberg](https://github.com/TomFreudenberg), [4commerce technologies AG](https://www.4commerce.de/), released under the MIT license
|
@@ -10,7 +10,7 @@ module MidiSmtpServer
|
|
10
10
|
class SmtpdIOTimeoutException < RuntimeError
|
11
11
|
end
|
12
12
|
|
13
|
-
# special internal exception to signal buffer size
|
13
|
+
# special internal exception to signal buffer size exceeding
|
14
14
|
# while waiting for incoming data line
|
15
15
|
class SmtpdIOBufferOverrunException < RuntimeError
|
16
16
|
end
|
@@ -286,7 +286,7 @@ module MidiSmtpServer
|
|
286
286
|
|
287
287
|
end
|
288
288
|
|
289
|
-
# Status when
|
289
|
+
# Status when expecting CRLF sequence as line breaks (RFC(2)822)
|
290
290
|
|
291
291
|
# 500 Bad input, missing CRLF line termination
|
292
292
|
class Smtpd500CrLfSequenceException < SmtpdException
|
@@ -69,9 +69,9 @@ module MidiSmtpServer
|
|
69
69
|
@ssl_context.cert.sign @ssl_context.key, OpenSSL::Digest.new('SHA256')
|
70
70
|
logger.debug("SSL: generated test certificate\r\n#{@ssl_context.cert.to_text}")
|
71
71
|
else
|
72
|
-
# if any is set, test the
|
73
|
-
raise "File
|
74
|
-
raise "File
|
72
|
+
# if any is set, test the paths
|
73
|
+
raise "File \"#{@cert_path}\" does not exist or is not a regular file. Could not load certificate." unless File.file?(@cert_path.to_s)
|
74
|
+
raise "File \"#{@key_path}\" does not exist or is not a regular file. Could not load private key." unless @key_path.nil? || File.file?(@key_path.to_s)
|
75
75
|
# try to load certificate and key
|
76
76
|
cert_lines = File.read(@cert_path.to_s).lines
|
77
77
|
# check if the cert file contains a chain of certs
|
data/lib/midi-smtp-server.rb
CHANGED
@@ -17,24 +17,27 @@ module MidiSmtpServer
|
|
17
17
|
# default values
|
18
18
|
DEFAULT_SMTPD_HOST = '127.0.0.1'
|
19
19
|
DEFAULT_SMTPD_PORT = 2525
|
20
|
+
DEFAULT_SMTPD_PRE_FORK = 0
|
20
21
|
DEFAULT_SMTPD_MAX_PROCESSINGS = 4
|
21
22
|
|
22
|
-
# default values for conformity to RFC(2)822 and
|
23
|
+
# default values for conformity to RFC(2)822 and additional
|
23
24
|
# if interested in details, checkout discussion on issue queue at:
|
24
25
|
# https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/16
|
25
26
|
CRLF_MODES = [:CRLF_ENSURE, :CRLF_LEAVE, :CRLF_STRICT].freeze
|
26
27
|
DEFAULT_CRLF_MODE = :CRLF_ENSURE
|
27
28
|
|
28
29
|
# default values for IO operations
|
30
|
+
DEFAULT_IO_WAITREADABLE_SLEEP = 0.1
|
29
31
|
DEFAULT_IO_CMD_TIMEOUT = 30
|
30
32
|
DEFAULT_IO_BUFFER_CHUNK_SIZE = 4 * 1024
|
31
33
|
DEFAULT_IO_BUFFER_MAX_SIZE = 1 * 1024 * 1024
|
32
34
|
|
33
35
|
# default value for SMTPD extensions support
|
36
|
+
DEFAULT_PROXY_EXTENSION_ENABLED = false
|
34
37
|
DEFAULT_PIPELINING_EXTENSION_ENABLED = false
|
35
38
|
DEFAULT_INTERNATIONALIZATION_EXTENSIONS_ENABLED = false
|
36
39
|
|
37
|
-
#
|
40
|
+
# Authentication modes
|
38
41
|
AUTH_MODES = [:AUTH_FORBIDDEN, :AUTH_OPTIONAL, :AUTH_REQUIRED].freeze
|
39
42
|
DEFAULT_AUTH_MODE = :AUTH_FORBIDDEN
|
40
43
|
|
@@ -43,31 +46,42 @@ module MidiSmtpServer
|
|
43
46
|
|
44
47
|
public
|
45
48
|
|
46
|
-
#
|
49
|
+
# Create the server
|
47
50
|
def start
|
48
|
-
|
51
|
+
create_service
|
52
|
+
# immediately attach the threads to running single master process (default)
|
53
|
+
attach_threads unless pre_fork?
|
49
54
|
end
|
50
55
|
|
51
56
|
# Stop the server
|
52
57
|
def stop(wait_seconds_before_close: 2, gracefully: true)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
58
|
+
begin
|
59
|
+
# signal pre_forked workers to stop
|
60
|
+
@workers.each { |worker_pid| Process.kill(:TERM, worker_pid) } if pre_fork? && master?
|
61
|
+
# always signal shutdown
|
62
|
+
shutdown if gracefully
|
63
|
+
# wait if some connection(s) need(s) more time to handle shutdown
|
64
|
+
sleep wait_seconds_before_close if connections?
|
65
|
+
# drop tcp_servers while raising SmtpdStopServiceException
|
66
|
+
@connections_mutex.synchronize do
|
67
|
+
@tcp_server_threads.each do |tcp_server_thread|
|
68
|
+
# use safe navigation (&.) to make sure that obj exists like ... if tcp_server_thread
|
69
|
+
tcp_server_thread&.raise SmtpdStopServiceException
|
70
|
+
end
|
62
71
|
end
|
72
|
+
|
73
|
+
ensure
|
74
|
+
# check for removing TCPServers
|
75
|
+
@tcp_servers.each { |tcp_server| remove_tcp_server(tcp_server) } if master?
|
63
76
|
end
|
77
|
+
|
64
78
|
# wait if some connection(s) still need(s) more time to come down
|
65
79
|
sleep wait_seconds_before_close if connections? || !stopped?
|
66
80
|
end
|
67
81
|
|
68
82
|
# Returns true if the server has stopped.
|
69
83
|
def stopped?
|
70
|
-
@tcp_server_threads.empty? && @tcp_servers.empty?
|
84
|
+
master? ? @workers.empty? && @tcp_server_threads.empty? && @tcp_servers.empty? : @tcp_server_threads.empty?
|
71
85
|
end
|
72
86
|
|
73
87
|
# Schedule a shutdown for the server
|
@@ -100,34 +114,67 @@ module MidiSmtpServer
|
|
100
114
|
@processings.any?
|
101
115
|
end
|
102
116
|
|
117
|
+
# Return if in pre-fork mode
|
118
|
+
def pre_fork?
|
119
|
+
@pre_fork > 1
|
120
|
+
end
|
121
|
+
|
122
|
+
# Return if this is the master process
|
123
|
+
def master?
|
124
|
+
!@is_forked
|
125
|
+
end
|
126
|
+
|
127
|
+
# Return if this is a forked worker process
|
128
|
+
def worker?
|
129
|
+
@is_forked
|
130
|
+
end
|
131
|
+
|
132
|
+
# Return number of forked worker processes
|
133
|
+
def workers
|
134
|
+
@workers.size
|
135
|
+
end
|
136
|
+
|
137
|
+
# Return if has active forked worker processes
|
138
|
+
def workers?
|
139
|
+
@workers.any?
|
140
|
+
end
|
141
|
+
|
103
142
|
# Join with the server thread(s)
|
104
143
|
# before joining the server threads, check and wait optionally a few seconds
|
105
144
|
# to let the service(s) come up
|
106
145
|
def join(sleep_seconds_before_join: 1)
|
107
146
|
# check already existing TCPServers
|
108
147
|
return if @tcp_servers.empty?
|
109
|
-
#
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
148
|
+
# check number of processes to pre-fork
|
149
|
+
|
150
|
+
if pre_fork?
|
151
|
+
# create a number of pre-fork processes and attach and join threads within workers
|
152
|
+
@pre_fork.times do
|
153
|
+
# append worker pid to list of workers
|
154
|
+
@workers << fork do
|
155
|
+
# set state for a forked process
|
156
|
+
@is_forked = true
|
157
|
+
# just attach and join the threads to forked worker process
|
158
|
+
attach_threads
|
159
|
+
join_threads(sleep_seconds_before_join: sleep_seconds_before_join)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
# Blocking wait until each worker process has been finished
|
163
|
+
@workers.each { |pid| Process.waitpid(pid) }
|
118
164
|
|
119
|
-
|
120
|
-
|
165
|
+
else
|
166
|
+
# just join the threads to running single master process (default)
|
167
|
+
join_threads(sleep_seconds_before_join: sleep_seconds_before_join)
|
121
168
|
end
|
122
169
|
end
|
123
170
|
|
124
|
-
# Array of ports on which to bind, set as string
|
171
|
+
# Array of ports on which to bind, set as string separated by commata like '2525, 3535' or '2525:3535, 2525'
|
125
172
|
def ports
|
126
173
|
# prevent original array from being changed
|
127
174
|
@ports.dup
|
128
175
|
end
|
129
176
|
|
130
|
-
# Array of hosts / ip_addresses on which to bind, set as string
|
177
|
+
# Array of hosts / ip_addresses on which to bind, set as string separated by commata like 'name.domain.com, 127.0.0.1, ::1'
|
131
178
|
def hosts
|
132
179
|
# prevent original array from being changed
|
133
180
|
@hosts.dup
|
@@ -139,7 +186,7 @@ module MidiSmtpServer
|
|
139
186
|
@addresses.dup
|
140
187
|
end
|
141
188
|
|
142
|
-
# Current TLS OpenSSL::SSL::SSLContext when
|
189
|
+
# Current TLS OpenSSL::SSL::SSLContext when initialized by :TLS_OPTIONAL, :TLS_REQUIRED
|
143
190
|
def ssl_context
|
144
191
|
@tls&.ssl_context
|
145
192
|
end
|
@@ -150,15 +197,17 @@ module MidiSmtpServer
|
|
150
197
|
attr_reader :max_connections
|
151
198
|
# CRLF handling based on conformity to RFC(2)822
|
152
199
|
attr_reader :crlf_mode
|
200
|
+
# Time in seconds to sleep on IO::WaitReadable exception
|
201
|
+
attr_reader :io_waitreadable_sleep
|
153
202
|
# Maximum time in seconds to wait for a complete incoming data line, as a FixNum
|
154
203
|
attr_reader :io_cmd_timeout
|
155
204
|
# Bytes to read non-blocking from socket into buffer, as a FixNum
|
156
205
|
attr_reader :io_buffer_chunk_size
|
157
|
-
# Maximum bytes to read as buffer before expecting
|
206
|
+
# Maximum bytes to read as buffer before expecting completed incoming data line, as a FixNum
|
158
207
|
attr_reader :io_buffer_max_size
|
159
208
|
# Flag if should do reverse DNS lookups on incoming connections
|
160
209
|
attr_reader :do_dns_reverse_lookup
|
161
|
-
#
|
210
|
+
# Authentication mode
|
162
211
|
attr_reader :auth_mode
|
163
212
|
# Encryption mode
|
164
213
|
attr_reader :encrypt_mode
|
@@ -166,26 +215,31 @@ module MidiSmtpServer
|
|
166
215
|
attr_reader :pipelining_extension
|
167
216
|
# handle SMTP 8BITMIME and SMTPUTF8 extension
|
168
217
|
attr_reader :internationalization_extensions
|
218
|
+
# handle PROXY connections
|
219
|
+
attr_reader :proxy_extension
|
169
220
|
|
170
|
-
# logging object, may be
|
221
|
+
# logging object, may be overridden by special loggers like YELL or others
|
171
222
|
attr_reader :logger
|
172
223
|
|
173
224
|
# Initialize SMTP Server class
|
174
225
|
#
|
175
226
|
# +ports+:: ports to listen on. Allows multiple ports like "2525, 3535" or "2525:3535, 2525". Default value = DEFAULT_SMTPD_PORT
|
176
227
|
# +hosts+:: interface ip or hostname to listen on or "*" to listen on all interfaces, allows multiple hostnames and ip_addresses like "name.domain.com, 127.0.0.1, ::1". Default value = DEFAULT_SMTPD_HOST
|
228
|
+
# +pre_fork+:: number of processes to pre-fork to enable load balancing over multiple cores. Default value = DEFAULT_SMTPD_PRE_FORK
|
177
229
|
# +max_processings+:: maximum number of simultaneous processed connections, this does not limit the number of concurrent TCP connections. Default value = DEFAULT_SMTPD_MAX_PROCESSINGS
|
178
230
|
# +max_connections+:: maximum number of connections, this does limit the number of concurrent TCP connections (not set or nil => unlimited)
|
179
231
|
# +crlf_mode+:: CRLF handling support (:CRLF_ENSURE [default], :CRLF_LEAVE, :CRLF_STRICT)
|
180
232
|
# +do_dns_reverse_lookup+:: flag if this smtp server should do reverse DNS lookups on incoming connections
|
233
|
+
# +io_waitreadable_sleep+:: seconds to sleep in loop when no input data is available (DEFAULT_IO_WAITREADABLE_SLEEP)
|
181
234
|
# +io_cmd_timeout+:: time in seconds to wait until complete line of data is expected (DEFAULT_IO_CMD_TIMEOUT, nil => disabled test)
|
182
235
|
# +io_buffer_chunk_size+:: size of chunks (bytes) to read non-blocking from socket (DEFAULT_IO_BUFFER_CHUNK_SIZE)
|
183
236
|
# +io_buffer_max_size+:: max size of buffer (max line length) until \lf ist expected (DEFAULT_IO_BUFFER_MAX_SIZE, nil => disabled test)
|
184
237
|
# +pipelining_extension+:: set to true for support of SMTP PIPELINING extension (DEFAULT_PIPELINING_EXTENSION_ENABLED)
|
185
238
|
# +internationalization_extensions+:: set to true for support of SMTP 8BITMIME and SMTPUTF8 extensions (DEFAULT_INTERNATIONALIZATION_EXTENSIONS_ENABLED)
|
239
|
+
# +proxy_extension+:: set to true for supporting PROXY connections (DEFAULT_PROXY_EXTENSION_ENABLED)
|
186
240
|
# +auth_mode+:: enable builtin authentication support (:AUTH_FORBIDDEN [default], :AUTH_OPTIONAL, :AUTH_REQUIRED)
|
187
241
|
# +tls_mode+:: enable builtin TLS support (:TLS_FORBIDDEN [default], :TLS_OPTIONAL, :TLS_REQUIRED)
|
188
|
-
# +tls_cert_path+:: path to tls
|
242
|
+
# +tls_cert_path+:: path to tls certificate chain file
|
189
243
|
# +tls_key_path+:: path to tls key file
|
190
244
|
# +tls_ciphers+:: allowed ciphers for connection
|
191
245
|
# +tls_methods+:: allowed methods for protocol
|
@@ -196,15 +250,18 @@ module MidiSmtpServer
|
|
196
250
|
def initialize(
|
197
251
|
ports: DEFAULT_SMTPD_PORT,
|
198
252
|
hosts: DEFAULT_SMTPD_HOST,
|
253
|
+
pre_fork: DEFAULT_SMTPD_PRE_FORK,
|
199
254
|
max_processings: DEFAULT_SMTPD_MAX_PROCESSINGS,
|
200
255
|
max_connections: nil,
|
201
256
|
crlf_mode: nil,
|
202
257
|
do_dns_reverse_lookup: nil,
|
258
|
+
io_waitreadable_sleep: nil,
|
203
259
|
io_cmd_timeout: nil,
|
204
260
|
io_buffer_chunk_size: nil,
|
205
261
|
io_buffer_max_size: nil,
|
206
262
|
pipelining_extension: nil,
|
207
263
|
internationalization_extensions: nil,
|
264
|
+
proxy_extension: nil,
|
208
265
|
auth_mode: nil,
|
209
266
|
tls_mode: nil,
|
210
267
|
tls_cert_path: nil,
|
@@ -216,7 +273,7 @@ module MidiSmtpServer
|
|
216
273
|
logger: nil,
|
217
274
|
logger_severity: nil
|
218
275
|
)
|
219
|
-
# create an exposed logger to forward
|
276
|
+
# create an exposed logger to forward logging to the on_logging_event
|
220
277
|
@logger = MidiSmtpServer::ForwardingLogger.new(method(:on_logging_event))
|
221
278
|
|
222
279
|
# external logging
|
@@ -231,6 +288,11 @@ module MidiSmtpServer
|
|
231
288
|
logger.warn('Deprecated: "logger" was set on new! Please use "on_logging_event" instead.')
|
232
289
|
end
|
233
290
|
|
291
|
+
# initialize as master process
|
292
|
+
@is_forked = false
|
293
|
+
# no forked worker processes
|
294
|
+
@workers = []
|
295
|
+
|
234
296
|
# list of TCPServers
|
235
297
|
@tcp_servers = []
|
236
298
|
# list of running threads
|
@@ -311,12 +373,16 @@ module MidiSmtpServer
|
|
311
373
|
end
|
312
374
|
end
|
313
375
|
|
376
|
+
# read pre_fork
|
377
|
+
@pre_fork = pre_fork
|
378
|
+
raise 'Number of processes to pre-fork (pre_fork) must be zero or a positive integer greater than 1!' unless @pre_fork.is_a?(Integer) && (@pre_fork.zero? || pre_fork?)
|
314
379
|
# read max_processings
|
315
380
|
@max_processings = max_processings
|
316
381
|
raise 'Number of simultaneous processings (max_processings) must be a positive integer!' unless @max_processings.is_a?(Integer) && @max_processings.positive?
|
317
382
|
# check max_connections
|
318
383
|
@max_connections = max_connections
|
319
|
-
raise 'Number of concurrent connections
|
384
|
+
raise 'Number of concurrent connections (max_connections) must be nil or a positive integer!' unless @max_connections.nil? || (@max_connections.is_a?(Integer) && @max_connections.positive?)
|
385
|
+
raise 'Number of concurrent connections (max_connections) is lower than number of simultaneous processings (max_processings)!' if !@max_connections.nil? && @max_connections < @max_processings
|
320
386
|
|
321
387
|
# check for crlf mode
|
322
388
|
@crlf_mode = crlf_mode.nil? ? DEFAULT_CRLF_MODE : crlf_mode
|
@@ -328,6 +394,7 @@ module MidiSmtpServer
|
|
328
394
|
@do_dns_reverse_lookup = do_dns_reverse_lookup.nil? ? true : do_dns_reverse_lookup
|
329
395
|
|
330
396
|
# io and buffer settings
|
397
|
+
@io_waitreadable_sleep = io_waitreadable_sleep.nil? ? DEFAULT_IO_WAITREADABLE_SLEEP : io_waitreadable_sleep
|
331
398
|
@io_cmd_timeout = io_cmd_timeout.nil? ? DEFAULT_IO_CMD_TIMEOUT : io_cmd_timeout
|
332
399
|
@io_buffer_chunk_size = io_buffer_chunk_size.nil? ? DEFAULT_IO_BUFFER_CHUNK_SIZE : io_buffer_chunk_size
|
333
400
|
@io_buffer_max_size = io_buffer_max_size.nil? ? DEFAULT_IO_BUFFER_MAX_SIZE : io_buffer_max_size
|
@@ -335,10 +402,12 @@ module MidiSmtpServer
|
|
335
402
|
# smtp extensions
|
336
403
|
@pipelining_extension = pipelining_extension.nil? ? DEFAULT_PIPELINING_EXTENSION_ENABLED : pipelining_extension
|
337
404
|
@internationalization_extensions = internationalization_extensions.nil? ? DEFAULT_INTERNATIONALIZATION_EXTENSIONS_ENABLED : internationalization_extensions
|
405
|
+
@proxy_extension = proxy_extension.nil? ? DEFAULT_PROXY_EXTENSION_ENABLED : proxy_extension
|
406
|
+
require 'ipaddr' if @proxy_extension
|
338
407
|
|
339
|
-
# check for
|
408
|
+
# check for authentication
|
340
409
|
@auth_mode = auth_mode.nil? ? DEFAULT_AUTH_MODE : auth_mode
|
341
|
-
raise "Unknown
|
410
|
+
raise "Unknown authentication mode #{@auth_mode} was given!" unless AUTH_MODES.include?(@auth_mode)
|
342
411
|
|
343
412
|
# check for encryption
|
344
413
|
@encrypt_mode = tls_mode.nil? ? DEFAULT_ENCRYPT_MODE : tls_mode
|
@@ -409,7 +478,7 @@ module MidiSmtpServer
|
|
409
478
|
on_logging_event(ctx, Logger::DEBUG, "Client connect from #{ctx[:server][:remote_ip]}:#{ctx[:server][:remote_port]} to #{ctx[:server][:local_ip]}:#{ctx[:server][:local_port]}")
|
410
479
|
end
|
411
480
|
|
412
|
-
# event before
|
481
|
+
# event before DISCONNECT
|
413
482
|
def on_disconnect_event(ctx)
|
414
483
|
on_logging_event(ctx, Logger::DEBUG, "Client disconnect from #{ctx[:server][:remote_ip]}:#{ctx[:server][:remote_port]} on #{ctx[:server][:local_ip]}:#{ctx[:server][:local_port]}")
|
415
484
|
end
|
@@ -420,13 +489,20 @@ module MidiSmtpServer
|
|
420
489
|
# the value is not allowed to return CR nor LF chars and will be stripped
|
421
490
|
def on_helo_event(ctx, helo_data) end
|
422
491
|
|
423
|
-
#
|
492
|
+
# event on PROXY
|
493
|
+
# you may raise an exception if you want to block some addresses
|
494
|
+
# you also may change or add any value of the hash:
|
495
|
+
# {proto, source_ip, source_host, source_port, dest_ip, dest_host, dest_port}
|
496
|
+
# a returned value hash is set as ctx[:server][:proxy]
|
497
|
+
def on_proxy_event(ctx, proxy_data) end
|
498
|
+
|
499
|
+
# check the authentication on AUTH
|
424
500
|
# if any value returned, that will be used for ongoing processing
|
425
501
|
# otherwise the original value will be used for authorization_id
|
426
502
|
def on_auth_event(ctx, authorization_id, authentication_id, authentication)
|
427
|
-
# if
|
503
|
+
# if authentication is used, override this event
|
428
504
|
# and implement your own user management.
|
429
|
-
# otherwise all
|
505
|
+
# otherwise all authentications are blocked per default
|
430
506
|
on_logging_event(ctx, Logger::DEBUG, "Deny access from #{ctx[:server][:remote_ip]}:#{ctx[:server][:remote_port]} for #{authentication_id}" + (authorization_id == '' ? '' : "/#{authorization_id}") + " with #{authentication}")
|
431
507
|
raise Smtpd535Exception
|
432
508
|
end
|
@@ -473,8 +549,8 @@ module MidiSmtpServer
|
|
473
549
|
|
474
550
|
protected
|
475
551
|
|
476
|
-
#
|
477
|
-
def
|
552
|
+
# Prepare all listeners for all hosts
|
553
|
+
def create_service
|
478
554
|
raise 'Service was already started' unless stopped?
|
479
555
|
|
480
556
|
# set flag to signal shutdown by stop / shutdown command
|
@@ -485,12 +561,12 @@ module MidiSmtpServer
|
|
485
561
|
# break address into ip_address and port and serve service
|
486
562
|
ip_address = address.rpartition(':').first
|
487
563
|
port = address.rpartition(':').last
|
488
|
-
|
564
|
+
create_service_on_ip_address_and_port(ip_address, port)
|
489
565
|
end
|
490
566
|
end
|
491
567
|
|
492
|
-
#
|
493
|
-
def
|
568
|
+
# Prepare a listener on single ip_address and port
|
569
|
+
def create_service_on_ip_address_and_port(ip_address, port)
|
494
570
|
# log information
|
495
571
|
logger.info("Starting service on #{ip_address}:#{port}")
|
496
572
|
# check that there is a specific ip_address defined
|
@@ -499,7 +575,47 @@ module MidiSmtpServer
|
|
499
575
|
tcp_server = TCPServer.new(ip_address, port)
|
500
576
|
# append this server to the list of TCPServers
|
501
577
|
@tcp_servers << tcp_server
|
578
|
+
end
|
579
|
+
|
580
|
+
# Close and remove the given tcp_server
|
581
|
+
def remove_tcp_server(tcp_server)
|
582
|
+
begin
|
583
|
+
# drop the service
|
584
|
+
tcp_server.close
|
585
|
+
# remove from list
|
586
|
+
@tcp_servers.delete(tcp_server)
|
587
|
+
rescue StandardError
|
588
|
+
# ignore any error from here
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
# Join with the server thread(s)
|
593
|
+
# before joining the server threads, wait optionally a few seconds
|
594
|
+
# to let the service(s) come up
|
595
|
+
def join_threads(sleep_seconds_before_join: 1)
|
596
|
+
# wait some seconds before joining the upcoming threads
|
597
|
+
# and check that all TCPServers got one thread
|
598
|
+
while (@tcp_server_threads.length < @tcp_servers.length) && sleep_seconds_before_join.positive?
|
599
|
+
sleep_seconds_before_join -= 1
|
600
|
+
sleep 1
|
601
|
+
end
|
602
|
+
# try to join any thread
|
603
|
+
begin
|
604
|
+
@tcp_server_threads.each(&:join)
|
605
|
+
|
606
|
+
# catch ctrl-c to stop service
|
607
|
+
rescue Interrupt
|
608
|
+
end
|
609
|
+
end
|
502
610
|
|
611
|
+
# Create and attach threads to all listeners
|
612
|
+
def attach_threads
|
613
|
+
# loop for all TCPServers listener
|
614
|
+
@tcp_servers.each { |tcp_server| attach_thread(tcp_server) }
|
615
|
+
end
|
616
|
+
|
617
|
+
# Create and attach a thread to a listener
|
618
|
+
def attach_thread(tcp_server)
|
503
619
|
# run thread until shutdown
|
504
620
|
@tcp_server_threads << Thread.new do
|
505
621
|
begin
|
@@ -527,7 +643,7 @@ module MidiSmtpServer
|
|
527
643
|
ensure
|
528
644
|
begin
|
529
645
|
# always gracefully shutdown connection.
|
530
|
-
# if the io object was
|
646
|
+
# if the io object was overridden by the
|
531
647
|
# result from serve_client() due to ssl
|
532
648
|
# io, the ssl + io socket will be closed
|
533
649
|
io.close
|
@@ -552,16 +668,7 @@ module MidiSmtpServer
|
|
552
668
|
# log fatal error while starting new thread
|
553
669
|
on_logging_event(nil, Logger::FATAL, "#{e} (#{e.class})".strip, err: e.clone)
|
554
670
|
ensure
|
555
|
-
|
556
|
-
# drop the service
|
557
|
-
tcp_server.close
|
558
|
-
# remove from list
|
559
|
-
@tcp_servers.delete(tcp_server)
|
560
|
-
# reset local var
|
561
|
-
tcp_server = nil
|
562
|
-
rescue StandardError
|
563
|
-
# ignore any error from here
|
564
|
-
end
|
671
|
+
# proper connection down?
|
565
672
|
if shutdown?
|
566
673
|
# wait for finishing opened connections
|
567
674
|
@connections_mutex.synchronize do
|
@@ -604,7 +711,7 @@ module MidiSmtpServer
|
|
604
711
|
on_connect_event(session[:ctx])
|
605
712
|
|
606
713
|
# drop connection (respond 421) if too busy
|
607
|
-
raise 'Abort connection while too busy, exceeding max_connections!' if max_connections && connections > max_connections
|
714
|
+
raise Smtpd421Exception, 'Abort connection while too busy, exceeding max_connections!' if !max_connections.nil? && connections > max_connections
|
608
715
|
|
609
716
|
# check active processings for new client
|
610
717
|
@connections_mutex.synchronize do
|
@@ -656,7 +763,7 @@ module MidiSmtpServer
|
|
656
763
|
raise SmtpdIOTimeoutException if @io_cmd_timeout && Time.now.to_i - timestamp_timeout > @io_cmd_timeout
|
657
764
|
# read chunks of input data until line-feed
|
658
765
|
io_buffer << io.read_nonblock(@io_buffer_chunk_size)
|
659
|
-
# check for
|
766
|
+
# check for buffer size
|
660
767
|
raise SmtpdIOBufferOverrunException if @io_buffer_max_size && io_buffer.length > @io_buffer_max_size
|
661
768
|
# check for lf in current io_buffer
|
662
769
|
io_buffer_line_lf = io_buffer.index("\n")
|
@@ -665,7 +772,7 @@ module MidiSmtpServer
|
|
665
772
|
# ignore exception when no input data is available yet
|
666
773
|
rescue IO::WaitReadable
|
667
774
|
# but wait a few moment to slow down system utilization
|
668
|
-
sleep
|
775
|
+
sleep @io_waitreadable_sleep
|
669
776
|
end
|
670
777
|
|
671
778
|
# check if io_buffer is filled and contains already a line-feed
|
@@ -679,12 +786,12 @@ module MidiSmtpServer
|
|
679
786
|
# process commands and handle special SmtpdExceptions
|
680
787
|
begin
|
681
788
|
# check for pipelining extension or violation
|
682
|
-
raise Smtpd500PipeliningException unless @pipelining_extension ||
|
789
|
+
raise Smtpd500PipeliningException unless !io_buffer_line_lf || @pipelining_extension || (proxy_extension && (session[:cmd_sequence] == :CMD_HELO)) || (session[:cmd_sequence] == :CMD_DATA)
|
683
790
|
|
684
791
|
# handle input line based on @crlf_mode
|
685
792
|
case crlf_mode
|
686
793
|
when :CRLF_ENSURE
|
687
|
-
# remove any \r or \n
|
794
|
+
# remove any \r or \n occurrence from line
|
688
795
|
line.delete!("\r\n")
|
689
796
|
# log line, verbosity based on log severity and command sequence
|
690
797
|
on_logging_event(session[:ctx], Logger::DEBUG, +'<<< ' << line << "\n") if session[:cmd_sequence] != :CMD_DATA
|
@@ -859,6 +966,88 @@ module MidiSmtpServer
|
|
859
966
|
return "250 OK #{session[:ctx][:server][:helo_response].to_s.strip}".strip
|
860
967
|
end
|
861
968
|
|
969
|
+
when @proxy_extension && (/^PROXY(\s+)/i)
|
970
|
+
# PROXY
|
971
|
+
# 250 Requested mail action okay, completed
|
972
|
+
# 421 <domain> Service not available, closing transmission channel
|
973
|
+
# 500 Syntax error, command unrecognised
|
974
|
+
# 501 Syntax error in parameters or arguments
|
975
|
+
# ---------
|
976
|
+
# Documentation at https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt
|
977
|
+
# syntax
|
978
|
+
# PROXY PROTO source-ip dest-ip source-port dest-port
|
979
|
+
# supported commands:
|
980
|
+
# PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535
|
981
|
+
# PROXY TCP6 ffff:f...f:ffff ffff:f...f:ffff 65535 65535
|
982
|
+
# PROXY UNKNOWN
|
983
|
+
# PROXY UNKNOWN ffff:f...f:ffff ffff:f...f:ffff 65535 65535
|
984
|
+
# ---------
|
985
|
+
# check valid command sequence
|
986
|
+
raise Smtpd503Exception if session[:cmd_sequence] != :CMD_HELO
|
987
|
+
# check valid command
|
988
|
+
raise Smtpd421Exception, 'Abort connection while illegal PROXY command!' unless line.match?(/^PROXY(\s+)(UNKNOWN(|(\s+).*)|TCP(4|6)(\s+)([0-9a-f.:]+)(\s+)([0-9a-f.:]+)(\s+)([0-9]+)(\s+)([0-9]+)(\s*))$/i)
|
989
|
+
# check command usage is allowed only once
|
990
|
+
raise Smtpd421Exception, 'Abort connection while PROXY already set!' if session[:ctx][:server][:proxy]
|
991
|
+
# get values from proxy command
|
992
|
+
cmd_data = line.gsub(/^PROXY\ /i, '').strip.gsub(/\s+/, ' ').split
|
993
|
+
# create an empty hash to inspect by event
|
994
|
+
proxy_data = {
|
995
|
+
proto: cmd_data[0].upcase,
|
996
|
+
source_ip: nil,
|
997
|
+
source_host: nil,
|
998
|
+
source_port: nil,
|
999
|
+
dest_ip: nil,
|
1000
|
+
dest_host: nil,
|
1001
|
+
dest_port: nil
|
1002
|
+
}
|
1003
|
+
# test proto
|
1004
|
+
unless proxy_data[:proto] == 'UNKNOWN'
|
1005
|
+
begin
|
1006
|
+
# try to build valid addresses from given strings
|
1007
|
+
proxy_data[:source_ip] = IPAddr.new(cmd_data[1])
|
1008
|
+
proxy_data[:source_port] = cmd_data[3].to_i
|
1009
|
+
proxy_data[:dest_ip] = IPAddr.new(cmd_data[2])
|
1010
|
+
proxy_data[:dest_port] = cmd_data[4].to_i
|
1011
|
+
# check that given addresses correct by type
|
1012
|
+
if proxy_data[:proto] == 'TCP4'
|
1013
|
+
raise unless proxy_data[:source_ip].ipv4?
|
1014
|
+
raise unless proxy_data[:dest_ip].ipv4?
|
1015
|
+
else
|
1016
|
+
raise unless proxy_data[:source_ip].ipv6?
|
1017
|
+
raise unless proxy_data[:dest_ip].ipv6?
|
1018
|
+
end
|
1019
|
+
# check that ports within valid ranges
|
1020
|
+
raise unless proxy_data[:source_port].between?(1, 65_535)
|
1021
|
+
raise unless proxy_data[:dest_port].between?(1, 65_535)
|
1022
|
+
|
1023
|
+
# update hash to inspect by event
|
1024
|
+
# normalize ip addresses
|
1025
|
+
proxy_data[:source_ip] = proxy_data[:source_ip].to_s
|
1026
|
+
proxy_data[:source_host] = proxy_data[:source_ip]
|
1027
|
+
proxy_data[:dest_ip] = proxy_data[:dest_ip].to_s
|
1028
|
+
proxy_data[:dest_host] = proxy_data[:dest_ip]
|
1029
|
+
|
1030
|
+
rescue StandardError
|
1031
|
+
# change exception into Smtpd exception and drop connection
|
1032
|
+
raise Smtpd421Exception, 'Abort connection for unsupported PROXY parameters!'
|
1033
|
+
end
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
# call event to handle data
|
1037
|
+
return_value = on_proxy_event(session[:ctx], proxy_data)
|
1038
|
+
if return_value
|
1039
|
+
# overwrite data with returned value
|
1040
|
+
proxy_data = return_value
|
1041
|
+
end
|
1042
|
+
# if no error raised, append to server hash
|
1043
|
+
session[:ctx][:server][:proxy] = proxy_data
|
1044
|
+
|
1045
|
+
# reply nothing
|
1046
|
+
# otherwise on buffering clients or enabled feature pipelining
|
1047
|
+
# the original client will receive unhandleable responses
|
1048
|
+
# and gets interrupted
|
1049
|
+
return ''
|
1050
|
+
|
862
1051
|
when /^STARTTLS\s*$/i
|
863
1052
|
# STARTTLS
|
864
1053
|
# 220 Ready to start TLS
|
@@ -1201,6 +1390,7 @@ module MidiSmtpServer
|
|
1201
1390
|
remote_host: +'',
|
1202
1391
|
remote_ip: +'',
|
1203
1392
|
remote_port: +'',
|
1393
|
+
proxy: nil,
|
1204
1394
|
helo: +'',
|
1205
1395
|
helo_response: +'',
|
1206
1396
|
connected: +'',
|
@@ -1235,7 +1425,7 @@ module MidiSmtpServer
|
|
1235
1425
|
)
|
1236
1426
|
end
|
1237
1427
|
|
1238
|
-
# handle plain
|
1428
|
+
# handle plain authentication
|
1239
1429
|
def process_auth_plain(session, encoded_auth_response)
|
1240
1430
|
begin
|
1241
1431
|
# extract auth id (and password)
|
metadata
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: midi-smtp-server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Freudenberg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-08-15 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description:
|
14
|
-
for AUTH and SSL/STARTTLS
|
13
|
+
description: MidiSmtpServer is the highly customizable ruby SMTP-Server and SMTP-Service
|
14
|
+
library with builtin support for AUTH and SSL/STARTTLS, 8BITMIME and SMTPUTF8, IPv4
|
15
|
+
and IPv6 and additional features.
|
15
16
|
email: develop.rb.midi-smtp-server@4commerce.net
|
16
17
|
executables: []
|
17
18
|
extensions: []
|
@@ -25,7 +26,7 @@ files:
|
|
25
26
|
- lib/midi-smtp-server/logger.rb
|
26
27
|
- lib/midi-smtp-server/tls-transport.rb
|
27
28
|
- lib/midi-smtp-server/version.rb
|
28
|
-
homepage:
|
29
|
+
homepage: https://4commerce-technologies-ag.github.io/midi-smtp-server
|
29
30
|
licenses:
|
30
31
|
- MIT
|
31
32
|
metadata:
|
@@ -33,7 +34,7 @@ metadata:
|
|
33
34
|
source_code_uri: https://github.com/4commerce-technologies-AG/midi-smtp-server
|
34
35
|
changelog_uri: https://github.com/4commerce-technologies-AG/midi-smtp-server#changes-and-updates
|
35
36
|
bug_tracker_uri: https://github.com/4commerce-technologies-AG/midi-smtp-server/issues
|
36
|
-
documentation_uri: https://www.rubydoc.info/gems/midi-smtp-server/3.
|
37
|
+
documentation_uri: https://www.rubydoc.info/gems/midi-smtp-server/3.2.1
|
37
38
|
wiki_uri: https://midi-smtp-server.readthedocs.io/
|
38
39
|
post_install_message:
|
39
40
|
rdoc_options: []
|
@@ -50,7 +51,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
50
51
|
- !ruby/object:Gem::Version
|
51
52
|
version: '0'
|
52
53
|
requirements: []
|
53
|
-
rubygems_version: 3.
|
54
|
+
rubygems_version: 3.4.10
|
54
55
|
signing_key:
|
55
56
|
specification_version: 4
|
56
57
|
summary: MidiSmtpServer Class
|