Git Product home page Git Product logo

subnet's Introduction

subnet

VPN server/client for the rest of us.

Authors note: Subnet works but lacks thorough review, and hits performance limits over ~100Mbps. I strongly recommend Wireguard instead for real deployments.

Overview

subnet establishes a TLS connection to the server. A TUN interface is created, and setup with the given network parameters (local IP, subnet). All traffic that matches the localIP + subnet gets routed to the VPN server.

On the server, all traffic which is received is checked against all client's localIPs. If it matches, it goes down there. If it doesn't, it gets routed to the servers TUN device (to its network). If the server's kernel is configured correctly, packets coming back into the TUN device will be NATed, and hence can be routed correctly. They then get routed back to the correct client.

Use cases

Tunnel all non-LAN traffic through another box on the internet (traditional VPN).

Setup the server:

export GOPATH=`pwd` #set your GOPATH where you want the build to happen
go get -u github.com/twitchyliquid64/subnet
sysctl net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -j MASQUERADE
./bin/subnet --mode init-server-certs --cert server.certPEM --key server.keyPEM --ca ca.certPEM --ca_key ca.keyPEM
./bin/subnet --mode server --key server.keyPEM --cert server.certPEM --ca ca.certPEM --network 192.168.69.1/24 0.0.0.0

Setup the client:

First, generate a certificate/key pair for each client, by running this on the server:

./bin/subnet --mode make-client-cert --ca ca.certPEM --ca_key ca.keyPEM client.certPEM client.keyPEM

Then, transfer client.certPEM, client.keyPEM and ca.certPEM to your client.

Now, run this on the client:

export GOPATH=`pwd` #set your GOPATH where you want the build to happen
go get -u github.com/twitchyliquid64/subnet
sudo ./bin/subnet -gw 192.168.69.1 -network 192.168.69.4/24 -cert client.certPEM -key client.keyPEM -ca ca.certPEM <server address>

#If you are on Mac OSX (replace 'Wi-Fi' with your interface):
networksetup -setdnsservers Wi-Fi 8.8.8.8

Explanation:

  • subnet is downloaded and compiled on both client and server.
  • A CA certificate is generated, and a server certificate is generated which is signed by the CA cert (init-server-certs mode).
  • A client certificate is generated, which again is based off the CA cert (make-client-cert mode).
  • Server's networking stack is told to allow the forwarding of packets and to apply NAT to the packets.
  • Server gets the VPN address 192.168.69.1, managing traffic for 192.168.69.1 - 192.168.69.255.
  • Client gets the address 192.168.69.4.
  • Client remaps its default gateway to 192.168.69.1, forcing all non-LAN traffic through the VPN server.
  • On connection, both sides verify the TLS cert against the CA cert given on the command line.

Make a remote LAN accessible on your machine.

Setup the server (linux only):

export GOPATH=`pwd` #set your GOPATH where you want the build to happen
go get -u github.com/twitchyliquid64/subnet
sysctl net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -j MASQUERADE
./bin/subnet --mode init-server-certs --cert server.certPEM --key server.keyPEM --ca ca.certPEM --ca_key ca.keyPEM
./bin/subnet --mode server --key server.keyPEM --cert server.certPEM --ca ca.certPEM --network 192.168.69.1/24 0.0.0.0

Setup the client:

First, generate a certificate/key pair for each client, by running this on the server:

./bin/subnet --mode make-client-cert --ca ca.certPEM --ca_key ca.keyPEM client.certPEM client.keyPEM

Then, transfer client.certPEM, client.keyPEM and ca.certPEM to your client.

Now, run this on the client:

export GOPATH=`pwd` #set your GOPATH where you want the build to happen
go get -u github.com/twitchyliquid64/subnet
sudo ./bin/subnet -network 192.168.69.4/24 -cert client.certPEM -key client.keyPEM -ca ca.certPEM <server address>

Explanation:

  • subnet is downloaded and compiled on both client and server.
  • Certificates are generated, all based on the CA cert which is also generated.
  • Server gets the VPN address 192.168.69.1, managing traffic for 192.168.69.1 - 192.168.69.255.
  • Client gets the address 192.168.69.4. The /24 subnet mask means traffic for addresses 192.168.69.1 to 192.168.69.255 will be routed through the VPN.
  • Any traffic to 192.168.69.1 will go to the VPN server. Any traffic to 192.168.69.1 to 192.168.69.255 will go to clients connected to the same server with that address. All other traffic is routed outside of subnet.

