oversip 0.9.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/AUTHORS.txt +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +16 -0
- data/Rakefile +55 -0
- data/bin/oversip +182 -0
- data/ext/common/c_util.h +74 -0
- data/ext/common/ruby_c_util.h +88 -0
- data/ext/sip_parser/common_headers.h +209 -0
- data/ext/sip_parser/ext_help.h +18 -0
- data/ext/sip_parser/extconf.rb +3 -0
- data/ext/sip_parser/sip_parser.c +29649 -0
- data/ext/sip_parser/sip_parser.h +227 -0
- data/ext/sip_parser/sip_parser_ruby.c +1292 -0
- data/ext/stud/extconf.rb +27 -0
- data/ext/stud/stud.tar.gz +0 -0
- data/ext/stun/ext_help.h +16 -0
- data/ext/stun/extconf.rb +3 -0
- data/ext/stun/stun_ruby.c +391 -0
- data/ext/utils/ext_help.h +14 -0
- data/ext/utils/extconf.rb +3 -0
- data/ext/utils/haproxy_protocol.c +6163 -0
- data/ext/utils/haproxy_protocol.h +27 -0
- data/ext/utils/ip_utils.c +5952 -0
- data/ext/utils/ip_utils.h +61 -0
- data/ext/utils/outbound_utils.c +3227 -0
- data/ext/utils/outbound_utils.h +27 -0
- data/ext/utils/utils_ruby.c +384 -0
- data/ext/utils/utils_ruby.h +75 -0
- data/ext/websocket_framing_utils/ext_help.h +18 -0
- data/ext/websocket_framing_utils/extconf.rb +3 -0
- data/ext/websocket_framing_utils/ws_framing_utils.h +46 -0
- data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
- data/ext/websocket_http_parser/ext_help.h +18 -0
- data/ext/websocket_http_parser/extconf.rb +3 -0
- data/ext/websocket_http_parser/ws_http_parser.c +2598 -0
- data/ext/websocket_http_parser/ws_http_parser.h +86 -0
- data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
- data/lib/oversip/config.rb +541 -0
- data/lib/oversip/config_validators.rb +126 -0
- data/lib/oversip/errors.rb +7 -0
- data/lib/oversip/fiber_pool.rb +56 -0
- data/lib/oversip/launcher.rb +507 -0
- data/lib/oversip/logger.rb +170 -0
- data/lib/oversip/master_process.rb +67 -0
- data/lib/oversip/posix_mq.rb +121 -0
- data/lib/oversip/proxies_config.rb +169 -0
- data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
- data/lib/oversip/sip/client_transaction.rb +587 -0
- data/lib/oversip/sip/constants.rb +87 -0
- data/lib/oversip/sip/grammar/name_addr.rb +27 -0
- data/lib/oversip/sip/grammar/uri.rb +116 -0
- data/lib/oversip/sip/launcher.rb +180 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/reactor.rb +39 -0
- data/lib/oversip/sip/listeners/tcp_client.rb +73 -0
- data/lib/oversip/sip/listeners/tcp_reactor.rb +185 -0
- data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
- data/lib/oversip/sip/listeners/tls_client.rb +117 -0
- data/lib/oversip/sip/listeners/tls_server.rb +70 -0
- data/lib/oversip/sip/listeners/tls_tunnel_reactor.rb +113 -0
- data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
- data/lib/oversip/sip/listeners/udp_reactor.rb +213 -0
- data/lib/oversip/sip/listeners.rb +28 -0
- data/lib/oversip/sip/logic.rb +14 -0
- data/lib/oversip/sip/message.rb +168 -0
- data/lib/oversip/sip/message_processor.rb +202 -0
- data/lib/oversip/sip/modules/core.rb +200 -0
- data/lib/oversip/sip/modules/registrar_without_path.rb +75 -0
- data/lib/oversip/sip/modules/user_assertion.rb +123 -0
- data/lib/oversip/sip/proxy.rb +460 -0
- data/lib/oversip/sip/request.rb +128 -0
- data/lib/oversip/sip/response.rb +30 -0
- data/lib/oversip/sip/rfc3263.rb +646 -0
- data/lib/oversip/sip/server_transaction.rb +295 -0
- data/lib/oversip/sip/sip.rb +74 -0
- data/lib/oversip/sip/tags.rb +39 -0
- data/lib/oversip/sip/timers.rb +55 -0
- data/lib/oversip/sip/transport_manager.rb +129 -0
- data/lib/oversip/syslogger_process.rb +119 -0
- data/lib/oversip/tls.rb +179 -0
- data/lib/oversip/utils.rb +25 -0
- data/lib/oversip/version.rb +23 -0
- data/lib/oversip/websocket/constants.rb +56 -0
- data/lib/oversip/websocket/default_policy.rb +19 -0
- data/lib/oversip/websocket/http_request.rb +63 -0
- data/lib/oversip/websocket/launcher.rb +207 -0
- data/lib/oversip/websocket/listeners/ipv4_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/tcp_server.rb +265 -0
- data/lib/oversip/websocket/listeners/tls_server.rb +69 -0
- data/lib/oversip/websocket/listeners/tls_tunnel_server.rb +100 -0
- data/lib/oversip/websocket/listeners.rb +12 -0
- data/lib/oversip/websocket/ws_app.rb +75 -0
- data/lib/oversip/websocket/ws_apps/ipv4_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv4_wss_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_wss_sip_app.rb +22 -0
- data/lib/oversip/websocket/ws_apps/ws_autobahn_app.rb +23 -0
- data/lib/oversip/websocket/ws_apps/ws_sip_app.rb +156 -0
- data/lib/oversip/websocket/ws_apps.rb +9 -0
- data/lib/oversip/websocket/ws_framing.rb +597 -0
- data/lib/oversip.rb +59 -0
- data/test/oversip_test_helper.rb +20 -0
- data/test/test_http_parser.rb +73 -0
- data/test/test_sip_parser.rb +139 -0
- metadata +256 -0
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
module OverSIP
|
|
2
|
+
|
|
3
|
+
module Config
|
|
4
|
+
|
|
5
|
+
# Pre-declaration of Validators module (defined in other file).
|
|
6
|
+
module Config::Validators ; end
|
|
7
|
+
|
|
8
|
+
extend ::OverSIP::Logger
|
|
9
|
+
extend ::OverSIP::Config::Validators
|
|
10
|
+
|
|
11
|
+
DEFAULT_CONFIG_DIR = "/etc/oversip/"
|
|
12
|
+
DEFAULT_TLS_DIR = "tls/"
|
|
13
|
+
DEFAULT_TLS_CA_DIR = "tls/ca/"
|
|
14
|
+
CONF_FILE = "oversip.conf"
|
|
15
|
+
PROXIES_FILE = "proxies.conf"
|
|
16
|
+
LOGIC_FILE = "logic.rb"
|
|
17
|
+
WEBSOCKET_POLICY_FILE = "websocket_policy.rb"
|
|
18
|
+
|
|
19
|
+
def self.log_id
|
|
20
|
+
@log_id ||= "Config"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.conf_file
|
|
24
|
+
@conf_file ||= ::File.join(@conf_dir, CONF_FILE)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.proxies_file
|
|
28
|
+
@proxies_file ||= ::File.join(@conf_dir, PROXIES_FILE)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.logic_file
|
|
32
|
+
@logic_file ||= ::File.join(@conf_dir, LOGIC_FILE)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.websocket_policy_file
|
|
36
|
+
@websocket_policy_file ||= ::File.join(@conf_dir, WEBSOCKET_POLICY_FILE)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
@configuration = {
|
|
40
|
+
:core => {
|
|
41
|
+
:nameservers => nil,
|
|
42
|
+
:syslog_facility => "user",
|
|
43
|
+
:syslog_level => "info"
|
|
44
|
+
},
|
|
45
|
+
:sip => {
|
|
46
|
+
:sip_udp => true,
|
|
47
|
+
:sip_tcp => true,
|
|
48
|
+
:sip_tls => false,
|
|
49
|
+
:enable_ipv4 => true,
|
|
50
|
+
:listen_ipv4 => nil,
|
|
51
|
+
:enable_ipv6 => true,
|
|
52
|
+
:listen_ipv6 => nil,
|
|
53
|
+
:listen_port => 5060,
|
|
54
|
+
:listen_port_tls => 5061,
|
|
55
|
+
:use_tls_tunnel => false,
|
|
56
|
+
:listen_port_tls_tunnel => 5062,
|
|
57
|
+
:local_domains => nil,
|
|
58
|
+
:tcp_keepalive_interval => nil,
|
|
59
|
+
:record_route_hostname_tls_ipv4 => nil,
|
|
60
|
+
:record_route_hostname_tls_ipv6 => nil
|
|
61
|
+
},
|
|
62
|
+
:websocket => {
|
|
63
|
+
:sip_ws => false,
|
|
64
|
+
:sip_wss => false,
|
|
65
|
+
:enable_ipv4 => true,
|
|
66
|
+
:listen_ipv4 => nil,
|
|
67
|
+
:enable_ipv6 => true,
|
|
68
|
+
:listen_ipv6 => nil,
|
|
69
|
+
:listen_port => 10080,
|
|
70
|
+
:listen_port_tls => 10443,
|
|
71
|
+
:use_tls_tunnel => false,
|
|
72
|
+
:listen_port_tls_tunnel => 10444,
|
|
73
|
+
:max_ws_message_size => 65536,
|
|
74
|
+
:max_ws_frame_size => 65536,
|
|
75
|
+
:ws_keepalive_interval => nil
|
|
76
|
+
},
|
|
77
|
+
:tls => {
|
|
78
|
+
:public_cert => nil,
|
|
79
|
+
:private_cert => nil,
|
|
80
|
+
:ca_dir => nil
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
CONFIG_VALIDATIONS = {
|
|
85
|
+
:core => {
|
|
86
|
+
:nameservers => [ :ipv4, :multi_value ],
|
|
87
|
+
:syslog_facility => [
|
|
88
|
+
[ :choices,
|
|
89
|
+
%w{ kern user daemon local0 local1 local2 local3 local4 local5 local6 local7 } ]
|
|
90
|
+
],
|
|
91
|
+
:syslog_level => [
|
|
92
|
+
[ :choices,
|
|
93
|
+
%w{ debug info notice warn error crit } ]
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
:sip => {
|
|
97
|
+
:sip_udp => :boolean,
|
|
98
|
+
:sip_tcp => :boolean,
|
|
99
|
+
:sip_tls => :boolean,
|
|
100
|
+
:enable_ipv4 => :boolean,
|
|
101
|
+
:listen_ipv4 => :ipv4,
|
|
102
|
+
:enable_ipv6 => :boolean,
|
|
103
|
+
:listen_ipv6 => :ipv6,
|
|
104
|
+
:listen_port => :port,
|
|
105
|
+
:listen_port_tls => :port,
|
|
106
|
+
:use_tls_tunnel => :boolean,
|
|
107
|
+
# TODO, si use_tls_tunnel es yes entonces listen_port_tls_tunnel debe estar puesto.
|
|
108
|
+
:listen_port_tls_tunnel => :port,
|
|
109
|
+
:local_domains => [ :domain, :multi_value ],
|
|
110
|
+
:tcp_keepalive_interval => [ :fixnum, [ :greater_equal_than, 180 ] ],
|
|
111
|
+
:record_route_hostname_tls_ipv4 => :domain,
|
|
112
|
+
:record_route_hostname_tls_ipv6 => :domain,
|
|
113
|
+
},
|
|
114
|
+
:websocket => {
|
|
115
|
+
:sip_ws => :boolean,
|
|
116
|
+
:sip_wss => :boolean,
|
|
117
|
+
:enable_ipv4 => :boolean,
|
|
118
|
+
:listen_ipv4 => :ipv4,
|
|
119
|
+
:enable_ipv6 => :boolean,
|
|
120
|
+
:listen_ipv6 => :ipv6,
|
|
121
|
+
:listen_port => :port,
|
|
122
|
+
:listen_port_tls => :port,
|
|
123
|
+
:use_tls_tunnel => :boolean,
|
|
124
|
+
:listen_port_tls_tunnel => :port,
|
|
125
|
+
:max_ws_message_size => [ :fixnum, [ :minor_than, 1048576 ] ],
|
|
126
|
+
:max_ws_frame_size => [ :fixnum, [ :minor_than, 1048576 ] ],
|
|
127
|
+
:ws_keepalive_interval => [ :fixnum, [ :greater_equal_than, 180 ] ]
|
|
128
|
+
},
|
|
129
|
+
:tls => {
|
|
130
|
+
:public_cert => [ :readable_file, :tls_pem_chain ],
|
|
131
|
+
:private_cert => [ :readable_file, :tls_pem_private ],
|
|
132
|
+
:ca_dir => :readable_dir
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def self.load conf_dir = nil
|
|
138
|
+
@conf_dir ||= DEFAULT_CONFIG_DIR
|
|
139
|
+
|
|
140
|
+
begin
|
|
141
|
+
conf_yaml = ::YAML.load_file conf_file
|
|
142
|
+
rescue => e
|
|
143
|
+
fatal "error loading configuration file '#{conf_file}': #{e.message} (#{e.class})"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
begin
|
|
147
|
+
proxies_yaml = ::YAML.load_file proxies_file
|
|
148
|
+
rescue => e
|
|
149
|
+
fatal "error loading proxies configuration file '#{proxies_file}': #{e.message} (#{e.class})"
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
begin
|
|
153
|
+
Kernel.load logic_file
|
|
154
|
+
rescue LoadError => e
|
|
155
|
+
fatal "error loading logic file '#{logic_file}': #{e.message} (#{e.class})"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
begin
|
|
159
|
+
Kernel.load websocket_policy_file
|
|
160
|
+
rescue LoadError => e
|
|
161
|
+
log_system_warn "cannot load WebSocket Policy file '#{websocket_policy_file}': #{e.message} (#{e.class}), using default policy (allow all)"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
begin
|
|
165
|
+
pre_check(conf_yaml)
|
|
166
|
+
|
|
167
|
+
CONFIG_VALIDATIONS.each_key do |section|
|
|
168
|
+
CONFIG_VALIDATIONS[section].each do |parameter, validations|
|
|
169
|
+
values = conf_yaml[section.to_s][parameter.to_s] rescue nil
|
|
170
|
+
validations = [ validations ] unless validations.is_a?(Array)
|
|
171
|
+
|
|
172
|
+
if values == nil
|
|
173
|
+
if validations.include? :required
|
|
174
|
+
fatal "#{section}[#{parameter}] requires a value"
|
|
175
|
+
end
|
|
176
|
+
next
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
if values.is_a? Array
|
|
180
|
+
unless validations.include? :multi_value
|
|
181
|
+
fatal "#{section}[#{parameter}] does not allow multiple values"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
if validations.include? :non_empty and values.empty?
|
|
185
|
+
fatal "#{section}[#{parameter}] does not allow empty values"
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
values = ( values.is_a?(Array) ? values : [ values ] )
|
|
190
|
+
|
|
191
|
+
values.each do |value|
|
|
192
|
+
validations.each do |validation|
|
|
193
|
+
|
|
194
|
+
if validation.is_a? Symbol
|
|
195
|
+
args = []
|
|
196
|
+
elsif validation.is_a? Array
|
|
197
|
+
args = validation[1..-1]
|
|
198
|
+
validation = validation[0]
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
next if [:required, :multi_value, :non_empty].include? validation
|
|
202
|
+
|
|
203
|
+
unless send validation, value, *args
|
|
204
|
+
fatal "#{section}[#{parameter}] has invalid value '#{humanize_value value}' (does not satisfy '#{validation}' validation requirement)"
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
@configuration[section][parameter] = ( validations.include?(:multi_value) ? values : values[0] )
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
end # CONFIG_VALIDATIONS[section].each
|
|
212
|
+
end # CONFIG_VALIDATIONS.each_key
|
|
213
|
+
|
|
214
|
+
post_process
|
|
215
|
+
post_check
|
|
216
|
+
|
|
217
|
+
rescue OverSIP::ConfigurationError => e
|
|
218
|
+
fatal "configuration error: #{e.message}"
|
|
219
|
+
rescue => e
|
|
220
|
+
fatal e
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
::OverSIP.configuration = @configuration
|
|
224
|
+
|
|
225
|
+
::OverSIP::ProxiesConfig.load proxies_yaml
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def self.pre_check conf_yaml
|
|
230
|
+
# If TLS files/directories are given as relative path, convert them into absolute paths.
|
|
231
|
+
|
|
232
|
+
tls_public_cert = conf_yaml["tls"]["public_cert"] rescue nil
|
|
233
|
+
tls_private_cert = conf_yaml["tls"]["private_cert"] rescue nil
|
|
234
|
+
tls_ca_dir = conf_yaml["tls"]["ca_dir"] rescue nil
|
|
235
|
+
|
|
236
|
+
if tls_public_cert.is_a?(String) and tls_public_cert[0] != "/"
|
|
237
|
+
conf_yaml["tls"]["public_cert"] = ::File.join(@conf_dir, DEFAULT_TLS_DIR, tls_public_cert)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
if tls_private_cert.is_a?(String) and tls_private_cert[0] != "/"
|
|
241
|
+
conf_yaml["tls"]["private_cert"] = ::File.join(@conf_dir, DEFAULT_TLS_DIR, tls_private_cert)
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
if tls_ca_dir.is_a?(String) and tls_ca_dir[0] != "/"
|
|
245
|
+
conf_yaml["tls"]["ca_dir"] = ::File.join(@conf_dir, DEFAULT_TLS_DIR, tls_ca_dir)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def self.post_process
|
|
250
|
+
if @configuration[:tls][:public_cert] and @configuration[:tls][:private_cert]
|
|
251
|
+
@use_tls = true
|
|
252
|
+
# Generate a full PEM file containing both the public and private certificate (for Stud).
|
|
253
|
+
full_cert = Tempfile.new("oversip_full_cert_")
|
|
254
|
+
full_cert.puts File.read(@configuration[:tls][:public_cert])
|
|
255
|
+
full_cert.puts File.read(@configuration[:tls][:private_cert])
|
|
256
|
+
@configuration[:tls][:full_cert] = full_cert.path
|
|
257
|
+
full_cert.close
|
|
258
|
+
else
|
|
259
|
+
@configuration[:sip][:sip_tls] = false
|
|
260
|
+
@configuration[:websocket][:sip_wss] = false
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
if @configuration[:sip][:sip_udp] or @configuration[:sip][:sip_tcp]
|
|
264
|
+
@use_sip_udp_or_tcp = true
|
|
265
|
+
else
|
|
266
|
+
@configuration[:sip][:listen_port] = nil
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
if @configuration[:sip][:sip_tls] and @use_tls
|
|
270
|
+
@use_sip_tls = true
|
|
271
|
+
else
|
|
272
|
+
@configuration[:sip][:listen_port_tls] = nil
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
unless @use_sip_udp_or_tcp or @use_sip_tls
|
|
276
|
+
@configuration[:sip][:listen_ipv4] = nil
|
|
277
|
+
@configuration[:sip][:listen_ipv6] = nil
|
|
278
|
+
@configuration[:sip][:enable_ipv4] = nil
|
|
279
|
+
@configuration[:sip][:enable_ipv6] = nil
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
unless @configuration[:sip][:enable_ipv4]
|
|
283
|
+
@configuration[:sip][:listen_ipv4] = nil
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
unless @configuration[:sip][:enable_ipv6]
|
|
287
|
+
@configuration[:sip][:listen_ipv6] = nil
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
if @configuration[:websocket][:sip_ws]
|
|
291
|
+
@use_sip_ws = true
|
|
292
|
+
else
|
|
293
|
+
@configuration[:websocket][:listen_port] = nil
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
if @configuration[:websocket][:sip_wss] and @use_tls
|
|
297
|
+
@use_sip_wss = true
|
|
298
|
+
else
|
|
299
|
+
@configuration[:websocket][:listen_port_tls] = nil
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
unless @use_sip_ws or @use_sip_wss
|
|
303
|
+
@configuration[:websocket][:listen_ipv4] = nil
|
|
304
|
+
@configuration[:websocket][:listen_ipv6] = nil
|
|
305
|
+
@configuration[:websocket][:enable_ipv4] = nil
|
|
306
|
+
@configuration[:websocket][:enable_ipv6] = nil
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
if ( @use_sip_udp_or_tcp or @use_sip_tls ) and @configuration[:sip][:listen_ipv4] == nil and @configuration[:sip][:enable_ipv4]
|
|
310
|
+
unless (@configuration[:sip][:listen_ipv4] = discover_local_ip(:ipv4))
|
|
311
|
+
log_system_warn "dissabling IPv4 for SIP"
|
|
312
|
+
@configuration[:sip][:listen_ipv4] = nil
|
|
313
|
+
@configuration[:sip][:enable_ipv4] = false
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
if ( @use_sip_udp_or_tcp or @use_sip_tls ) and @configuration[:sip][:listen_ipv6] == nil and @configuration[:sip][:enable_ipv6]
|
|
318
|
+
unless (@configuration[:sip][:listen_ipv6] = discover_local_ip(:ipv6))
|
|
319
|
+
log_system_warn "dissabling IPv6 for SIP"
|
|
320
|
+
@configuration[:sip][:listen_ipv6] = nil
|
|
321
|
+
@configuration[:sip][:enable_ipv6] = false
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
if ( @use_sip_ws or @use_sip_wss ) and @configuration[:websocket][:listen_ipv4] == nil and @configuration[:websocket][:enable_ipv4]
|
|
326
|
+
unless (@configuration[:websocket][:listen_ipv4] = discover_local_ip(:ipv4))
|
|
327
|
+
log_system_warn "dissabling IPv4 for WebSocket"
|
|
328
|
+
@configuration[:websocket][:listen_ipv4] = nil
|
|
329
|
+
@configuration[:websocket][:enable_ipv4] = false
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
if ( @use_sip_ws or @use_sip_wss ) and @configuration[:websocket][:listen_ipv6] == nil and @configuration[:websocket][:enable_ipv6]
|
|
334
|
+
unless (@configuration[:websocket][:listen_ipv6] = discover_local_ip(:ipv6))
|
|
335
|
+
log_system_warn "dissabling IPv6 for WebSocket"
|
|
336
|
+
@configuration[:websocket][:listen_ipv6] = nil
|
|
337
|
+
@configuration[:websocket][:enable_ipv6] = false
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
if @configuration[:sip][:local_domains]
|
|
342
|
+
if @configuration[:sip][:local_domains].is_a? String
|
|
343
|
+
@configuration[:sip][:local_domains] = [ @configuration[:sip][:local_domains].downcase ]
|
|
344
|
+
end
|
|
345
|
+
@configuration[:sip][:local_domains].each {|local_domain| local_domain.downcase!}
|
|
346
|
+
end
|
|
347
|
+
end # def self.post_process
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def self.post_check
|
|
351
|
+
binds = { :udp => [], :tcp => [] }
|
|
352
|
+
|
|
353
|
+
if @configuration[:sip][:enable_ipv4]
|
|
354
|
+
ipv4 = @configuration[:sip][:listen_ipv4]
|
|
355
|
+
|
|
356
|
+
if @configuration[:sip][:sip_udp]
|
|
357
|
+
binds[:udp] << [ ipv4, @configuration[:sip][:listen_port] ]
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
if @configuration[:sip][:sip_tcp]
|
|
361
|
+
binds[:tcp] << [ ipv4, @configuration[:sip][:listen_port] ]
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
if @configuration[:sip][:sip_tls]
|
|
365
|
+
unless @configuration[:sip][:use_tls_tunnel]
|
|
366
|
+
binds[:tcp] << [ ipv4, @configuration[:sip][:listen_port_tls] ]
|
|
367
|
+
else
|
|
368
|
+
binds[:tcp] << [ "127.0.0.1", @configuration[:sip][:listen_port_tls_tunnel] ]
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
if @configuration[:sip][:enable_ipv6]
|
|
374
|
+
ipv6 = @configuration[:sip][:listen_ipv6]
|
|
375
|
+
|
|
376
|
+
if @configuration[:sip][:sip_udp]
|
|
377
|
+
binds[:udp] << [ ipv6, @configuration[:sip][:listen_port] ]
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
if @configuration[:sip][:sip_tcp]
|
|
381
|
+
binds[:tcp] << [ ipv6, @configuration[:sip][:listen_port] ]
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
if @configuration[:sip][:sip_tls]
|
|
385
|
+
unless @configuration[:sip][:use_tls_tunnel]
|
|
386
|
+
binds[:tcp] << [ ipv6, @configuration[:sip][:listen_port_tls] ]
|
|
387
|
+
else
|
|
388
|
+
binds[:tcp] << [ "::1", @configuration[:sip][:listen_port_tls_tunnel] ]
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
if @configuration[:websocket][:enable_ipv4]
|
|
394
|
+
ipv4 = @configuration[:websocket][:listen_ipv4]
|
|
395
|
+
|
|
396
|
+
if @configuration[:websocket][:sip_ws]
|
|
397
|
+
binds[:tcp] << [ ipv4, @configuration[:websocket][:listen_port] ]
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
if @configuration[:websocket][:sip_wss]
|
|
401
|
+
unless @configuration[:sip][:use_tls_tunnel]
|
|
402
|
+
binds[:tcp] << [ ipv4, @configuration[:websocket][:listen_port_tls] ]
|
|
403
|
+
else
|
|
404
|
+
binds[:tcp] << [ "127.0.0.1", @configuration[:websocket][:listen_port_tls_tunnel] ]
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
if @configuration[:websocket][:enable_ipv6]
|
|
410
|
+
ipv6 = @configuration[:websocket][:listen_ipv6]
|
|
411
|
+
|
|
412
|
+
if @configuration[:websocket][:sip_ws]
|
|
413
|
+
binds[:tcp] << [ ipv6, @configuration[:websocket][:listen_port] ]
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
if @configuration[:websocket][:sip_wss]
|
|
417
|
+
unless @configuration[:sip][:use_tls_tunnel]
|
|
418
|
+
binds[:tcp] << [ ipv6, @configuration[:websocket][:listen_port_tls] ]
|
|
419
|
+
else
|
|
420
|
+
binds[:tcp] << [ "::1", @configuration[:websocket][:listen_port_tls_tunnel] ]
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
[:udp, :tcp].each do |transport|
|
|
426
|
+
transport_str = transport.to_s.upcase
|
|
427
|
+
binds[transport].each do |ip, port|
|
|
428
|
+
begin
|
|
429
|
+
unless (ip_type = ::OverSIP::Utils.ip_type(ip))
|
|
430
|
+
raise ::OverSIP::ConfigurationError, "given IP '#{ip}' is not IPv4 nor IPv6"
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
case transport
|
|
434
|
+
when :udp
|
|
435
|
+
case ip_type
|
|
436
|
+
when :ipv4
|
|
437
|
+
socket = ::UDPSocket.new ::Socket::AF_INET
|
|
438
|
+
when :ipv6
|
|
439
|
+
socket = ::UDPSocket.new ::Socket::AF_INET6
|
|
440
|
+
end
|
|
441
|
+
socket.bind ip, port
|
|
442
|
+
when :tcp
|
|
443
|
+
socket = ::TCPServer.open ip, port
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
socket.close
|
|
447
|
+
|
|
448
|
+
rescue ::Errno::EADDRNOTAVAIL
|
|
449
|
+
raise ::OverSIP::ConfigurationError, "cannot bind in #{transport_str} IP '#{ip}', address not available"
|
|
450
|
+
rescue ::Errno::EADDRINUSE
|
|
451
|
+
raise ::OverSIP::ConfigurationError, "#{transport_str} IP '#{ip}' and port #{port} already in use"
|
|
452
|
+
rescue ::Errno::EACCES
|
|
453
|
+
raise ::OverSIP::ConfigurationError, "no permission to bind in #{transport_str} IP '#{ip}' and port #{port}"
|
|
454
|
+
rescue => e
|
|
455
|
+
raise e.class, "error binding in #{transport_str} IP '#{ip}' and port #{port} (#{e.class}: #{e.message})"
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
end # def self.post_check
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
def self.print colorize=true
|
|
463
|
+
color = Term::ANSIColor if colorize
|
|
464
|
+
|
|
465
|
+
puts
|
|
466
|
+
@configuration.each_key do |section|
|
|
467
|
+
if colorize
|
|
468
|
+
puts " #{color.bold(section.to_s)}:"
|
|
469
|
+
else
|
|
470
|
+
puts " #{section.to_s}:"
|
|
471
|
+
end
|
|
472
|
+
@configuration[section].each do |parameter, value|
|
|
473
|
+
humanized_value = humanize_value value
|
|
474
|
+
color_value = case value
|
|
475
|
+
when TrueClass
|
|
476
|
+
colorize ? color.bold(color.green(humanized_value)) : humanized_value
|
|
477
|
+
when FalseClass
|
|
478
|
+
colorize ? color.bold(color.red(humanized_value)) : humanized_value
|
|
479
|
+
when NilClass
|
|
480
|
+
humanized_value
|
|
481
|
+
when String, Symbol
|
|
482
|
+
colorize ? color.yellow(humanized_value) : humanized_value
|
|
483
|
+
when Array
|
|
484
|
+
colorize ? color.yellow(humanized_value) : humanized_value
|
|
485
|
+
when Fixnum, Float
|
|
486
|
+
colorize ? color.bold(color.blue(humanized_value)) : humanized_value
|
|
487
|
+
else
|
|
488
|
+
humanized_value
|
|
489
|
+
end
|
|
490
|
+
printf(" %-32s: %s\n", parameter, color_value)
|
|
491
|
+
end
|
|
492
|
+
puts
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
def self.humanize_value value
|
|
497
|
+
case value
|
|
498
|
+
when TrueClass ; "yes"
|
|
499
|
+
when FalseClass ; "no"
|
|
500
|
+
when NilClass ; "null"
|
|
501
|
+
when String ; value
|
|
502
|
+
when Symbol ; value.to_s
|
|
503
|
+
when Array ; value.join(", ")
|
|
504
|
+
when Fixnum, Float ; value.to_s
|
|
505
|
+
else ; value.to_s
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
def self.discover_local_ip(type)
|
|
510
|
+
begin
|
|
511
|
+
if type == :ipv4
|
|
512
|
+
socket = ::UDPSocket.new ::Socket::AF_INET
|
|
513
|
+
socket.connect("1.2.3.4", 1)
|
|
514
|
+
elsif type == :ipv6
|
|
515
|
+
socket = ::UDPSocket.new ::Socket::AF_INET6
|
|
516
|
+
socket.connect("2001::1", 1)
|
|
517
|
+
end
|
|
518
|
+
ip = socket.local_address.ip_address
|
|
519
|
+
socket.close
|
|
520
|
+
return ip
|
|
521
|
+
rescue => e
|
|
522
|
+
log_system_warn "cannot autodiscover local #{type == :ipv4 ? "IPv4" : "IPv6"}: #{e.message} (#{e.class})"
|
|
523
|
+
return false
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
def self.reload_logic
|
|
528
|
+
begin
|
|
529
|
+
Kernel.load logic_file
|
|
530
|
+
log_system_info "logic reloaded"
|
|
531
|
+
true
|
|
532
|
+
rescue Exception => e
|
|
533
|
+
log_system_crit "error reloading logic"
|
|
534
|
+
log_system_crit e
|
|
535
|
+
false
|
|
536
|
+
end
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
require "openssl"
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module OverSIP
|
|
5
|
+
|
|
6
|
+
module Config
|
|
7
|
+
|
|
8
|
+
module Validators
|
|
9
|
+
|
|
10
|
+
extend ::OverSIP::Logger
|
|
11
|
+
|
|
12
|
+
DOMAIN_REGEXP = /^(([0-9a-zA-Z\-_])+\.)*([0-9a-zA-Z\-_])+$/
|
|
13
|
+
TLS_PEM_CHAIN_REGEXP = /-{5}BEGIN CERTIFICATE-{5}\n.*?-{5}END CERTIFICATE-{5}\n/m
|
|
14
|
+
|
|
15
|
+
def boolean value
|
|
16
|
+
value == true or value == false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def string value
|
|
20
|
+
value.is_a? String
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def fixnum value
|
|
24
|
+
value.is_a? Fixnum
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def port value
|
|
28
|
+
fixnum(value) and value.between?(1,65536)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def ipv4 value
|
|
32
|
+
return false unless value.is_a? String
|
|
33
|
+
::OverSIP::Utils.ip_type(value) == :ipv4 and value != "0.0.0.0"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def ipv6 value
|
|
37
|
+
return false unless value.is_a? String
|
|
38
|
+
::OverSIP::Utils.ip_type(value) == :ipv6 and ::OverSIP::Utils.normalize_ipv6(value) != "::"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def ipv4_any value
|
|
42
|
+
return false unless value.is_a? String
|
|
43
|
+
::OverSIP::Utils.ip_type(value) == :ipv4
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def ipv6_any value
|
|
47
|
+
return false unless value.is_a? String
|
|
48
|
+
::OverSIP::Utils.ip_type(value) == :ipv6
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def domain value
|
|
52
|
+
value =~ DOMAIN_REGEXP
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def choices value, choices
|
|
56
|
+
choices.include? value
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def greater_than value, minimum
|
|
60
|
+
value > minimum rescue false
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def greater_equal_than value, minimum
|
|
64
|
+
value >= minimum rescue false
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def minor_than value, maximum
|
|
68
|
+
value < maximum rescue false
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def minor_equal_than value, maximum
|
|
72
|
+
value <= maximum rescue false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def readable_file file
|
|
76
|
+
::File.file?(file) and ::File.readable?(file)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def readable_dir dir
|
|
80
|
+
::File.directory?(dir) and ::File.readable?(dir)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def tls_pem_chain file
|
|
84
|
+
chain = ::File.read file
|
|
85
|
+
pems = chain.scan(TLS_PEM_CHAIN_REGEXP).flatten
|
|
86
|
+
pem_found = nil
|
|
87
|
+
|
|
88
|
+
begin
|
|
89
|
+
pems.each do |pem|
|
|
90
|
+
::OpenSSL::X509::Certificate.new pem
|
|
91
|
+
pem_found = true
|
|
92
|
+
end
|
|
93
|
+
rescue => e
|
|
94
|
+
log_system_error "#{e.class}: #{e.message}"
|
|
95
|
+
return false
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
if pem_found
|
|
99
|
+
return true
|
|
100
|
+
else
|
|
101
|
+
log_system_error "no valid X509 PEM found in the file"
|
|
102
|
+
return false
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def tls_pem_private file
|
|
107
|
+
pem = ::File.read file
|
|
108
|
+
key_classes = [::OpenSSL::PKey::RSA, ::OpenSSL::PKey::DSA]
|
|
109
|
+
|
|
110
|
+
begin
|
|
111
|
+
key_class = key_classes.shift
|
|
112
|
+
key_class.new pem
|
|
113
|
+
return true
|
|
114
|
+
rescue => e
|
|
115
|
+
retry if key_classes.any?
|
|
116
|
+
log_system_error e.message
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
return false
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
end # module Validators
|
|
123
|
+
|
|
124
|
+
end # module Config
|
|
125
|
+
|
|
126
|
+
end
|