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,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
+