Usage

Usage of ./subnet:
./subnet <server address>
  -blockProfile
    	Enable block profiling
  -ca string
    	Path to PEM-encoded cert to validate client/serv
  -ca_key string
    	Path to PEM-encoded key to use generating certificates
  -cert string
    	Path to PEM-encoded cert for our side of the connection
  -cpuProfile
    	Enable CPU profiling
  -gw string
    	(Client only) Set the default gateway to this value
  -i string
    	TUN interface, one is picked if not specified
  -key string
    	Path to PEM-encoded key for our cert
  -mode string
    	Whether the process starts a server or as a client (default "client")
  -network string
    	Address for this interface with netmask (default "192.168.69.1/24")
  -port string
    	Port for the VPN connection (default "3234")

TODO

  • Fix server crash when processing packet when the client closes connection
  • Document server setup procedure, inc forward, masquasde & cert setup
  • Make client resilient to connection failures to the server
  • Test routing between two clients on the same server.
  • Fix throughput issues - 5% of normal connection speed. Latency is good though.
  • Get working on OSX.

subnet's People

Contributors

dnet avatar felixonmars avatar jpillora avatar twitchyliquid64 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

subnet's Issues

how the server handle the packet sent by client ?

Hi, budy. i have read source code, somewhere i could not understand. ^_^.

why does not the raw packet sent by client need modified ?
for example, changing source ip etc.

Is the non-modify raw packet sent to tun0 directly always routed back correctly ?

How does it compare it OpenVPN?

Is it just Yet Another VPN or something special? I see it gaining stars on Github, but don't see what is the point from cursory glance over the README.

The repository description (now just "Simple VPN") should mention the distinguishing characteristic of the project, also there should be some comparison with other competiting project in README.

accpet io/timeout err

Hi, it is alway say 'accept tcp [::]:9001: i/o timeout', it may be need to check the error type

subnet/subnet/server.go

Lines 107 to 109 in e330ba9

if !s.isShuttingDown {
log.Printf("Listener err: %s\n", err.Error())
}

i try to give solution like below:

              if err != nil {
			if !s.isShuttingDown {
				if !err.(net.Error).Timeout() {
					log.Infof("Listener err: %s", err.Error())
				}
			}
		} else {
			s.handleClient(conn)
		}

Can subnet client run on windows?

Try to run the subnet client run on the windows.
I have installed golang and git on windows.
with the following command:
set GOPATH=C:\Users\37406
go get -u github.com/twitchyliquid64/subnet

there goes the error message:

github.com/twitchyliquid64/subnet/subnet

src\github.com\twitchyliquid64\subnet\subnet\client.go:111:12: undefined: SetDevIP
src\github.com\twitchyliquid64\subnet\subnet\client.go:118:29: undefined: GetNetGateway
src\github.com\twitchyliquid64\subnet\subnet\client.go:126:13: undefined: AddRoute
src\github.com\twitchyliquid64\subnet\subnet\client.go:143:10: undefined: SetDefaultGateway
src\github.com\twitchyliquid64\subnet\subnet\client.go:150:9: undefined: SetInterfaceStatus
src\github.com\twitchyliquid64\subnet\subnet\reverser.go:48:8: undefined: DelRoute
src\github.com\twitchyliquid64\subnet\subnet\server.go:79:11: undefined: SetDevIP

Did i miss something or the subnet client does not design to run on windows?

Package structure updates

Cheers on a neat package, and one that has made it to hackernews :)

Your project structure is fighting the Go ecosystem. You should modify the structure so that you are not checking in src. This makes your package non go get-able.

The contents of your subnet directory should become the contents of your root project available at github.com/twitchyliquid64/subnet and then (with your README still in the project root), change it from:

git clone https://github.com/twitchyliquid64/subnet
cd subnet
export GOPATH=`pwd`
go build -o subnet *.go

to

go get github.com/twitchyliquid64/subnet

