1 |
|
-module(mongoose_c2s_socket). |
2 |
|
|
3 |
|
-include_lib("public_key/include/public_key.hrl"). |
4 |
|
-include("mongoose_logger.hrl"). |
5 |
|
|
6 |
|
-export([new/3, |
7 |
|
handle_data/2, |
8 |
|
activate/1, |
9 |
|
close/1, |
10 |
|
is_channel_binding_supported/1, |
11 |
|
get_tls_last_message/1, |
12 |
|
get_peer_certificate/2, |
13 |
|
has_peer_cert/2, |
14 |
|
tcp_to_tls/2, |
15 |
|
is_ssl/1, |
16 |
|
send_xml/2]). |
17 |
|
|
18 |
|
-export([get_ip/1, |
19 |
|
get_transport/1, |
20 |
|
get_conn_type/1]). |
21 |
|
|
22 |
|
-callback socket_new(term(), mongoose_c2s:listener_opts()) -> state(). |
23 |
|
-callback socket_peername(state()) -> {inet:ip_address(), inet:port_number()}. |
24 |
|
-callback tcp_to_tls(state(), mongoose_c2s:listener_opts()) -> |
25 |
|
{ok, state()} | {error, term()}. |
26 |
|
-callback socket_handle_data(state(), {tcp | ssl, term(), iodata()}) -> |
27 |
|
iodata() | {raw, [exml:element()]} | {error, term()}. |
28 |
|
-callback socket_activate(state()) -> ok. |
29 |
|
-callback socket_close(state()) -> ok. |
30 |
|
-callback socket_send_xml(state(), iodata() | exml_stream:element() | [exml_stream:element()]) -> |
31 |
|
ok | {error, term()}. |
32 |
|
-callback get_peer_certificate(state(), mongoose_c2s:listener_opts()) -> peercert_return(). |
33 |
|
-callback has_peer_cert(state(), mongoose_c2s:listener_opts()) -> boolean(). |
34 |
|
-callback is_channel_binding_supported(state()) -> boolean(). |
35 |
|
-callback get_tls_last_message(state()) -> {ok, binary()} | {error, term()}. |
36 |
|
-callback is_ssl(state()) -> boolean(). |
37 |
|
|
38 |
|
-record(c2s_socket, {module :: module(), |
39 |
|
state :: state()}). |
40 |
|
-type socket() :: #c2s_socket{}. |
41 |
|
-type state() :: term(). |
42 |
|
-type conn_type() :: c2s | c2s_tls. |
43 |
|
-type peercert_return() :: no_peer_cert | {bad_cert, term()} | {ok, #'Certificate'{}}. |
44 |
|
-export_type([socket/0, state/0, conn_type/0, peercert_return/0]). |
45 |
|
|
46 |
|
-spec new(module(), term(), mongoose_listener:options()) -> socket(). |
47 |
|
new(Module, SocketOpts, LOpts) -> |
48 |
7771 |
State = Module:socket_new(SocketOpts, LOpts), |
49 |
7770 |
PeerIp = Module:socket_peername(State), |
50 |
7770 |
verify_ip_is_not_blacklisted(PeerIp), |
51 |
7770 |
C2SSocket = #c2s_socket{ |
52 |
|
module = Module, |
53 |
|
state = State}, |
54 |
7770 |
handle_socket_and_ssl_config(C2SSocket, LOpts). |
55 |
|
|
56 |
|
verify_ip_is_not_blacklisted(PeerIp) -> |
57 |
7770 |
case mongoose_hooks:check_bl_c2s(PeerIp) of |
58 |
|
true -> |
59 |
:-( |
?LOG_INFO(#{what => c2s_blacklisted_ip, ip => PeerIp, |
60 |
:-( |
text => <<"Connection attempt from blacklisted IP">>}), |
61 |
:-( |
throw({stop, {shutdown, ip_blacklisted}}); |
62 |
|
false -> |
63 |
7770 |
ok |
64 |
|
end. |
65 |
|
|
66 |
|
handle_socket_and_ssl_config(C2SSocket, #{tls := #{mode := tls}} = LOpts) -> |
67 |
827 |
case tcp_to_tls(C2SSocket, LOpts) of |
68 |
|
{ok, TlsC2SSocket} -> |
69 |
543 |
activate(TlsC2SSocket), |
70 |
543 |
TlsC2SSocket; |
71 |
|
{error, closed} -> |
72 |
:-( |
throw({stop, {shutdown, tls_closed}}); |
73 |
|
{error, timeout} -> |
74 |
:-( |
throw({stop, {shutdown, tls_timeout}}); |
75 |
|
{error, {tls_alert, TlsAlert}} -> |
76 |
284 |
throw({stop, TlsAlert}) |
77 |
|
end; |
78 |
|
handle_socket_and_ssl_config(C2SSocket, _Opts) -> |
79 |
6943 |
activate(C2SSocket), |
80 |
6943 |
C2SSocket. |
81 |
|
|
82 |
|
-spec tcp_to_tls(socket(), mongoose_listener:options()) -> {ok, socket()} | {error, term()}. |
83 |
|
tcp_to_tls(#c2s_socket{module = Module, state = State} = C2SSocket, LOpts) -> |
84 |
925 |
case Module:tcp_to_tls(State, LOpts) of |
85 |
|
{ok, NewState} -> |
86 |
638 |
{ok, C2SSocket#c2s_socket{state = NewState}}; |
87 |
|
Error -> |
88 |
287 |
Error |
89 |
|
end. |
90 |
|
|
91 |
|
-spec handle_data(socket(), {tcp | ssl, term(), iodata()}) -> |
92 |
|
iodata() | {raw, [term()]} | {error, term()}. |
93 |
|
handle_data(#c2s_socket{module = Module, state = State}, Payload) -> |
94 |
58104 |
Module:socket_handle_data(State, Payload); |
95 |
|
handle_data(_, _) -> |
96 |
:-( |
{error, bad_packet}. |
97 |
|
|
98 |
|
-spec activate(socket()) -> ok | {error, term()}. |
99 |
|
activate(#c2s_socket{module = Module, state = State}) -> |
100 |
65277 |
Module:socket_activate(State). |
101 |
|
|
102 |
|
-spec close(socket()) -> ok. |
103 |
|
close(#c2s_socket{module = Module, state = State}) -> |
104 |
7486 |
Module:socket_close(State). |
105 |
|
|
106 |
|
-spec send_xml(socket(), exml_stream:element() | [exml_stream:element()]) -> ok | {error, term()}. |
107 |
|
send_xml(#c2s_socket{module = Module, state = State}, XML) -> |
108 |
83123 |
Module:socket_send_xml(State, XML). |
109 |
|
|
110 |
|
-spec get_peer_certificate(socket(), mongoose_c2s:listener_opts()) -> peercert_return(). |
111 |
|
get_peer_certificate(#c2s_socket{module = Module, state = State}, LOpts) -> |
112 |
66 |
Module:get_peer_certificate(State, LOpts). |
113 |
|
|
114 |
|
-spec has_peer_cert(socket(), mongoose_listener:options()) -> boolean(). |
115 |
|
has_peer_cert(#c2s_socket{module = Module, state = State}, LOpts) -> |
116 |
192 |
Module:has_peer_cert(State, LOpts). |
117 |
|
|
118 |
|
-spec is_channel_binding_supported(socket()) -> boolean(). |
119 |
|
is_channel_binding_supported(#c2s_socket{module = Module, state = State}) -> |
120 |
15179 |
Module:is_channel_binding_supported(State). |
121 |
|
|
122 |
|
-spec is_ssl(socket()) -> boolean(). |
123 |
|
is_ssl(#c2s_socket{module = Module, state = State}) -> |
124 |
20453 |
Module:is_ssl(State). |
125 |
|
|
126 |
|
-spec get_transport(socket()) -> module(). |
127 |
|
get_transport(#c2s_socket{module = Module}) -> |
128 |
:-( |
Module. |
129 |
|
|
130 |
|
-spec get_tls_last_message(socket()) -> {ok, binary()} | {error, term()}. |
131 |
|
get_tls_last_message(#c2s_socket{module = Module, state = State}) -> |
132 |
20 |
Module:get_tls_last_message(State). |
133 |
|
|
134 |
|
-spec get_conn_type(socket()) -> conn_type(). |
135 |
|
get_conn_type(Socket) -> |
136 |
6581 |
case is_ssl(Socket) of |
137 |
74 |
true -> c2s_tls; |
138 |
6507 |
false -> c2s |
139 |
|
end. |
140 |
|
|
141 |
|
-spec get_ip(socket()) -> term(). |
142 |
|
get_ip(#c2s_socket{module = Module, state = State}) -> |
143 |
6967 |
Module:socket_peername(State). |