Procházet zdrojové kódy

Fix issue when exposing tunnel via IPv6, update readme

Billy Barrow před 1 rokem
rodič
revize
5b6cb4ab6b
5 změnil soubory, kde provedl 63 přidání a 35 odebrání
  1. 20 1
      README.md
  2. 3 4
      config
  3. 18 16
      src/client/client.vala
  4. 13 6
      src/server/server.vala
  5. 9 8
      src/server/tunnel/tunnel.vala

+ 20 - 1
README.md

@@ -11,4 +11,23 @@ Currently supports forwarding the following protocols:
 
 When a connection is made to the Astrogate server, it reads data from the client, and uses pattern matching to determine what protocol the client is likely talking. It uses this information to attempt to read out an intended hostname from the data and tunnels the connection to the configured host.
 
-It also supports tunnel mode, where by using the `astrogate-tunnel` client program creates a TUN interface where traffic will appear to be routed from their original IP addresses on the internet. This is useful since Astrogate does not modify any data it proxies, so there are not a HTTP `X-Forwarded-For` header to know where the request came from.
+It also supports tunnel mode, where by using the `astrogate-tunnel` client program creates a TUN interface where traffic will appear to be routed from their original IP addresses on the internet. This is useful since Astrogate does not modify any data it proxies, so there is not (for example) an HTTP `X-Forwarded-For` header for the server to know where the request came from.
+
+## Possible stretch goals
+- Raw TCP forwarding (port forwarding) without hostname check
+- Support for UDP datagrams and similar port forwarding
+- Support IPv6 in the tunnel virtual network (can still currently be hosted over IPv6)
+
+## Technical limitations
+
+### HTTP and HTTP over TLS
+
+This will work perfectly fine for HTTP/1.1 requests. Things get more hazy when it comes to technologies like streaming connections and HTTP3/Quic for example. Some of these new technologies will be "smart" about whether a connection is going to the same IP address (not just same host) and re-use an existing connection to that same IP. That means that if there are multuple HTTP/HTTPS destinations to reach via the one Astrogate server, servers with this technology enabled may receive requests intended for other domains under a special set of circumstances.
+
+This can be mitigated by not enabling these technologies on the server side.
+
+### Tunnel limitations
+
+The tunnel, along with the `astrogate-tunnel` client (ab)uses the Linux network stack to allow incoming connections to be routed through the tunnel for their lifetime. This means the IP routing table is constantly updated, with specific routes for specific IP addresses added and removed as needed. This could be disruptive to services running on the the client that are expected to be able to initiate connections to IP addresses that may connect to it via the tunnel.
+
+The tunnel acts as a sort of "reverse NAT", except connections *from* the internet get mapped instead of connections *to* the internet. This means that the tunnel client can't be used to initiate TCP connections to the internet through the proxy server. This makes it only useful to expose services that accept TCP connections (such as HTTP, Gemini, or Spartan servers) to the internet, not services that need to initiate connections (such as XMPP server-to-server communication for example).

+ 3 - 4
config

@@ -1,6 +1,6 @@
-BIND-TO 127.0.0.1
+BIND-TO 192.168.1.126
 BIND-TO 200:3785:eb78:5234:e4f1:d453:86d3:59ff