go get does two things, first, it pulls the files down into the user's GOPATH, and, second, it runs go install in that directory. This should make your binary available on their system without them altering their GOPATH. Folks should not have to alter their GOPATH to work with your package :)

This will automatically pull in the required dependencies. If you are worried that the wrong version of the dependencies would be pulled in, then you need to vendor them. To vendor your dependencies, after you have moved https://github.com/twitchyliquid64/subnet/tree/master/src/subnet to https://github.com/twitchyliquid64/subnet, then you can run the soon-to-be-official vendoring tool dep (https://github.com/golang/dep) or any other vendoring tool (govend, govendor, glide, ...). This will ensure that the expected versions of dependencies are used when the binary is installed.

Cheers!

ON MAC,the client is not stable

hi.
after i run: sudo subnet -gw 182.168.69.1 -network 182.168.69.4/24 -cert client.certPEM -key client.keyPEM -ca ca.certPEM server-ip

it shows:
2018/02/27 16:50:53 Created iface utun1
2018/02/27 16:50:54 Remote presented certificate 8947204077936876025 with time bounds (2018-02-27 06:47:34 +0000 UTC-2018-08-27 05:47:34 +0000 UTC). Verification error for certificate:
2018/02/27 16:50:54 IP of utun1 set to 182.168.69.4, localNetMask 255.255.255.0
2018/02/27 16:50:54 Default gateway is 192.168.1.1 on en0
2018/02/27 16:50:54 Traffic to my-vps-ip now routed via 192.168.1.1 on en0)

there is such words above: "Verification error for certificate: "

in china, then i open firefox,sometimes i can't visit some blogspot.com sites.
why?it's bcoz "Verification error for certificate: "?
how to fix it?tks

Small review of code and propositions

I've looked at code to find source of "Fix throughput issues - 5% of normal connection speed. Latency is good though." and found next issues:

  1. using gob encoder for transferring packed is big overhead - it's possible just to send uint16 for size and then just []byte of packet - in case of gob encode you have each time allocated new memory + processing (the same for decoding) (if you really need to pack it to some structure and so on on you can choose cheaper encoding, look at https://github.com/alecthomas/go_serialization_benchmarks)
  2. using channels is very expensive in this case: you need to allocate memory for each packet + internal it's mutex lock/unlock - if you'll use pre-allocated buffer it's no additional memory operations + just write to stream - on client this may be just on thread, on server cheaper solution will be to use mutex - lock before write, write and unlock
  3. in case if you really want to use channels you can use unbuffered ones - you'll still has linux kernel network buffers, but if your application is unable to process so much packets as you're receiving it's better to drop them on kernel level, so connection will slow-down but no additional packet lost created (maybe I'm not right, but from experience this way is better - creating one more buffer is additional cpu usage)

iOS and android

Looks like your code allows proper split vpn setups where certain trafficway gets forced over VPN and other does not.

This is something I need at home for home automation aspects.
I am able to build golang based iOS and android apps with a GUI and so think it might not be too hard to build a VPN client for mobiles that supports split also.

Then certain traffic on your phone will be forced to go over the VPN and other just standard network.

It feels lame how a user can't do this splitting .

Wandering if this is a good idea. I would be open to collaborating with others on this. I can get the mobile code base going with golang code integration.

DNS stops working when I start subnet on the client

Hi,
I am following the guide to accessing a LAN from a client; running this command: sudo go/bin/subnet -gw 192.168.69.1 -network 192.168.69.4/24 -cert Downloads/client.certPEM -key Downloads/client.keyPEM -ca Downloads/ca.certPEM my.server.ip does not report any error, however while it is running I can't ping any domains, however I can access them via IP alone.

I am on Gentoo Linux with openrc and using Go version 1.8.3 amd64. This issue does not seem to happen on the server. What can I do to get my DNS working again while I use subnet?

Build error : unknown tls.Config field 'GetCertificate

Hello,
I'm getting an error when getting subnet :

> go get -u github.com/twitchyliquid64/subnet
# github.com/twitchyliquid64/subnet/subnet/conn
src/github.com/twitchyliquid64/subnet/subnet/conn/tls.go:68: unknown tls.Config field 'VerifyPeerCertificate' in struct literal

Found this but I don't have a clue how to fix it myself
strukturag/spreed-webrtc#278

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.