oversip_p 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +22 -0
  3. data/LICENSE +25 -0
  4. data/README.md +43 -0
  5. data/Rakefile +54 -0
  6. data/bin/oversip +184 -0
  7. data/etc/oversip.conf +274 -0
  8. data/etc/proxies.conf +145 -0
  9. data/etc/server.rb +315 -0
  10. data/etc/tls/ca/cacert.pem +3894 -0
  11. data/etc/tls/demo-tls.oversip.net.crt +17 -0
  12. data/etc/tls/demo-tls.oversip.net.key +15 -0
  13. data/etc/tls/upgrade-cacert.sh +12 -0
  14. data/etc/tls/utils/create-cert.rb +162 -0
  15. data/etc/tls/utils/get-sip-identities.rb +95 -0
  16. data/ext/common/c_util.h +74 -0
  17. data/ext/common/ruby_c_util.h +88 -0
  18. data/ext/sip_parser/common_headers.h +210 -0
  19. data/ext/sip_parser/ext_help.h +18 -0
  20. data/ext/sip_parser/extconf.rb +3 -0
  21. data/ext/sip_parser/sip_message_parser.c +29741 -0
  22. data/ext/sip_parser/sip_parser.h +250 -0
  23. data/ext/sip_parser/sip_parser_ruby.c +1370 -0
  24. data/ext/sip_parser/sip_uri_parser.c +39699 -0
  25. data/ext/stud/extconf.rb +43 -0
  26. data/ext/stun/ext_help.h +16 -0
  27. data/ext/stun/extconf.rb +3 -0
  28. data/ext/stun/stun_ruby.c +394 -0
  29. data/ext/utils/ext_help.h +14 -0
  30. data/ext/utils/extconf.rb +3 -0
  31. data/ext/utils/haproxy_protocol.c +6163 -0
  32. data/ext/utils/haproxy_protocol.h +27 -0
  33. data/ext/utils/ip_utils.c +5952 -0
  34. data/ext/utils/ip_utils.h +64 -0
  35. data/ext/utils/outbound_utils.c +3227 -0
  36. data/ext/utils/outbound_utils.h +27 -0
  37. data/ext/utils/utils_ruby.c +392 -0
  38. data/ext/utils/utils_ruby.h +76 -0
  39. data/ext/websocket_framing_utils/ext_help.h +18 -0
  40. data/ext/websocket_framing_utils/extconf.rb +3 -0
  41. data/ext/websocket_framing_utils/ws_framing_utils.h +47 -0
  42. data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
  43. data/ext/websocket_http_parser/ext_help.h +18 -0
  44. data/ext/websocket_http_parser/extconf.rb +3 -0
  45. data/ext/websocket_http_parser/ws_http_parser.c +1635 -0
  46. data/ext/websocket_http_parser/ws_http_parser.h +87 -0
  47. data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
  48. data/lib/oversip/config.rb +597 -0
  49. data/lib/oversip/config_validators.rb +126 -0
  50. data/lib/oversip/default_server.rb +52 -0
  51. data/lib/oversip/errors.rb +10 -0
  52. data/lib/oversip/fiber_pool.rb +56 -0
  53. data/lib/oversip/launcher.rb +635 -0
  54. data/lib/oversip/logger.rb +84 -0
  55. data/lib/oversip/modules/outbound_mangling.rb +56 -0
  56. data/lib/oversip/modules/user_assertion.rb +73 -0
  57. data/lib/oversip/proxies_config.rb +189 -0
  58. data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
  59. data/lib/oversip/sip/client.rb +428 -0
  60. data/lib/oversip/sip/client_transaction.rb +586 -0
  61. data/lib/oversip/sip/constants.rb +88 -0
  62. data/lib/oversip/sip/core.rb +217 -0
  63. data/lib/oversip/sip/launcher.rb +221 -0
  64. data/lib/oversip/sip/listeners/connection.rb +54 -0
  65. data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
  66. data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +22 -0
  67. data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
  68. data/lib/oversip/sip/listeners/ipv4_tls_server.rb +22 -0
  69. data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +22 -0
  70. data/lib/oversip/sip/listeners/ipv4_udp_server.rb +21 -0
  71. data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
  72. data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +22 -0
  73. data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
  74. data/lib/oversip/sip/listeners/ipv6_tls_server.rb +22 -0
  75. data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +22 -0
  76. data/lib/oversip/sip/listeners/ipv6_udp_server.rb +21 -0
  77. data/lib/oversip/sip/listeners/tcp_client.rb +97 -0
  78. data/lib/oversip/sip/listeners/tcp_connection.rb +202 -0
  79. data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
  80. data/lib/oversip/sip/listeners/tls_client.rb +125 -0
  81. data/lib/oversip/sip/listeners/tls_server.rb +88 -0
  82. data/lib/oversip/sip/listeners/tls_tunnel_connection.rb +89 -0
  83. data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
  84. data/lib/oversip/sip/listeners/udp_connection.rb +214 -0
  85. data/lib/oversip/sip/listeners.rb +24 -0
  86. data/lib/oversip/sip/message.rb +177 -0
  87. data/lib/oversip/sip/message_processor.rb +213 -0
  88. data/lib/oversip/sip/name_addr.rb +51 -0
  89. data/lib/oversip/sip/proxy.rb +324 -0
  90. data/lib/oversip/sip/request.rb +179 -0
  91. data/lib/oversip/sip/response.rb +37 -0
  92. data/lib/oversip/sip/rfc3263.rb +643 -0
  93. data/lib/oversip/sip/server_transaction.rb +295 -0
  94. data/lib/oversip/sip/sip.rb +76 -0
  95. data/lib/oversip/sip/tags.rb +39 -0
  96. data/lib/oversip/sip/timers.rb +55 -0
  97. data/lib/oversip/sip/transport_manager.rb +130 -0
  98. data/lib/oversip/sip/uac.rb +89 -0
  99. data/lib/oversip/sip/uac_request.rb +84 -0
  100. data/lib/oversip/sip/uri.rb +208 -0
  101. data/lib/oversip/syslog.rb +68 -0
  102. data/lib/oversip/system_callbacks.rb +45 -0
  103. data/lib/oversip/tls.rb +172 -0
  104. data/lib/oversip/utils.rb +30 -0
  105. data/lib/oversip/version.rb +21 -0
  106. data/lib/oversip/websocket/constants.rb +55 -0
  107. data/lib/oversip/websocket/http_request.rb +59 -0
  108. data/lib/oversip/websocket/launcher.rb +183 -0
  109. data/lib/oversip/websocket/listeners/connection.rb +51 -0
  110. data/lib/oversip/websocket/listeners/ipv4_ws_server.rb +22 -0
  111. data/lib/oversip/websocket/listeners/ipv4_wss_server.rb +22 -0
  112. data/lib/oversip/websocket/listeners/ipv4_wss_tunnel_server.rb +22 -0
  113. data/lib/oversip/websocket/listeners/ipv6_ws_server.rb +22 -0
  114. data/lib/oversip/websocket/listeners/ipv6_wss_server.rb +22 -0
  115. data/lib/oversip/websocket/listeners/ipv6_wss_tunnel_server.rb +22 -0
  116. data/lib/oversip/websocket/listeners/ws_server.rb +331 -0
  117. data/lib/oversip/websocket/listeners/wss_server.rb +88 -0
  118. data/lib/oversip/websocket/listeners/wss_tunnel_server.rb +133 -0
  119. data/lib/oversip/websocket/listeners.rb +13 -0
  120. data/lib/oversip/websocket/websocket.rb +13 -0
  121. data/lib/oversip/websocket/ws_framing.rb +545 -0
  122. data/lib/oversip/websocket/ws_sip_app.rb +120 -0
  123. data/lib/oversip.rb +127 -0
  124. data/test/oversip_test_helper.rb +19 -0
  125. data/test/test_http_parser.rb +73 -0
  126. data/test/test_name_addr.rb +27 -0
  127. data/test/test_name_addr_parser.rb +24 -0
  128. data/test/test_sip_message_parser.rb +168 -0
  129. data/test/test_sip_uri_parser.rb +56 -0
  130. data/test/test_uri.rb +68 -0
  131. data/thirdparty/stud/stud.tar.gz +0 -0
  132. metadata +334 -0
