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.
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,185 @@
1
+ module OverSIP::SIP
2
+
3
+ class TcpReactor < Reactor
4
+
5
+ # Max size (bytes) of the buffered data when receiving message headers
6
+ # (avoid DoS attacks).
7
+ HEADERS_MAX_SIZE = 16384
8
+
9
+ def receive_data data
10
+ @state == :ignore and return
11
+ @buffer << data
12
+
13
+ while (case @state
14
+ when :init
15
+ @parser.reset
16
+ @parser_nbytes = 0
17
+ @state = :headers
18
+
19
+ when :headers
20
+ parse_headers
21
+ # TODO: Add a timer for the case in which an attacker sends us slow headers that never end:
22
+ # http://ha.ckers.org/slowloris/.
23
+
24
+ when :body
25
+ get_body
26
+
27
+ when :finished
28
+ # Invoke the custom logic for requests.
29
+ if @msg.request?
30
+ process_request
31
+ else
32
+ process_response
33
+ end
34
+
35
+ # Set state to :init.
36
+ @state = :init
37
+ # Return true to continue processing possible remaining data.
38
+ true
39
+
40
+ when :ignore
41
+ false
42
+ end)
43
+ end # while
44
+
45
+ end
46
+
47
+ def parse_headers
48
+ return false if @buffer.empty?
49
+
50
+ # Parse the currently buffered data. If parsing fails @parser_nbytes gets nil value.
51
+ unless @parser_nbytes = @parser.execute(@buffer.to_str, @parser_nbytes)
52
+ # The parsed data is invalid, however some data could be parsed so @parsed.parsed
53
+ # can be:
54
+ # - SIP::Request
55
+ # - SIP::Response
56
+ # - nil (the message is so wrong that cannot be neither a request or response).
57
+ if wrong_message = @parser.parsed
58
+ log_system_warn "parsing error for #{MSG_TYPE[wrong_message.class]}: \"#{@parser.error}\""
59
+ else
60
+ log_system_warn "parsing error: \"#{@parser.error}\""
61
+ end
62
+
63
+ close_connection_after_writing
64
+ @state = :ignore
65
+ return false
66
+ end
67
+
68
+ # Avoid flood attacks in TCP (very long headers).
69
+ if @parser_nbytes > HEADERS_MAX_SIZE
70
+ log_system_warn "DoS attack detected: headers size exceedes #{HEADERS_MAX_SIZE} bytes, closing connection with #{remote_desc}"
71
+ close_connection
72
+ # After closing client connection some data can still arrrive to "receive_data()"
73
+ # (explained in EM documentation). By setting @state = :ignore we ensure such
74
+ # remaining data is not processed.
75
+ @state = :ignore
76
+ return false
77
+ end
78
+
79
+ # If the parsing has not finished, it is correct in TCP so return false and wait for more data under :headers state.
80
+ return false unless @parser.finished?
81
+
82
+ # At this point we've got a SIP::Request, SIP::Response or :outbound_keepalive symbol.
83
+ @msg = @parser.parsed
84
+
85
+ # Clear parsed data from the buffer.
86
+ @buffer.read(@parser_nbytes)
87
+
88
+ # Received data is a Outbound keealive.
89
+ if @msg == :outbound_keepalive
90
+ log_system_debug "Outbound keepalive received, replying single CRLF" if $oversip_debug
91
+ # Reply a single CRLF over the same connection.
92
+ send_data CRLF
93
+ # If TCP then go back to :init state so possible remaining data would be processed.
94
+ @state = :init
95
+ return true
96
+ end
97
+
98
+ @parser.post_parsing
99
+
100
+ # Here we have received the entire headers of a SIP request or response. Fill some
101
+ # attributes.
102
+ @msg.connection = self
103
+ @msg.transport = self.class.transport
104
+ @msg.source_ip = @remote_ip
105
+ @msg.source_port = @remote_port
106
+ @msg.source_ip_type = @remote_ip_type || self.class.ip_type
107
+
108
+ unless valid_message?
109
+ close_connection_after_writing
110
+ @state = :ignore
111
+ return false
112
+ end
113
+
114
+ add_via_received_rport if @msg.request?
115
+
116
+ unless check_via_branch
117
+ close_connection_after_writing
118
+ @state = :ignore
119
+ return false
120
+ end
121
+
122
+ # Examine Content-Length header.
123
+ # In SIP over TCP Content-Length header is mandatory.
124
+ if (@body_length = @msg.content_length)
125
+ # There is body (or should be).
126
+ if @body_length > 0
127
+ @state = :body
128
+ # Return true to continue in get_body() method.
129
+ return true
130
+ # No body.
131
+ else
132
+ # Set :finished state and return true to process the parsed message.
133
+ @state = :finished
134
+ return true
135
+ end
136
+ # No Content-Length, invalid message!
137
+ else
138
+ # Log it and reply a 400 Bad Request (if it's a request).
139
+ # Close the connection, set :ignore state and return false to leave
140
+ # receive_data().
141
+ if @msg.request?
142
+ unless @msg.sip_method == :ACK
143
+ log_system_warn "request body size doesn't match Content-Length => 400"
144
+ @msg.reply 400, "Body size doesn't match Content-Length"
145
+ else
146
+ log_system_warn "ACK body size doesn't match Content-Length, ignoring it"
147
+ end
148
+ else
149
+ log_system_warn "response has not Content-Length header, ignoring it"
150
+ end
151
+ close_connection_after_writing
152
+ @state = :ignore
153
+ return false
154
+ end
155
+ end # parse_headers
156
+
157
+ def get_body
158
+ # Return false until the buffer gets all the body.
159
+ return false if @buffer.size < @body_length
160
+
161
+ ### TODO: Creo que es mejor forzarlo a BINARY y no a UTF-8. Aunque IOBuffer ya lo saca siempre en BINARY.
162
+ # ¿Por qué lo forcé a UTF-8?
163
+ # RESPUESTA: Si no lo hago y resulta que el body no es UTF-8 válido, al añadir el body a los headers (que
164
+ # se generan como un string en UTF-8 (aunque contengan símbolos no UTF-8) fallaría. O todo UTF-8 (aunque
165
+ # tenga símbolos inválidos) o todo BINARY.
166
+ @msg.body = @buffer.read(@body_length).force_encoding(::Encoding::UTF_8)
167
+ @state = :finished
168
+ return true
169
+ end
170
+
171
+
172
+ # Parameters ip and port are just included because they are needed in UDP, so the API remains equal.
173
+ def send_sip_msg msg, ip=nil, port=nil
174
+ if self.error?
175
+ log_system_notice "SIP message could not be sent, connection is closed"
176
+ return false
177
+ end
178
+ send_data msg
179
+ true
180
+ end
181
+
182
+ end
183
+
184
+ end
185
+
@@ -0,0 +1,71 @@
1
+ module OverSIP::SIP
2
+
3
+ class TcpServer < TcpReactor
4
+
5
+ attr_reader :outbound_flow_token
6
+
7
+ def post_connection
8
+ begin
9
+ @remote_port, @remote_ip = ::Socket.unpack_sockaddr_in(get_peername)
10
+ rescue => e
11
+ log_system_error "error obtaining remote IP/port (#{e.class}: #{e.message}), closing connection"
12
+ close_connection
13
+ @state = :ignore
14
+ return
15
+ end
16
+
17
+ log_system_info "connection opened from " << remote_desc
18
+
19
+ @connection_id = ::OverSIP::SIP::TransportManager.add_connection self, self.class, self.class.ip_type, @remote_ip, @remote_port
20
+
21
+ # Create an Outbound (RFC 5626) flow token for this connection.
22
+ @outbound_flow_token = ::OverSIP::SIP::TransportManager.add_outbound_connection self
23
+
24
+ ### Testing TCP keepalive.
25
+ # https://github.com/bklang/eventmachine/commit/74c65a56c733bc1b6f092e32a9f0d722501ade46
26
+ # http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/
27
+ if ::OverSIP::SIP.tcp_keepalive_interval
28
+ set_sock_opt Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true
29
+ set_sock_opt Socket::SOL_TCP, Socket::TCP_KEEPIDLE, ::OverSIP::SIP.tcp_keepalive_interval # First TCP ping.
30
+ set_sock_opt Socket::SOL_TCP, Socket::TCP_KEEPINTVL, ::OverSIP::SIP.tcp_keepalive_interval # Interval between TCP pings.
31
+ end
32
+ end
33
+
34
+ def remote_desc force=nil
35
+ if force
36
+ @remote_desc = case @remote_ip_type
37
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
38
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
39
+ end
40
+ else
41
+ @remote_desc ||= case self.class.ip_type
42
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
43
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
44
+ end
45
+ end
46
+ end
47
+
48
+
49
+ def unbind cause=nil
50
+ @state = :ignore
51
+
52
+ # Remove the connection.
53
+ self.class.connections.delete @connection_id
54
+
55
+ # Remove the Outbound token flow.
56
+ ::OverSIP::SIP::TransportManager.delete_outbound_connection @outbound_flow_token
57
+
58
+ @local_closed = true if cause == ::Errno::ETIMEDOUT
59
+
60
+ if $oversip_debug
61
+ log_msg = "connection from #{remote_desc} "
62
+ log_msg << ( @local_closed ? "locally closed" : "remotely closed" )
63
+ log_msg << " (cause: #{cause.inspect})" if cause
64
+ log_system_debug log_msg
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
@@ -0,0 +1,117 @@
1
+ module OverSIP::SIP
2
+
3
+ class TlsClient < TcpClient
4
+
5
+ TLS_HANDSHAKE_MAX_TIME = 4
6
+
7
+
8
+ attr_writer :tls_validation
9
+
10
+
11
+ def initialize ip, port
12
+ super
13
+ @pending_messages = []
14
+ end
15
+
16
+
17
+ def connection_completed
18
+ @server_pems = []
19
+ @server_last_pem = false
20
+
21
+ start_tls({
22
+ :verify_peer => @tls_validation,
23
+ :cert_chain_file => ::OverSIP.tls_public_cert,
24
+ :private_key_file => ::OverSIP.tls_private_cert
25
+ })
26
+
27
+ # If the remote server does never send us a TLS certificate
28
+ # after the TCP connection we would leak by storing more and
29
+ # more messages in @pending_messages array.
30
+ @timer_tls_handshake = ::EM::Timer.new(TLS_HANDSHAKE_MAX_TIME) do
31
+ unless @connected
32
+ log_system_notice "TLS handshake not performed within #{TLS_HANDSHAKE_MAX_TIME} seconds, closing the connection"
33
+ close_connection
34
+ end
35
+ end
36
+ end
37
+
38
+
39
+ # Called for every certificate provided by the peer.
40
+ # This is just called in case @tls_validation is true.
41
+ def ssl_verify_peer pem
42
+ # TODO: Dirty workaround for bug https://github.com/eventmachine/eventmachine/issues/194.
43
+ return true if @server_last_pem == pem
44
+
45
+ @server_last_pem = pem
46
+ @server_pems << pem
47
+
48
+ log_system_debug "received certificate num #{@server_pems.size} from server" if $oversip_debug
49
+
50
+ # Validation must be done in ssl_handshake_completed after receiving all the certs, so return true.
51
+ return true
52
+ end
53
+
54
+
55
+ # This is called after all the calls to ssl_verify_peer().
56
+ def ssl_handshake_completed
57
+ log_system_info "TLS connection established to " << remote_desc
58
+
59
+ # @connected in TlsClient means "TLS connection" rather than
60
+ # just "TCP connection".
61
+ @connected = true
62
+ @timer_tls_handshake.cancel if @timer_tls_handshake
63
+
64
+ if @tls_validation
65
+ validated, cert, tls_error, tls_error_string = ::OverSIP::TLS.validate @server_pems.pop, @server_pems
66
+ if validated
67
+ log_system_info "server provides a valid TLS certificate"
68
+ sip_identities = ::OverSIP::TLS.get_sip_identities(cert)
69
+ log_system_debug "SIP identities in peer cert: #{sip_identities.keys}" if $oversip_debug
70
+ else
71
+ log_system_notice "server's TLS certificate validation failed (TLS error: #{tls_error.inspect}, description: #{tls_error_string.inspect})"
72
+ @pending_client_transactions.each do |client_transaction|
73
+ client_transaction.tls_validation_failed
74
+ end
75
+ @pending_client_transactions.clear
76
+ @pending_messages.clear
77
+ close_connection
78
+ @state = :ignore
79
+ return
80
+ end
81
+ end
82
+
83
+ @pending_client_transactions.clear
84
+ @pending_messages.each do |msg|
85
+ send_data msg
86
+ end
87
+ @pending_messages.clear
88
+ end
89
+
90
+ def unbind cause=nil
91
+ super
92
+ @timer_tls_handshake.cancel if @timer_tls_handshake
93
+ @pending_messages.clear
94
+ end
95
+
96
+ # In TLS client, we must wait until ssl_handshake_completed is
97
+ # completed before sending data. If not, data will be sent in
98
+ # plain TCP.
99
+ # http://dev.sipdoc.net/issues/457
100
+ def send_sip_msg msg, ip=nil, port=nil
101
+ if self.error?
102
+ log_system_notice "SIP message could not be sent, connection is closed"
103
+ return false
104
+ end
105
+
106
+ if @connected
107
+ send_data msg
108
+ else
109
+ log_system_debug "TLS handshake not completed yet, waiting before sending the message" if $oversip_debug
110
+ @pending_messages << msg
111
+ end
112
+ true
113
+ end
114
+
115
+ end
116
+
117
+ end
@@ -0,0 +1,70 @@
1
+ module OverSIP::SIP
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
70
+
@@ -0,0 +1,113 @@
1
+ module OverSIP::SIP
2
+
3
+ class TlsTunnelReactor < TcpReactor
4
+
5
+ # Max size (bytes) of the buffered data when receiving message headers
6
+ # (avoid DoS attacks).
7
+ HEADERS_MAX_SIZE = 16384
8
+
9
+ def receive_data data
10
+ @state == :ignore and return
11
+ @buffer << data
12
+
13
+ while (case @state
14
+ when :init
15
+ @parser.reset
16
+ @parser_nbytes = 0
17
+ # If it's a TCP connection from the TLS tunnel then parse the HAProxy Protocol line
18
+ # if it's not yet done.
19
+ unless @haproxy_protocol_parsed
20
+ @state = :haproxy_protocol
21
+ else
22
+ @state = :headers
23
+ end
24
+
25
+ when :haproxy_protocol
26
+ parse_haproxy_protocol
27
+
28
+ when :client_pems
29
+ parse_client_pems
30
+
31
+ when :headers
32
+ parse_headers
33
+
34
+ when :body
35
+ get_body
36
+
37
+ when :finished
38
+ # Invoke the custom logic for requests.
39
+ if @msg.request?
40
+ process_request
41
+ else
42
+ process_response
43
+ end
44
+
45
+ # Set state to :init.
46
+ @state = :init
47
+ # Return true to continue processing possible remaining data.
48
+ true
49
+
50
+ when :ignore
51
+ false
52
+ end)
53
+ end # while
54
+
55
+ end
56
+
57
+ def parse_haproxy_protocol
58
+ if (haproxy_protocol_data = ::OverSIP::Utils.parse_haproxy_protocol(@buffer.to_str))
59
+ @haproxy_protocol_parsed = true
60
+
61
+ # Update connection information.
62
+ @remote_ip_type = haproxy_protocol_data[1]
63
+ @remote_ip = haproxy_protocol_data[2]
64
+ @remote_port = haproxy_protocol_data[3]
65
+
66
+ # Add the connection with the client's source data. Note that we pass a TlsServer as class, but
67
+ # the server instance is a TcpServer.
68
+ @connection_id = case @remote_ip_type
69
+ when :ipv4
70
+ ::OverSIP::SIP::TransportManager.add_connection self, ::OverSIP::SIP::IPv4TlsServer, :ipv4, @remote_ip, @remote_port
71
+ when :ipv6
72
+ ::OverSIP::SIP::TransportManager.add_connection self, ::OverSIP::SIP::IPv6TlsServer, :ipv6, @remote_ip, @remote_port
73
+ end
74
+
75
+ # Update log information.
76
+ remote_desc true
77
+
78
+ # Remove the HAProxy Protocol line from the received data.
79
+ @buffer.read haproxy_protocol_data[0]
80
+
81
+ @state = :headers
82
+
83
+ else
84
+ log_system_error "HAProxy Protocol parsing error, closing connection"
85
+ close_connection_after_writing
86
+ @state = :ignore
87
+ return false
88
+ end
89
+ end
90
+
91
+ # TODO: Not terminated yet.
92
+ def parse_client_pems
93
+ # TODO: Wrong, it could occur that here the last PEMs byte arries.
94
+ return false if @buffer.size < 3 # 3 bytes = 0\r\n (minimum data).
95
+
96
+ @pems_str ||= ""
97
+ @pems_str << @buffer.read(2)
98
+
99
+ # No PEMS.
100
+ if @pems_str == "\r\n"
101
+ @state = :headers
102
+ return true
103
+ end
104
+
105
+ #@pem_size_str =
106
+
107
+ @state = :headers
108
+ end
109
+
110
+ end
111
+
112
+ end
113
+
@@ -0,0 +1,61 @@
1
+ module OverSIP::SIP
2
+
3
+ class TlsTunnelServer < TlsTunnelReactor
4
+
5
+ attr_reader :outbound_flow_token
6
+
7
+ def post_connection
8
+ begin
9
+ # Temporal @remote_ip and @remote_port until the HAProxy protocol line is parsed.
10
+ @remote_port, @remote_ip = ::Socket.unpack_sockaddr_in(get_peername)
11
+ rescue => e
12
+ log_system_error "error obtaining remote IP/port (#{e.class}: #{e.message}), closing connection"
13
+ close_connection
14
+ @state = :ignore
15
+ return
16
+ end
17
+
18
+ log_system_debug "connection from the TLS tunnel " << remote_desc
19
+
20
+ # Create an Outbound (RFC 5626) flow token for this connection.
21
+ @outbound_flow_token = ::OverSIP::SIP::TransportManager.add_outbound_connection self
22
+ end
23
+
24
+ def remote_desc force=nil
25
+ if force
26
+ @remote_desc = case @remote_ip_type
27
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
28
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
29
+ end
30
+ else
31
+ @remote_desc ||= case self.class.ip_type
32
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
33
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
34
+ end
35
+ end
36
+ end
37
+
38
+
39
+ def unbind cause=nil
40
+ @state = :ignore
41
+
42
+ # Remove the connection.
43
+ self.class.connections.delete @connection_id if @connection_id
44
+
45
+ # Remove the Outbound token flow.
46
+ ::OverSIP::SIP::TransportManager.delete_outbound_connection @outbound_flow_token
47
+
48
+ @local_closed = true if cause == ::Errno::ETIMEDOUT
49
+
50
+ if $oversip_debug
51
+ log_msg = "connection from the TLS tunnel #{remote_desc} "
52
+ log_msg << ( @local_closed ? "locally closed" : "remotely closed" )
53
+ log_msg << " (cause: #{cause.inspect})" if cause
54
+ log_system_debug log_msg
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+