Skip to content
This repository was archived by the owner on Aug 22, 2021. It is now read-only.

Commit 6241fc2

Browse files
committed
Fixes and refactoring for SOCKS5 UDP.
1 parent ae4edfb commit 6241fc2

File tree

15 files changed

+544
-290
lines changed

15 files changed

+544
-290
lines changed

compile-tun2socks.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ system/BConnection_common.c
6161
system/BTime.c
6262
system/BUnixSignal.c
6363
system/BNetwork.c
64+
system/BDatagram_common.c
6465
system/BDatagram_unix.c
6566
flow/StreamRecvInterface.c
6667
flow/PacketRecvInterface.c
@@ -109,6 +110,7 @@ base/BPending.c
109110
flowextra/PacketPassInactivityMonitor.c
110111
tun2socks/SocksUdpGwClient.c
111112
udpgw_client/UdpGwClient.c
113+
socks_udp_client/SocksUdpClient.c
112114
"
113115

114116
set -e

socks_udp_client/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
badvpn_add_library(socks_udp_client "system;flow;flowextra" "" SocksUdpClient.c)
1+
badvpn_add_library(socks_udp_client "base;system;flow;flowextra;socksclient" "" SocksUdpClient.c)

socks_udp_client/SocksUdpClient.c

Lines changed: 301 additions & 209 deletions
Large diffs are not rendered by default.

socks_udp_client/SocksUdpClient.h

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (C) 2018 Jigsaw Operations LLC
3+
* Copyright (C) 2019 Ambroz Bizjak (modifications)
34
*
45
* Redistribution and use in source and binary forms, with or without
56
* modification, are permitted provided that the following conditions are met:
@@ -27,37 +28,35 @@
2728
#ifndef BADVPN_SOCKS_UDP_CLIENT_SOCKSUDPCLIENT_H
2829
#define BADVPN_SOCKS_UDP_CLIENT_SOCKSUDPCLIENT_H
2930

31+
#include <stddef.h>
3032
#include <stdint.h>
3133

3234
#include <base/BPending.h>
3335
#include <base/DebugObject.h>
3436
#include <flow/BufferWriter.h>
3537
#include <flow/PacketBuffer.h>
3638
#include <flow/SinglePacketBuffer.h>
39+
#include <flow/PacketPassInterface.h>
3740
#include <flowextra/PacketPassInactivityMonitor.h>
38-
#include <misc/debug.h>
39-
#include <misc/socks_proto.h>
4041
#include <socksclient/BSocksClient.h>
4142
#include <structure/BAVL.h>
4243
#include <system/BAddr.h>
4344
#include <system/BDatagram.h>
4445
#include <system/BReactor.h>
4546
#include <system/BTime.h>
4647

47-
// This sets the number of packets to accept while waiting for SOCKS server to authenticate and
48-
// connect. A slow or far-away SOCKS server could require 300 ms to connect, and a chatty
49-
// client (e.g. STUN) could send a packet every 20 ms, so a limit of 16 seems reasonable.
50-
#define SOCKS_UDP_SEND_BUFFER_PACKETS 16
51-
52-
typedef void (*SocksUdpClient_handler_received) (void *user, BAddr local_addr, BAddr remote_addr, const uint8_t *data, int data_len);
48+
typedef void (*SocksUdpClient_handler_received) (
49+
void *user, BAddr local_addr, BAddr remote_addr, const uint8_t *data, int data_len);
5350

