postfix-xforward 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|