oversip 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/AUTHORS.txt +11 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +16 -0
  4. data/Rakefile +55 -0
  5. data/bin/oversip +182 -0
  6. data/ext/common/c_util.h +74 -0
  7. data/ext/common/ruby_c_util.h +88 -0
  8. data/ext/sip_parser/common_headers.h +209 -0
  9. data/ext/sip_parser/ext_help.h +18 -0
  10. data/ext/sip_parser/extconf.rb +3 -0
  11. data/ext/sip_parser/sip_parser.c +29649 -0
  12. data/ext/sip_parser/sip_parser.h +227 -0
  13. data/ext/sip_parser/sip_parser_ruby.c +1292 -0
  14. data/ext/stud/extconf.rb +27 -0
  15. data/ext/stud/stud.tar.gz +0 -0
  16. data/ext/stun/ext_help.h +16 -0
  17. data/ext/stun/extconf.rb +3 -0
  18. data/ext/stun/stun_ruby.c +391 -0
  19. data/ext/utils/ext_help.h +14 -0
  20. data/ext/utils/extconf.rb +3 -0
  21. data/ext/utils/haproxy_protocol.c +6163 -0
  22. data/ext/utils/haproxy_protocol.h +27 -0
  23. data/ext/utils/ip_utils.c +5952 -0
  24. data/ext/utils/ip_utils.h +61 -0
  25. data/ext/utils/outbound_utils.c +3227 -0
  26. data/ext/utils/outbound_utils.h +27 -0
  27. data/ext/utils/utils_ruby.c +384 -0
  28. data/ext/utils/utils_ruby.h +75 -0
  29. data/ext/websocket_framing_utils/ext_help.h +18 -0
  30. data/ext/websocket_framing_utils/extconf.rb +3 -0
  31. data/ext/websocket_framing_utils/ws_framing_utils.h +46 -0
  32. data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
  33. data/ext/websocket_http_parser/ext_help.h +18 -0
  34. data/ext/websocket_http_parser/extconf.rb +3 -0
  35. data/ext/websocket_http_parser/ws_http_parser.c +2598 -0
  36. data/ext/websocket_http_parser/ws_http_parser.h +86 -0
  37. data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
  38. data/lib/oversip/config.rb +541 -0
  39. data/lib/oversip/config_validators.rb +126 -0
  40. data/lib/oversip/errors.rb +7 -0
  41. data/lib/oversip/fiber_pool.rb +56 -0
  42. data/lib/oversip/launcher.rb +507 -0
  43. data/lib/oversip/logger.rb +170 -0
  44. data/lib/oversip/master_process.rb +67 -0
  45. data/lib/oversip/posix_mq.rb +121 -0
  46. data/lib/oversip/proxies_config.rb +169 -0
  47. data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
  48. data/lib/oversip/sip/client_transaction.rb +587 -0
  49. data/lib/oversip/sip/constants.rb +87 -0
  50. data/lib/oversip/sip/grammar/name_addr.rb +27 -0
  51. data/lib/oversip/sip/grammar/uri.rb +116 -0
  52. data/lib/oversip/sip/launcher.rb +180 -0
  53. data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
  54. data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +21 -0
  55. data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
  56. data/lib/oversip/sip/listeners/ipv4_tls_server.rb +21 -0
  57. data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +21 -0
  58. data/lib/oversip/sip/listeners/ipv4_udp_server.rb +20 -0
  59. data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
  60. data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +21 -0
  61. data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
  62. data/lib/oversip/sip/listeners/ipv6_tls_server.rb +21 -0
  63. data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +21 -0
  64. data/lib/oversip/sip/listeners/ipv6_udp_server.rb +20 -0
  65. data/lib/oversip/sip/listeners/reactor.rb +39 -0
  66. data/lib/oversip/sip/listeners/tcp_client.rb +73 -0
  67. data/lib/oversip/sip/listeners/tcp_reactor.rb +185 -0
  68. data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
  69. data/lib/oversip/sip/listeners/tls_client.rb +117 -0
  70. data/lib/oversip/sip/listeners/tls_server.rb +70 -0
  71. data/lib/oversip/sip/listeners/tls_tunnel_reactor.rb +113 -0
  72. data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
  73. data/lib/oversip/sip/listeners/udp_reactor.rb +213 -0
  74. data/lib/oversip/sip/listeners.rb +28 -0
  75. data/lib/oversip/sip/logic.rb +14 -0
  76. data/lib/oversip/sip/message.rb +168 -0
  77. data/lib/oversip/sip/message_processor.rb +202 -0
  78. data/lib/oversip/sip/modules/core.rb +200 -0
  79. data/lib/oversip/sip/modules/registrar_without_path.rb +75 -0
  80. data/lib/oversip/sip/modules/user_assertion.rb +123 -0
  81. data/lib/oversip/sip/proxy.rb +460 -0
  82. data/lib/oversip/sip/request.rb +128 -0
  83. data/lib/oversip/sip/response.rb +30 -0
  84. data/lib/oversip/sip/rfc3263.rb +646 -0
  85. data/lib/oversip/sip/server_transaction.rb +295 -0
  86. data/lib/oversip/sip/sip.rb +74 -0
  87. data/lib/oversip/sip/tags.rb +39 -0
  88. data/lib/oversip/sip/timers.rb +55 -0
  89. data/lib/oversip/sip/transport_manager.rb +129 -0
  90. data/lib/oversip/syslogger_process.rb +119 -0
  91. data/lib/oversip/tls.rb +179 -0
  92. data/lib/oversip/utils.rb +25 -0
  93. data/lib/oversip/version.rb +23 -0
  94. data/lib/oversip/websocket/constants.rb +56 -0
  95. data/lib/oversip/websocket/default_policy.rb +19 -0
  96. data/lib/oversip/websocket/http_request.rb +63 -0
  97. data/lib/oversip/websocket/launcher.rb +207 -0
  98. data/lib/oversip/websocket/listeners/ipv4_tcp_server.rb +15 -0
  99. data/lib/oversip/websocket/listeners/ipv4_tls_server.rb +15 -0
  100. data/lib/oversip/websocket/listeners/ipv4_tls_tunnel_server.rb +15 -0
  101. data/lib/oversip/websocket/listeners/ipv6_tcp_server.rb +15 -0
  102. data/lib/oversip/websocket/listeners/ipv6_tls_server.rb +15 -0
  103. data/lib/oversip/websocket/listeners/ipv6_tls_tunnel_server.rb +15 -0
  104. data/lib/oversip/websocket/listeners/tcp_server.rb +265 -0
  105. data/lib/oversip/websocket/listeners/tls_server.rb +69 -0
  106. data/lib/oversip/websocket/listeners/tls_tunnel_server.rb +100 -0
  107. data/lib/oversip/websocket/listeners.rb +12 -0
  108. data/lib/oversip/websocket/ws_app.rb +75 -0
  109. data/lib/oversip/websocket/ws_apps/ipv4_ws_sip_app.rb +21 -0
  110. data/lib/oversip/websocket/ws_apps/ipv4_wss_sip_app.rb +21 -0
  111. data/lib/oversip/websocket/ws_apps/ipv6_ws_sip_app.rb +21 -0
  112. data/lib/oversip/websocket/ws_apps/ipv6_wss_sip_app.rb +22 -0
  113. data/lib/oversip/websocket/ws_apps/ws_autobahn_app.rb +23 -0
  114. data/lib/oversip/websocket/ws_apps/ws_sip_app.rb +156 -0
  115. data/lib/oversip/websocket/ws_apps.rb +9 -0
  116. data/lib/oversip/websocket/ws_framing.rb +597 -0
  117. data/lib/oversip.rb +59 -0
  118. data/test/oversip_test_helper.rb +20 -0
  119. data/test/test_http_parser.rb +73 -0
  120. data/test/test_sip_parser.rb +139 -0
  121. 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
@@ -0,0 +1,7 @@
1
+ module OverSIP
2
+
3
+ class Error < StandardError ; end
4
+ class ConfigurationError < Error ; end
5
+ class LogicError < Error ; end
6
+
7
+ end