1 |
|
-module(mongoose_c2s_ranch). |
2 |
|
-behaviour(mongoose_c2s_socket). |
3 |
|
|
4 |
|
-export([socket_new/2, |
5 |
|
socket_peername/1, |
6 |
|
tcp_to_tls/2, |
7 |
|
socket_handle_data/2, |
8 |
|
socket_activate/1, |
9 |
|
socket_close/1, |
10 |
|
socket_send_xml/2, |
11 |
|
get_peer_certificate/2, |
12 |
|
has_peer_cert/2, |
13 |
|
is_channel_binding_supported/1, |
14 |
|
get_tls_last_message/1, |
15 |
|
is_ssl/1]). |
16 |
|
|
17 |
|
-record(state, { |
18 |
|
transport :: transport(), |
19 |
|
ranch_ref :: ranch:ref(), |
20 |
|
socket :: ranch_transport:socket(), |
21 |
|
ip :: {inet:ip_address(), inet:port_number()} |
22 |
|
}). |
23 |
|
|
24 |
|
-type state() :: #state{}. |
25 |
|
-type transport() :: ranch_tcp | just_tls | fast_tls. |
26 |
|
|
27 |
|
-spec socket_new(term(), mongoose_listener:options()) -> state(). |
28 |
|
socket_new({ranch_tcp, RanchRef}, #{proxy_protocol := true}) -> |
29 |
2 |
{ok, #{src_address := PeerIp, src_port := PeerPort}} = ranch:recv_proxy_header(RanchRef, 1000), |
30 |
1 |
{ok, TcpSocket} = ranch:handshake(RanchRef), |
31 |
1 |
#state{ |
32 |
|
transport = ranch_tcp, |
33 |
|
ranch_ref = RanchRef, |
34 |
|
socket = TcpSocket, |
35 |
|
ip = {PeerIp, PeerPort}}; |
36 |
|
socket_new({ranch_tcp, RanchRef}, #{proxy_protocol := false}) -> |
37 |
4313 |
{ok, TcpSocket} = ranch:handshake(RanchRef), |
38 |
4313 |
{ok, Ip} = ranch_tcp:peername(TcpSocket), |
39 |
4313 |
#state{ |
40 |
|
transport = ranch_tcp, |
41 |
|
ranch_ref = RanchRef, |
42 |
|
socket = TcpSocket, |
43 |
|
ip = Ip}. |
44 |
|
|
45 |
|
-spec socket_peername(state()) -> {inet:ip_address(), inet:port_number()}. |
46 |
|
socket_peername(#state{ip = Ip}) -> |
47 |
7841 |
Ip. |
48 |
|
|
49 |
|
-spec tcp_to_tls(state(), mongoose_listener:options()) -> |
50 |
|
{ok, state()} | {error, term()}. |
51 |
|
tcp_to_tls(#state{socket = TcpSocket} = State, #{tls := #{module := TlsMod} = TlsConfig}) -> |
52 |
925 |
case tcp_to_tls(TlsMod, TcpSocket, TlsConfig) of |
53 |
|
{ok, TlsSocket} -> |
54 |
638 |
{ok, State#state{transport = TlsMod, socket = TlsSocket}}; |
55 |
|
{error, Reason} -> |
56 |
287 |
{error, Reason} |
57 |
|
end. |
58 |
|
|
59 |
|
tcp_to_tls(fast_tls, TcpSocket, TlsConfig) -> |
60 |
561 |
PreparedOpts = mongoose_tls:prepare_options(fast_tls, maps:remove(module, TlsConfig)), |
61 |
561 |
ranch_tcp:setopts(TcpSocket, [{active, false}]), |
62 |
561 |
case fast_tls:tcp_to_tls(TcpSocket, PreparedOpts) of |
63 |
|
{ok, TlsSocket} -> |
64 |
561 |
fast_tls:recv_data(TlsSocket, <<>>), |
65 |
561 |
{ok, TlsSocket}; |
66 |
:-( |
Other -> Other |
67 |
|
end; |
68 |
|
tcp_to_tls(just_tls, TcpSocket, TlsConfig) -> |
69 |
364 |
case just_tls:tcp_to_tls(TcpSocket, TlsConfig) of |
70 |
77 |
{ok, TlsSocket} -> {ok, TlsSocket}; |
71 |
287 |
Other -> Other |
72 |
|
end. |
73 |
|
|
74 |
|
-spec socket_handle_data(state(), {tcp | ssl, term(), iodata()}) -> |
75 |
|
iodata() | {raw, [exml:element()]} | {error, term()}. |
76 |
|
socket_handle_data(#state{transport = fast_tls, socket = TlsSocket}, {tcp, _, Data}) -> |
77 |
1358 |
case fast_tls:recv_data(TlsSocket, Data) of |
78 |
|
{ok, DecryptedData} -> |
79 |
958 |
DataSize = byte_size(DecryptedData), |
80 |
958 |
mongoose_metrics:update(global, [data, xmpp, received, c2s, tls], DataSize), |
81 |
958 |
DecryptedData; |
82 |
|
{error, Reason} -> |
83 |
400 |
{error, Reason} |
84 |
|
end; |
85 |
|
socket_handle_data(#state{transport = just_tls}, {ssl, _, Data}) -> |
86 |
210 |
mongoose_metrics:update(global, [data, xmpp, received, c2s, tls], byte_size(Data)), |
87 |
210 |
Data; |
88 |
|
socket_handle_data(#state{transport = ranch_tcp, socket = Socket}, {tcp, Socket, Data}) -> |
89 |
26210 |
mongoose_metrics:update(global, [data, xmpp, received, c2s, tcp], byte_size(Data)), |
90 |
26210 |
Data. |
91 |
|
|
92 |
|
-spec socket_activate(state()) -> ok. |
93 |
|
socket_activate(#state{transport = fast_tls, socket = Socket}) -> |
94 |
1519 |
fast_tls:setopts(Socket, [{active, once}]); |
95 |
|
socket_activate(#state{transport = just_tls, socket = Socket}) -> |
96 |
287 |
just_tls:setopts(Socket, [{active, once}]); |
97 |
|
socket_activate(#state{transport = ranch_tcp, socket = Socket}) -> |
98 |
29689 |
ranch_tcp:setopts(Socket, [{active, once}]). |
99 |
|
|
100 |
|
-spec socket_close(state()) -> ok. |
101 |
|
socket_close(#state{transport = fast_tls, socket = Socket}) -> |
102 |
561 |
fast_tls:close(Socket); |
103 |
|
socket_close(#state{transport = just_tls, socket = Socket}) -> |
104 |
77 |
just_tls:close(Socket); |
105 |
|
socket_close(#state{transport = ranch_tcp, socket = Socket}) -> |
106 |
3390 |
ranch_tcp:close(Socket). |
107 |
|
|
108 |
|
-spec socket_send_xml(state(), iodata() | exml_stream:element() | [exml_stream:element()]) -> |
109 |
|
ok | {error, term()}. |
110 |
|
socket_send_xml(#state{transport = Transport, socket = Socket}, XML) -> |
111 |
36999 |
Text = exml:to_iolist(XML), |
112 |
36999 |
case send(Transport, Socket, Text) of |
113 |
|
ok -> |
114 |
36847 |
ok; |
115 |
|
Error -> |
116 |
152 |
Error |
117 |
|
end. |
118 |
|
|
119 |
|
-spec send(transport(), ranch_transport:socket(), iodata()) -> ok | {error, term()}. |
120 |
|
send(fast_tls, Socket, Data) -> |
121 |
619 |
mongoose_metrics:update(global, [data, xmpp, sent, c2s, tls], iolist_size(Data)), |
122 |
619 |
fast_tls:send(Socket, Data); |
123 |
|
send(just_tls, Socket, Data) -> |
124 |
263 |
mongoose_metrics:update(global, [data, xmpp, sent, c2s, tls], iolist_size(Data)), |
125 |
263 |
just_tls:send(Socket, Data); |
126 |
|
send(ranch_tcp, Socket, Data) -> |
127 |
36117 |
mongoose_metrics:update(global, [data, xmpp, sent, c2s, tcp], iolist_size(Data)), |
128 |
36117 |
ranch_tcp:send(Socket, Data). |
129 |
|
|
130 |
|
-spec get_peer_certificate(state(), mongoose_listener:options()) -> |
131 |
|
mongoose_c2s_socket:peercert_return(). |
132 |
|
get_peer_certificate(#state{transport = fast_tls, socket = Socket}, #{tls := TlsOpts}) -> |
133 |
60 |
case {fast_tls:get_verify_result(Socket), fast_tls:get_peer_certificate(Socket), TlsOpts} of |
134 |
54 |
{0, {ok, Cert}, _} -> {ok, Cert}; |
135 |
|
%% 18 is OpenSSL's and fast_tls's error code for self-signed certs |
136 |
:-( |
{18, {ok, Cert}, #{verify_mode := selfsigned_peer}} -> {ok, Cert}; |
137 |
3 |
{Error, {ok, Cert}, _} -> {bad_cert, fast_tls:get_cert_verify_string(Error, Cert)}; |
138 |
3 |
{_, error, _} -> no_peer_cert |
139 |
|
end; |
140 |
|
get_peer_certificate(#state{transport = just_tls, socket = Socket}, _) -> |
141 |
120 |
just_tls:get_peer_certificate(Socket); |
142 |
|
get_peer_certificate(#state{transport = ranch_tcp}, _) -> |
143 |
60 |
no_peer_cert. |
144 |
|
|
145 |
|
-spec has_peer_cert(state(), mongoose_listener:options()) -> boolean(). |
146 |
|
has_peer_cert(State, LOpts) -> |
147 |
180 |
case get_peer_certificate(State, LOpts) of |
148 |
110 |
{ok, _} -> true; |
149 |
70 |
_ -> false |
150 |
|
end. |
151 |
|
|
152 |
|
-spec is_channel_binding_supported(state()) -> boolean(). |
153 |
|
is_channel_binding_supported(#state{transport = Transport}) -> |
154 |
8164 |
fast_tls == Transport. |
155 |
|
|
156 |
|
-spec get_tls_last_message(state()) -> {ok, binary()} | {error, term()}. |
157 |
|
get_tls_last_message(#state{transport = fast_tls, socket = Socket}) -> |
158 |
20 |
fast_tls:get_tls_last_message(peer, Socket); |
159 |
|
get_tls_last_message(_) -> |
160 |
:-( |
{error, undefined}. |
161 |
|
|
162 |
|
-spec is_ssl(state()) -> boolean(). |
163 |
|
is_ssl(#state{transport = Transport}) -> |
164 |
10104 |
ranch_tcp /= Transport. |