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,22 @@
1
+ module OverSIP::SIP
2
+
3
+ class IPv6TlsServer < TlsServer
4
+
5
+ @ip_type = :ipv6
6
+ @transport = :tls
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
+ @is_outbound_listener = true
14
+
15
+ LOG_ID = "SIP TLS IPv6 server"
16
+ def log_id
17
+ LOG_ID
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,22 @@
1
+ module OverSIP::SIP
2
+
3
+ class IPv6TlsTunnelServer < TlsTunnelServer
4
+
5
+ @ip_type = :ipv6
6
+ @transport = :tls
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
+ @is_outbound_listener = true
14
+
15
+ LOG_ID = "SIP TLS-Tunnel IPv6 server"
16
+ def log_id
17
+ LOG_ID
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,21 @@
1
+ module OverSIP::SIP
2
+
3
+ class IPv6UdpServer < UdpConnection
4
+
5
+ @ip_type = :ipv6
6
+ @transport = :udp
7
+ @connections = nil # To be set after creating the unique server instance.
8
+ @invite_server_transactions = {}
9
+ @non_invite_server_transactions = {}
10
+ @invite_client_transactions = {}
11
+ @non_invite_client_transactions = {}
12
+ @is_outbound_listener = true
13
+
14
+ LOG_ID = "SIP UDP IPv6 server"
15
+ def log_id
16
+ LOG_ID
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,97 @@
1
+ module OverSIP::SIP
2
+
3
+ class TcpClient < TcpConnection
4
+
5
+ class << self
6
+ attr_reader :server_class
7
+ end
8
+
9
+ attr_reader :connected
10
+ attr_reader :pending_client_transactions
11
+
12
+ def initialize ip, port
13
+ # NOTE: The parent class implementing "initialize" method is Connection, and allows no arguments.
14
+ # If we call just "super" from here it will fail since "ip" and "port" will be passed as
15
+ # arguments. So we must use "super()" and we are done (no arguments are passed to parent).
16
+ super()
17
+
18
+ @remote_ip = ip
19
+ @remote_port = port
20
+ @connection_id = ::OverSIP::SIP::TransportManager.add_connection self, self.class, self.class.ip_type, @remote_ip, @remote_port
21
+ @connected = false
22
+ @pending_client_transactions = []
23
+
24
+ ### TODO: make it configurable.
25
+ set_pending_connect_timeout 2.0
26
+ end
27
+
28
+
29
+ def connection_completed
30
+ log_system_info "TCP connection opened to " << remote_desc
31
+
32
+ @connected = true
33
+ @pending_client_transactions.clear
34
+ end
35
+
36
+
37
+ def remote_desc
38
+ @remote_desc ||= case self.class.ip_type
39
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
40
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
41
+ end
42
+ end
43
+
44
+
45
+ def unbind cause=nil
46
+ @state = :ignore
47
+
48
+ # Remove the connection.
49
+ self.class.connections.delete @connection_id
50
+
51
+ @local_closed = true if cause == ::Errno::ETIMEDOUT
52
+
53
+ if @connected
54
+ log_msg = "connection to #{remote_desc} "
55
+ log_msg << ( @local_closed ? "locally closed" : "remotely closed" )
56
+ log_msg << " (cause: #{cause.inspect})" if cause
57
+ log_system_debug log_msg if $oversip_debug
58
+
59
+ # If the TCP client connection has failed (remote server rejected the connection) then
60
+ # inform to all the pending client transactions.
61
+ else
62
+ log_system_notice "connection to #{remote_desc} failed" if $oversip_debug
63
+
64
+ @pending_client_transactions.each do |client_transaction|
65
+ client_transaction.connection_failed
66
+ end
67
+ @pending_client_transactions.clear
68
+ end unless $!
69
+
70
+ @connected = false
71
+ end
72
+
73
+
74
+ # For the case in which OverSIP receives a SIP request from a connection open by OverSIP.
75
+ def record_route
76
+ @record_route and return @record_route
77
+
78
+ server_class = self.class.server_class
79
+ local_port, local_ip = ::Socket.unpack_sockaddr_in(get_sockname)
80
+
81
+ case
82
+ when server_class == ::OverSIP::SIP::IPv4TcpServer
83
+ uri_ip = local_ip
84
+ when server_class == ::OverSIP::SIP::IPv6TcpServer
85
+ uri_ip = "[#{local_ip}]"
86
+ when server_class == ::OverSIP::SIP::IPv4TlsServer
87
+ uri_ip = local_ip
88
+ when server_class == ::OverSIP::SIP::IPv6TlsServer
89
+ uri_ip = "[#{local_ip}]"
90
+ end
91
+
92
+ @record_route = "<sip:#{uri_ip}:#{local_port};transport=#{server_class.transport.to_s};lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
93
+ end
94
+
95
+ end
96
+
97
+ end
@@ -0,0 +1,202 @@
1
+ module OverSIP::SIP
2
+
3
+ class TcpConnection < Connection
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 remote_ip_type
10
+ @remote_ip_type || self.class.ip_type
11
+ end
12
+
13
+ def remote_ip
14
+ @remote_ip
15
+ end
16
+
17
+ def remote_port
18
+ @remote_port
19
+ end
20
+
21
+ def receive_data data
22
+ @state == :ignore and return
23
+ @buffer << data
24
+ @state == :waiting_for_on_client_tls_handshake and return
25
+
26
+ process_received_data
27
+ end
28
+
29
+ def process_received_data
30
+ @state == :ignore and return
31
+
32
+ while (case @state
33
+ when :init
34
+ @parser.reset
35
+ @parser_nbytes = 0
36
+ @state = :headers
37
+
38
+ when :headers
39
+ parse_headers
40
+ # TODO: Add a timer for the case in which an attacker sends us slow headers that never end:
41
+ # http://ha.ckers.org/slowloris/.
42
+
43
+ when :body
44
+ get_body
45
+
46
+ when :finished
47
+ if @msg.request?
48
+ process_request
49
+ else
50
+ process_response
51
+ end
52
+
53
+ # Set state to :init.
54
+ @state = :init
55
+ # Return true to continue processing possible remaining data.
56
+ true
57
+
58
+ when :ignore
59
+ false
60
+ end)
61
+ end # while
62
+ end
63
+
64
+ def parse_headers
65
+ return false if @buffer.empty?
66
+
67
+ # Parse the currently buffered data. If parsing fails @parser_nbytes gets nil value.
68
+ unless @parser_nbytes = @parser.execute(@buffer.to_str, @parser_nbytes)
69
+ # The parsed data is invalid, however some data could be parsed so @parsed.parsed
70
+ # can be:
71
+ # - SIP::Request
72
+ # - SIP::Response
73
+ # - nil (the message is so wrong that cannot be neither a request or response).
74
+ if wrong_message = @parser.parsed
75
+ log_system_warn "parsing error for #{MSG_TYPE[wrong_message.class]}: \"#{@parser.error}\""
76
+ else
77
+ log_system_warn "parsing error: \"#{@parser.error}\""
78
+ end
79
+
80
+ close_connection_after_writing
81
+ @state = :ignore
82
+ return false
83
+ end
84
+
85
+ # Avoid flood attacks in TCP (very long headers).
86
+ if @parser_nbytes > HEADERS_MAX_SIZE
87
+ log_system_warn "DoS attack detected: headers size exceedes #{HEADERS_MAX_SIZE} bytes, closing connection with #{remote_desc}"
88
+ close_connection
89
+ # After closing client connection some data can still arrrive to "receive_data()"
90
+ # (explained in EM documentation). By setting @state = :ignore we ensure such
91
+ # remaining data is not processed.
92
+ @state = :ignore
93
+ return false
94
+ end
95
+
96
+ # If the parsing has not finished, it is correct in TCP so return false and wait for more data under :headers state.
97
+ return false unless @parser.finished?
98
+
99
+ # At this point we've got a SIP::Request, SIP::Response or :outbound_keepalive symbol.
100
+ @msg = @parser.parsed
101
+
102
+ # Clear parsed data from the buffer.
103
+ @buffer.read(@parser_nbytes)
104
+
105
+ # Received data is a Outbound keealive.
106
+ if @msg == :outbound_keepalive
107
+ log_system_debug "Outbound keepalive received, replying single CRLF" if $oversip_debug
108
+ # Reply a single CRLF over the same connection.
109
+ send_data CRLF
110
+ # If TCP then go back to :init state so possible remaining data would be processed.
111
+ @state = :init
112
+ return true
113
+ end
114
+
115
+ @parser.post_parsing
116
+
117
+ # Here we have received the entire headers of a SIP request or response. Fill some
118
+ # attributes.
119
+ @msg.connection = self
120
+ @msg.transport = self.class.transport
121
+ @msg.source_ip = @remote_ip
122
+ @msg.source_port = @remote_port
123
+ @msg.source_ip_type = @remote_ip_type || self.class.ip_type
124
+
125
+ unless valid_message? @parser
126
+ close_connection_after_writing
127
+ @state = :ignore
128
+ return false
129
+ end
130
+
131
+ add_via_received_rport if @msg.request?
132
+
133
+ unless check_via_branch
134
+ close_connection_after_writing
135
+ @state = :ignore
136
+ return false
137
+ end
138
+
139
+ # Examine Content-Length header.
140
+ # In SIP over TCP Content-Length header is mandatory.
141
+ if (@body_length = @msg.content_length)
142
+ # There is body (or should be).
143
+ if @body_length > 0
144
+ @state = :body
145
+ # Return true to continue in get_body() method.
146
+ return true
147
+ # No body.
148
+ else
149
+ # Set :finished state and return true to process the parsed message.
150
+ @state = :finished
151
+ return true
152
+ end
153
+ # No Content-Length, invalid message!
154
+ else
155
+ # Log it and reply a 400 Bad Request (if it's a request).
156
+ # Close the connection, set :ignore state and return false to leave
157
+ # receive_data().
158
+ if @msg.request?
159
+ unless @msg.sip_method == :ACK
160
+ log_system_warn "request body size doesn't match Content-Length => 400"
161
+ @msg.reply 400, "Body size doesn't match Content-Length"
162
+ else
163
+ log_system_warn "ACK body size doesn't match Content-Length, ignoring it"
164
+ end
165
+ else
166
+ log_system_warn "response has not Content-Length header, ignoring it"
167
+ end
168
+ close_connection_after_writing
169
+ @state = :ignore
170
+ return false
171
+ end
172
+ end # parse_headers
173
+
174
+ def get_body
175
+ # Return false until the buffer gets all the body.
176
+ return false if @buffer.size < @body_length
177
+
178
+ ### TODO: Creo que es mejor forzarlo a BINARY y no a UTF-8. Aunque IOBuffer ya lo saca siempre en BINARY.
179
+ # ¿Por qué lo forcé a UTF-8?
180
+ # 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
181
+ # se generan como un string en UTF-8 (aunque contengan símbolos no UTF-8) fallaría. O todo UTF-8 (aunque
182
+ # tenga símbolos inválidos) o todo BINARY.
183
+ @msg.body = @buffer.read(@body_length).force_encoding(::Encoding::UTF_8)
184
+ @state = :finished
185
+ return true
186
+ end
187
+
188
+
189
+ # Parameters ip and port are just included because they are needed in UDP, so the API remains equal.
190
+ def send_sip_msg msg, ip=nil, port=nil
191
+ if self.error?
192
+ log_system_notice "SIP message could not be sent, connection is closed"
193
+ return false
194
+ end
195
+ send_data msg
196
+ true
197
+ end
198
+
199
+ end
200
+
201
+ end
202
+
@@ -0,0 +1,71 @@
1
+ module OverSIP::SIP
2
+
3
+ class TcpServer < TcpConnection
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
+ @connection_id = ::OverSIP::SIP::TransportManager.add_connection self, self.class, self.class.ip_type, @remote_ip, @remote_port
18
+
19
+ # Create an Outbound (RFC 5626) flow token for this connection.
20
+ @outbound_flow_token = ::OverSIP::SIP::TransportManager.add_outbound_connection self
21
+
22
+ ### Testing TCP keepalive.
23
+ # https://github.com/bklang/eventmachine/commit/74c65a56c733bc1b6f092e32a9f0d722501ade46
24
+ # http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/
25
+ if ::OverSIP::SIP.tcp_keepalive_interval
26
+ set_sock_opt Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true
27
+ set_sock_opt Socket::SOL_TCP, Socket::TCP_KEEPIDLE, ::OverSIP::SIP.tcp_keepalive_interval # First TCP ping.
28
+ set_sock_opt Socket::SOL_TCP, Socket::TCP_KEEPINTVL, ::OverSIP::SIP.tcp_keepalive_interval # Interval between TCP pings.
29
+ end
30
+
31
+ log_system_debug("connection opened from " << remote_desc) if $oversip_debug
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 unless $!
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
@@ -0,0 +1,125 @@
1
+ module OverSIP::SIP
2
+
3
+ class TlsClient < TcpClient
4
+
5
+ TLS_HANDSHAKE_MAX_TIME = 4
6
+
7
+
8
+ attr_writer :callback_on_server_tls_handshake
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 => @callback_on_server_tls_handshake,
23
+ :cert_chain_file => ::OverSIP.tls_public_cert,
24
+ :private_key_file => ::OverSIP.tls_private_cert,
25
+ :ssl_version => %w(tlsv1 tlsv1_1 tlsv1_2)
26
+ })
27
+
28
+ # If the remote server does never send us a TLS certificate
29
+ # after the TCP connection we would leak by storing more and
30
+ # more messages in @pending_messages array.
31
+ @timer_tls_handshake = ::EM::Timer.new(TLS_HANDSHAKE_MAX_TIME) do
32
+ unless @connected
33
+ log_system_notice "TLS handshake not performed within #{TLS_HANDSHAKE_MAX_TIME} seconds, closing the connection"
34
+ close_connection
35
+ end
36
+ end
37
+ end
38
+
39
+
40
+ # Called for every certificate provided by the peer.
41
+ # This is just called in case @callback_on_server_tls_handshake is true.
42
+ def ssl_verify_peer pem
43
+ # TODO: Dirty workaround for bug https://github.com/eventmachine/eventmachine/issues/194.
44
+ return true if @server_last_pem == pem
45
+
46
+ @server_last_pem = pem
47
+ @server_pems << pem
48
+
49
+ log_system_debug "received certificate num #{@server_pems.size} from server" if $oversip_debug
50
+
51
+ # Validation must be done in ssl_handshake_completed after receiving all the certs, so return true.
52
+ return true
53
+ end
54
+
55
+
56
+ # This is called after all the calls to ssl_verify_peer().
57
+ def ssl_handshake_completed
58
+ log_system_debug("TLS connection established to " << remote_desc) if $oversip_debug
59
+
60
+ # @connected in TlsClient means "TLS connection" rather than
61
+ # just "TCP connection".
62
+ @connected = true
63
+ @timer_tls_handshake.cancel if @timer_tls_handshake
64
+
65
+ # Run OverSIP::SipEvents.on_server_tls_handshake.
66
+ ::Fiber.new do
67
+ if @callback_on_server_tls_handshake
68
+ log_system_debug "running OverSIP::SipEvents.on_server_tls_handshake()..." if $oversip_debug
69
+ begin
70
+ ::OverSIP::SipEvents.on_server_tls_handshake self, @server_pems
71
+ rescue ::Exception => e
72
+ log_system_error "error calling OverSIP::SipEvents.on_server_tls_handshake():"
73
+ log_system_error e
74
+ close_connection
75
+ end
76
+
77
+ # If the user or peer has closed the connection in the on_server_tls_handshake() callback
78
+ # then notify pending transactions.
79
+ if @local_closed or error?
80
+ log_system_debug "connection closed, aborting" if $oversip_debug
81
+ @pending_client_transactions.each do |client_transaction|
82
+ client_transaction.tls_validation_failed
83
+ end
84
+ @pending_client_transactions.clear
85
+ @pending_messages.clear
86
+ @state = :ignore
87
+ end
88
+ end
89
+
90
+ @pending_client_transactions.clear
91
+ @pending_messages.each do |msg|
92
+ send_data msg
93
+ end
94
+ @pending_messages.clear
95
+ end.resume
96
+ end
97
+
98
+ def unbind cause=nil
99
+ super
100
+ @timer_tls_handshake.cancel if @timer_tls_handshake
101
+ @pending_messages.clear
102
+ end
103
+
104
+ # In TLS client, we must wait until ssl_handshake_completed is
105
+ # completed before sending data. If not, data will be sent in
106
+ # plain TCP.
107
+ # http://dev.sipdoc.net/issues/457
108
+ def send_sip_msg msg, ip=nil, port=nil
109
+ if self.error?
110
+ log_system_notice "SIP message could not be sent, connection is closed"
111
+ return false
112
+ end
113
+
114
+ if @connected
115
+ send_data msg
116
+ else
117
+ log_system_debug "TLS handshake not completed yet, waiting before sending the message" if $oversip_debug
118
+ @pending_messages << msg
119
+ end
120
+ true
121
+ end
122
+
123
+ end
124
+
125
+ end
@@ -0,0 +1,88 @@
1
+ module OverSIP::SIP
2
+
3
+ class TlsServer < TcpServer
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(tlsv1 tlsv1_1 tlsv1_2)
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_info "TLS connection established from " << remote_desc
47
+
48
+ # @connected in TlsServer 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::SIP.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::SipEvents.on_client_tls_handshake.
59
+ ::Fiber.new do
60
+ begin
61
+ log_system_debug "running OverSIP::SipEvents.on_client_tls_handshake()..." if $oversip_debug
62
+ ::OverSIP::SipEvents.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, aborting" if $oversip_debug
70
+ end
71
+
72
+ rescue ::Exception => e
73
+ log_system_error "error calling OverSIP::SipEvents.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