Sfoglia il codice sorgente

tun2socks, udpgw: transparent DNS support, contributed by Kerem Hadimli. No Windows support for now.

ambrop7 13 anni fa
parent
commit
e363bd457d

+ 5 - 9
protocol/udpgw_proto.h

@@ -1,8 +1,7 @@
-/**
- * @file udpgw_proto.h
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- * 
- * @section LICENSE
+/*
+ * Copyright (C) Ambroz Bizjak <ambrop7@gmail.com>
+ * Contributions:
+ * Transparent DNS: Copyright (C) Kerem Hadimli <kerem.hadimli@gmail.com>
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -25,10 +24,6 @@
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Protocol for forwarding UDP over TCP. Messages should be carried with PacketProto.
  */
 
 #ifndef BADVPN_PROTOCOL_UDPGW_PROTO_H
@@ -41,6 +36,7 @@
 
 #define UDPGW_CLIENT_FLAG_KEEPALIVE (1 << 0)
 #define UDPGW_CLIENT_FLAG_REBIND (1 << 1)
+#define UDPGW_CLIENT_FLAG_DNS (1 << 2)
 
 B_START_PACKED
 struct udpgw_header {

+ 7 - 7
tun2socks/SocksUdpGwClient.c

@@ -1,8 +1,7 @@
-/**
- * @file SocksUdpGwClient.c
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- * 
- * @section LICENSE
+/*
+ * Copyright (C) Ambroz Bizjak <ambrop7@gmail.com>
+ * Contributions:
+ * Transparent DNS: Copyright (C) Kerem Hadimli <kerem.hadimli@gmail.com>
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -222,7 +221,7 @@ void SocksUdpGwClient_Free (SocksUdpGwClient *o)
     UdpGwClient_Free(&o->udpgw_client);
 }
 
-void SocksUdpGwClient_SubmitPacket (SocksUdpGwClient *o, BAddr local_addr, BAddr remote_addr, const uint8_t *data, int data_len)
+void SocksUdpGwClient_SubmitPacket (SocksUdpGwClient *o, BAddr local_addr, BAddr remote_addr, int is_dns, const uint8_t *data, int data_len)
 {
     DebugObject_Access(&o->d_obj);
     ASSERT(local_addr.type == BADDR_TYPE_IPV4)
@@ -231,5 +230,6 @@ void SocksUdpGwClient_SubmitPacket (SocksUdpGwClient *o, BAddr local_addr, BAddr
     ASSERT(data_len <= o->udp_mtu)
     
     // submit to udpgw client
-    UdpGwClient_SubmitPacket(&o->udpgw_client, local_addr, remote_addr, data, data_len);
+    UdpGwClient_SubmitPacket(&o->udpgw_client, local_addr, remote_addr, is_dns, data, data_len);
 }
+

+ 5 - 6
tun2socks/SocksUdpGwClient.h

@@ -1,8 +1,7 @@
-/**
- * @file SocksUdpGwClient.h
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- * 
- * @section LICENSE
+/*
+ * Copyright (C) Ambroz Bizjak <ambrop7@gmail.com>
+ * Contributions:
+ * Transparent DNS: Copyright (C) Kerem Hadimli <kerem.hadimli@gmail.com>
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -60,6 +59,6 @@ int SocksUdpGwClient_Init (SocksUdpGwClient *o, int udp_mtu, int max_connections
                            BAddr remote_udpgw_addr, btime_t reconnect_time, BReactor *reactor, void *user,
                            SocksUdpGwClient_handler_received handler_received) WARN_UNUSED;
 void SocksUdpGwClient_Free (SocksUdpGwClient *o);
-void SocksUdpGwClient_SubmitPacket (SocksUdpGwClient *o, BAddr local_addr, BAddr remote_addr, const uint8_t *data, int data_len);
+void SocksUdpGwClient_SubmitPacket (SocksUdpGwClient *o, BAddr local_addr, BAddr remote_addr, int is_dns, const uint8_t *data, int data_len);
 
 #endif

+ 17 - 6
tun2socks/tun2socks.c

@@ -1,8 +1,7 @@
-/**
- * @file tun2socks.c
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- * 
- * @section LICENSE
+/*
+ * Copyright (C) Ambroz Bizjak <ambrop7@gmail.com>
+ * Contributions:
+ * Transparent DNS: Copyright (C) Kerem Hadimli <kerem.hadimli@gmail.com>
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -105,6 +104,7 @@ struct {
     char *udpgw_remote_server_addr;
     int udpgw_max_connections;
     int udpgw_connection_buffer_size;
+    int udpgw_transparent_dns;
 } options;
 
 // TCP client
@@ -460,6 +460,7 @@ void print_help (const char *name)
         "        [--udpgw-remote-server-addr <addr>]\n"
         "        [--udpgw-max-connections <number>]\n"
         "        [--udpgw-connection-buffer-size <number>]\n"
+        "        [--udpgw-transparent-dns]\n"
         "Address format is a.b.c.d:port (IPv4) or [addr]:port (IPv6).\n",
         name
     );
@@ -497,6 +498,7 @@ int parse_arguments (int argc, char *argv[])
     options.udpgw_remote_server_addr = NULL;
     options.udpgw_max_connections = DEFAULT_UDPGW_MAX_CONNECTIONS;
     options.udpgw_connection_buffer_size = DEFAULT_UDPGW_CONNECTION_BUFFER_SIZE;
+    options.udpgw_transparent_dns = 0;
     
     int i;
     for (i = 1; i < argc; i++) {
@@ -660,6 +662,9 @@ int parse_arguments (int argc, char *argv[])
             }
             i++;
         }
+        else if (!strcmp(arg, "--udpgw-transparent-dns")) {
+            options.udpgw_transparent_dns = 1;
+        }
         else {
             fprintf(stderr, "unknown option: %s\n", arg);
             return 0;
@@ -962,8 +967,14 @@ int process_device_udp_packet (uint8_t *data, int data_len)
     BAddr remote_addr;
     BAddr_InitIPv4(&remote_addr, ipv4_header.destination_address, udp_header.dest_port);
     
+    // if transparent DNS is enabled, any packet arriving at out netif
+    // address to port 53 is considered a DNS packet
+    int is_dns = (options.udpgw_transparent_dns &&
+                  ipv4_header.destination_address == netif_ipaddr.ipv4 &&
+                  udp_header.dest_port == hton16(53));
+    
     // submit packet to udpgw
-    SocksUdpGwClient_SubmitPacket(&udpgw_client, local_addr, remote_addr, data, data_len);
+    SocksUdpGwClient_SubmitPacket(&udpgw_client, local_addr, remote_addr, is_dns, data, data_len);
     
     return 1;
     

+ 2 - 5
tun2socks/tun2socks.h

@@ -1,8 +1,5 @@
-/**
- * @file tun2socks.h
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- * 
- * @section LICENSE
+/*
+ * Copyright (C) Ambroz Bizjak <ambrop7@gmail.com>
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:

+ 79 - 14
udpgw/udpgw.c

@@ -1,8 +1,7 @@
-/**
- * @file udpgw.c
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- * 
- * @section LICENSE
+/*
+ * Copyright (C) Ambroz Bizjak <ambrop7@gmail.com>
+ * Contributions:
+ * Transparent DNS: Copyright (C) Kerem Hadimli <kerem.hadimli@gmail.com>
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -31,6 +30,7 @@
 #include <string.h>
 #include <stdarg.h>
 #include <stdlib.h>
+#include <limits.h>
 
 #include <protocol/udpgw_proto.h>
 #include <misc/debug.h>
@@ -60,6 +60,8 @@
 
 #ifndef BADVPN_USE_WINAPI
 #include <base/BLog_syslog.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
 #endif
 
 #include <udpgw/udpgw.h>
@@ -69,6 +71,8 @@
 #define LOGGER_STDOUT 1
 #define LOGGER_SYSLOG 2
 
+#define DNS_UPDATE_TIME 2000
+
 struct client {
     BConnection con;
     BAddr addr;
@@ -88,6 +92,7 @@ struct connection {
     struct client *client;
     uint16_t conid;
     BAddr addr;
+    BAddr orig_addr;
     const uint8_t *first_data;
     int first_data_len;
     btime_t last_use_time;
@@ -146,6 +151,10 @@ int num_listen_addrs;
 // local UDP port range, if options.local_udp_num_ports>=0
 BAddr local_udp_addr;
 
+// DNS forwarding
+BAddr dns_addr;
+btime_t last_dns_update_time;
+
 // reactor
 BReactor ss;
 
@@ -171,7 +180,7 @@ static void client_connection_handler (struct client *client, int event);
 static void client_decoder_handler_error (struct client *client);
 static void client_recv_if_handler_send (struct client *client, uint8_t *data, int data_len);
 static uint8_t * build_port_usage_array_and_find_least_used_connection (BAddr remote_addr, struct connection **out_con);
-static void connection_init (struct client *client, uint16_t conid, BAddr addr, const uint8_t *data, int data_len);
+static void connection_init (struct client *client, uint16_t conid, BAddr addr, BAddr orig_addr, const uint8_t *data, int data_len);
 static void connection_free (struct connection *con);
 static void connection_logfunc (struct connection *con);
 static void connection_log (struct connection *con, int level, const char *fmt, ...);
@@ -185,6 +194,7 @@ static void connection_dgram_handler_event (struct connection *con, int event);
 static void connection_udp_recv_if_handler_send (struct connection *con, uint8_t *data, int data_len);
 static struct connection * find_connection (struct client *client, uint16_t conid);
 static int uint16_comparator (void *unused, uint16_t *v1, uint16_t *v2);
+static void maybe_update_dns (void);
 
 int main (int argc, char **argv)
 {
@@ -266,6 +276,11 @@ int main (int argc, char **argv)
     // init time
     BTime_Init();
     
+    // init DNS forwarding
+    BAddr_InitNone(&dns_addr);
+    last_dns_update_time = INT64_MIN;
+    maybe_update_dns();
+    
     // init reactor
     if (!BReactor_Init(&ss)) {
         BLog(BLOG_ERROR, "BReactor_Init failed");
@@ -799,9 +814,8 @@ void client_recv_if_handler_send (struct client *client, uint8_t *data, int data
     ASSERT(!con || !con->closing)
     
     // if connection exists, close it if needed
-    if (con && ((flags & UDPGW_CLIENT_FLAG_REBIND) || con->addr.ipv4.ip != header.addr_ip || con->addr.ipv4.port != header.addr_port)) {
+    if (con && ((flags & UDPGW_CLIENT_FLAG_REBIND) || con->orig_addr.ipv4.ip != header.addr_ip || con->orig_addr.ipv4.port != header.addr_port)) {
         connection_log(con, BLOG_DEBUG, "close old");
-        
         connection_close(con);
         con = NULL;
     }
@@ -816,11 +830,23 @@ void client_recv_if_handler_send (struct client *client, uint8_t *data, int data
         }
         
         // read address
-        BAddr addr;
-        BAddr_InitIPv4(&addr, header.addr_ip, header.addr_port);
+        BAddr orig_addr;
+        BAddr_InitIPv4(&orig_addr, header.addr_ip, header.addr_port);
+        BAddr addr = orig_addr;
+        
+        // if this is DNS, replace actual address, but keep header.addr_ip header.addr_port intact
+        if ((flags & UDPGW_CLIENT_FLAG_DNS)) {
+            maybe_update_dns();
+            if (dns_addr.type == BADDR_TYPE_NONE) {
+                client_log(client, BLOG_WARNING, "received DNS packet, but no DNS server available");
+            } else {
+                client_log(client, BLOG_DEBUG, "received DNS");
+                addr = dns_addr;
+            }
+        }
         
         // create new connection
-        connection_init(client, conid, addr, data, data_len);
+        connection_init(client, conid, addr, orig_addr, data, data_len);
     } else {
         // submit packet to existing connection
         connection_send_to_udp(con, data, data_len);
@@ -881,12 +907,13 @@ uint8_t * build_port_usage_array_and_find_least_used_connection (BAddr remote_ad
     return port_usage;
 }
 
-void connection_init (struct client *client, uint16_t conid, BAddr addr, const uint8_t *data, int data_len)
+void connection_init (struct client *client, uint16_t conid, BAddr addr, BAddr orig_addr, const uint8_t *data, int data_len)
 {
     ASSERT(client->num_connections < options.max_connections_for_client)
     ASSERT(!find_connection(client, conid))
     BAddr_Assert(&addr);
     ASSERT(addr.type == BADDR_TYPE_IPV4)
+    ASSERT(orig_addr.type == BADDR_TYPE_IPV4)
     ASSERT(data_len >= 0)
     ASSERT(data_len <= options.udp_mtu)
     
@@ -901,6 +928,7 @@ void connection_init (struct client *client, uint16_t conid, BAddr addr, const u
     con->client = client;
     con->conid = conid;
     con->addr = addr;
+    con->orig_addr = orig_addr;
     con->first_data = data;
     con->first_data_len = data_len;
     
@@ -1151,8 +1179,8 @@ int connection_send_to_client (struct connection *con, uint8_t flags, const uint
     struct udpgw_header header;
     header.flags = htol8(flags);
     header.conid = htol16(con->conid);
-    header.addr_ip = con->addr.ipv4.ip;
-    header.addr_port = con->addr.ipv4.port;
+    header.addr_ip = con->orig_addr.ipv4.ip;
+    header.addr_port = con->orig_addr.ipv4.port;
     memcpy(out, &header, sizeof(header));
     
     // write message
@@ -1295,3 +1323,40 @@ int uint16_comparator (void *unused, uint16_t *v1, uint16_t *v2)
 {
     return B_COMPARE(*v1, *v2);
 }
+
+void maybe_update_dns (void)
+{
+#ifndef BADVPN_USE_WINAPI
+    btime_t now = btime_gettime();
+    if (now < btime_add(last_dns_update_time, DNS_UPDATE_TIME)) {
+        return;
+    }
+    last_dns_update_time = now;
+    BLog(BLOG_DEBUG, "update dns");
+    
+    if (res_init() != 0) {
+        BLog(BLOG_ERROR, "res_init failed");
+        goto fail;
+    }
+    
+    if (_res.nscount == 0) {
+        BLog(BLOG_ERROR, "no name servers available");
+        goto fail;
+    }
+    
+    BAddr addr;
+    BAddr_InitIPv4(&addr, _res.nsaddr_list[0].sin_addr.s_addr, hton16(53));
+    
+    if (!BAddr_Compare(&addr, &dns_addr)) {
+        char str[BADDR_MAX_PRINT_LEN];
+        BAddr_Print(&addr, str);
+        BLog(BLOG_INFO, "using DNS server %s", str);
+    }
+    
+    dns_addr = addr;
+    return;
+    
+fail:
+    BAddr_InitNone(&dns_addr);
+#endif
+}

+ 2 - 5
udpgw/udpgw.h

@@ -1,8 +1,5 @@
-/**
- * @file udpgw.h
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- * 
- * @section LICENSE
+/*
+ * Copyright (C) Ambroz Bizjak <ambrop7@gmail.com>
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:

+ 15 - 10
udpgw_client/UdpGwClient.c

@@ -1,8 +1,7 @@
-/**
- * @file UdpGwClient.c
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- * 
- * @section LICENSE
+/*
+ * Copyright (C) Ambroz Bizjak <ambrop7@gmail.com>
+ * Contributions:
+ * Transparent DNS: Copyright (C) Kerem Hadimli <kerem.hadimli@gmail.com>
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -50,7 +49,7 @@ static void keepalive_if_handler_done (UdpGwClient *o);
 static struct UdpGwClient_connection * find_connection_by_conaddr (UdpGwClient *o, struct UdpGwClient_conaddr conaddr);
 static struct UdpGwClient_connection * find_connection_by_conid (UdpGwClient *o, uint16_t conid);
 static uint16_t find_unused_conid (UdpGwClient *o);
-static void connection_init (UdpGwClient *o, struct UdpGwClient_conaddr conaddr, const uint8_t *data, int data_len);
+static void connection_init (UdpGwClient *o, struct UdpGwClient_conaddr conaddr, uint8_t flags, const uint8_t *data, int data_len);
 static void connection_free (struct UdpGwClient_connection *con);
 static void connection_first_job_handler (struct UdpGwClient_connection *con);
 static void connection_send (struct UdpGwClient_connection *con, uint8_t flags, const uint8_t *data, int data_len);
@@ -227,7 +226,7 @@ static uint16_t find_unused_conid (UdpGwClient *o)
     }
 }
 
-static void connection_init (UdpGwClient *o, struct UdpGwClient_conaddr conaddr, const uint8_t *data, int data_len)
+static void connection_init (UdpGwClient *o, struct UdpGwClient_conaddr conaddr, uint8_t flags, const uint8_t *data, int data_len)
 {
     ASSERT(o->num_connections < o->max_connections)
     ASSERT(!find_connection_by_conaddr(o, conaddr))
@@ -244,6 +243,7 @@ static void connection_init (UdpGwClient *o, struct UdpGwClient_conaddr conaddr,
     // init arguments
     con->client = o;
     con->conaddr = conaddr;
+    con->first_flags = flags;
     con->first_data = data;
     con->first_data_len = data_len;
     
@@ -318,7 +318,7 @@ static void connection_free (struct UdpGwClient_connection *con)
 
 static void connection_first_job_handler (struct UdpGwClient_connection *con)
 {
-    connection_send(con, UDPGW_CLIENT_FLAG_REBIND, con->first_data, con->first_data_len);
+    connection_send(con, UDPGW_CLIENT_FLAG_REBIND|con->first_flags, con->first_data, con->first_data_len);
 }
 
 static void connection_send (struct UdpGwClient_connection *con, uint8_t flags, const uint8_t *data, int data_len)
@@ -483,7 +483,7 @@ void UdpGwClient_Free (UdpGwClient *o)
     PacketPassConnector_Free(&o->send_connector);
 }
 
-void UdpGwClient_SubmitPacket (UdpGwClient *o, BAddr local_addr, BAddr remote_addr, const uint8_t *data, int data_len)
+void UdpGwClient_SubmitPacket (UdpGwClient *o, BAddr local_addr, BAddr remote_addr, int is_dns, const uint8_t *data, int data_len)
 {
     DebugObject_Access(&o->d_obj);
     ASSERT(local_addr.type == BADDR_TYPE_IPV4)
@@ -500,6 +500,11 @@ void UdpGwClient_SubmitPacket (UdpGwClient *o, BAddr local_addr, BAddr remote_ad
     struct UdpGwClient_connection *con = find_connection_by_conaddr(o, conaddr);
     
     uint8_t flags = 0;
+
+    if (is_dns) {
+        // route to remote DNS server instead of provided address
+        flags |= UDPGW_CLIENT_FLAG_DNS;
+    }
     
     // if no connection and can't create a new one, reuse the least recently used une
     if (!con && o->num_connections == o->max_connections) {
@@ -509,7 +514,7 @@ void UdpGwClient_SubmitPacket (UdpGwClient *o, BAddr local_addr, BAddr remote_ad
     
     if (!con) {
         // create new connection
-        connection_init(o, conaddr, data, data_len);
+        connection_init(o, conaddr, flags, data, data_len);
     } else {
         // move connection to front of the list
         LinkedList1_Remove(&o->connections_list, &con->connections_list_node);

+ 6 - 6
udpgw_client/UdpGwClient.h

@@ -1,8 +1,7 @@
-/**
- * @file UdpGwClient.h
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- * 
- * @section LICENSE
+/*
+ * Copyright (C) Ambroz Bizjak <ambrop7@gmail.com>
+ * Contributions:
+ * Transparent DNS: Copyright (C) Kerem Hadimli <kerem.hadimli@gmail.com>
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -95,6 +94,7 @@ struct UdpGwClient_conaddr {
 struct UdpGwClient_connection {
     UdpGwClient *client;
     struct UdpGwClient_conaddr conaddr;
+    uint8_t first_flags;
     const uint8_t *first_data;
     int first_data_len;
     uint16_t conid;
@@ -111,7 +111,7 @@ int UdpGwClient_Init (UdpGwClient *o, int udp_mtu, int max_connections, int send
                       UdpGwClient_handler_servererror handler_servererror,
                       UdpGwClient_handler_received handler_received) WARN_UNUSED;
 void UdpGwClient_Free (UdpGwClient *o);
-void UdpGwClient_SubmitPacket (UdpGwClient *o, BAddr local_addr, BAddr remote_addr, const uint8_t *data, int data_len);
+void UdpGwClient_SubmitPacket (UdpGwClient *o, BAddr local_addr, BAddr remote_addr, int is_dns, const uint8_t *data, int data_len);
 int UdpGwClient_ConnectServer (UdpGwClient *o, StreamPassInterface *send_if, StreamRecvInterface *recv_if) WARN_UNUSED;
 void UdpGwClient_DisconnectServer (UdpGwClient *o);