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,15 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv4TcpServer < TcpServer
4
+
5
+ @ip_type = :ipv4
6
+ @transport = :tcp
7
+
8
+ LOG_ID = "WS TCP IPv4 server"
9
+ def log_id
10
+ LOG_ID
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv4TlsServer < TlsServer
4
+
5
+ @ip_type = :ipv4
6
+ @transport = :tls
7
+
8
+ LOG_ID = "WS TLS IPv4 server"
9
+ def log_id
10
+ LOG_ID
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv4TlsTunnelServer < TlsTunnelServer
4
+
5
+ @ip_type = :ipv4
6
+ @transport = :tls
7
+
8
+ LOG_ID = "WS TLS-Tunnel IPv4 server"
9
+ def log_id
10
+ LOG_ID
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv6TcpServer < TcpServer
4
+
5
+ @ip_type = :ipv6
6
+ @transport = :tcp
7
+
8
+ LOG_ID = "WS TCP IPv6 server"
9
+ def log_id
10
+ LOG_ID
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv6TlsServer < TlsServer
4
+
5
+ @ip_type = :ipv6
6
+ @transport = :tls
7
+
8
+ LOG_ID = "WS TLS IPv6 server"
9
+ def log_id
10
+ LOG_ID
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv6TlsTunnelServer < TlsTunnelServer
4
+
5
+ @ip_type = :ipv6
6
+ @transport = :tls
7
+
8
+ LOG_ID = "WS TLS-Tunnel IPv6 server"
9
+ def log_id
10
+ LOG_ID
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,265 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class TcpServer < ::EM::Connection
4
+
5
+ include ::OverSIP::Logger
6
+ include ::OverSIP::WebSocket::DefaultPolicy
7
+ include ::OverSIP::WebSocket::Policy rescue nil # As it could not exist (i.e. the user deleted the file).
8
+
9
+ # Max size (bytes) of the buffered data when receiving message headers
10
+ # (avoid DoS attacks).
11
+ HEADERS_MAX_SIZE = 2048
12
+
13
+ WS_MAGIC_GUID_04 = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".freeze
14
+ WS_VERSIONS = { 7=>true, 8=>true, 13=>true }
15
+ HDR_SUPPORTED_WEBSOCKET_VERSIONS = [ "X-Supported-WebSocket-Versions: #{WS_VERSIONS.keys.join(", ")}" ]
16
+
17
+
18
+ class << self
19
+ attr_accessor :ip_type, :transport
20
+ end
21
+
22
+ attr_accessor :ws_protocol, :ws_app_klass
23
+ attr_reader :connection_log_id, :remote_ip_type, :remote_ip, :remote_port
24
+
25
+
26
+ def initialize
27
+ @http_parser = ::OverSIP::WebSocket::HttpRequestParser.new
28
+ @buffer = ::IO::Buffer.new
29
+ @state = :init
30
+ end
31
+
32
+
33
+ def post_connection
34
+ begin
35
+ @remote_port, @remote_ip = ::Socket.unpack_sockaddr_in(get_peername)
36
+ rescue => e
37
+ log_system_error "error obtaining remote IP/port (#{e.class}: #{e.message}), closing connection"
38
+ close_connection
39
+ @state = :ignore
40
+ return
41
+ end
42
+ @connection_log_id = ::SecureRandom.hex(4)
43
+
44
+ log_system_info "connection opened from " << remote_desc
45
+ end
46
+
47
+
48
+ def remote_desc force=nil
49
+ if force
50
+ @remote_desc = case @remote_ip_type
51
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
52
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
53
+ end
54
+ else
55
+ @remote_desc ||= case self.class.ip_type
56
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
57
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
58
+ end
59
+ end
60
+ end
61
+
62
+
63
+ def unbind cause=nil
64
+ @local_closed = true if cause == ::Errno::ETIMEDOUT
65
+
66
+ log_msg = "connection from #{remote_desc} "
67
+ log_msg << ( @local_closed ? "locally closed" : "remotely closed" )
68
+ log_msg << " (cause: #{cause.inspect})" if cause
69
+ log_system_debug log_msg if $oversip_debug
70
+
71
+ @ws_framing.tcp_closed if @ws_framing
72
+ end
73
+
74
+
75
+ def receive_data data
76
+ @state == :ignore and return
77
+ @buffer << data
78
+
79
+ while (case @state
80
+ when :init
81
+ @http_request = ::OverSIP::WebSocket::HttpRequest.new
82
+ @http_parser.reset
83
+ @http_parser_nbytes = 0
84
+ @bytes_remaining = 0
85
+ @state = :http_headers
86
+
87
+ when :http_headers
88
+ parse_http_headers
89
+
90
+ when :check_http_request
91
+ check_http_request
92
+
93
+ when :accept_ws_handshake
94
+ accept_ws_handshake
95
+
96
+ when :websocket_frames
97
+ return false if @buffer.size.zero?
98
+
99
+ @ws_framing.receive_data
100
+ false
101
+
102
+ when :ignore
103
+ false
104
+ end)
105
+ end # while
106
+
107
+ end
108
+
109
+
110
+ def parse_http_headers
111
+ return false if @buffer.empty?
112
+
113
+ # Parse the currently buffered data. If parsing fails @http_parser_nbytes gets nil value.
114
+ unless @http_parser_nbytes = @http_parser.execute(@http_request, @buffer.to_str, @http_parser_nbytes)
115
+ log_system_warn "parsing error: \"#{@http_parser.error}\""
116
+ close_connection_after_writing
117
+ @state = :ignore
118
+ return false
119
+ end
120
+
121
+ # Avoid flood attacks in TCP (very long headers).
122
+ if @http_parser_nbytes > HEADERS_MAX_SIZE
123
+ log_system_warn "DoS attack detected: headers size exceedes #{HEADERS_MAX_SIZE} bytes, closing connection with #{remote_desc}"
124
+ close_connection
125
+ @state = :ignore
126
+ return false
127
+ end
128
+
129
+ return false unless @http_parser.finished?
130
+
131
+ # Clear parsed data from the buffer.
132
+ @buffer.read(@http_parser_nbytes)
133
+
134
+ @http_request.connection = self
135
+ @http_request.transport = self.class.transport
136
+ @http_request.source_ip = @remote_ip
137
+ @http_request.source_port = @remote_port
138
+ @http_request.source_ip_type = @remote_ip_type ||= self.class.ip_type
139
+
140
+ @state = :check_http_request
141
+ true
142
+ end # parse_headers
143
+
144
+
145
+ def check_http_request
146
+
147
+ # HTTP method must be GET.
148
+ if @http_request.http_method != :GET
149
+ log_system_notice "rejecting HTTP #{@http_request.http_method} request => 405"
150
+ http_reject 405
151
+ return false
152
+ end
153
+
154
+ # "Sec-WebSocket-Version" must be 8.
155
+ unless WS_VERSIONS[@http_request.hdr_sec_websocket_version]
156
+ if @http_request.hdr_sec_websocket_version
157
+ log_system_notice "WebSocket version #{@http_request.hdr_sec_websocket_version} not implemented => 426"
158
+ else
159
+ log_system_notice "WebSocket version header not present => 426"
160
+ end
161
+ http_reject 426, nil, HDR_SUPPORTED_WEBSOCKET_VERSIONS
162
+ return false
163
+ end
164
+
165
+ # Connection header must include "upgrade".
166
+ unless @http_request.hdr_connection and @http_request.hdr_connection.include? "upgrade"
167
+ log_system_notice "Connection header must include \"upgrade\" => 400"
168
+ http_reject 400, "Connection header must include \"upgrade\""
169
+ return false
170
+ end
171
+
172
+ # "Upgrade: websocket" is required.
173
+ unless @http_request.hdr_upgrade == "websocket"
174
+ log_system_notice "Upgrade header must be \"websocket\" => 400"
175
+ http_reject 400, "Upgrade header must be \"websocket\""
176
+ return false
177
+ end
178
+
179
+ # Sec-WebSocket-Key is required.
180
+ unless @http_request.hdr_sec_websocket_key
181
+ log_system_notice "Sec-WebSocket-Key header not present => 400"
182
+ http_reject 400, "Sec-WebSocket-Key header not present"
183
+ return false
184
+ end
185
+
186
+ # Check Sec-WebSocket-Protocol.
187
+ if @http_request.hdr_sec_websocket_protocol
188
+ if @http_request.hdr_sec_websocket_protocol.include? @ws_protocol
189
+ @websocket_protocol_negotiated = true
190
+ else
191
+ log_system_notice "Sec-WebSocket-Protocol does not contain a supported protocol but #{@http_request.hdr_sec_websocket_protocol} => 501"
192
+ http_reject 501, "No Suitable WebSocket Protocol"
193
+ return false
194
+ end
195
+ end
196
+
197
+ # Check WebSocket policy.
198
+
199
+ unless check_hostport(@http_request.host, @http_request.port)
200
+ log_system_notice "host/port policy not satisfied (host=#{@http_request.host.inspect}, port=#{@http_request.port.inspect}) => 403"
201
+ http_reject 403, "request host/port not satisfied"
202
+ return false
203
+ end
204
+
205
+ unless check_origin(@http_request.hdr_origin)
206
+ log_system_notice "'Origin' policy not satisfied (origin=#{@http_request.hdr_origin.inspect}) => 403"
207
+ http_reject 403, "request 'Origin' not satisfied"
208
+ return false
209
+ end
210
+
211
+ unless check_request_uri(@http_request.uri_path, @http_request.uri_query)
212
+ log_system_notice "request URI path/query not satisfied (path=#{@http_request.uri_path.inspect}, query=#{@http_request.uri_query.inspect}) => 403"
213
+ http_reject 403, "request URI path/query not satisfied"
214
+ return false
215
+ end
216
+
217
+ @state = :accept_ws_handshake
218
+ true
219
+ end
220
+
221
+
222
+ def accept_ws_handshake
223
+ sec_websocket_accept = Digest::SHA1::base64digest @http_request.hdr_sec_websocket_key + WS_MAGIC_GUID_04
224
+
225
+ extra_headers = [
226
+ "Upgrade: websocket",
227
+ "Connection: Upgrade",
228
+ "Sec-WebSocket-Accept: #{sec_websocket_accept}"
229
+ ]
230
+
231
+ if @websocket_protocol_negotiated
232
+ extra_headers << "Sec-WebSocket-Protocol: #{@ws_protocol}"
233
+ end
234
+
235
+ if @websocket_extensions
236
+ extra_headers << "Sec-WebSocket-Extensions: #{@websocket_extensions.to_s}"
237
+ end
238
+
239
+ @http_request.reply 101, nil, extra_headers
240
+
241
+ # Set the WS framming layer and WS application layer.
242
+ @ws_framing = ::OverSIP::WebSocket::WsFraming.new(self, @buffer)
243
+ @ws_framing.ws_app = @ws_app_klass.new(self, @ws_framing)
244
+
245
+ @state = :websocket_frames
246
+ true
247
+ end
248
+
249
+
250
+ def http_reject status_code, reason_phrase=nil, extra_headers=nil
251
+ @http_request.reply(status_code, reason_phrase, extra_headers)
252
+ close_connection_after_writing
253
+ @state = :ignore
254
+ end
255
+
256
+
257
+ def ignore_incoming_data
258
+ @state = :ignore # The WS application needs to set the connection in :ignore state
259
+ # after sending a close frame to the client.
260
+ end
261
+
262
+ end # class TcpServer
263
+
264
+ end
265
+
@@ -0,0 +1,69 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class TlsServer < TcpServer
4
+
5
+ TLS_HANDSHAKE_MAX_TIME = 8
6
+
7
+
8
+ def post_init
9
+ @client_pems = []
10
+ @client_last_pem = false
11
+
12
+ start_tls({
13
+ :verify_peer => true,
14
+ :cert_chain_file => ::OverSIP.tls_public_cert,
15
+ :private_key_file => ::OverSIP.tls_private_cert
16
+ })
17
+
18
+ # If the remote client does never send us a TLS certificate
19
+ # after the TCP connection we would leak by storing more and
20
+ # more messages in @pending_messages array.
21
+ @timer_tls_handshake = ::EM::Timer.new(TLS_HANDSHAKE_MAX_TIME) do
22
+ unless @connected
23
+ log_system_notice "TLS handshake not performed within #{TLS_HANDSHAKE_MAX_TIME} seconds, closing the connection"
24
+ close_connection
25
+ end
26
+ end
27
+ end
28
+
29
+
30
+ def ssl_verify_peer pem
31
+ # TODO: Dirty workaround for bug https://github.com/eventmachine/eventmachine/issues/194.
32
+ return true if @client_last_pem == pem
33
+
34
+ @client_last_pem = pem
35
+ @client_pems << pem
36
+
37
+ log_system_debug "received certificate num #{@client_pems.size} from client" if $oversip_debug
38
+
39
+ # Validation must be done in ssl_handshake_completed after receiving all the certs, so return true.
40
+ return true
41
+ end
42
+
43
+
44
+ def ssl_handshake_completed
45
+ log_system_info "TLS connection established from " << remote_desc
46
+
47
+ # TODO: What to do it falidation fails? always do validation?
48
+
49
+ validated, cert, tls_error, tls_error_string = ::OverSIP::TLS.validate @client_pems.pop, @client_pems
50
+ if validated
51
+ log_system_info "client provides a valid TLS certificate"
52
+ else
53
+ log_system_notice "client's TLS certificate validation failed (TLS error: #{tls_error.inspect}, description: #{tls_error_string.inspect})"
54
+ end
55
+
56
+ # @connected in TlsServer means "TLS connection" rather than
57
+ # just "TCP connection".
58
+ @connected = true
59
+ @timer_tls_handshake.cancel if @timer_tls_handshake
60
+ end
61
+
62
+
63
+ def unbind cause=nil
64
+ super
65
+ @timer_tls_handshake.cancel if @timer_tls_handshake
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,100 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class TlsTunnelServer < TcpServer
4
+
5
+ def initialize
6
+ @http_parser = ::OverSIP::WebSocket::HttpRequestParser.new
7
+ @buffer = ::IO::Buffer.new
8
+ @state = :init
9
+ end
10
+
11
+
12
+ def post_connection
13
+ begin
14
+ @remote_port, @remote_ip = ::Socket.unpack_sockaddr_in(get_peername)
15
+ rescue => e
16
+ log_system_error "error obtaining remote IP/port (#{e.class}: #{e.message}), closing connection"
17
+ close_connection
18
+ @state = :ignore
19
+ return
20
+ end
21
+ @connection_log_id = ::SecureRandom.hex(4)
22
+
23
+ log_system_info "connection from the TLS tunnel " << remote_desc
24
+ end
25
+
26
+
27
+ def receive_data data
28
+ @state == :ignore and return
29
+ @buffer << data
30
+
31
+ while (case @state
32
+ when :init
33
+ @http_request = ::OverSIP::WebSocket::HttpRequest.new
34
+ @http_parser.reset
35
+ @http_parser_nbytes = 0
36
+ @bytes_remaining = 0
37
+ # If it's a TCP connection from the TLS proxy then parse the HAProxy Protocol line
38
+ # if it's not yet done.
39
+ unless @haproxy_protocol_parsed
40
+ @state = :haproxy_protocol
41
+ else
42
+ @state = :http_headers
43
+ end
44
+
45
+ when :haproxy_protocol
46
+ parse_haproxy_protocol
47
+
48
+ when :http_headers
49
+ parse_http_headers
50
+
51
+ when :check_http_request
52
+ check_http_request
53
+
54
+ when :accept_ws_handshake
55
+ accept_ws_handshake
56
+
57
+ when :websocket_frames
58
+ return false if @buffer.size.zero?
59
+
60
+ @ws_framing.receive_data
61
+ false
62
+
63
+ when :ignore
64
+ false
65
+ end)
66
+ end # while
67
+
68
+ end
69
+
70
+
71
+ def parse_haproxy_protocol
72
+ if (haproxy_protocol_data = ::OverSIP::Utils.parse_haproxy_protocol(@buffer.to_str))
73
+ @haproxy_protocol_parsed = true
74
+
75
+ # Update connection information.
76
+ @remote_ip_type = haproxy_protocol_data[1]
77
+ @remote_ip = haproxy_protocol_data[2]
78
+ @remote_port = haproxy_protocol_data[3]
79
+
80
+ # Update log information.
81
+ remote_desc true
82
+
83
+ # Remove the HAProxy Protocol line from the received data.
84
+ @buffer.read haproxy_protocol_data[0]
85
+
86
+ @state = :http_headers
87
+
88
+ # If parsing fails then the TLS proxy has sent us a wrong HAProxy Protocol line ¿?
89
+ else
90
+ log_system_error "HAProxy Protocol parsing error, closing connection"
91
+ close_connection_after_writing
92
+ @state = :ignore
93
+ return false
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ end
100
+
@@ -0,0 +1,12 @@
1
+ # OverSIP files
2
+
3
+ require "oversip/websocket/listeners/tcp_server"
4
+ require "oversip/websocket/listeners/tls_server"
5
+ require "oversip/websocket/listeners/tls_tunnel_server"
6
+
7
+ require "oversip/websocket/listeners/ipv4_tcp_server"
8
+ require "oversip/websocket/listeners/ipv6_tcp_server"
9
+ require "oversip/websocket/listeners/ipv4_tls_server"
10
+ require "oversip/websocket/listeners/ipv6_tls_server"
11
+ require "oversip/websocket/listeners/ipv4_tls_tunnel_server"
12
+ require "oversip/websocket/listeners/ipv6_tls_tunnel_server"
@@ -0,0 +1,75 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class WsApp
4
+
5
+ include ::OverSIP::Logger
6
+
7
+
8
+ def self.class_init
9
+ @@max_message_size = ::OverSIP.configuration[:websocket][:max_ws_message_size]
10
+ @@ws_keepalive_interval = ::OverSIP.configuration[:websocket][:ws_keepalive_interval]
11
+ end
12
+
13
+
14
+ def initialize connection, ws_framing
15
+ @connection = connection
16
+ @ws_framing = ws_framing
17
+ @ws_message = ::IO::Buffer.new
18
+
19
+ # Mantain WebSocket keepalive.
20
+ @ws_framing.do_keep_alive @@ws_keepalive_interval if @@ws_keepalive_interval
21
+ end
22
+
23
+
24
+ def close_connection status=nil, reason=nil
25
+ @ws_framing.send_close_frame status, reason
26
+ end
27
+
28
+
29
+ def receive_payload_data payload_data
30
+ # payload_data is always Encoding::BINARY so also @ws_message.to_str.
31
+ @ws_message << payload_data
32
+
33
+ # Check max message size.
34
+ if @ws_message.size > @@max_message_size
35
+ close_connection 1009, "message too big"
36
+ return false
37
+ end
38
+ true
39
+ end
40
+
41
+
42
+ def message_done type
43
+ log_system_debug "received WS message: length=#{@ws_message.size}" if $oversip_debug
44
+
45
+ case type
46
+
47
+ when :text
48
+ ws_message = @ws_message.to_str.force_encoding ::Encoding::UTF_8
49
+ process_text_message ws_message
50
+
51
+ when :binary
52
+ process_binary_message @ws_message.to_str # As IO::Buffer#to_str always generates Encoding::BINARY.
53
+ end
54
+
55
+ @ws_message.clear
56
+ true
57
+ end
58
+
59
+
60
+ def tcp_closed
61
+ nil
62
+ end
63
+
64
+
65
+ # Methods to be overriden by child classes.
66
+ def process_text_message ws_message
67
+ end
68
+
69
+ def process_binary_message ws_message
70
+ end
71
+
72
+
73
+ end # WsApplication
74
+
75
+ end
@@ -0,0 +1,21 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv4WsSipApp < WsSipApp
4
+
5
+ @ip_type = :ipv4
6
+ @transport = :ws
7
+ @connections = {}
8
+ @invite_server_transactions = {}
9
+ @non_invite_server_transactions = {}
10
+ @invite_client_transactions = {}
11
+ @non_invite_client_transactions = {}
12
+ @is_reliable_transport_listener = true
13
+
14
+ LOG_ID = "WS IPv4 SIP app"
15
+ def log_id
16
+ LOG_ID
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,21 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv4WssSipApp < WsSipApp
4
+
5
+ @ip_type = :ipv4
6
+ @transport = :wss
7
+ @connections = {}
8
+ @invite_server_transactions = {}
9
+ @non_invite_server_transactions = {}
10
+ @invite_client_transactions = {}
11
+ @non_invite_client_transactions = {}
12
+ @is_reliable_transport_listener = true
13
+
14
+ LOG_ID = "WSS IPv4 SIP app"
15
+ def log_id
16
+ LOG_ID
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,21 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv6WsSipApp < WsSipApp
4
+
5
+ @ip_type = :ipv6
6
+ @transport = :ws
7
+ @connections = {}
8
+ @invite_server_transactions = {}
9
+ @non_invite_server_transactions = {}
10
+ @invite_client_transactions = {}
11
+ @non_invite_client_transactions = {}
12
+ @is_reliable_transport_listener = true
13
+
14
+ LOG_ID = "WS IPv6 SIP app"
15
+ def log_id
16
+ LOG_ID
17
+ end
18
+
19
+ end
20
+
21
+ end