BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright (C) 2018 Jigsaw Operations LLC |
||
3 | * Copyright (C) 2019 Ambroz Bizjak (modifications) |
||
4 | * |
||
5 | * Redistribution and use in source and binary forms, with or without |
||
6 | * modification, are permitted provided that the following conditions are met: |
||
7 | * 1. Redistributions of source code must retain the above copyright |
||
8 | * notice, this list of conditions and the following disclaimer. |
||
9 | * 2. Redistributions in binary form must reproduce the above copyright |
||
10 | * notice, this list of conditions and the following disclaimer in the |
||
11 | * documentation and/or other materials provided with the distribution. |
||
12 | * 3. Neither the name of the author nor the |
||
13 | * names of its contributors may be used to endorse or promote products |
||
14 | * derived from this software without specific prior written permission. |
||
15 | * |
||
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
26 | */ |
||
27 | |||
28 | #include <stddef.h> |
||
29 | #include <stdint.h> |
||
30 | #include <stdlib.h> |
||
31 | #include <string.h> |
||
32 | |||
33 | #include <misc/balloc.h> |
||
34 | #include <misc/offset.h> |
||
35 | #include <misc/byteorder.h> |
||
36 | #include <misc/compare.h> |
||
37 | #include <misc/socks_proto.h> |
||
38 | #include <misc/debug.h> |
||
39 | #include <misc/bsize.h> |
||
40 | #include <base/BLog.h> |
||
41 | #include <system/BAddr.h> |
||
42 | |||
43 | #include <socks_udp_client/SocksUdpClient.h> |
||
44 | |||
45 | #include <generated/blog_channel_SocksUdpClient.h> |
||
46 | |||
47 | static const int DnsPort = 53; |
||
48 | |||
49 | static int addr_comparator (void *unused, BAddr *v1, BAddr *v2); |
||
50 | static struct SocksUdpClient_connection * find_connection (SocksUdpClient *o, BAddr addr); |
||
51 | static void socks_state_handler (struct SocksUdpClient_connection *con, int event); |
||
52 | static void datagram_state_handler (struct SocksUdpClient_connection *con, int event); |
||
53 | static void send_monitor_handler (struct SocksUdpClient_connection *con); |
||
54 | static void recv_if_handler_send ( |
||
55 | struct SocksUdpClient_connection *con, uint8_t *data, int data_len); |
||
56 | static struct SocksUdpClient_connection * connection_init ( |
||
57 | SocksUdpClient *o, BAddr local_addr, BAddr first_remote_addr, |
||
58 | const uint8_t *first_data, int first_data_len); |
||
59 | static void connection_free (struct SocksUdpClient_connection *con); |
||
60 | static void connection_send (struct SocksUdpClient_connection *con, |
||
61 | BAddr remote_addr, const uint8_t *data, int data_len); |
||
62 | static void first_job_handler (struct SocksUdpClient_connection *con); |
||
63 | static int compute_socks_mtu (int udp_mtu); |
||
64 | static int get_dns_id (BAddr *remote_addr, const uint8_t *data, int data_len); |
||
65 | |||
66 | int addr_comparator (void *unused, BAddr *v1, BAddr *v2) |
||
67 | { |
||
68 | return BAddr_CompareOrder(v1, v2); |
||
69 | } |
||
70 | |||
71 | struct SocksUdpClient_connection * find_connection (SocksUdpClient *o, BAddr addr) |
||
72 | { |
||
73 | BAVLNode *tree_node = BAVL_LookupExact(&o->connections_tree, &addr); |
||
74 | if (!tree_node) { |
||
75 | return NULL; |
||
76 | } |
||
77 | |||
78 | return UPPER_OBJECT(tree_node, struct SocksUdpClient_connection, connections_tree_node); |
||
79 | } |
||
80 | |||
81 | void socks_state_handler (struct SocksUdpClient_connection *con, int event) |
||
82 | { |
||
83 | DebugObject_Access(&con->client->d_obj); |
||
84 | |||
85 | switch (event) { |
||
86 | case BSOCKSCLIENT_EVENT_CONNECTED: { |
||
87 | // Get the local address of the SOCKS TCP connection. |
||
88 | BAddr tcp_local_addr; |
||
89 | if (!BSocksClient_GetLocalAddr(&con->socks, &tcp_local_addr)) { |
||
90 | BLog(BLOG_ERROR, "Failed to get TCP local address."); |
||
91 | return connection_free(con); |
||
92 | } |
||
93 | |||
94 | // Sanity check the address type (required by SetPort below). |
||
95 | if (tcp_local_addr.type != BADDR_TYPE_IPV4 && |
||
96 | tcp_local_addr.type != BADDR_TYPE_IPV6) |
||
97 | { |
||
98 | BLog(BLOG_ERROR, "Bad address type in TCP local address."); |
||
99 | return connection_free(con); |
||
100 | } |
||
101 | |||
102 | // Bind the UDP socket to the same IP address and let the kernel pick the port. |
||
103 | BAddr udp_bound_addr = tcp_local_addr; |
||
104 | BAddr_SetPort(&udp_bound_addr, 0); |
||
105 | if (!BDatagram_Bind(&con->socket, udp_bound_addr)) { |
||
106 | BLog(BLOG_ERROR, "Failed to bind the UDP socket."); |
||
107 | return connection_free(con); |
||
108 | } |
||
109 | |||
110 | // Update udp_bound_addr to the actual address that was bound. |
||
111 | if (!BDatagram_GetLocalAddr(&con->socket, &udp_bound_addr)) { |
||
112 | BLog(BLOG_ERROR, "Failed to get UDP bound address."); |
||
113 | return connection_free(con); |
||
114 | } |
||
115 | |||
116 | // Set the DST.ADDR for SOCKS. |
||
117 | BSocksClient_SetDestAddr(&con->socks, udp_bound_addr); |
||
118 | } break; |
||
119 | |||
120 | case BSOCKSCLIENT_EVENT_UP: { |
||
121 | // The remote address to send datagrams to is the BND.ADDR provided by the |
||
122 | // SOCKS server. |
||
123 | BAddr remote_addr = BSocksClient_GetBindAddr(&con->socks); |
||
124 | |||
125 | // Don't bother setting a source address for datagrams since we are bound. |
||
126 | BIPAddr local_addr; |
||
127 | BIPAddr_InitInvalid(&local_addr); |
||
128 | |||
129 | // Set the addresses for BDatagram. |
||
130 | // This will unblock the queue of outgoing packets. |
||
131 | BDatagram_SetSendAddrs(&con->socket, remote_addr, local_addr); |
||
132 | } break; |
||
133 | |||
134 | case BSOCKSCLIENT_EVENT_ERROR: { |
||
135 | char local_buffer[BADDR_MAX_PRINT_LEN]; |
||
136 | BAddr_Print(&con->local_addr, local_buffer); |
||
137 | BLog(BLOG_ERROR, |
||
138 | "SOCKS error event for %s, removing connection.", local_buffer); |
||
139 | |||
140 | connection_free(con); |
||
141 | } break; |
||
142 | |||
143 | case BSOCKSCLIENT_EVENT_ERROR_CLOSED: { |
||
144 | char local_buffer[BADDR_MAX_PRINT_LEN]; |
||
145 | BAddr_Print(&con->local_addr, local_buffer); |
||
146 | BLog(BLOG_WARNING, |
||
147 | "SOCKS closed event for %s, removing connection.", local_buffer); |
||
148 | |||
149 | connection_free(con); |
||
150 | } break; |
||
151 | } |
||
152 | } |
||
153 | |||
154 | void datagram_state_handler (struct SocksUdpClient_connection *con, int event) |
||
155 | { |
||
156 | DebugObject_Access(&con->client->d_obj); |
||
157 | |||
158 | if (event == BDATAGRAM_EVENT_ERROR) { |
||
159 | char local_buffer[BADDR_MAX_PRINT_LEN]; |
||
160 | BAddr_Print(&con->local_addr, local_buffer); |
||
161 | BLog(BLOG_ERROR, |
||
162 | "Low-level datagram error %s, removing connection.", local_buffer); |
||
163 | |||
164 | // Remove the connection. Note that BDatagram requires that we free |
||
165 | // the BDatagram after an error is reported. |
||
166 | connection_free(con); |
||
167 | } |
||
168 | } |
||
169 | |||
170 | void send_monitor_handler (struct SocksUdpClient_connection *con) |
||
171 | { |
||
172 | DebugObject_Access(&con->client->d_obj); |
||
173 | |||
174 | char local_buffer[BADDR_MAX_PRINT_LEN]; |
||
175 | BAddr_Print(&con->local_addr, local_buffer); |
||
176 | BLog(BLOG_INFO, |
||
177 | "Removing connection for %s due to inactivity.", local_buffer); |
||
178 | |||
179 | // The connection has passed its idle timeout. Remove it. |
||
180 | connection_free(con); |
||
181 | } |
||
182 | |||
183 | void recv_if_handler_send ( |
||
184 | struct SocksUdpClient_connection *con, uint8_t *data, int data_len) |
||
185 | { |
||
186 | DebugObject_Access(&con->client->d_obj); |
||
187 | SocksUdpClient *o = con->client; |
||
188 | ASSERT(data_len >= 0) |
||
189 | ASSERT(data_len <= o->socks_mtu) |
||
190 | |||
191 | // accept packet |
||
192 | PacketPassInterface_Done(&con->recv_if); |
||
193 | |||
194 | // check header |
||
195 | struct socks_udp_header header; |
||
196 | if (data_len < sizeof(header)) { |
||
197 | BLog(BLOG_ERROR, "Missing SOCKS-UDP header."); |
||
198 | return; |
||
199 | } |
||
200 | memcpy(&header, data, sizeof(header)); |
||
201 | data += sizeof(header); |
||
202 | data_len -= sizeof(header); |
||
203 | |||
204 | // parse address |
||
205 | BAddr remote_addr; |
||
206 | switch (header.atyp) { |
||
207 | case SOCKS_ATYP_IPV4: { |
||
208 | struct socks_addr_ipv4 addr_ipv4; |
||
209 | if (data_len < sizeof(addr_ipv4)) { |
||
210 | BLog(BLOG_ERROR, "Missing IPv4 address."); |
||
211 | return; |
||
212 | } |
||
213 | memcpy(&addr_ipv4, data, sizeof(addr_ipv4)); |
||
214 | data += sizeof(addr_ipv4); |
||
215 | data_len -= sizeof(addr_ipv4); |
||
216 | remote_addr.type = BADDR_TYPE_IPV4; |
||
217 | remote_addr.ipv4.ip = addr_ipv4.addr; |
||
218 | remote_addr.ipv4.port = addr_ipv4.port; |
||
219 | } break; |
||
220 | case SOCKS_ATYP_IPV6: { |
||
221 | struct socks_addr_ipv6 addr_ipv6; |
||
222 | if (data_len < sizeof(addr_ipv6)) { |
||
223 | BLog(BLOG_ERROR, "Missing IPv6 address."); |
||
224 | return; |
||
225 | } |
||
226 | memcpy(&addr_ipv6, data, sizeof(addr_ipv6)); |
||
227 | data += sizeof(addr_ipv6); |
||
228 | data_len -= sizeof(addr_ipv6); |
||
229 | remote_addr.type = BADDR_TYPE_IPV6; |
||
230 | memcpy(remote_addr.ipv6.ip, addr_ipv6.addr, sizeof(remote_addr.ipv6.ip)); |
||
231 | remote_addr.ipv6.port = addr_ipv6.port; |
||
232 | } break; |
||
233 | default: { |
||
234 | BLog(BLOG_ERROR, "Bad address type"); |
||
235 | return; |
||
236 | } break; |
||
237 | } |
||
238 | |||
239 | // check remaining data |
||
240 | if (data_len > o->udp_mtu) { |
||
241 | BLog(BLOG_ERROR, "too much data"); |
||
242 | return; |
||
243 | } |
||
244 | |||
245 | // pass packet to user |
||
246 | SocksUdpClient *client = con->client; |
||
247 | client->handler_received(client->user, con->local_addr, remote_addr, data, data_len); |
||
248 | |||
249 | // Was this connection used for a DNS query? |
||
250 | if (con->dns_id >= 0) { |
||
251 | // Get the DNS transaction ID of the response. |
||
252 | int recv_dns_id = get_dns_id(&remote_addr, data, data_len); |
||
253 | |||
254 | // Does the transaction ID matche that of the request? |
||
255 | if (recv_dns_id == con->dns_id) { |
||
256 | // We have now forwarded the response, so this connection is no longer needed. |
||
257 | char local_buffer[BADDR_MAX_PRINT_LEN]; |
||
258 | BAddr_Print(&con->local_addr, local_buffer); |
||
259 | BLog(BLOG_DEBUG, |
||
260 | "Removing connection for %s after the DNS response.", local_buffer); |
||
261 | |||
262 | connection_free(con); |
||
263 | } else { |
||
264 | BLog(BLOG_INFO, "DNS client port received an unexpected non-DNS packet, " |
||
265 | "disabling DNS optimization."); |
||
266 | |||
267 | con->dns_id = -1; |
||
268 | } |
||
269 | } |
||
270 | } |
||
271 | |||
272 | struct SocksUdpClient_connection * connection_init ( |
||
273 | SocksUdpClient *o, BAddr local_addr, BAddr first_remote_addr, |
||
274 | const uint8_t *first_data, int first_data_len) |
||
275 | { |
||
276 | ASSERT(o->num_connections <= o->max_connections) |
||
277 | ASSERT(!find_connection(o, local_addr)) |
||
278 | |||
279 | char local_buffer[BADDR_MAX_PRINT_LEN]; |
||
280 | BAddr_Print(&local_addr, local_buffer); |
||
281 | BLog(BLOG_DEBUG, "Creating connection for %s.", local_buffer); |
||
282 | |||
283 | // allocate structure |
||
284 | struct SocksUdpClient_connection *con = |
||
285 | (struct SocksUdpClient_connection *)BAlloc(sizeof(*con)); |
||
286 | if (!con) { |
||
287 | BLog(BLOG_ERROR, "BAlloc connection failed"); |
||
288 | goto fail0; |
||
289 | } |
||
290 | |||
291 | // set basic things |
||
292 | con->client = o; |
||
293 | con->local_addr = local_addr; |
||
294 | |||
295 | // store first outgoing packet |
||
296 | con->first_data = BAlloc(first_data_len); |
||
297 | if (!con->first_data) { |
||
298 | BLog(BLOG_ERROR, "BAlloc first data failed"); |
||
299 | goto fail1; |
||
300 | } |
||
301 | memcpy(con->first_data, first_data, first_data_len); |
||
302 | con->first_data_len = first_data_len; |
||
303 | con->first_remote_addr = first_remote_addr; |
||
304 | |||
305 | // Get the DNS transaction ID from the packet, if any. |
||
306 | con->dns_id = get_dns_id(&first_remote_addr, first_data, first_data_len); |
||
307 | |||
308 | BPendingGroup *pg = BReactor_PendingGroup(o->reactor); |
||
309 | |||
310 | // Init first job, to send the first packet asynchronously. This has to happen |
||
311 | // asynchronously because con->send_writer (a BufferWriter) cannot accept writes until |
||
312 | // after it is linked with its PacketBuffer (con->send_buffer), which happens |
||
313 | // asynchronously. |
||
314 | BPending_Init(&con->first_job, pg, (BPending_handler)first_job_handler, con); |
||
315 | // Add the first job to the pending set. BPending acts as a LIFO stack, and |
||
316 | // first_job_handler needs to run after async actions that occur in PacketBuffer_Init, |
||
317 | // so we need to put first_job on the stack first. |
||
318 | BPending_Set(&con->first_job); |
||
319 | |||
320 | // Create a datagram socket |
||
321 | if (!BDatagram_Init(&con->socket, con->local_addr.type, o->reactor, con, |
||
322 | (BDatagram_handler)datagram_state_handler)) |
||
323 | { |
||
324 | BLog(BLOG_ERROR, "Failed to create a UDP socket"); |
||
325 | goto fail2; |
||
326 | } |
||
327 | |||
328 | // We will set the DST.ADDR for SOCKS later (BSOCKSCLIENT_EVENT_CONNECTED). |
||
329 | BAddr dummy_dst_addr; |
||
330 | BAddr_InitNone(&dummy_dst_addr); |
||
331 | |||
332 | // Initiate connection to socks server |
||
333 | if (!BSocksClient_Init(&con->socks, o->server_addr, o->auth_info, o->num_auth_info, |
||
334 | dummy_dst_addr, true, (BSocksClient_handler)socks_state_handler, con, o->reactor)) |
||
335 | { |
||
336 | BLog(BLOG_ERROR, "Failed to initialize SOCKS client"); |
||
337 | goto fail3; |
||
338 | } |
||
339 | |||
340 | // Since we use o->socks_mtu for send and receive pipelines, we can handle maximally |
||
341 | // sized packets (o->udp_mtu) including the SOCKS-UDP header. |
||
342 | |||
343 | // Send pipeline: send_writer -> send_buffer -> send_monitor -> send_if -> socket. |
||
344 | BDatagram_SendAsync_Init(&con->socket, o->socks_mtu); |
||
345 | PacketPassInactivityMonitor_Init(&con->send_monitor, |
||
346 | BDatagram_SendAsync_GetIf(&con->socket), o->reactor, o->keepalive_time, |
||
347 | (PacketPassInactivityMonitor_handler)send_monitor_handler, con); |
||
348 | BufferWriter_Init(&con->send_writer, o->socks_mtu, pg); |
||
349 | if (!PacketBuffer_Init(&con->send_buffer, BufferWriter_GetOutput(&con->send_writer), |
||
350 | PacketPassInactivityMonitor_GetInput(&con->send_monitor), o->send_buf_size, pg)) |
||
351 | { |
||
352 | BLog(BLOG_ERROR, "Send buffer init failed"); |
||
353 | goto fail4; |
||
354 | } |
||
355 | |||
356 | // Receive pipeline: socket -> recv_buffer -> recv_if |
||
357 | BDatagram_RecvAsync_Init(&con->socket, o->socks_mtu); |
||
358 | PacketPassInterface_Init(&con->recv_if, o->socks_mtu, |
||
359 | (PacketPassInterface_handler_send)recv_if_handler_send, con, pg); |
||
360 | if (!SinglePacketBuffer_Init(&con->recv_buffer, |
||
361 | BDatagram_RecvAsync_GetIf(&con->socket), &con->recv_if, pg)) |
||
362 | { |
||
363 | BLog(BLOG_ERROR, "Receive buffer init failed"); |
||
364 | goto fail5; |
||
365 | } |
||
366 | |||
367 | // Insert to connections tree, it must succeed because of the assert. |
||
368 | int inserted = BAVL_Insert(&o->connections_tree, &con->connections_tree_node, NULL); |
||
369 | ASSERT(inserted) |
||
370 | B_USE(inserted) |
||
371 | |||
372 | // increment number of connections |
||
373 | o->num_connections++; |
||
374 | |||
375 | return con; |
||
376 | |||
377 | fail5: |
||
378 | PacketPassInterface_Free(&con->recv_if); |
||
379 | BDatagram_RecvAsync_Free(&con->socket); |
||
380 | PacketBuffer_Free(&con->send_buffer); |
||
381 | fail4: |
||
382 | BufferWriter_Free(&con->send_writer); |
||
383 | PacketPassInactivityMonitor_Free(&con->send_monitor); |
||
384 | BDatagram_SendAsync_Free(&con->socket); |
||
385 | BSocksClient_Free(&con->socks); |
||
386 | fail3: |
||
387 | BDatagram_Free(&con->socket); |
||
388 | fail2: |
||
389 | BPending_Free(&con->first_job); |
||
390 | BFree(con->first_data); |
||
391 | fail1: |
||
392 | BFree(con); |
||
393 | fail0: |
||
394 | return NULL; |
||
395 | } |
||
396 | |||
397 | void connection_free (struct SocksUdpClient_connection *con) |
||
398 | { |
||
399 | SocksUdpClient *o = con->client; |
||
400 | |||
401 | // decrement number of connections |
||
402 | ASSERT(o->num_connections > 0) |
||
403 | o->num_connections--; |
||
404 | |||
405 | // remove from connections tree |
||
406 | BAVL_Remove(&o->connections_tree, &con->connections_tree_node); |
||
407 | |||
408 | // Free UDP receive pipeline components |
||
409 | SinglePacketBuffer_Free(&con->recv_buffer); |
||
410 | PacketPassInterface_Free(&con->recv_if); |
||
411 | BDatagram_RecvAsync_Free(&con->socket); |
||
412 | |||
413 | // Free UDP send pipeline components |
||
414 | PacketBuffer_Free(&con->send_buffer); |
||
415 | BufferWriter_Free(&con->send_writer); |
||
416 | PacketPassInactivityMonitor_Free(&con->send_monitor); |
||
417 | BDatagram_SendAsync_Free(&con->socket); |
||
418 | |||
419 | // Free SOCKS client |
||
420 | BSocksClient_Free(&con->socks); |
||
421 | |||
422 | // Free UDP socket |
||
423 | BDatagram_Free(&con->socket); |
||
424 | |||
425 | // Free first job |
||
426 | BPending_Free(&con->first_job); |
||
427 | |||
428 | // Free first outgoing packet |
||
429 | BFree(con->first_data); |
||
430 | |||
431 | // Free structure |
||
432 | BFree(con); |
||
433 | } |
||
434 | |||
435 | void connection_send (struct SocksUdpClient_connection *con, |
||
436 | BAddr remote_addr, const uint8_t *data, int data_len) |
||
437 | { |
||
438 | ASSERT(data_len >= 0) |
||
439 | ASSERT(data_len <= con->client->udp_mtu) |
||
440 | |||
441 | if (con->dns_id >= 0) { |
||
442 | // So far, this connection has only sent a single DNS query. |
||
443 | int new_dns_id = get_dns_id(&remote_addr, data, data_len); |
||
444 | if (new_dns_id != con->dns_id) { |
||
445 | BLog(BLOG_DEBUG, "Client reused DNS query port. Disabling DNS optimization."); |
||
446 | con->dns_id = -1; |
||
447 | } |
||
448 | } |
||
449 | |||
450 | // Check if we're sending to an IPv4 or IPv6 destination. |
||
451 | int atyp; |
||
452 | size_t address_size; |
||
453 | // write address |
||
454 | switch (remote_addr.type) { |
||
455 | case BADDR_TYPE_IPV4: { |
||
456 | atyp = SOCKS_ATYP_IPV4; |
||
457 | address_size = sizeof(struct socks_addr_ipv4); |
||
458 | } break; |
||
459 | case BADDR_TYPE_IPV6: { |
||
460 | atyp = SOCKS_ATYP_IPV6; |
||
461 | address_size = sizeof(struct socks_addr_ipv6); |
||
462 | } break; |
||
463 | default: { |
||
464 | BLog(BLOG_ERROR, "Bad address type in outgoing packet."); |
||
465 | return; |
||
466 | } break; |
||
467 | } |
||
468 | |||
469 | // Determine total packet size in the buffer. |
||
470 | // This cannot exceed o->socks_mtu because data_len is required to not exceed |
||
471 | // o->udp_mtu and o->socks_mtu is calculated to accomodate any UDP packet not |
||
472 | // not exceeding o->udp_mtu. |
||
473 | size_t total_len = sizeof(struct socks_udp_header) + address_size + data_len; |
||
474 | ASSERT(total_len <= con->client->socks_mtu) |
||
475 | |||
476 | // Get a pointer to write the packet to. |
||
477 | uint8_t *out_data_begin; |
||
478 | if (!BufferWriter_StartPacket(&con->send_writer, &out_data_begin)) { |
||
479 | BLog(BLOG_ERROR, "Send buffer is full."); |
||
480 | return; |
||
481 | } |
||
482 | uint8_t *out_data = out_data_begin; |
||
483 | |||
484 | // Write header |
||
485 | struct socks_udp_header header; |
||
486 | header.rsv = 0; |
||
487 | header.frag = 0; |
||
488 | header.atyp = atyp; |
||
489 | memcpy(out_data, &header, sizeof(header)); |
||
490 | out_data += sizeof(header); |
||
491 | |||
492 | // Write address |
||
493 | switch (atyp) { |
||
494 | case SOCKS_ATYP_IPV4: { |
||
495 | struct socks_addr_ipv4 addr_ipv4; |
||
496 | addr_ipv4.addr = remote_addr.ipv4.ip; |
||
497 | addr_ipv4.port = remote_addr.ipv4.port; |
||
498 | memcpy(out_data, &addr_ipv4, sizeof(addr_ipv4)); |
||
499 | out_data += sizeof(addr_ipv4); |
||
500 | } break; |
||
501 | case SOCKS_ATYP_IPV6: { |
||
502 | struct socks_addr_ipv6 addr_ipv6; |
||
503 | memcpy(addr_ipv6.addr, remote_addr.ipv6.ip, sizeof(addr_ipv6.addr)); |
||
504 | addr_ipv6.port = remote_addr.ipv6.port; |
||
505 | memcpy(out_data, &addr_ipv6, sizeof(addr_ipv6)); |
||
506 | out_data += sizeof(addr_ipv6); |
||
507 | } break; |
||
508 | } |
||
509 | |||
510 | // Write payload |
||
511 | memcpy(out_data, data, data_len); |
||
512 | out_data += data_len; |
||
513 | |||
514 | ASSERT(out_data - out_data_begin == total_len) |
||
515 | |||
516 | // Submit packet to buffer |
||
517 | BufferWriter_EndPacket(&con->send_writer, total_len); |
||
518 | } |
||
519 | |||
520 | void first_job_handler (struct SocksUdpClient_connection *con) |
||
521 | { |
||
522 | DebugObject_Access(&con->client->d_obj); |
||
523 | ASSERT(con->first_data) |
||
524 | |||
525 | // Send the first packet. |
||
526 | connection_send(con, con->first_remote_addr, con->first_data, con->first_data_len); |
||
527 | |||
528 | // Release the first packet buffer. |
||
529 | BFree(con->first_data); |
||
530 | con->first_data = NULL; |
||
531 | con->first_data_len = 0; |
||
532 | } |
||
533 | |||
534 | int compute_socks_mtu (int udp_mtu) |
||
535 | { |
||
536 | bsize_t bs = bsize_add( |
||
537 | bsize_fromint(udp_mtu), |
||
538 | bsize_add( |
||
539 | bsize_fromsize(sizeof(struct socks_udp_header)), |
||
540 | bsize_fromsize(sizeof(struct socks_addr_ipv6)) |
||
541 | ) |
||
542 | ); |
||
543 | int s; |
||
544 | return bsize_toint(bs, &s) ? s : -1; |
||
545 | } |
||
546 | |||
547 | // Get the DNS transaction ID, or -1 if this does not look like a DNS packet. |
||
548 | int get_dns_id (BAddr *remote_addr, const uint8_t *data, int data_len) |
||
549 | { |
||
550 | if (ntoh16(BAddr_GetPort(remote_addr)) == DnsPort && data_len >= 2) { |
||
551 | return (data[0] << 8) | data[1]; |
||
552 | } else { |
||
553 | return -1; |
||
554 | } |
||
555 | } |
||
556 | |||
557 | int SocksUdpClient_Init (SocksUdpClient *o, int udp_mtu, int max_connections, |
||
558 | int send_buf_size, btime_t keepalive_time, BAddr server_addr, |
||
559 | const struct BSocksClient_auth_info *auth_info, size_t num_auth_info, |
||
560 | BReactor *reactor, void *user, SocksUdpClient_handler_received handler_received) |
||
561 | { |
||
562 | ASSERT(udp_mtu >= 0) |
||
563 | ASSERT(max_connections > 0) |
||
564 | ASSERT(send_buf_size > 0) |
||
565 | |||
566 | // init simple things |
||
567 | o->server_addr = server_addr; |
||
568 | o->auth_info = auth_info; |
||
569 | o->num_auth_info = num_auth_info; |
||
570 | o->num_connections = 0; |
||
571 | o->max_connections = max_connections; |
||
572 | o->send_buf_size = send_buf_size; |
||
573 | o->udp_mtu = udp_mtu; |
||
574 | o->keepalive_time = keepalive_time; |
||
575 | o->reactor = reactor; |
||
576 | o->user = user; |
||
577 | o->handler_received = handler_received; |
||
578 | |||
579 | // calculate full MTU with SOCKS header |
||
580 | o->socks_mtu = compute_socks_mtu(udp_mtu); |
||
581 | if (o->socks_mtu < 0) { |
||
582 | BLog(BLOG_ERROR, "SocksUdpClient_Init: MTU too large."); |
||
583 | goto fail0; |
||
584 | } |
||
585 | |||
586 | // init connections tree |
||
587 | BAVL_Init(&o->connections_tree, |
||
588 | OFFSET_DIFF(struct SocksUdpClient_connection, local_addr, connections_tree_node), |
||
589 | (BAVL_comparator)addr_comparator, NULL); |
||
590 | |||
591 | DebugObject_Init(&o->d_obj); |
||
592 | return 1; |
||
593 | |||
594 | fail0: |
||
595 | return 0; |
||
596 | } |
||
597 | |||
598 | void SocksUdpClient_Free (SocksUdpClient *o) |
||
599 | { |
||
600 | DebugObject_Free(&o->d_obj); |
||
601 | |||
602 | // free connections |
||
603 | while (!BAVL_IsEmpty(&o->connections_tree)) { |
||
604 | BAVLNode *node = BAVL_GetFirst(&o->connections_tree); |
||
605 | struct SocksUdpClient_connection *con = |
||
606 | UPPER_OBJECT(node, struct SocksUdpClient_connection, connections_tree_node); |
||
607 | connection_free(con); |
||
608 | } |
||
609 | } |
||
610 | |||
611 | void SocksUdpClient_SubmitPacket (SocksUdpClient *o, |
||
612 | BAddr local_addr, BAddr remote_addr, const uint8_t *data, int data_len) |
||
613 | { |
||
614 | DebugObject_Access(&o->d_obj); |
||
615 | ASSERT(local_addr.type == BADDR_TYPE_IPV4 || local_addr.type == BADDR_TYPE_IPV6) |
||
616 | ASSERT(remote_addr.type == BADDR_TYPE_IPV4 || remote_addr.type == BADDR_TYPE_IPV6) |
||
617 | ASSERT(data_len >= 0) |
||
618 | ASSERT(data_len <= o->udp_mtu) |
||
619 | |||
620 | // lookup connection |
||
621 | struct SocksUdpClient_connection *con = find_connection(o, local_addr); |
||
622 | if (!con) { |
||
623 | if (o->num_connections >= o->max_connections) { |
||
624 | // Drop the packet. |
||
625 | BLog(BLOG_WARNING, "Dropping UDP packet, reached max number of connections."); |
||
626 | return; |
||
627 | } |
||
628 | // create new connection and enqueue the packet |
||
629 | connection_init(o, local_addr, remote_addr, data, data_len); |
||
630 | } else { |
||
631 | // send packet |
||
632 | connection_send(con, remote_addr, data, data_len); |
||
633 | } |
||
634 | } |