oversip_p 1.0.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 (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