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,119 @@
|
|
|
1
|
+
# Ruby built-in libraries.
|
|
2
|
+
|
|
3
|
+
require "syslog"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Ruby external gems.
|
|
7
|
+
|
|
8
|
+
gem "eventmachine-le", ">= 1.1.0"
|
|
9
|
+
require "eventmachine-le"
|
|
10
|
+
|
|
11
|
+
gem "em-posixmq", ">= 0.2.3"
|
|
12
|
+
require "em-posixmq"
|
|
13
|
+
|
|
14
|
+
# OverSIP libraries.
|
|
15
|
+
# (not required to be loaded as needed ones have been already
|
|
16
|
+
# loaded before forking).
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
module OverSIP
|
|
21
|
+
|
|
22
|
+
module SysLoggerProcess
|
|
23
|
+
|
|
24
|
+
SYSLOG_FACILITY_MAPPING = {
|
|
25
|
+
"kern" => Syslog::LOG_KERN,
|
|
26
|
+
"user" => Syslog::LOG_USER,
|
|
27
|
+
"daemon" => Syslog::LOG_DAEMON,
|
|
28
|
+
"local0" => Syslog::LOG_LOCAL0,
|
|
29
|
+
"local1" => Syslog::LOG_LOCAL1,
|
|
30
|
+
"local2" => Syslog::LOG_LOCAL2,
|
|
31
|
+
"local3" => Syslog::LOG_LOCAL3,
|
|
32
|
+
"local4" => Syslog::LOG_LOCAL4,
|
|
33
|
+
"local5" => Syslog::LOG_LOCAL5,
|
|
34
|
+
"local6" => Syslog::LOG_LOCAL6,
|
|
35
|
+
"local7" => Syslog::LOG_LOCAL7
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
class SysLoggerWatcher < ::EM::PosixMQ::Watcher
|
|
39
|
+
|
|
40
|
+
def receive_message string, priority
|
|
41
|
+
level = string.getbyte 0
|
|
42
|
+
msg = string[1..-1].gsub(/%/,"%%").gsub(/\x00/,"")
|
|
43
|
+
|
|
44
|
+
case level
|
|
45
|
+
when 48 # "0" =>DEBUG
|
|
46
|
+
::Syslog.debug sprintf("%7s %s", "DEBUG:", msg)
|
|
47
|
+
when 49 # "1" => INFO
|
|
48
|
+
::Syslog.info sprintf("%7s %s", "INFO:", msg)
|
|
49
|
+
when 50 # "2" => NOTICE
|
|
50
|
+
::Syslog.notice sprintf("%7s %s", "NOTICE:", msg)
|
|
51
|
+
when 51 # "3" => WARN
|
|
52
|
+
::Syslog.warning sprintf("%7s %s", "WARN:", msg)
|
|
53
|
+
when 52 # "4" => ERR
|
|
54
|
+
::Syslog.err sprintf("%7s %s", "ERROR:", msg)
|
|
55
|
+
when 53 # "5" => CRIT
|
|
56
|
+
::Syslog.crit sprintf("%7s %s", "CRIT:", msg)
|
|
57
|
+
when 54 # "6" => ALERT
|
|
58
|
+
::Syslog.alert sprintf("%7s %s", "ALERT:", msg)
|
|
59
|
+
when 55 # "7" => EMERG
|
|
60
|
+
::Syslog.emerg sprintf("%7s %s", "EMERG:", msg)
|
|
61
|
+
else # Shouldn't occur.
|
|
62
|
+
::Syslog.err sprintf("%7s %s", "UNKNOWN:", msg)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end # class SysLoggerWatcher
|
|
67
|
+
|
|
68
|
+
def self.run options={}
|
|
69
|
+
$0 = ::OverSIP.master_name + "_syslogger"
|
|
70
|
+
|
|
71
|
+
syslog_options = ::Syslog::LOG_PID | ::Syslog::LOG_NDELAY
|
|
72
|
+
syslog_facility = SYSLOG_FACILITY_MAPPING[::OverSIP.configuration[:core][:syslog_facility]]
|
|
73
|
+
::Syslog.open(::OverSIP.master_name, syslog_options, syslog_facility)
|
|
74
|
+
|
|
75
|
+
ppid = ::Process.ppid
|
|
76
|
+
|
|
77
|
+
at_exit do
|
|
78
|
+
::Syslog.notice sprintf("%7s %s", "INFO:", "<syslogger> syslogger process terminated")
|
|
79
|
+
exit!
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
EM.run do
|
|
83
|
+
begin
|
|
84
|
+
syslogger_mq = ::POSIX_MQ.new ::OverSIP.syslogger_mq_name, ::IO::RDONLY | ::IO::NONBLOCK
|
|
85
|
+
::EM::PosixMQ.run syslogger_mq, SysLoggerWatcher
|
|
86
|
+
|
|
87
|
+
# Change process permissions if requested.
|
|
88
|
+
::OverSIP::Launcher.set_user_group(options[:user], options[:group])
|
|
89
|
+
|
|
90
|
+
rescue => e
|
|
91
|
+
::Syslog.crit sprintf("%7s %s", "CRIT:", "<syslogger> #{e.class}: #{e}")
|
|
92
|
+
::Syslog.crit sprintf("%7s %s", "CRIT:", "<syslogger> syslogger process terminated")
|
|
93
|
+
exit! 1
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Periodically check that master process remains alive and
|
|
97
|
+
# die otherwise.
|
|
98
|
+
::EM.add_periodic_timer(1) do
|
|
99
|
+
if ::Process.ppid != ppid
|
|
100
|
+
# Wait 0.5 seconds. Maybe the master process has been killed properly and just now
|
|
101
|
+
# it's sending us the QUIT signal.
|
|
102
|
+
::EM.add_timer(0.5) do
|
|
103
|
+
::Syslog.crit sprintf("%7s %s", "CRIT:", "<syslogger> master process died, syslogger process terminated")
|
|
104
|
+
exit! 1
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
::EM.error_handler do |e|
|
|
110
|
+
::Syslog.crit sprintf("%7s %s", "CRIT:", "<syslogger> error raised during event loop and rescued by EM.error_handler: #{e.message} (#{e.class})\n#{(e.backtrace || [])[0..3].join("\n")}")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
::Syslog.info sprintf("%7s %s", "INFO:", "<syslogger> syslogger process (PID #{$$}) ready")
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
end # module SysLoggerProcess
|
|
118
|
+
|
|
119
|
+
end
|
data/lib/oversip/tls.rb
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
module OverSIP
|
|
2
|
+
|
|
3
|
+
module TLS
|
|
4
|
+
|
|
5
|
+
extend ::OverSIP::Logger
|
|
6
|
+
|
|
7
|
+
TLS_PEM_CHAIN_REGEXP = /-{5}BEGIN CERTIFICATE-{5}\n.*?-{5}END CERTIFICATE-{5}\n/m
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def self.log_id
|
|
11
|
+
@log_id ||= "TLS"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def self.module_init
|
|
16
|
+
configuration = ::OverSIP.configuration
|
|
17
|
+
if configuration[:tls][:public_cert] and configuration[:tls][:private_cert]
|
|
18
|
+
log_system_info "TLS enabled"
|
|
19
|
+
|
|
20
|
+
::OverSIP.tls = true
|
|
21
|
+
::OverSIP.tls_public_cert = configuration[:tls][:public_cert]
|
|
22
|
+
::OverSIP.tls_private_cert = configuration[:tls][:private_cert]
|
|
23
|
+
|
|
24
|
+
if (::OverSIP.tls_proxy_ipv4 = configuration[:tls][:tls_proxy_ipv4])
|
|
25
|
+
log_system_info "TLS proxy enabled from IPv4 #{::OverSIP.tls_proxy_ipv4}"
|
|
26
|
+
end
|
|
27
|
+
if (::OverSIP.tls_proxy_ipv6 = configuration[:tls][:tls_proxy_ipv6])
|
|
28
|
+
log_system_info "TLS proxy enabled from IPv6 #{::OverSIP.tls_proxy_ipv6}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
else
|
|
32
|
+
log_system_info "TLS dissabled"
|
|
33
|
+
return
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if (ca_dir = configuration[:tls][:ca_dir])
|
|
37
|
+
@store = ::OpenSSL::X509::Store.new
|
|
38
|
+
num_certs_added = 0
|
|
39
|
+
|
|
40
|
+
::Dir.chdir ca_dir
|
|
41
|
+
ca_files = ::Dir["*"]
|
|
42
|
+
ca_files.select! { |ca_file| ::File.file?(ca_file) and ::File.readable?(ca_file) }
|
|
43
|
+
ca_files.each do |ca_file|
|
|
44
|
+
log_system_info "inspecting CA file '#{ca_file}'..."
|
|
45
|
+
|
|
46
|
+
ca_file_content = ::File.read(ca_file)
|
|
47
|
+
unless ca_file_content.valid_encoding?
|
|
48
|
+
log_system_error "ignoring '#{ca_file}', invalid symbols found"
|
|
49
|
+
next
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
pems = ca_file_content.scan(TLS_PEM_CHAIN_REGEXP).flatten
|
|
53
|
+
num_pems = pems.size
|
|
54
|
+
|
|
55
|
+
if num_pems == 0
|
|
56
|
+
log_system_warn "'#{ca_file}': no public certificates found"
|
|
57
|
+
next
|
|
58
|
+
end
|
|
59
|
+
log_system_info "'#{ca_file}': #{num_pems} public certificates found"
|
|
60
|
+
|
|
61
|
+
now = ::Time.now
|
|
62
|
+
certs = []
|
|
63
|
+
pems.each do |pem|
|
|
64
|
+
begin
|
|
65
|
+
certs << ::OpenSSL::X509::Certificate.new(pem)
|
|
66
|
+
rescue => e
|
|
67
|
+
log_system_error "ignoring invalid X509 certificate: #{e.message} (#{e.class})"
|
|
68
|
+
num_pems -= 1
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
certs.reject! { |cert| cert.not_after < now }
|
|
73
|
+
if certs.size != num_pems
|
|
74
|
+
log_system_info "'#{ca_file}': ignoring #{num_pems - certs.size} expired certificates"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
certs.each do |cert|
|
|
78
|
+
begin
|
|
79
|
+
@store.add_cert cert
|
|
80
|
+
num_certs_added += 1
|
|
81
|
+
# This occurs when a certificate is repeated.
|
|
82
|
+
rescue ::OpenSSL::X509::StoreError => e
|
|
83
|
+
log_system_warn "'#{ca_file}': ignoring certificate: #{e.message} (#{e.class})"
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
if num_certs_added == 0
|
|
89
|
+
log_system_notice "zero public certificates found in '#{ca_dir}' directory, dissabling TLS validation"
|
|
90
|
+
@store = nil
|
|
91
|
+
end
|
|
92
|
+
log_system_info "#{num_certs_added} public certificates available for TLS validation"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
end # def self.module_init
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# Return an array with the result of the TLS certificate validation as follows:
|
|
99
|
+
# validated, cert, tls_error, tls_error_string
|
|
100
|
+
# where:
|
|
101
|
+
# - validated: true if the given certificate(s) have been validated, false otherwise
|
|
102
|
+
# and nil if no certificate is provided by peer or no CA's were configured
|
|
103
|
+
# for TLS validation.
|
|
104
|
+
# - cert: the ::OpenSSL::X509::Certificate instance of the first PEM provided by
|
|
105
|
+
# the peer, nil otherwise.
|
|
106
|
+
# - tls_error: OpenSSL validation error code (Fixnum) in case of validation error.
|
|
107
|
+
# - tls_error_string: OpenSSL validation error string in case of validation error.
|
|
108
|
+
def self.validate pem, intermediate_pems=nil
|
|
109
|
+
return nil, nil, nil, "no CAs provided, validation dissabled" unless @store
|
|
110
|
+
return nil, nil, nil, "no certificate provided by peer" unless pem
|
|
111
|
+
|
|
112
|
+
begin
|
|
113
|
+
cert = ::OpenSSL::X509::Certificate.new pem
|
|
114
|
+
|
|
115
|
+
if intermediate_pems and intermediate_pems.any?
|
|
116
|
+
intermediate_certs = []
|
|
117
|
+
intermediate_pems.each do |pem|
|
|
118
|
+
intermediate_certs << ::OpenSSL::X509::Certificate.new(pem)
|
|
119
|
+
end
|
|
120
|
+
else
|
|
121
|
+
intermediate_certs = nil
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
if @store.verify cert, intermediate_certs
|
|
125
|
+
return true, cert
|
|
126
|
+
else
|
|
127
|
+
return false, cert, @store.error, @store.error_string
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
rescue => e
|
|
131
|
+
log_system_error "exception validating a certificate: #{e.class}: #{e.message}"
|
|
132
|
+
return false, nil, e.class, e.message
|
|
133
|
+
end
|
|
134
|
+
end # def self.validate
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def self.get_sip_identities cert
|
|
138
|
+
verify_subjectAltName_DNS = true
|
|
139
|
+
verify_CN = true
|
|
140
|
+
subjectAltName_URI_sip_entries = []
|
|
141
|
+
subjectAltName_DNS_entries = []
|
|
142
|
+
sip_identities = {}
|
|
143
|
+
|
|
144
|
+
cert.extensions.each do |ext|
|
|
145
|
+
next if ext.oid != "subjectAltName"
|
|
146
|
+
verify_CN = false
|
|
147
|
+
|
|
148
|
+
ext.value.split(/,\s+/).each do |name|
|
|
149
|
+
if /^URI:sip:([^@]*)/i =~ name
|
|
150
|
+
verify_subjectAltName_DNS = false
|
|
151
|
+
subjectAltName_URI_sip_entries << $1.downcase
|
|
152
|
+
elsif verify_subjectAltName_DNS && /^DNS:(.*)/i =~ name
|
|
153
|
+
subjectAltName_DNS_entries << $1.downcase
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
unless verify_CN
|
|
159
|
+
unless verify_subjectAltName_DNS
|
|
160
|
+
subjectAltName_URI_sip_entries.each {|domain| sip_identities[domain] = true}
|
|
161
|
+
else
|
|
162
|
+
subjectAltName_DNS_entries.each {|domain| sip_identities[domain] = true}
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
else
|
|
166
|
+
cert.subject.to_a.each do |oid, value|
|
|
167
|
+
if oid == "CN"
|
|
168
|
+
sip_identities[value.downcase] = true
|
|
169
|
+
break
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
return sip_identities
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module OverSIP
|
|
2
|
+
|
|
3
|
+
module Utils
|
|
4
|
+
|
|
5
|
+
# It ensures that two identical byte secuences are matched regardless
|
|
6
|
+
# they have different encoding.
|
|
7
|
+
# For example in Ruby the following returns false:
|
|
8
|
+
# "iñaki".force_encoding(::Encoding::BINARY) == "iñaki"
|
|
9
|
+
def self.string_compare string1, string2
|
|
10
|
+
string1.force_encoding(::Encoding::BINARY) == string2.force_encoding(::Encoding::BINARY)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# This avoid "invalid byte sequence in UTF-8" when the directly doing:
|
|
14
|
+
# string =~ /EXPRESSION/
|
|
15
|
+
# and string has invalid UTF-8 bytes secuence.
|
|
16
|
+
# NOTE: expression argument must be a Regexp expression (with / symbols at the
|
|
17
|
+
# begining and at the end).
|
|
18
|
+
def self.regexp_compare string, expression
|
|
19
|
+
return false unless string && string.valid_encoding?
|
|
20
|
+
string.force_encoding(::Encoding::BINARY) =~ expression
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
module OverSIP
|
|
4
|
+
|
|
5
|
+
module Version
|
|
6
|
+
MAJOR = 0
|
|
7
|
+
MINOR = 9
|
|
8
|
+
TINY = 0
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
PROGRAM_NAME = "OverSIP"
|
|
12
|
+
PROGRAM_NAME_LOW = PROGRAM_NAME.downcase
|
|
13
|
+
PROGRAM_DESC = "OverSIP Server"
|
|
14
|
+
VERSION = [Version::MAJOR, Version::MINOR, Version::TINY].join('.')
|
|
15
|
+
AUTHOR = "Iñaki Baz Castillo"
|
|
16
|
+
AUTHOR_EMAIL = "ibc@aliax.net"
|
|
17
|
+
DESCRIPTION = "#{PROGRAM_NAME} #{VERSION}\n2012, #{AUTHOR} <#{AUTHOR_EMAIL}>"
|
|
18
|
+
|
|
19
|
+
module GemVersion
|
|
20
|
+
VERSION = ::OverSIP::VERSION
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module OverSIP::WebSocket
|
|
2
|
+
|
|
3
|
+
CRLF = "\r\n"
|
|
4
|
+
|
|
5
|
+
REASON_PHARSE = {
|
|
6
|
+
100 => "Continue",
|
|
7
|
+
101 => "Switching Protocols",
|
|
8
|
+
200 => "OK",
|
|
9
|
+
201 => "Created",
|
|
10
|
+
202 => "Accepted",
|
|
11
|
+
203 => "Non-Authoritative Information",
|
|
12
|
+
204 => "No Content",
|
|
13
|
+
205 => "Reset Content",
|
|
14
|
+
206 => "Partial Content",
|
|
15
|
+
300 => "Multiple Choices",
|
|
16
|
+
301 => "Moved Permanently",
|
|
17
|
+
302 => "Found",
|
|
18
|
+
303 => "See Other",
|
|
19
|
+
304 => "Not Modified",
|
|
20
|
+
305 => "Use Proxy",
|
|
21
|
+
307 => "Temporary Redirect",
|
|
22
|
+
400 => "Bad Request",
|
|
23
|
+
401 => "Unauthorized",
|
|
24
|
+
402 => "Payment Required",
|
|
25
|
+
403 => "Forbidden",
|
|
26
|
+
404 => "Not Found",
|
|
27
|
+
405 => "Method Not Allowed",
|
|
28
|
+
406 => "Not Acceptable",
|
|
29
|
+
407 => "Proxy Authentication Required",
|
|
30
|
+
408 => "Request Timeout",
|
|
31
|
+
409 => "Conflict",
|
|
32
|
+
410 => "Gone",
|
|
33
|
+
411 => "Length Required",
|
|
34
|
+
412 => "Precondition Failed",
|
|
35
|
+
413 => "Request Entity Too Large",
|
|
36
|
+
414 => "Request-URI Too Long",
|
|
37
|
+
415 => "Unsupported Media Type",
|
|
38
|
+
416 => "Requested Range Not Satisfiable",
|
|
39
|
+
417 => "Expectation Failed",
|
|
40
|
+
426 => "Upgrade Required", # RFC 2817
|
|
41
|
+
500 => "Server Internal Error",
|
|
42
|
+
501 => "Not Implemented",
|
|
43
|
+
502 => "Bad Gateway",
|
|
44
|
+
503 => "Service Unavailable",
|
|
45
|
+
504 => "Gateway Time-out",
|
|
46
|
+
505 => "HTTP Version Not Supported"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
REASON_PHARSE_NOT_SET = "Reason Phrase Not Set"
|
|
50
|
+
|
|
51
|
+
HDR_SERVER = "Server: #{::OverSIP::PROGRAM_DESC}/#{::OverSIP::VERSION}"
|
|
52
|
+
|
|
53
|
+
WS_SIP_PROTOCOL = "sip"
|
|
54
|
+
WS_AUTOBAHN_PROTOCOL = "autobahn"
|
|
55
|
+
|
|
56
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module OverSIP::WebSocket
|
|
2
|
+
|
|
3
|
+
class HttpRequest < ::Hash
|
|
4
|
+
|
|
5
|
+
include ::OverSIP::Logger
|
|
6
|
+
|
|
7
|
+
# HTTP related attributes.
|
|
8
|
+
attr_accessor :transport
|
|
9
|
+
attr_accessor :source_ip
|
|
10
|
+
attr_accessor :source_ip_type
|
|
11
|
+
attr_accessor :source_port
|
|
12
|
+
attr_accessor :connection
|
|
13
|
+
|
|
14
|
+
# HTTP request attributes.
|
|
15
|
+
attr_reader :http_method
|
|
16
|
+
attr_reader :http_version
|
|
17
|
+
attr_reader :uri_scheme
|
|
18
|
+
attr_reader :uri
|
|
19
|
+
attr_reader :uri_path
|
|
20
|
+
attr_reader :uri_query
|
|
21
|
+
attr_reader :uri_fragment
|
|
22
|
+
attr_reader :host
|
|
23
|
+
attr_reader :port
|
|
24
|
+
attr_reader :content_length
|
|
25
|
+
attr_reader :hdr_connection
|
|
26
|
+
attr_reader :hdr_upgrade
|
|
27
|
+
attr_reader :hdr_origin
|
|
28
|
+
attr_reader :hdr_sec_websocket_version
|
|
29
|
+
attr_reader :hdr_sec_websocket_key
|
|
30
|
+
attr_reader :hdr_sec_websocket_protocol
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def log_id
|
|
34
|
+
@log_id ||= "HTTP Request #{@connection.connection_log_id}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def unknown_method? ; @is_unknown_method end
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def reply status_code, reason_phrase=nil, extra_headers={}
|
|
41
|
+
reason_phrase ||= REASON_PHARSE[status_code] || REASON_PHARSE_NOT_SET
|
|
42
|
+
extra_headers ||= {}
|
|
43
|
+
|
|
44
|
+
response = "#{@http_version} #{status_code} #{reason_phrase}\r\n"
|
|
45
|
+
|
|
46
|
+
extra_headers.each {|header| response << header << "\r\n"}
|
|
47
|
+
|
|
48
|
+
response << HDR_SERVER << "\r\n\r\n"
|
|
49
|
+
|
|
50
|
+
log_system_debug "replying #{status_code} \"#{reason_phrase}\"" if $oversip_debug
|
|
51
|
+
|
|
52
|
+
if @connection.error?
|
|
53
|
+
log_system_warn "cannot send response, TCP connection is closed"
|
|
54
|
+
return false
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
@connection.send_data response
|
|
58
|
+
return true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end # class HttpRequest
|
|
62
|
+
|
|
63
|
+
end
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
module OverSIP::WebSocket
|
|
2
|
+
|
|
3
|
+
module Launcher
|
|
4
|
+
|
|
5
|
+
extend OverSIP::Logger
|
|
6
|
+
|
|
7
|
+
IP_TYPE = {
|
|
8
|
+
:ipv4 => "IPv4",
|
|
9
|
+
:ipv6 => "IPv6"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def self.log_id
|
|
14
|
+
@log_id ||= "WebSocket launcher"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def self.run enabled, ip_type, ip, port, transport, ws_protocol, virtual_ip=nil, virtual_port=nil
|
|
19
|
+
uri_ip = case ip_type
|
|
20
|
+
when :ipv4 ; ip
|
|
21
|
+
when :ipv6 ; "[#{ip}]"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if virtual_ip
|
|
25
|
+
uri_virtual_ip = case ip_type
|
|
26
|
+
when :ipv4 ; virtual_ip
|
|
27
|
+
when :ipv6 ; "[#{virtual_ip}]"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
klass = case transport
|
|
32
|
+
when :tcp
|
|
33
|
+
case ip_type
|
|
34
|
+
when :ipv4 ; OverSIP::WebSocket::IPv4TcpServer
|
|
35
|
+
when :ipv6 ; OverSIP::WebSocket::IPv6TcpServer
|
|
36
|
+
end
|
|
37
|
+
when :tls
|
|
38
|
+
case ip_type
|
|
39
|
+
when :ipv4 ; OverSIP::WebSocket::IPv4TlsServer
|
|
40
|
+
when :ipv6 ; OverSIP::WebSocket::IPv6TlsServer
|
|
41
|
+
end
|
|
42
|
+
when :tls_tunnel
|
|
43
|
+
case ip_type
|
|
44
|
+
when :ipv4 ; OverSIP::WebSocket::IPv4TlsTunnelServer
|
|
45
|
+
when :ipv6 ; OverSIP::WebSocket::IPv6TlsTunnelServer
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
case ws_protocol
|
|
50
|
+
|
|
51
|
+
when OverSIP::WebSocket::WS_SIP_PROTOCOL
|
|
52
|
+
|
|
53
|
+
ws_app_klass = case transport
|
|
54
|
+
when :tcp
|
|
55
|
+
case ip_type
|
|
56
|
+
when :ipv4 ; OverSIP::WebSocket::IPv4WsSipApp
|
|
57
|
+
when :ipv6 ; OverSIP::WebSocket::IPv6WsSipApp
|
|
58
|
+
end
|
|
59
|
+
when :tls, :tls_tunnel
|
|
60
|
+
case ip_type
|
|
61
|
+
when :ipv4 ; OverSIP::WebSocket::IPv4WssSipApp
|
|
62
|
+
when :ipv6 ; OverSIP::WebSocket::IPv6WssSipApp
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
ws_app_klass.ip = virtual_ip || ip
|
|
67
|
+
ws_app_klass.port = virtual_port || port
|
|
68
|
+
|
|
69
|
+
case
|
|
70
|
+
|
|
71
|
+
when klass == OverSIP::WebSocket::IPv4TcpServer
|
|
72
|
+
ws_app_klass.via_core = "SIP/2.0/WS #{uri_ip}:#{port}"
|
|
73
|
+
ws_app_klass.record_route = "<sip:#{uri_ip}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
|
74
|
+
ws_app_klass.outbound_record_route_fragment = "@#{uri_ip}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
|
75
|
+
ws_app_klass.outbound_path_fragment = "@#{uri_ip}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid};ob>"
|
|
76
|
+
|
|
77
|
+
if enabled
|
|
78
|
+
EM.start_server(ip, port, klass) do |conn|
|
|
79
|
+
conn.ws_protocol = ws_protocol
|
|
80
|
+
conn.ws_app_klass = ws_app_klass
|
|
81
|
+
conn.post_connection
|
|
82
|
+
conn.set_comm_inactivity_timeout 3600 # TODO
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
when klass == OverSIP::WebSocket::IPv6TcpServer
|
|
87
|
+
ws_app_klass.via_core = "SIP/2.0/WS #{uri_ip}:#{port}"
|
|
88
|
+
ws_app_klass.record_route = "<sip:#{uri_ip}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
|
89
|
+
ws_app_klass.outbound_record_route_fragment = "@#{uri_ip}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
|
90
|
+
ws_app_klass.outbound_path_fragment = "@#{uri_ip}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid};ob>"
|
|
91
|
+
|
|
92
|
+
if enabled
|
|
93
|
+
EM.start_server(ip, port, klass) do |conn|
|
|
94
|
+
conn.ws_protocol = ws_protocol
|
|
95
|
+
conn.ws_app_klass = ws_app_klass
|
|
96
|
+
conn.post_connection
|
|
97
|
+
conn.set_comm_inactivity_timeout 3600 # TODO
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
when klass == OverSIP::WebSocket::IPv4TlsServer
|
|
102
|
+
ws_app_klass.via_core = "SIP/2.0/WSS #{uri_ip}:#{port}"
|
|
103
|
+
rr_host = ::OverSIP.configuration[:sip][:record_route_hostname_tls_ipv4] || uri_ip
|
|
104
|
+
ws_app_klass.record_route = "<sip:#{rr_host}:#{port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
|
105
|
+
ws_app_klass.outbound_record_route_fragment = "@#{rr_host}:#{port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
|
106
|
+
ws_app_klass.outbound_path_fragment = "@#{rr_host}:#{port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid};ob>"
|
|
107
|
+
|
|
108
|
+
if enabled
|
|
109
|
+
EM.start_server(ip, port, klass) do |conn|
|
|
110
|
+
conn.ws_protocol = ws_protocol
|
|
111
|
+
conn.ws_app_klass = ws_app_klass
|
|
112
|
+
conn.post_connection
|
|
113
|
+
conn.set_comm_inactivity_timeout 3600 # TODO
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
when klass == OverSIP::WebSocket::IPv6TlsServer
|
|
118
|
+
ws_app_klass.via_core = "SIP/2.0/WSS #{uri_ip}:#{port}"
|
|
119
|
+
rr_host = ::OverSIP.configuration[:sip][:record_route_hostname_tls_ipv6] || uri_ip
|
|
120
|
+
ws_app_klass.record_route = "<sips:#{rr_host}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
|
121
|
+
ws_app_klass.outbound_record_route_fragment = "@#{rr_host}:#{port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
|
122
|
+
ws_app_klass.outbound_path_fragment = "@#{rr_host}:#{port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid};ob>"
|
|
123
|
+
|
|
124
|
+
if enabled
|
|
125
|
+
EM.start_server(ip, port, klass) do |conn|
|
|
126
|
+
conn.ws_protocol = ws_protocol
|
|
127
|
+
conn.ws_app_klass = ws_app_klass
|
|
128
|
+
conn.post_connection
|
|
129
|
+
conn.set_comm_inactivity_timeout 3600 # TODO
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
when klass == OverSIP::WebSocket::IPv4TlsTunnelServer
|
|
134
|
+
ws_app_klass.via_core = "SIP/2.0/WSS #{uri_virtual_ip}:#{virtual_port}"
|
|
135
|
+
rr_host = ::OverSIP.configuration[:sip][:record_route_hostname_tls_ipv4] || uri_virtual_ip
|
|
136
|
+
ws_app_klass.record_route = "<sip:#{rr_host}:#{virtual_port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
|
137
|
+
ws_app_klass.outbound_record_route_fragment = "@#{rr_host}:#{virtual_port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
|
138
|
+
ws_app_klass.outbound_path_fragment = "@#{rr_host}:#{virtual_port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid};ob>"
|
|
139
|
+
|
|
140
|
+
if enabled
|
|
141
|
+
EM.start_server(ip, port, klass) do |conn|
|
|
142
|
+
conn.ws_protocol = ws_protocol
|
|
143
|
+
conn.ws_app_klass = ws_app_klass
|
|
144
|
+
conn.post_connection
|
|
145
|
+
conn.set_comm_inactivity_timeout 3600 # TODO
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
when klass == OverSIP::WebSocket::IPv6TlsTunnelServer
|
|
150
|
+
ws_app_klass.via_core = "SIP/2.0/WSS #{uri_virtual_ip}:#{virtual_port}"
|
|
151
|
+
rr_host = ::OverSIP.configuration[:sip][:record_route_hostname_tls_ipv6] || uri_virtual_ip
|
|
152
|
+
ws_app_klass.record_route = "<sip:#{rr_host}:#{virtual_port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
|
153
|
+
ws_app_klass.outbound_record_route_fragment = "@#{rr_host}:#{virtual_port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
|
154
|
+
ws_app_klass.outbound_path_fragment = "@#{rr_host}:#{virtual_port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid};ob>"
|
|
155
|
+
|
|
156
|
+
if enabled
|
|
157
|
+
EM.start_server(ip, port, klass) do |conn|
|
|
158
|
+
conn.ws_protocol = ws_protocol
|
|
159
|
+
conn.ws_app_klass = ws_app_klass
|
|
160
|
+
conn.post_connection
|
|
161
|
+
conn.set_comm_inactivity_timeout 3600 # TODO
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
end # case
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
when OverSIP::WebSocket::WS_AUTOBAHN_PROTOCOL
|
|
169
|
+
|
|
170
|
+
ws_app_klass = case transport
|
|
171
|
+
when :tcp
|
|
172
|
+
case ip_type
|
|
173
|
+
when :ipv4 ; OverSIP::WebSocket::WsAutobahnApp
|
|
174
|
+
end
|
|
175
|
+
when :tls
|
|
176
|
+
case ip_type
|
|
177
|
+
when :ipv4 ; OverSIP::WebSocket::WsAutobahnApp
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
EM.start_server(ip, port, klass) do |conn|
|
|
182
|
+
conn.ws_protocol = ws_protocol
|
|
183
|
+
conn.ws_app_klass = ws_app_klass
|
|
184
|
+
conn.post_connection
|
|
185
|
+
conn.set_comm_inactivity_timeout 60
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
else
|
|
190
|
+
fatal "unknown WebSocket protocol: #{ws_protocol}"
|
|
191
|
+
|
|
192
|
+
end # case
|
|
193
|
+
|
|
194
|
+
transport_str = case transport
|
|
195
|
+
when :tls_tunnel ; "TLS-Tunnel"
|
|
196
|
+
else ; transport.to_s.upcase
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
if enabled
|
|
200
|
+
log_system_info "WebSocket #{transport_str} server listening on #{IP_TYPE[ip_type]} #{uri_ip}:#{port} provides '#{ws_protocol}' WS subprotocol"
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
end # def self.run
|
|
204
|
+
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
end
|