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.
- checksums.yaml +7 -0
- data/AUTHORS +22 -0
- data/LICENSE +25 -0
- data/README.md +43 -0
- data/Rakefile +54 -0
- data/bin/oversip +184 -0
- data/etc/oversip.conf +274 -0
- data/etc/proxies.conf +145 -0
- data/etc/server.rb +315 -0
- data/etc/tls/ca/cacert.pem +3894 -0
- data/etc/tls/demo-tls.oversip.net.crt +17 -0
- data/etc/tls/demo-tls.oversip.net.key +15 -0
- data/etc/tls/upgrade-cacert.sh +12 -0
- data/etc/tls/utils/create-cert.rb +162 -0
- data/etc/tls/utils/get-sip-identities.rb +95 -0
- data/ext/common/c_util.h +74 -0
- data/ext/common/ruby_c_util.h +88 -0
- data/ext/sip_parser/common_headers.h +210 -0
- data/ext/sip_parser/ext_help.h +18 -0
- data/ext/sip_parser/extconf.rb +3 -0
- data/ext/sip_parser/sip_message_parser.c +29741 -0
- data/ext/sip_parser/sip_parser.h +250 -0
- data/ext/sip_parser/sip_parser_ruby.c +1370 -0
- data/ext/sip_parser/sip_uri_parser.c +39699 -0
- data/ext/stud/extconf.rb +43 -0
- data/ext/stun/ext_help.h +16 -0
- data/ext/stun/extconf.rb +3 -0
- data/ext/stun/stun_ruby.c +394 -0
- data/ext/utils/ext_help.h +14 -0
- data/ext/utils/extconf.rb +3 -0
- data/ext/utils/haproxy_protocol.c +6163 -0
- data/ext/utils/haproxy_protocol.h +27 -0
- data/ext/utils/ip_utils.c +5952 -0
- data/ext/utils/ip_utils.h +64 -0
- data/ext/utils/outbound_utils.c +3227 -0
- data/ext/utils/outbound_utils.h +27 -0
- data/ext/utils/utils_ruby.c +392 -0
- data/ext/utils/utils_ruby.h +76 -0
- data/ext/websocket_framing_utils/ext_help.h +18 -0
- data/ext/websocket_framing_utils/extconf.rb +3 -0
- data/ext/websocket_framing_utils/ws_framing_utils.h +47 -0
- data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
- data/ext/websocket_http_parser/ext_help.h +18 -0
- data/ext/websocket_http_parser/extconf.rb +3 -0
- data/ext/websocket_http_parser/ws_http_parser.c +1635 -0
- data/ext/websocket_http_parser/ws_http_parser.h +87 -0
- data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
- data/lib/oversip/config.rb +597 -0
- data/lib/oversip/config_validators.rb +126 -0
- data/lib/oversip/default_server.rb +52 -0
- data/lib/oversip/errors.rb +10 -0
- data/lib/oversip/fiber_pool.rb +56 -0
- data/lib/oversip/launcher.rb +635 -0
- data/lib/oversip/logger.rb +84 -0
- data/lib/oversip/modules/outbound_mangling.rb +56 -0
- data/lib/oversip/modules/user_assertion.rb +73 -0
- data/lib/oversip/proxies_config.rb +189 -0
- data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
- data/lib/oversip/sip/client.rb +428 -0
- data/lib/oversip/sip/client_transaction.rb +586 -0
- data/lib/oversip/sip/constants.rb +88 -0
- data/lib/oversip/sip/core.rb +217 -0
- data/lib/oversip/sip/launcher.rb +221 -0
- data/lib/oversip/sip/listeners/connection.rb +54 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv4_udp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv6_udp_server.rb +21 -0
- data/lib/oversip/sip/listeners/tcp_client.rb +97 -0
- data/lib/oversip/sip/listeners/tcp_connection.rb +202 -0
- data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
- data/lib/oversip/sip/listeners/tls_client.rb +125 -0
- data/lib/oversip/sip/listeners/tls_server.rb +88 -0
- data/lib/oversip/sip/listeners/tls_tunnel_connection.rb +89 -0
- data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
- data/lib/oversip/sip/listeners/udp_connection.rb +214 -0
- data/lib/oversip/sip/listeners.rb +24 -0
- data/lib/oversip/sip/message.rb +177 -0
- data/lib/oversip/sip/message_processor.rb +213 -0
- data/lib/oversip/sip/name_addr.rb +51 -0
- data/lib/oversip/sip/proxy.rb +324 -0
- data/lib/oversip/sip/request.rb +179 -0
- data/lib/oversip/sip/response.rb +37 -0
- data/lib/oversip/sip/rfc3263.rb +643 -0
- data/lib/oversip/sip/server_transaction.rb +295 -0
- data/lib/oversip/sip/sip.rb +76 -0
- data/lib/oversip/sip/tags.rb +39 -0
- data/lib/oversip/sip/timers.rb +55 -0
- data/lib/oversip/sip/transport_manager.rb +130 -0
- data/lib/oversip/sip/uac.rb +89 -0
- data/lib/oversip/sip/uac_request.rb +84 -0
- data/lib/oversip/sip/uri.rb +208 -0
- data/lib/oversip/syslog.rb +68 -0
- data/lib/oversip/system_callbacks.rb +45 -0
- data/lib/oversip/tls.rb +172 -0
- data/lib/oversip/utils.rb +30 -0
- data/lib/oversip/version.rb +21 -0
- data/lib/oversip/websocket/constants.rb +55 -0
- data/lib/oversip/websocket/http_request.rb +59 -0
- data/lib/oversip/websocket/launcher.rb +183 -0
- data/lib/oversip/websocket/listeners/connection.rb +51 -0
- data/lib/oversip/websocket/listeners/ipv4_ws_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv4_wss_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv4_wss_tunnel_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv6_ws_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv6_wss_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv6_wss_tunnel_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ws_server.rb +331 -0
- data/lib/oversip/websocket/listeners/wss_server.rb +88 -0
- data/lib/oversip/websocket/listeners/wss_tunnel_server.rb +133 -0
- data/lib/oversip/websocket/listeners.rb +13 -0
- data/lib/oversip/websocket/websocket.rb +13 -0
- data/lib/oversip/websocket/ws_framing.rb +545 -0
- data/lib/oversip/websocket/ws_sip_app.rb +120 -0
- data/lib/oversip.rb +127 -0
- data/test/oversip_test_helper.rb +19 -0
- data/test/test_http_parser.rb +73 -0
- data/test/test_name_addr.rb +27 -0
- data/test/test_name_addr_parser.rb +24 -0
- data/test/test_sip_message_parser.rb +168 -0
- data/test/test_sip_uri_parser.rb +56 -0
- data/test/test_uri.rb +68 -0
- data/thirdparty/stud/stud.tar.gz +0 -0
- 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
|