1/*
2 This file is part of Mtproto-proxy Library.
3
4 Mtproto-proxy Library is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 Mtproto-proxy Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with Mtproto-proxy Library. If not, see <http://www.gnu.org/licenses/>.
16
17 Copyright 2013 Vkontakte Ltd
18 2013 Vitaliy Valtman
19 2013 Anton Maydell
20
21 Copyright 2014 Telegram Messenger Inc
22 2014 Vitaly Valtman
23 2014 Anton Maydell
24
25 Copyright 2015-2016 Telegram Messenger Inc
26 2015-2016 Vitaliy Valtman
27*/
28#include <arpa/inet.h>
29#include <stdarg.h>
30#include <unistd.h>
31#include <fcntl.h>
32
33#include "common/kprintf.h"
34#include "common/server-functions.h"
35
36#include "engine/engine.h"
37#include "engine/engine-net.h"
38
39#include "net/net-tcp-rpc-client.h"
40
41void default_close_network_sockets (void) /* {{{ */ {
42 engine_t *E = engine_state;
43
44 if (E->sfd > 0) {
45 close (E->sfd);
46 E->sfd = -1;
47 }
48}
49/* }}} */
50
51int get_port_mod (void) /* {{{ */ {
52 return -1;
53}
54/* }}} */
55
56int try_open_port (int port, int quit_on_fail) /* {{{ */ {
57 engine_t *E = engine_state;
58 int enable_ipv6 = engine_check_ipv6_enabled () ? SM_IPV6 : 0;
59 if (engine_check_tcp_enabled ()) {
60 struct in_addr l;
61 l.s_addr = htonl(0x7f000001);
62 E->sfd = server_socket (port, l, engine_get_backlog (), enable_ipv6);
63 vkprintf (1, "opened tcp socket\n");
64 if (E->sfd < 0) {
65 if (quit_on_fail) {
66 kprintf ("cannot open server socket at port %d: %m\n", port);
67 exit (1);
68 } else {
69 return -1;
70 }
71 }
72 }
73 return 0;
74}
75/* }}} */
76
77int try_open_port_range (int start_port, int end_port, int mod_port, int rem_port, int quit_on_fail) /* {{{ */ {
78 int s = start_port;
79 for (;start_port <= end_port; start_port ++) {
80 if (mod_port && rem_port >= 0 && (start_port % mod_port) != (rem_port % mod_port)) { continue; }
81 if (try_open_port (start_port, 0) >= 0) {
82 return start_port;
83 }
84 }
85 if (quit_on_fail) {
86 kprintf ("cannot open server socket at port %d-%d\n", s, end_port);
87 exit (2);
88 }
89 return -1;
90}
91/* }}} */
92
93void engine_do_open_port (void) /* {{{ */ {
94 int port_mod = get_port_mod ();
95
96 int port = engine_state->port;
97 int start_port = engine_state->start_port;
98 int end_port = engine_state->end_port;
99
100 if (port > 0 && port < PRIVILEGED_TCP_PORTS) {
101 assert (try_open_port (port, 1) >= 0);
102 return;
103 }
104
105 if (port <= 0 && start_port <= end_port && start_port < PRIVILEGED_TCP_PORTS) {
106 engine_state->port = try_open_port_range (start_port, end_port, 100, port_mod, 1);
107 assert (engine_state->port >= 0);
108 return;
109 }
110}
111/* }}} */
112
113struct tcp_rpc_server_functions default_engine_tcp_rpc_methods = {
114 .execute = default_tl_tcp_rpcs_execute,
115 .check_ready = server_check_ready,
116 .flush_packet = tcp_rpc_flush_packet,
117 .rpc_check_perm = tcp_rpcs_default_check_perm,
118 .rpc_init_crypto = tcp_rpcs_init_crypto,
119 .rpc_close = default_tl_close_conn,
120};
121
122void engine_set_tcp_methods (struct tcp_rpc_server_functions *F) {
123 default_engine_tcp_rpc_methods = *F;
124}
125
126
127void engine_set_http_fallback (conn_type_t *http_type, struct http_server_functions *http_functions) {
128 default_engine_tcp_rpc_methods.http_fallback_type = http_type;
129 default_engine_tcp_rpc_methods.http_fallback_extra = http_functions;
130}
131
132void engine_server_init (void) {
133 server_init (&ct_tcp_rpc_server, &default_engine_tcp_rpc_methods);
134}
135
136void set_maxconn (int val) {
137 if (val <= 0) {
138 val = MAX_CONNECTIONS;
139 }
140 engine_state->maxconn = val;
141 tcp_set_max_connections (val);
142}
143
144
145static int f_parse_option_net (int val) {
146 switch (val) {
147 case 'b':
148 engine_set_backlog (atoi (optarg));
149 break;
150 case 'c':
151 set_maxconn (atoi (optarg));
152 break;
153 case 'p':
154 {
155 int start_port, end_port;
156 int x = sscanf (optarg, "%d:%d", &start_port, &end_port);
157 if (!x) {
158 usage ();
159 }
160 if (x == 1) {
161 if (start_port <= 0) {
162 usage ();
163 }
164 engine_state->port = start_port;
165 } else {
166 if (start_port <= 0 || start_port > end_port) {
167 usage ();
168 }
169 engine_state->start_port = start_port;
170 engine_state->end_port = end_port;
171 }
172 }
173 break;
174 case '6':
175 engine_enable_ipv6 ();
176 break;
177 case 200:
178 engine_set_aes_pwd_file (optarg);
179 break;
180 case 214:
181 engine_disable_tcp ();
182 break;
183 case 224:
184 tcp_set_default_rpc_flags (0xffffffff, RPCF_USE_CRC32C);
185 break;
186 case 229:
187 tcp_set_default_rpc_flags (0xffffffff, RPCF_ALLOW_SKIP_DH);
188 break;
189 case 230:
190 tcp_force_enable_dh ();
191 break;
192 case 249:
193 tcp_set_max_accept_rate (atoi (optarg));
194 break;
195 case 250:
196 tcp_set_max_dh_accept_rate (atoi (optarg));
197 break;
198 case 372:
199 if (net_add_nat_info (optarg) < 0) {
200 usage ();
201 exit (2);
202 }
203 break;
204 case 373:
205 {
206 engine_t *E = engine_state;
207 assert (E);
208 if (inet_pton (AF_INET, optarg, &E->settings_addr) != 1) {
209 kprintf ("Can not convert '%s' to ip addr: %m\n", optarg);
210 exit (4);
211 }
212 }
213 break;
214 default:
215 return -1;
216 }
217 return 0;
218}
219
220static void parse_option_net_builtin (const char *name, int arg, int *var, int val, unsigned flags, const char *help, ...) __attribute__ ((format (printf, 6, 7)));
221static void parse_option_net_builtin (const char *name, int arg, int *var, int val, unsigned flags, const char *help, ...) {
222 char *h = NULL;
223 va_list ap;
224 va_start (ap, help);
225 assert (vasprintf (&h, help, ap) >= 0);
226 va_end (ap);
227
228 parse_option_ex (name, arg, var, val, flags, f_parse_option_net, "%s", h);
229 free (h);
230}
231
232void engine_add_net_parse_options (void) {
233 parse_option_net_builtin ("backlog", required_argument, 0, 'b', LONGOPT_TCP_SET, "sets backlog size");
234 parse_option_net_builtin ("connections", required_argument, 0, 'c', LONGOPT_TCP_SET, "sets maximal connections number");
235 parse_option_net_builtin ("port", required_argument, 0, 'p', LONGOPT_NET_SET, "<port> or <sport>:<eport> sets listening port number or port range");
236 parse_option_net_builtin ("aes-pwd", required_argument, 0, 200, LONGOPT_NET_SET, "sets custom secret.conf file");
237 parse_option_net_builtin ("ipv6", no_argument, 0, '6', LONGOPT_NET_SET, "enables ipv6 TCP/UDP support");
238 parse_option_net_builtin ("disable-tcp", no_argument, 0, 214, LONGOPT_TCP_SET, "do not open listening tcp socket");
239 parse_option_net_builtin ("crc32c", no_argument, 0, 224, LONGOPT_TCP_SET, "Try to use crc32c instead of crc32 in tcp rpc");
240 parse_option_net_builtin ("allow-skip-dh", no_argument, 0, 229, LONGOPT_TCP_SET, "Allow skipping DH during RPC handshake");
241 parse_option_net_builtin ("force-dh", no_argument, 0, 230, LONGOPT_TCP_SET, "Force using DH for all outbound RPC connections");
242 parse_option_net_builtin ("max-accept-rate", required_argument, 0, 249, LONGOPT_TCP_SET, "max number of connections per second that is allowed to accept");
243 parse_option_net_builtin ("max-dh-accept-rate", required_argument, 0, 250, LONGOPT_TCP_SET, "max number of DH connections per second that is allowed to accept");
244 parse_option_net_builtin ("nat-info", required_argument, 0, 372, LONGOPT_NET_SET, "<local-addr>:<global-addr>\tsets network address translation for RPC protocol handshake");
245 parse_option_net_builtin ("address", required_argument, 0, 373, LONGOPT_NET_SET, "tries to bind socket only to specified address");
246}
247