postfix-xforward 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +4 -0
- data/LICENSE +18 -0
- data/README.rdoc +71 -0
- data/lib/postfix-xforward.rb +12 -0
- data/lib/postfix-xforward/smtp.rb +265 -0
- data/lib/postfix-xforward/utils.rb +10 -0
- data/lib/postfix-xforward/version.rb +8 -0
- metadata +78 -0
data/CHANGELOG.rdoc
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2010 Kendall Gifford
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
7
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
8
|
+
subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
15
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
= Postfix XFORWARD Extension for Net::SMTP
|
2
|
+
|
3
|
+
The postfix-xforward extension adds methods to Ruby's Net::SMTP library to support the
|
4
|
+
{XFORWARD}[http://www.postfix.org/XFORWARD_README.html] SMTP extension, as defined and
|
5
|
+
supported by the {Postfix MTA}[http://www.postfix.org/].
|
6
|
+
|
7
|
+
Code that currently uses
|
8
|
+
{Net::SMTP}[http://ruby-doc.org/stdlib/libdoc/net/smtp/rdoc/index.html] as follows:
|
9
|
+
|
10
|
+
require 'net/smtp'
|
11
|
+
to = 'some@address.tld'
|
12
|
+
from = 'other@domain.tld'
|
13
|
+
msg = <<EMAIL
|
14
|
+
To: #{to}
|
15
|
+
From: #{from}
|
16
|
+
Subject: Test Message
|
17
|
+
|
18
|
+
This is a test message.
|
19
|
+
EMAIL
|
20
|
+
|
21
|
+
Net::SMTP.start('mail.localdomain', 25, 'my-hostname') do |smtp|
|
22
|
+
smtp.send_message(msg, from, to)
|
23
|
+
end
|
24
|
+
|
25
|
+
... can now use it this way in order to include XFORWARD attributes:
|
26
|
+
|
27
|
+
require 'postfix-xforward'
|
28
|
+
attr = { 'NAME' => 'actual.domain.tld', 'ADDR' => '123.234.012.123' }
|
29
|
+
to = 'some@address.tld'
|
30
|
+
from = 'other@domain.tld'
|
31
|
+
msg = <<EMAIL
|
32
|
+
To: #{to}
|
33
|
+
From: #{from}
|
34
|
+
Subject: Test Message
|
35
|
+
|
36
|
+
This is a test message.
|
37
|
+
EMAIL
|
38
|
+
|
39
|
+
Net::SMTP.start('mail.localdomain', 25, 'my-hostname', nil, nil, nil, attr) do |smtp|
|
40
|
+
smtp.send_message(msg, from, to)
|
41
|
+
end
|
42
|
+
|
43
|
+
== Details
|
44
|
+
|
45
|
+
The XFORWARD extension, supported by the Postfix MTA is very simple really. It allows the
|
46
|
+
SMTP client to include various attributes before the MAIL TO command. These attributes
|
47
|
+
tell the server where the email message *really* came from.
|
48
|
+
|
49
|
+
This is almost always used on special, private instances of an SMTP server where only
|
50
|
+
trusted (usually local) clients can connect. This is usually used in configurations such
|
51
|
+
as the following:
|
52
|
+
|
53
|
+
client -> smtp-server-1 -> filter-script -> smtp-server-2 -> nexthop
|
54
|
+
|
55
|
+
In these setups, smtp-server-1 and 2 both run under the same Postfix instance in order
|
56
|
+
to provide {after-queue content filtering}[http://www.postfix.org/FILTER_README.html].
|
57
|
+
The smtp-server-1 instance has access to the actual information about the client that
|
58
|
+
is sending the message. It can pass this on, if configured correctly to an external
|
59
|
+
filter-script.
|
60
|
+
|
61
|
+
This library makes it possible, using Net::SMTP to write filter-script in Ruby and to
|
62
|
+
be able to pass original client information on when speaking SMTP to smtp-server-2
|
63
|
+
using XFORWARD.
|
64
|
+
|
65
|
+
This has just been thrown together so any comments, fixes, improvemnts, or other contributions
|
66
|
+
are appreciated.
|
67
|
+
|
68
|
+
== Authors and Credits
|
69
|
+
|
70
|
+
Authors:: Kendall Gifford
|
71
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
module PostfixXForward
|
3
|
+
class << self
|
4
|
+
# hooks PostfixXForward::SMTP into Net::SMTP
|
5
|
+
def enable
|
6
|
+
return if Net::SMTP.respond_to? :xstart
|
7
|
+
require 'postfix-xforward/smtp'
|
8
|
+
Net::SMTP.send :include, SMTP
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
PostfixXForward.enable
|
@@ -0,0 +1,265 @@
|
|
1
|
+
require 'postfix-xforward/version'
|
2
|
+
require 'postfix-xforward/utils'
|
3
|
+
|
4
|
+
module PostfixXForward
|
5
|
+
module SMTP
|
6
|
+
|
7
|
+
# RFC 822: maximum SMTP command line length is 512 (including <CRLF>)
|
8
|
+
# This is set to the maximum length, NOT including the <CRLF>
|
9
|
+
MAXLEN = 510
|
10
|
+
|
11
|
+
# Official XFORWARD command extension name
|
12
|
+
XCMD = 'XFORWARD'
|
13
|
+
|
14
|
+
# Extend Net::SMTP to support XFORWARD
|
15
|
+
def self.included(base)
|
16
|
+
base.class_eval do
|
17
|
+
extend ClassMethods
|
18
|
+
alias_method :initialize_without_xforward, :initialize
|
19
|
+
alias_method :initialize, :initialize_with_xforward
|
20
|
+
alias_method :do_start_without_xforward, :do_start
|
21
|
+
alias_method :do_start, :do_start_with_xforward
|
22
|
+
alias_method :do_finish_without_xforward, :do_finish
|
23
|
+
alias_method :do_finish, :do_finish_with_xforward
|
24
|
+
end
|
25
|
+
class << base
|
26
|
+
alias_method :start_without_xforward, :start
|
27
|
+
alias_method :start, :start_with_xforward
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module ClassMethods
|
32
|
+
# - Aliased as #start
|
33
|
+
# - Original #start available as #start_without_xforward
|
34
|
+
#
|
35
|
+
# This version adds an optional xforward_attrs parameter to the end of the
|
36
|
+
# list. You may provide a hash for this parameter to specify any XFORWARD
|
37
|
+
# attribute values you wish to provide the SMTP server on the other end.
|
38
|
+
#
|
39
|
+
# If the server doesn't support XFORWARD, then XFORWARD won't be
|
40
|
+
# attempted. Each of the provided XFORWARD attributes aren't supported by
|
41
|
+
# the server won't be transmitted either. So, for an attribute to be
|
42
|
+
# successfully transmitted via XFORWARD, the server must support the
|
43
|
+
# XFORWARD attribute specifically (and XFORWARD generally).
|
44
|
+
#
|
45
|
+
# Currently, Postfix documents the following XFORWARD attributes
|
46
|
+
# (from http://www.postfix.com/XFORWARD_README.html):
|
47
|
+
#
|
48
|
+
# NAME:: The up-stream hostname
|
49
|
+
# ADDR:: The up-stream network address
|
50
|
+
# PORT:: The up-stream client TCP port number
|
51
|
+
# PROTO:: Protocol used for receiving mail from the up-stream host
|
52
|
+
# HELO:: Hostname that the up-stream announced itself with
|
53
|
+
# IDENT:: Local message identifier on the up-stream host
|
54
|
+
# SOURCE:: Either "LOCAL" or "REMOTE" : where the up-stream host received
|
55
|
+
# the message from
|
56
|
+
def start_with_xforward(address,
|
57
|
+
port = nil,
|
58
|
+
helo = 'localhost.localdomain',
|
59
|
+
user = nil,
|
60
|
+
secret = nil,
|
61
|
+
authtype = nil,
|
62
|
+
xforward_attrs = nil,
|
63
|
+
&block
|
64
|
+
)
|
65
|
+
new(address, port, xforward_attrs).start(helo, user, secret, authtype, &block)
|
66
|
+
end
|
67
|
+
|
68
|
+
# This method accomplishes the same thing as our overridden version of
|
69
|
+
# the #start class method above (#start_with_xforward) but re-orders the
|
70
|
+
# parameters, giving priority (and making required) the xforward_attrs
|
71
|
+
# hash. Also the server address and port are now combined in one string
|
72
|
+
# that should use 'domain.tld:10025' syntax to explicitely define a port.
|
73
|
+
def xstart(address_and_port, xforward_attrs,
|
74
|
+
helo = 'localhost.localdomain',
|
75
|
+
user = nil,
|
76
|
+
secret = nil,
|
77
|
+
authtype = nil,
|
78
|
+
&block
|
79
|
+
)
|
80
|
+
address = address_and_port
|
81
|
+
port = 25
|
82
|
+
if address_and_port =~ /^(.+):(\d+)$/
|
83
|
+
address = $1
|
84
|
+
port = $2.to_i
|
85
|
+
end
|
86
|
+
new(address, port, xforward_attrs).start(helo, user, secret, authtype, &block)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# - Aliased as #initialize
|
91
|
+
# - Original #initialize available as #initialize_without_xforward
|
92
|
+
# This extended version of #initialize allows us to receive an optional
|
93
|
+
# Hash of XFORWARD attributes as the final parameter.
|
94
|
+
def initialize_with_xforward(address, port = nil, xforward_attrs = nil)
|
95
|
+
initialize_without_xforward(address, port)
|
96
|
+
@xforward = false
|
97
|
+
@xforward_attrs = {}
|
98
|
+
if xforward_attrs.is_a?(Hash)
|
99
|
+
@xforward = true
|
100
|
+
# Normalize all provided XFORWARD attribute names to upper case
|
101
|
+
# TODO: explicit validation of attributes
|
102
|
+
xforward_attrs.each do |k, v|
|
103
|
+
@xforward_attrs[k.upcase] = v
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Query whether to try to use XFORWARD or not.
|
109
|
+
def xforward ; @xforward ; end
|
110
|
+
# Set whether to try to use XFORWARD or not. This should be done before
|
111
|
+
# calling #start. Note that if #start is called in XFORWARD mode but the
|
112
|
+
# server doesn't support XFORWARD then it won't by tried anyway.
|
113
|
+
def xforward=(bool)
|
114
|
+
if @started
|
115
|
+
logging('ignoring request to enable/disable use of XFORWARD: SMTP session already started')
|
116
|
+
return
|
117
|
+
end
|
118
|
+
@xforward = bool
|
119
|
+
end
|
120
|
+
|
121
|
+
# The following attribute accessors allow you to set or query the various
|
122
|
+
# XFORWARD attributes that will be sent when the SMTP session is started,
|
123
|
+
# so long as the attribute (and XFORWARD in general) is supported by the
|
124
|
+
# server. Note that setting an attribute to a non-nil value will
|
125
|
+
# automatically set #xforward to true (requesting the use of XFORWARD).
|
126
|
+
def xforward_name ; @xforward_attrs['NAME'] ; end
|
127
|
+
def xforward_name=(name)
|
128
|
+
@xforward = true
|
129
|
+
@xforward_attrs['NAME'] = name
|
130
|
+
end
|
131
|
+
def xforward_addr ; @xforward_attrs['ADDR'] ; end
|
132
|
+
def xforward_addr=(addr)
|
133
|
+
@xforward = true
|
134
|
+
@xforward_attrs['ADDR'] = addr
|
135
|
+
end
|
136
|
+
def xforward_port ; @xforward_attrs['PORT'] ; end
|
137
|
+
def xforward_port=(port)
|
138
|
+
@xforward = true
|
139
|
+
@xforward_attrs['PORT'] = port
|
140
|
+
end
|
141
|
+
def xforward_proto ; @xforward_attrs['PROTO'] ; end
|
142
|
+
def xforward_proto=(proto)
|
143
|
+
@xforward = true
|
144
|
+
@xforward_attrs['PROTO'] = proto
|
145
|
+
end
|
146
|
+
def xforward_helo ; @xforward_attrs['HELO'] ; end
|
147
|
+
def xforward_helo=(helo)
|
148
|
+
@xforward = true
|
149
|
+
@xforward_attrs['HELO'] = helo
|
150
|
+
end
|
151
|
+
def xforward_ident ; @xforward_attrs['IDENT'] ; end
|
152
|
+
def xforward_ident=(ident)
|
153
|
+
@xforward = true
|
154
|
+
@xforward_attrs['IDENT'] = ident
|
155
|
+
end
|
156
|
+
def xforward_source ; @xforward_attrs['SOURCE'] ; end
|
157
|
+
def xforward_source=(source)
|
158
|
+
@xforward = true
|
159
|
+
@xforward_attrs['SOURCE'] = source
|
160
|
+
end
|
161
|
+
|
162
|
+
# true if server advertises XFORWARD.
|
163
|
+
# You cannot get a valid value before opening an SMTP session.
|
164
|
+
def capable_xforward?
|
165
|
+
capapble?(XCMD)
|
166
|
+
end
|
167
|
+
|
168
|
+
# true if server advertises XFORWARD attribute NAME.
|
169
|
+
# You cannot get a valid value before opening an SMTP session.
|
170
|
+
def capable_xforward_name?
|
171
|
+
xforward_capable?('NAME')
|
172
|
+
end
|
173
|
+
|
174
|
+
# true if server advertises XFORWARD attribute ADDR.
|
175
|
+
# You cannot get a valid value before opening an SMTP session.
|
176
|
+
def capable_xforward_addr?
|
177
|
+
xforward_capable?('ADDR')
|
178
|
+
end
|
179
|
+
|
180
|
+
# true if server advertises XFORWARD attribute PORT.
|
181
|
+
# You cannot get a valid value before opening an SMTP session.
|
182
|
+
def capable_xforward_port?
|
183
|
+
xforward_capable?('PORT')
|
184
|
+
end
|
185
|
+
|
186
|
+
# true if server advertises XFORWARD attribute PROTO.
|
187
|
+
# You cannot get a valid value before opening an SMTP session.
|
188
|
+
def capable_xforward_proto?
|
189
|
+
xforward_capable?('PROTO')
|
190
|
+
end
|
191
|
+
|
192
|
+
# true if server advertises XFORWARD attribute HELO.
|
193
|
+
# You cannot get a valid value before opening an SMTP session.
|
194
|
+
def capable_xforward_helo?
|
195
|
+
xforward_capable?('HELO')
|
196
|
+
end
|
197
|
+
|
198
|
+
# true if server advertises XFORWARD attribute IDENT.
|
199
|
+
# You cannot get a valid value before opening an SMTP session.
|
200
|
+
def capable_xforward_ident?
|
201
|
+
xforward_capable?('IDENT')
|
202
|
+
end
|
203
|
+
|
204
|
+
# true if server advertises XFORWARD attribute SOURCE.
|
205
|
+
# You cannot get a valid value before opening an SMTP session.
|
206
|
+
def capable_xforward_source?
|
207
|
+
xforward_capable?('SOURCE')
|
208
|
+
end
|
209
|
+
|
210
|
+
# Returns supported XFORWARD attributes on the SMTP server.
|
211
|
+
# You cannot get valid values before opening SMTP session.
|
212
|
+
def capable_xforward_attrs
|
213
|
+
return [] unless @capabilities
|
214
|
+
return [] unless @capabilities[XCMD]
|
215
|
+
@capabilities[XCMD]
|
216
|
+
end
|
217
|
+
|
218
|
+
private
|
219
|
+
|
220
|
+
def xforward_capapble?(attr)
|
221
|
+
return nil unless @capabilities
|
222
|
+
return false unless @capabilities[XCMD]
|
223
|
+
@capabilities[XCMD].include?(attr)
|
224
|
+
end
|
225
|
+
|
226
|
+
def do_start_with_xforward(helo_domain, user, secret, authtype)
|
227
|
+
do_start_without_xforward(helo_domain, user, secret, authtype)
|
228
|
+
if @started and @xforward
|
229
|
+
if capable?(XCMD)
|
230
|
+
do_xforward
|
231
|
+
else
|
232
|
+
logging("ignoring request to do XFORWARD: server isn't capable")
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def do_finish_with_xforward
|
238
|
+
do_finish_without_xforward
|
239
|
+
@xforward = false
|
240
|
+
@xforward_attrs = {}
|
241
|
+
end
|
242
|
+
|
243
|
+
# Issues the XFORWARD smtp command, sending each of the supplied
|
244
|
+
# XFORWARD attributes (as long as they are supported). Unsupported
|
245
|
+
# XFORWARD attributes are ignored.
|
246
|
+
def do_xforward
|
247
|
+
cmd = XCMD.dup
|
248
|
+
cap = capable_xforward_attrs
|
249
|
+
@xforward_attrs.each do |attr, value|
|
250
|
+
if cap.include?(attr)
|
251
|
+
tmp = " #{attr}=#{Utils.xtext(value)}"
|
252
|
+
if cmd.length + tmp.length > MAXLEN
|
253
|
+
getok(cmd)
|
254
|
+
cmd = XCMD.dup
|
255
|
+
end
|
256
|
+
cmd << tmp
|
257
|
+
else
|
258
|
+
logging("ignoring XFORWARD attribute '#{attr}': unsupported by server")
|
259
|
+
end
|
260
|
+
end
|
261
|
+
getok(cmd) if cmd != XCMD
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: postfix-xforward
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Kendall Gifford
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-08-20 00:00:00 -06:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: |-
|
23
|
+
This extends ruby's Net::SMTP library to support the Postfix MTA's
|
24
|
+
XFORWARD SMTP extension.
|
25
|
+
email:
|
26
|
+
- zettabyte@gmail.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- lib/postfix-xforward/smtp.rb
|
35
|
+
- lib/postfix-xforward/utils.rb
|
36
|
+
- lib/postfix-xforward/version.rb
|
37
|
+
- lib/postfix-xforward.rb
|
38
|
+
- LICENSE
|
39
|
+
- README.rdoc
|
40
|
+
- CHANGELOG.rdoc
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://github.com/zettabyte/postfix-xforward
|
43
|
+
licenses: []
|
44
|
+
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
hash: 3
|
56
|
+
segments:
|
57
|
+
- 0
|
58
|
+
version: "0"
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
hash: 23
|
65
|
+
segments:
|
66
|
+
- 1
|
67
|
+
- 3
|
68
|
+
- 6
|
69
|
+
version: 1.3.6
|
70
|
+
requirements: []
|
71
|
+
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 1.3.7
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: Net::SMTP extension to support Postfix MTA's XFORWARD SMTP extension.
|
77
|
+
test_files: []
|
78
|
+
|