@@ -0,0 +1,331 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class WsServer < Connection
4
+
5
+ # Max size (bytes) of the buffered data when receiving HTTP headers
6
+ # (avoid DoS attacks).
7
+ HEADERS_MAX_SIZE = 2048
8
+
9
+ WS_MAGIC_GUID_04 = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".freeze
10
+ WS_VERSIONS = { 7=>true, 8=>true, 13=>true }
11
+ HDR_SUPPORTED_WEBSOCKET_VERSIONS = [ "X-Supported-WebSocket-Versions: #{WS_VERSIONS.keys.join(", ")}" ]
12
+
13
+
14
+ attr_reader :outbound_flow_token
15
+ attr_writer :ws_established, :client_closed
16
+
17
+
18
+ def remote_ip_type
19
+ @remote_ip_type || self.class.ip_type
20
+ end
21
+
22
+ def remote_ip
23
+ @remote_ip
24
+ end
25
+
26
+ def remote_port
27
+ @remote_port
28
+ end
29
+
30
+ def transport
31
+ self.class.transport
32
+ end
33
+
34
+ def post_connection
35
+ begin
36
+ @remote_port, @remote_ip = ::Socket.unpack_sockaddr_in(get_peername)
37
+ rescue => e
38
+ log_system_error "error obtaining remote IP/port (#{e.class}: #{e.message}), closing connection"
39
+ close_connection
40
+ @state = :ignore
41
+ return
42
+ end
43
+
44
+ @connection_id = ::OverSIP::SIP::TransportManager.add_connection self, self.class, self.class.ip_type, @remote_ip, @remote_port
45
+
46
+ # Create an Outbound (RFC 5626) flow token for this connection.
47
+ @outbound_flow_token = ::OverSIP::SIP::TransportManager.add_outbound_connection self
48
+
49
+ log_system_debug("connection opened from " << remote_desc) if $oversip_debug
50
+ end
51
+
52
+
53
+ def remote_desc force=nil
54
+ if force
55
+ @remote_desc = case @remote_ip_type
56
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
57
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
58
+ end
59
+ else
60
+ @remote_desc ||= case self.class.ip_type
61
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
62
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
63
+ end
64
+ end
65
+ end
66
+
67
+
68
+ def unbind cause=nil
69
+ @state = :ignore
70
+
71
+ # Remove the connection.
72
+ self.class.connections.delete @connection_id
73
+
74
+ # Remove the Outbound token flow.
75
+ ::OverSIP::SIP::TransportManager.delete_outbound_connection @outbound_flow_token
76
+
77
+ @local_closed = true if cause == ::Errno::ETIMEDOUT
78
+ @local_closed = false if @client_closed
79
+
80
+ if $oversip_debug
81
+ log_msg = "connection from #{remote_desc} "
82
+ log_msg << ( @local_closed ? "locally closed" : "remotely closed" )
83
+ log_msg << " (cause: #{cause.inspect})" if cause
84
+ log_system_debug log_msg
85
+ end unless $!
86
+
87
+ if @ws_established
88
+ # Run OverSIP::WebSocketEvents.on_disconnection
89
+ ::Fiber.new do
90
+ begin
91
+ ::OverSIP::WebSocketEvents.on_disconnection self, !@local_closed
92
+ rescue ::Exception => e
93
+ log_system_error "error calling OverSIP::WebSocketEvents.on_disconnection():"
94
+ log_system_error e
95
+ end
96
+ end.resume
97
+ end unless $!
98
+ end
99
+
100
+
101
+ def receive_data data
102
+ @state == :ignore and return
103
+ @buffer << data
104
+ @state == :waiting_for_on_client_tls_handshake and return
105
+ @state == :waiting_for_on_connection and return
106
+
107
+ process_received_data
108
+ end
109
+
110
+ def process_received_data
111
+ @state == :ignore and return
112
+
113
+ while (case @state
114
+ when :init
115
+ @http_parser = ::OverSIP::WebSocket::HttpRequestParser.new
116
+ @http_request = ::OverSIP::WebSocket::HttpRequest.new
117
+ @http_parser_nbytes = 0
118
+ @bytes_remaining = 0
119
+ @state = :http_headers
120
+
121
+ when :http_headers
122
+ parse_http_headers
123
+
124
+ when :check_http_request
125
+ check_http_request
126
+
127
+ when :on_connection_callback
128
+ do_on_connection_callback
129
+ false
130
+
131
+ when :accept_ws_handshake
132
+ accept_ws_handshake
133
+
134
+ when :websocket
135
+ @ws_established = true
136
+ @ws_framing.receive_data
137
+ false
138
+
139
+ when :ignore
140
+ false
141
+ end)
142
+ end # while
143
+
144
+ end
145
+
146
+
147
+ def parse_http_headers
148
+ return false if @buffer.empty?
149
+
150
+ # Parse the currently buffered data. If parsing fails @http_parser_nbytes gets nil value.
151
+ unless @http_parser_nbytes = @http_parser.execute(@http_request, @buffer.to_str, @http_parser_nbytes)
152
+ log_system_warn "parsing error: \"#{@http_parser.error}\""
153
+ close_connection_after_writing
154
+ @state = :ignore
155
+ return false
156
+ end
157
+
158
+ # Avoid flood attacks in TCP (very long headers).
159
+ if @http_parser_nbytes > HEADERS_MAX_SIZE
160
+ log_system_warn "DoS attack detected: headers size exceedes #{HEADERS_MAX_SIZE} bytes, closing connection with #{remote_desc}"
161
+ close_connection
162
+ @state = :ignore
163
+ return false
164
+ end
165
+
166
+ return false unless @http_parser.finished?
167
+
168
+ # Clear parsed data from the buffer.
169
+ @buffer.read(@http_parser_nbytes)
170
+
171
+ @http_request.connection = self
172
+
173
+ @state = :check_http_request
174
+ true
175
+ end # parse_headers
176
+
177
+
178
+ def check_http_request
179
+ # Check OverSIP status.
180
+ unless ::OverSIP.status == :running
181
+ case ::OverSIP.status
182
+ when :loading
183
+ http_reject 500, "Server Still Loading", [ "Retry-After: 5" ]
184
+ when :terminating
185
+ http_reject 500, "Server is Being Stopped"
186
+ end
187
+ return false
188
+ end
189
+
190
+ # HTTP method must be GET.
191
+ if @http_request.http_method != :GET
192
+ log_system_notice "rejecting HTTP #{@http_request.http_method} request => 405"
193
+ http_reject 405
194
+ return false
195
+ end
196
+
197
+ # "Sec-WebSocket-Version" must be 8.
198
+ unless WS_VERSIONS[@http_request.hdr_sec_websocket_version]
199
+ if @http_request.hdr_sec_websocket_version
200
+ log_system_notice "WebSocket version #{@http_request.hdr_sec_websocket_version} not implemented => 426"
201
+ else
202
+ log_system_notice "WebSocket version header not present => 426"
203
+ end
204
+ http_reject 426, nil, HDR_SUPPORTED_WEBSOCKET_VERSIONS
205
+ return false
206
+ end
207
+
208
+ # Connection header must include "upgrade".
209
+ unless @http_request.hdr_connection and @http_request.hdr_connection.include? "upgrade"
210
+ log_system_notice "Connection header must include \"upgrade\" => 400"
211
+ http_reject 400, "Connection header must include \"upgrade\""
212
+ return false
213
+ end
214
+
215
+ # "Upgrade: websocket" is required.
216
+ unless @http_request.hdr_upgrade == "websocket"
217
+ log_system_notice "Upgrade header must be \"websocket\" => 400"
218
+ http_reject 400, "Upgrade header must be \"websocket\""
219
+ return false
220
+ end
221
+
222
+ # Sec-WebSocket-Key is required.
223
+ unless @http_request.hdr_sec_websocket_key
224
+ log_system_notice "Sec-WebSocket-Key header not present => 400"
225
+ http_reject 400, "Sec-WebSocket-Key header not present"
226
+ return false
227
+ end
228
+
229
+ # Check Sec-WebSocket-Protocol.
230
+ if @http_request.hdr_sec_websocket_protocol
231
+ if @http_request.hdr_sec_websocket_protocol.include? WS_SIP_PROTOCOL
232
+ @websocket_protocol_negotiated = true
233
+ else
234
+ log_system_notice "Sec-WebSocket-Protocol does not contain a supported protocol but #{@http_request.hdr_sec_websocket_protocol} => 501"
235
+ http_reject 501, "No Suitable WebSocket Protocol"
236
+ return false
237
+ end
238
+ end
239
+
240
+ @state = :on_connection_callback
241
+ true
242
+ end
243
+
244
+
245
+ def do_on_connection_callback
246
+ # Set the state to :waiting_for_on_connection so data received before
247
+ # user callback validation is just stored.
248
+ @state = :waiting_for_on_connection
249
+
250
+ # Run OverSIP::WebSocketEvents.on_connection.
251
+ ::Fiber.new do
252
+ begin
253
+ log_system_debug "running OverSIP::WebSocketEvents.on_connection()..." if $oversip_debug
254
+ ::OverSIP::WebSocketEvents.on_connection self, @http_request
255
+ # If the user of the peer has not closed the connection then continue.
256
+ unless @local_closed or error?
257
+ @state = :accept_ws_handshake
258
+ # Call process_received_data() to process possible data received in the meanwhile.
259
+ process_received_data
260
+ else
261
+ log_system_debug "connection closed during OverSIP::WebSocketEvents.on_connection(), aborting" if $oversip_debug
262
+ end
263
+
264
+ rescue ::Exception => e
265
+ log_system_error "error calling OverSIP::WebSocketEvents.on_connection() => 500:"
266
+ log_system_error e
267
+ http_reject 500
268
+ end
269
+ end.resume
270
+ end
271
+
272
+
273
+ def accept_ws_handshake
274
+ sec_websocket_accept = Digest::SHA1::base64digest @http_request.hdr_sec_websocket_key + WS_MAGIC_GUID_04
275
+
276
+ extra_headers = [
277
+ "Upgrade: websocket",
278
+ "Connection: Upgrade",
279
+ "Sec-WebSocket-Accept: #{sec_websocket_accept}"
280
+ ]
281
+
282
+ if @websocket_protocol_negotiated
283
+ extra_headers << "Sec-WebSocket-Protocol: #{WS_SIP_PROTOCOL}"
284
+ end
285
+
286
+ if @websocket_extensions
287
+ extra_headers << "Sec-WebSocket-Extensions: #{@websocket_extensions.to_s}"
288
+ end
289
+
290
+ @http_request.reply 101, nil, extra_headers
291
+
292
+ # Set the WS framing layer and WS application layer.
293
+ @ws_framing = ::OverSIP::WebSocket::WsFraming.new self, @buffer
294
+ ws_sip_app = ::OverSIP::WebSocket::WsSipApp.new self, @ws_framing
295
+ @ws_framing.ws_app = ws_sip_app
296
+
297
+ @state = :websocket
298
+ true
299
+ end
300
+
301
+
302
+ def http_reject status_code=403, reason_phrase=nil, extra_headers=nil
303
+ @http_request.reply(status_code, reason_phrase, extra_headers)
304
+ close_connection_after_writing
305
+ @state = :ignore
306
+ end
307
+
308
+
309
+ # Parameters ip and port are just included because they are needed in UDP, so the API remains equal.
310
+ def send_sip_msg msg, ip=nil, port=nil
311
+ if self.error?
312
+ log_system_notice "SIP message could not be sent, connection is closed"
313
+ return false
314
+ end
315
+
316
+ # If the SIP message is fully valid UTF-8 send a WS text frame.
317
+ if msg.force_encoding(::Encoding::UTF_8).valid_encoding?
318
+ @ws_framing.send_text_frame msg
319
+
320
+ # If not, send a WS binary frame.
321
+ else
322
+ @ws_framing.send_binary_frame msg
323
+ end
324
+
325
+ true
326
+ end
327
+
328
+ end
329
+
330
+ end
331
+
@@ -0,0 +1,88 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class WssServer < WsServer
4
+
5
+ TLS_HANDSHAKE_MAX_TIME = 4
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
+ :ssl_version => %w(sslv2) # USE SSL instead of TLS. TODO: yes?
17
+ })
18
+
19
+ # If the remote client does never send us a TLS certificate
20
+ # after the TCP connection we would leak by storing more and
21
+ # more messages in @pending_messages array.
22
+ @timer_tls_handshake = ::EM::Timer.new(TLS_HANDSHAKE_MAX_TIME) do
23
+ unless @connected
24
+ log_system_notice "TLS handshake not performed within #{TLS_HANDSHAKE_MAX_TIME} seconds, closing the connection"
25
+ close_connection
26
+ end
27
+ end
28
+ end
29
+
30
+
31
+ def ssl_verify_peer pem
32
+ # TODO: Dirty workaround for bug https://github.com/eventmachine/eventmachine/issues/194.
33
+ return true if @client_last_pem == pem
34
+
35
+ @client_last_pem = pem
36
+ @client_pems << pem
37
+
38
+ log_system_debug "received certificate num #{@client_pems.size} from client" if $oversip_debug
39
+
40
+ # Validation must be done in ssl_handshake_completed after receiving all the certs, so return true.
41
+ return true
42
+ end
43
+
44
+
45
+ def ssl_handshake_completed
46
+ log_system_debug ("TLS connection established from " << remote_desc) if $oversip_debug
47
+
48
+ # @connected in WssServer means "TLS connection" rather than
49
+ # just "TCP connection".
50
+ @connected = true
51
+ @timer_tls_handshake.cancel if @timer_tls_handshake
52
+
53
+ if ::OverSIP::WebSocket.callback_on_client_tls_handshake
54
+ # Set the state to :waiting_for_on_client_tls_handshake so data received after TLS handshake but before
55
+ # user callback validation is just stored.
56
+ @state = :waiting_for_on_client_tls_handshake
57
+
58
+ # Run OverSIP::WebSocketEvents.on_client_tls_handshake.
59
+ ::Fiber.new do
60
+ begin
61
+ log_system_debug "running OverSIP::SipWebSocketEvents.on_client_tls_handshake()..." if $oversip_debug
62
+ ::OverSIP::WebSocketEvents.on_client_tls_handshake self, @client_pems
63
+ # If the user of the peer has not closed the connection then continue.
64
+ unless @local_closed or error?
65
+ @state = :init
66
+ # Call process_received_data() to process possible data received in the meanwhile.
67
+ process_received_data
68
+ else
69
+ log_system_debug "connection closed during OverSIP::SipWebSocketEvents.on_client_tls_handshake(), aborting" if $oversip_debug
70
+ end
71
+
72
+ rescue ::Exception => e
73
+ log_system_error "error calling OverSIP::WebSocketEvents.on_client_tls_handshake():"
74
+ log_system_error e
75
+ close_connection
76
+ end
77
+ end.resume
78
+ end
79
+ end
80
+
81
+
82
+ def unbind cause=nil
83
+ @timer_tls_handshake.cancel if @timer_tls_handshake
84
+ super
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,133 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class WssTunnelServer < WsServer
4
+
5
+ def post_connection
6
+ begin
7
+ # Temporal @remote_ip and @remote_port until the HAProxy protocol line is parsed.
8
+ @remote_port, @remote_ip = ::Socket.unpack_sockaddr_in(get_peername)
9
+ rescue => e
10
+ log_system_error "error obtaining remote IP/port (#{e.class}: #{e.message}), closing connection"
11
+ close_connection
12
+ @state = :ignore
13
+ return
14
+ end
15
+
16
+ # Create an Outbound (RFC 5626) flow token for this connection.
17
+ @outbound_flow_token = ::OverSIP::SIP::TransportManager.add_outbound_connection self
18
+
19
+ log_system_debug ("connection from the TLS tunnel " << remote_desc) if $oversip_debug
20
+ end
21
+
22
+
23
+ def unbind cause=nil
24
+ @state = :ignore
25
+
26
+ # Remove the connection.
27
+ self.class.connections.delete @connection_id if @connection_id
28
+
29
+ # Remove the Outbound token flow.
30
+ ::OverSIP::SIP::TransportManager.delete_outbound_connection @outbound_flow_token
31
+
32
+ @local_closed = true if cause == ::Errno::ETIMEDOUT
33
+ @local_closed = false if @client_closed
34
+
35
+ if $oversip_debug
36
+ log_msg = "connection from the TLS tunnel #{remote_desc} "
37
+ log_msg << ( @local_closed ? "locally closed" : "remotely closed" )
38
+ log_msg << " (cause: #{cause.inspect})" if cause
39
+ log_system_debug log_msg
40
+ end unless $!
41
+
42
+ if @ws_established
43
+ # Run OverSIP::WebSocketEvents.on_disconnection
44
+ ::Fiber.new do
45
+ begin
46
+ ::OverSIP::WebSocketEvents.on_disconnection self, !@local_closed
47
+ rescue ::Exception => e
48
+ log_system_error "error calling OverSIP::WebSocketEvents.on_disconnection():"
49
+ log_system_error e
50
+ end
51
+ end.resume
52
+ end unless $!
53
+ end
54
+
55
+
56
+ def process_received_data
57
+ @state == :ignore and return
58
+
59
+ while (case @state
60
+ when :init
61
+ @http_parser = ::OverSIP::WebSocket::HttpRequestParser.new
62
+ @http_request = ::OverSIP::WebSocket::HttpRequest.new
63
+ @http_parser.reset
64
+ @http_parser_nbytes = 0
65
+ @bytes_remaining = 0
66
+ # If it's a TCP connection from the TLS proxy then parse the HAProxy Protocol line
67
+ # if it's not yet done.
68
+ unless @haproxy_protocol_parsed
69
+ @state = :haproxy_protocol
70
+ else
71
+ @state = :http_headers
72
+ end
73
+
74
+ when :haproxy_protocol
75
+ parse_haproxy_protocol
76
+
77
+ when :http_headers
78
+ parse_http_headers
79
+
80
+ when :check_http_request
81
+ check_http_request
82
+
83
+ when :on_connection_callback
84
+ do_on_connection_callback
85
+ false
86
+
87
+ when :accept_ws_handshake
88
+ accept_ws_handshake
89
+
90
+ when :websocket
91
+ @ws_established = true
92
+ return false if @buffer.size.zero?
93
+ @ws_framing.receive_data
94
+ false
95
+
96
+ when :ignore
97
+ false
98
+ end)
99
+ end # while
100
+
101
+ end
102
+
103
+
104
+ def parse_haproxy_protocol
105
+ if (haproxy_protocol_data = ::OverSIP::Utils.parse_haproxy_protocol(@buffer.to_str))
106
+ @haproxy_protocol_parsed = true
107
+
108
+ # Update connection information.
109
+ @remote_ip_type = haproxy_protocol_data[1]
110
+ @remote_ip = haproxy_protocol_data[2]
111
+ @remote_port = haproxy_protocol_data[3]
112
+
113
+ # Update log information.
114
+ remote_desc true
115
+
116
+ # Remove the HAProxy Protocol line from the received data.
117
+ @buffer.read haproxy_protocol_data[0]
118
+
119
+ @state = :http_headers
120
+
121
+ # If parsing fails then the TLS proxy has sent us a wrong HAProxy Protocol line ¿?
122
+ else
123
+ log_system_error "HAProxy Protocol parsing error, closing connection"
124
+ close_connection_after_writing
125
+ @state = :ignore
126
+ return false
127
+ end
128
+ end
129
+
130
+ end
131
+
132
+ end
133
+
@@ -0,0 +1,13 @@
1
+ # OverSIP files
2
+
3
+ require "oversip/websocket/listeners/connection"
4
+ require "oversip/websocket/listeners/ws_server"
5
+ require "oversip/websocket/listeners/wss_server"
6
+ require "oversip/websocket/listeners/wss_tunnel_server"
7
+
8
+ require "oversip/websocket/listeners/ipv4_ws_server"
9
+ require "oversip/websocket/listeners/ipv6_ws_server"
10
+ require "oversip/websocket/listeners/ipv4_wss_server"
11
+ require "oversip/websocket/listeners/ipv6_wss_server"
12
+ require "oversip/websocket/listeners/ipv4_wss_tunnel_server"
13
+ require "oversip/websocket/listeners/ipv6_wss_tunnel_server"
@@ -0,0 +1,13 @@
1
+ module OverSIP::WebSocket
2
+
3
+ def self.module_init
4
+ conf = ::OverSIP.configuration
5
+
6
+ @callback_on_client_tls_handshake = conf[:websocket][:callback_on_client_tls_handshake]
7
+ end
8
+
9
+ def self.callback_on_client_tls_handshake
10
+ @callback_on_client_tls_handshake
11
+ end
12
+
13
+ end