-TUNNEL 192.168.1.126 6060 tun0 10.60.0.0 255.255.0.0
+TUNNEL 200:3785:eb78:5234:e4f1:d453:86d3:59ff 6060 tun0 10.60.0.0 255.255.0.0
 
 TLS billy.barrow.nz 443 ROUND-ROBIN {
     192.168.1.232 443
@@ -10,8 +10,7 @@ TLS billy.barrow.nz 443 ROUND-ROBIN {
 }
 
 HTTP billy.barrow.nz 80 {
-    tun/192.168.1.206 8081
-    tun/127.0.0.1 8081
+    tun/200:5aa3:aaa7:7a2:a496:e6dd:1388:6f79 8081
 }
 
 

+ 18 - 16
src/client/client.vala

@@ -4,11 +4,12 @@ namespace AstrogateTunnel {
 
     private static Socket socket;
     private static int tun_fd;
-
+    
     private static string ifname;
     private static InetSocketAddress server_address;
     private static InetSocketAddress client_address;
-
+    
+    private static Socket vpn_socket;
     private static InetAddress vpn_network;
     private static InetAddress vpn_netmask;
     private static InetAddress vpn_ip;
@@ -30,13 +31,6 @@ namespace AstrogateTunnel {
             socket = new Socket(server_address.family, SocketType.DATAGRAM, SocketProtocol.UDP);
             socket.bind(client_address, false);
 
-            // Open tun device
-            tun_fd = handle_posix_error("opening tun device", Posix.open("/dev/net/tun", Posix.O_RDWR));
-
-            // Create tunnel device
-            var request = generate_ifreq();
-            handle_posix_error("creating tun interface", Linux.ioctl(tun_fd, IfTun.Tun.SETIFF, &request));
-
             // Register with server
             var registration_message = new uint8[] { 'R' };
             socket.connect(server_address);
@@ -69,6 +63,14 @@ namespace AstrogateTunnel {
                 return -3;
             }
 
+            // Open tun device
+            tun_fd = handle_posix_error("opening tun device", Posix.open("/dev/net/tun", Posix.O_RDWR));
+
+            // Create tunnel device
+            var request = generate_ifreq();
+            handle_posix_error("creating tun interface", Linux.ioctl(tun_fd, IfTun.Tun.SETIFF, &request));
+            vpn_socket = new Socket(vpn_network.family, SocketType.DATAGRAM, SocketProtocol.UDP);
+
             uint16 mtu_val = 0;
             Memory.copy(&mtu_val, mtu_dat, sizeof(uint16));
             mtu = mtu_val.to_big_endian();
@@ -81,19 +83,19 @@ namespace AstrogateTunnel {
             
             request.ifr_flags = 0;
             request.ifr_mtu = mtu;
-            handle_posix_error(@"setting MTU for $ifname", Linux.ioctl(socket.fd, Linux.Network.SIOCSIFMTU, &request));
+            handle_posix_error(@"setting MTU for $ifname", Linux.ioctl(vpn_socket.fd, Linux.Network.SIOCSIFMTU, &request));
 
             request.ifr_flags |= Linux.Network.IfFlag.UP;
-            handle_posix_error(@"bringing $ifname up", Linux.ioctl(socket.fd, Linux.Network.SIOCSIFFLAGS, &request));
+            handle_posix_error(@"bringing $ifname up", Linux.ioctl(vpn_socket.fd, Linux.Network.SIOCSIFFLAGS, &request));
             
             address_to_posix(vpn_ip, &request.ifr_addr);
-            handle_posix_error(@"setting IP address for $ifname", Linux.ioctl(socket.fd, Linux.Network.SIOCSIFADDR, &request));
+            handle_posix_error(@"setting IP address for $ifname", Linux.ioctl(vpn_socket.fd, Linux.Network.SIOCSIFADDR, &request));
 
             address_to_posix(vpn_netmask, &request.ifr_addr);
-            handle_posix_error(@"setting subnet mask for $ifname", Linux.ioctl(socket.fd, Linux.Network.SIOCSIFNETMASK, &request));
+            handle_posix_error(@"setting subnet mask for $ifname", Linux.ioctl(vpn_socket.fd, Linux.Network.SIOCSIFNETMASK, &request));
 
             address_to_posix(vpn_network, &request.ifr_addr);
-            handle_posix_error(@"setting destination network for $ifname", Linux.ioctl(socket.fd, Linux.Network.SIOCSIFDSTADDR, &request));
+            handle_posix_error(@"setting destination network for $ifname", Linux.ioctl(vpn_socket.fd, Linux.Network.SIOCSIFDSTADDR, &request));
         }
         catch(Error e) {
             print(@"Fatal error: $(e.message)\n");
@@ -162,7 +164,7 @@ namespace AstrogateTunnel {
         print(@"Linking IP $(address)\n");
         var route = build_rtentry(address);
 
-        var res = Linux.ioctl(socket.fd, Linux.Network.SIOCADDRT, &route);
+        var res = Linux.ioctl(vpn_socket.fd, Linux.Network.SIOCADDRT, &route);
         if(res < 0 && errno != Posix.EEXIST) {
             handle_posix_error(@"adding route to $address", res);
         }
@@ -175,7 +177,7 @@ namespace AstrogateTunnel {
         var address = new InetAddress.from_bytes(buffer[1:buffer.length], vpn_ip.family);
         print(@"Uninking IP $(address)\n");
         var route = build_rtentry(address);
-        handle_posix_error(@"adding route to $address", Linux.ioctl(socket.fd, Linux.Network.SIOCDELRT, &route));
+        handle_posix_error(@"adding route to $address", Linux.ioctl(vpn_socket.fd, Linux.Network.SIOCDELRT, &route));
     }
 
     private Linux.Network.RtEntry build_rtentry(InetAddress address) {

+ 13 - 6
src/server/server.vala

@@ -203,12 +203,18 @@ namespace Astrogate {
         }
         
         var mapping = tunnel.map(source.address, dest.socket_address.address, (uint16)dest.socket_address.port);
-        var local_addr = new InetSocketAddress(tunnel.proxy_internal_ip, mapping.source_port);
-        client.set_local_address(local_addr);
-        print(@"TUNNEL CONNECTION: $(local_addr) -> $(new InetSocketAddress(mapping.internal_address, mapping.target_port))");
-        var connection = yield client.connect_async(new InetSocketAddress(mapping.internal_address, mapping.target_port), cancellation_token);
-        connection.notify["closed"].connect(() => tunnel.unmap(mapping));
-        return new ProxyConnection(connection, mapping);
+        try {
+            var local_addr = new InetSocketAddress(tunnel.proxy_internal_ip, mapping.source_port);
+            client.set_local_address(local_addr);
+            print(@"TUNNEL CONNECTION: $(local_addr) -> $(new InetSocketAddress(mapping.internal_address, mapping.target_port))");
+            var connection = yield client.connect_async(new InetSocketAddress(mapping.internal_address, mapping.target_port), cancellation_token);
+            return new ProxyConnection(connection, mapping);
+        }
+        catch(Error e) {
+            // Clean up mapping for failed connection
+            tunnel.unmap(mapping);
+            throw e;
+        }
     }
 
     private class ProxyConnection {
@@ -227,6 +233,7 @@ namespace Astrogate {
             print("Cleanup connection!\n");
             cancellation_token.cancel();
             connection = null;
+            // Give the TCP connections some time to finish up before unmapping
             GLib.Timeout.add_seconds_once(10, () => {
                 if(mapping != null) {
                     tunnel.unmap(mapping);

+ 9 - 8
src/server/tunnel/tunnel.vala

@@ -39,6 +39,7 @@ namespace Astrogate {
             proxy_internal_ip = allocate_address();
 
             var socket = new Socket(proxy_socket_address.family, SocketType.DATAGRAM, SocketProtocol.UDP);
+            var internal_socket = new Socket(internal_network_ip.family, SocketType.STREAM, SocketProtocol.TCP);
 
             // Open tun device
             fd = handle_posix_error("opening tun device", Posix.open("/dev/net/tun", Posix.O_RDWR));
@@ -50,19 +51,19 @@ namespace Astrogate {
             
             request.ifr_flags = 0;
             request.ifr_mtu = mtu;
-            handle_posix_error(@"setting MTU for $iface", Linux.ioctl(socket.fd, Linux.Network.SIOCSIFMTU, &request));
+            handle_posix_error(@"setting MTU for $iface", Linux.ioctl(internal_socket.fd, Linux.Network.SIOCSIFMTU, &request));
             
             request.ifr_flags |= Linux.Network.IfFlag.UP;
-            handle_posix_error(@"bringing $iface up", Linux.ioctl(socket.fd, Linux.Network.SIOCSIFFLAGS, &request));
+            handle_posix_error(@"bringing $iface up", Linux.ioctl(internal_socket.fd, Linux.Network.SIOCSIFFLAGS, &request));
 
             address_to_posix(proxy_internal_ip, &request.ifr_addr);
-            handle_posix_error(@"setting IP address for $iface", Linux.ioctl(socket.fd, Linux.Network.SIOCSIFADDR, &request));
+            handle_posix_error(@"setting IP address for $iface", Linux.ioctl(internal_socket.fd, Linux.Network.SIOCSIFADDR, &request));
             
             address_to_posix(internal_network_mask, &request.ifr_addr);
-            handle_posix_error(@"setting subnet mask for $iface", Linux.ioctl(socket.fd, Linux.Network.SIOCSIFNETMASK, &request));
+            handle_posix_error(@"setting subnet mask for $iface", Linux.ioctl(internal_socket.fd, Linux.Network.SIOCSIFNETMASK, &request));
             
             address_to_posix(internal_network_ip, &request.ifr_addr);
-            handle_posix_error(@"setting destination network for $iface", Linux.ioctl(socket.fd, Linux.Network.SIOCSIFDSTADDR, &request));
+            handle_posix_error(@"setting destination network for $iface", Linux.ioctl(internal_socket.fd, Linux.Network.SIOCSIFDSTADDR, &request));
             
             udp_server = new TunnelServer(proxy_socket_address, this);
         }
@@ -86,7 +87,7 @@ namespace Astrogate {
             mapping.source_port = allocate_port();
 
 
-            mapping.external_address = new InetAddress.from_string("8.8.8.8");
+            //mapping.external_address = new InetAddress.from_string("8.8.8.8");
 
             address_mapping.add(mapping);
             udp_server.link_ip(mapping.forward_address, mapping.external_address);
@@ -94,7 +95,7 @@ namespace Astrogate {
         }
 
         public void unmap(TunnelAddressMapping mapping) throws Error {
-            print("Unmapping!");
+            print("Unmapping!\n");
             lock(available_ports) {
                 var index = address_mapping.index_of(m => m == mapping);
                 if(index == -1) {
@@ -255,7 +256,7 @@ namespace Astrogate {
 
         public uint16 allocate_port() throws TunnelError {
             lock(available_ports) {
-                for(int i = 10; i < available_ports.length; i++) {
+                for(int i = 11; i < available_ports.length; i++) {
                     if(available_ports[i] == false) {
                         available_ports[i] = true;
                         return (uint16)i;