5451
typedef struct {
5552
BAddr server_addr;
5653
const struct BSocksClient_auth_info *auth_info;
5754
size_t num_auth_info;
5855
int num_connections;
5956
int max_connections;
57+
int send_buf_size;
6058
int udp_mtu;
59+
int socks_mtu;
6160
btime_t keepalive_time;
6261
BReactor *reactor;
6362
void *user;
@@ -77,8 +76,8 @@ struct SocksUdpClient_connection {
7776
BDatagram socket;
7877
PacketPassInterface recv_if;
7978
SinglePacketBuffer recv_buffer;
80-
// The first_* members represent the initial packet, which has to be stored so it can wait for
81-
// send_writer to become ready.
79+
// The first_* members represent the initial packet, which has to be stored so it can
80+
// wait for send_writer to become ready.
8281
uint8_t *first_data;
8382
int first_data_len;
8483
BAddr first_remote_addr;
@@ -92,43 +91,59 @@ struct SocksUdpClient_connection {
9291

9392
/**
9493
* Initializes the SOCKS5-UDP client object.
95-
* This function does not perform network access, so it will always succeed if the arguments
96-
* are valid.
94+
*
95+
* This function only initialzies the object and does not perform network access.
9796
*
9897
* Currently, this function only supports connection to a SOCKS5 server that is routable from
99-
* localhost (i.e. running on the local machine). It may be possible to add support for remote
100-
* servers, but SOCKS5 does not support UDP if there is a NAT or firewall between the client
101-
* and the proxy.
98+
* localhost (i.e. running on the local machine). It may be possible to add support for
99+
* remote servers, but SOCKS5 does not support UDP if there is a NAT or firewall between the
100+
* client and the proxy.
102101
*
103102
* @param o the object
104103
* @param udp_mtu the maximum size of packets that will be sent through the tunnel
105104
* @param max_connections how many local ports to track before dropping packets
105+
* @param send_buf_size maximum number of buffered outgoing packets per connection
106106
* @param keepalive_time how long to track an idle local port before forgetting it
107107
* @param server_addr SOCKS5 server address. MUST BE ON LOCALHOST.
108+
* @param auth_info List of authentication info for BSocksClient. The pointer must remain
109+
* valid while this object exists, the data is not copied.
110+
* @param num_auth_info Number of the above.
108111
* @param reactor reactor we live in
109112
* @param user value passed to handler
110113
* @param handler_received handler for incoming UDP packets
114+
* @return 1 on success, 0 on failure
115+
*/
116+
int SocksUdpClient_Init (SocksUdpClient *o, int udp_mtu, int max_connections,
117+
int send_buf_size, btime_t keepalive_time, BAddr server_addr,
118+
const struct BSocksClient_auth_info *auth_info, size_t num_auth_info,
119+
BReactor *reactor, void *user, SocksUdpClient_handler_received handler_received);
120+
121+
/**
122+
* Frees the SOCKS5-UDP client object.
123+
*
124+
* @param o the object
111125
*/
112-
void SocksUdpClient_Init (SocksUdpClient *o, int udp_mtu, int max_connections, btime_t keepalive_time,
113-
BAddr server_addr, const struct BSocksClient_auth_info *auth_info, size_t num_auth_info,
114-
BReactor *reactor, void *user, SocksUdpClient_handler_received handler_received);
115126
void SocksUdpClient_Free (SocksUdpClient *o);
116127

117128
/**
118129
* Submit a packet to be sent through the proxy.
119130
*
120131
* This will reuse an existing connection for packets from local_addr, or create one if
121-
* there is none. If the number of live connections exceeds max_connections, or if the number of
122-
* buffered packets from this port exceeds a limit, packets will be dropped silently.
132+
* there is none. If the number of live connections exceeds max_connections, or if the
133+
* number of buffered packets from this port exceeds a limit, packets will be dropped
134+
* silently.
123135
*
124-
* As a resource optimization, if a connection has only been used to send one DNS query, then
125-
* the connection will be closed and freed once the reply is received.
136+
* As a resource optimization, if a connection has only been used to send one DNS query,
137+
* then the connection will be closed and freed once the reply is received.
126138
*
127139
* @param o the object
128-
* @param local_addr the UDP packet's source address, and the expected destination for replies
140+
* @param local_addr the UDP packet's source address, and the expected destination for
141+
* replies
129142
* @param remote_addr the destination of the packet after it exits the proxy
130-
* @param data the packet contents. Caller retains ownership.
143+
* @param data the packet contents. Caller retains ownership.
144+
* @param data_len number of bytes in the data
131145
*/
132-
void SocksUdpClient_SubmitPacket (SocksUdpClient *o, BAddr local_addr, BAddr remote_addr, const uint8_t *data, int data_len);
146+
void SocksUdpClient_SubmitPacket (SocksUdpClient *o,
147+
BAddr local_addr, BAddr remote_addr, const uint8_t *data, int data_len);
133148

134149
#endif

socksclient/BSocksClient.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -375,14 +375,16 @@ void recv_handler_done (BSocksClient *o, int data_len)
375375
void *addr_buffer = o->buffer + sizeof(struct socks_reply_header);
376376
switch (o->bind_addr.type) {
377377
case BADDR_TYPE_IPV4: {
378-
struct socks_addr_ipv4 *ip4 = addr_buffer;
379-
o->bind_addr.ipv4.ip = ip4->addr;
380-
o->bind_addr.ipv4.port = ip4->port;
378+
struct socks_addr_ipv4 ip4;
379+
memcpy(&ip4, addr_buffer, sizeof(ip4));
380+
o->bind_addr.ipv4.ip = ip4.addr;
381+
o->bind_addr.ipv4.port = ip4.port;
381382
} break;
382383
case BADDR_TYPE_IPV6: {
383-
struct socks_addr_ipv6 *ip6 = addr_buffer;
384-
memcpy(o->bind_addr.ipv6.ip, ip6->addr, sizeof(ip6->addr));
385-
o->bind_addr.ipv6.port = ip6->port;
384+
struct socks_addr_ipv6 ip6;
385+
memcpy(&ip6, addr_buffer, sizeof(ip6));
386+
memcpy(o->bind_addr.ipv6.ip, ip6.addr, sizeof(ip6.addr));
387+
o->bind_addr.ipv6.port = ip6.port;
386388
} break;
387389
default: ASSERT(0);
388390
}
@@ -395,6 +397,8 @@ void recv_handler_done (BSocksClient *o, int data_len)
395397
free_control_io(o);
396398

397399
// init up I/O
400+
// Initializing this is not needed for UDP ASSOCIATE but it doesn't hurt.
401+
// We anyway don't allow the user to use these interfaces in that case.
398402
init_up_io(o);
399403

400404
// set state
@@ -614,9 +618,18 @@ void BSocksClient_Free (BSocksClient *o)
614618
}
615619
}
616620

621+
BAddr BSocksClient_GetBindAddr (BSocksClient *o)
622+
{
623+
ASSERT(o->state == STATE_UP)
624+
DebugObject_Access(&o->d_obj);
625+
626+
return o->bind_addr;
627+
}
628+
617629
StreamPassInterface * BSocksClient_GetSendInterface (BSocksClient *o)
618630
{
619631
ASSERT(o->state == STATE_UP)
632+
ASSERT(!o->udp)
620633
DebugObject_Access(&o->d_obj);
621634

622635
return BConnection_SendAsync_GetIf(&o->con);
@@ -625,6 +638,7 @@ StreamPassInterface * BSocksClient_GetSendInterface (BSocksClient *o)
625638
StreamRecvInterface * BSocksClient_GetRecvInterface (BSocksClient *o)
626639
{
627640
ASSERT(o->state == STATE_UP)
641+
ASSERT(!o->udp)
628642
DebugObject_Access(&o->d_obj);
629643

630644
return BConnection_RecvAsync_GetIf(&o->con);

socksclient/BSocksClient.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#ifndef BADVPN_SOCKS_BSOCKSCLIENT_H
3535
#define BADVPN_SOCKS_BSOCKSCLIENT_H
3636

37+
#include <stddef.h>
3738
#include <stdint.h>
3839
#include <stdbool.h>
3940

@@ -112,7 +113,14 @@ struct BSocksClient_auth_info BSocksClient_auth_password (const char *username,
112113
*
113114
* @param o the object
114115
* @param server_addr SOCKS5 server address
116+
* @param auth_info List of supported authentication methods and associated parameters.
117+
* Initialize these using functions such as BSocksClient_auth_none() and
118+
* BSocksClient_auth_password(). The pointer must remain valid while this object
119+
* exists, the data is not copied.
120+
* @param num_auth_info Number of the above. There should be at least one, otherwise it
121+
* certainly won't work.
115122
* @param dest_addr remote address
123+
* @param udp whether to do UDP ASSOCIATE instead of CONNECT
116124
* @param handler handler for up and error events
117125
* @param user value passed to handler
118126
* @param reactor reactor we live in
@@ -129,9 +137,20 @@ int BSocksClient_Init (BSocksClient *o,
129137
*/
130138
void BSocksClient_Free (BSocksClient *o);
131139

140+
/**
141+
* Return the bind address that the SOCKS server reported.
142+
* The object must be in up state. The bind address is needed for UDP ASSOCIATE
143+
* because it is the address that the client should send UDP packets to.
144+
*
145+
* @param o the object
146+
* @return The bind address, of type BADDR_TYPE_IPV4 or BADDR_TYPE_IPV6.
147+
*/
148+
BAddr BSocksClient_GetBindAddr (BSocksClient *o);
149+
132150
/**
133151
* Returns the send interface.
134-
* The object must be in up state.
152+
* The object must be in up state. Additionally this must not be called if the
153+
* object was initialized in UDP ASSOCIATE mode.
135154
*
136155
* @param o the object
137156
* @return send interface
@@ -140,7 +159,8 @@ StreamPassInterface * BSocksClient_GetSendInterface (BSocksClient *o);
140159

141160
/**
142161
* Returns the receive interface.
143-
* The object must be in up state.
162+
* The object must be in up state. Additionally this must not be called if the
163+
* object was initialized in UDP ASSOCIATE mode.
144164
*
145165
* @param o the object
146166
* @return receive interface

system/BAddr.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ static int BIPAddr_Resolve (BIPAddr *addr, char *str, int noresolve) WARN_UNUSED
9797

9898
static int BIPAddr_Compare (BIPAddr *addr1, BIPAddr *addr2);
9999

100+
static void BIPAddr_InitLocalhost (BIPAddr *addr, int addr_type);
101+
100102
/**
101103
* Converts an IP address to human readable form.
102104
*
@@ -805,4 +807,20 @@ int BAddr_CompareOrder (BAddr *addr1, BAddr *addr2)
805807
}
806808
}
807809

810+
void BIPAddr_InitLocalhost (BIPAddr *addr, int addr_type)
811+
{
812+
if (addr_type == BADDR_TYPE_IPV4) {
813+
addr->type = addr_type;
814+
addr->ipv4 = hton32(0x7f000001);
815+
}
816+
else if (addr_type == BADDR_TYPE_IPV6) {
817+
addr->type = addr_type;
818+
memset(addr->ipv6, 0, 16);
819+
addr->ipv6[15] = 1;
820+
}
821+
else {
822+
addr->type = BADDR_TYPE_NONE;
823+
}
824+
}
825+
808826
#endif

system/BDatagram.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,22 @@ void BDatagram_SetSendAddrs (BDatagram *o, BAddr remote_addr, BIPAddr local_addr
124124
int BDatagram_GetLastReceiveAddrs (BDatagram *o, BAddr *remote_addr, BIPAddr *local_addr);
125125

126126
/**
127-
* Returns the bound port.
128-
* Fails if and only if a port is not yet bound.
127+
* Determines the local address.
128+
*
129+
* This calls getsockname() to determine the local address and returns the result as
130+
* BAddr. This function fails if the address cannot be determined or translated to
131+
* BAddr (it never succeeds but returns a BADDR_TYPE_NONE address).
132+
*
133+
* @param o the object
134+
* @param local_addr returns the local bound address.
135+
* @return 1 on success, 0 on failure
136+
*/
137+
int BDatagram_GetLocalAddr (BDatagram *o, BAddr *local_addr);
138+
139+
/**
140+
* Returns the local port.
141+
*
142+
* This is a convenience function implemented based on BDatagram_GetLocalAddr.
129143
*
130144
* @param o the object
131145
* @param local_port returns the local bound port.

system/BDatagram_common.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* @file BDatagram_unix.c
3+
* @author Ambroz Bizjak <ambrop7@gmail.com>
4+
*
5+
* @section LICENSE
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
* 1. Redistributions of source code must retain the above copyright
10+
* notice, this list of conditions and the following disclaimer.
11+
* 2. Redistributions in binary form must reproduce the above copyright
12+
* notice, this list of conditions and the following disclaimer in the
13+
* documentation and/or other materials provided with the distribution.
14+
* 3. Neither the name of the author nor the
15+
* names of its contributors may be used to endorse or promote products
16+
* derived from this software without specific prior written permission.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22+
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+
*/
29+
30+
#include <base/BLog.h>
31+
#include <system/BAddr.h>
32+
33+
#include "BDatagram.h"
34+
35+
#include <generated/blog_channel_BDatagram.h>
36+
37+
int BDatagram_GetLocalPort (BDatagram *o, uint16_t *local_port)
38+
{
39+
BAddr addr;
40+
if (!BDatagram_GetLocalAddr(o, &addr)) {
41+
return 0;
42+
}
43+
44+
if (addr.type != BADDR_TYPE_IPV4 && addr.type != BADDR_TYPE_IPV6) {
45+
BLog(BLOG_ERROR,
46+
"BDatagram_GetLocalPort: Port not defined for this address type.");
47+
return 0;
48+
}
49+
50+
*local_port = BAddr_GetPort(&addr);
51+
return 1;
52+
}

0 commit comments

Comments
 (0)