mirror of
https://github.com/net-byte/vtun
synced 2024-03-14 10:50:03 +08:00
Add vtun
This commit is contained in:
commit
51ab983d43
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# Mac OS X files
|
||||
.DS_Store
|
||||
# Binaries for programs and plugins
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
|
||||
logs/
|
||||
bin/
|
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@ -0,0 +1,9 @@
|
||||
FROM golang:1.14.3-alpine
|
||||
|
||||
WORKDIR /app
|
||||
COPY . /app
|
||||
ENV GO111MODULE=on
|
||||
RUN go build -o ./bin/vtun ./main.go
|
||||
|
||||
ENTRYPOINT ["./bin/vtun"]
|
||||
|
20
LICENSE
Executable file
20
LICENSE
Executable file
@ -0,0 +1,20 @@
|
||||
The MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
18
README.md
Normal file
18
README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# vtun
|
||||
|
||||
A simple p2p vpn.
|
||||
|
||||
# Usage
|
||||
|
||||
```
|
||||
Usage of ./vtun:
|
||||
|
||||
-k string
|
||||
Encrypt key (default "6da62287-979a-4eb4-a5ab-8b3d89da134b")
|
||||
-l string
|
||||
Local tun interface IP/MASK like 172.16.0.1/24 (default "172.16.0.1/24")
|
||||
-p int
|
||||
UDP port (default 2001)
|
||||
-r string
|
||||
Remote server external IP like 172.16.0.2 (default "172.16.0.2")
|
||||
```
|
135
cmd/vtun.go
Normal file
135
cmd/vtun.go
Normal file
@ -0,0 +1,135 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
|
||||
"github.com/songgao/water"
|
||||
)
|
||||
|
||||
const (
|
||||
BufferSize = 1500
|
||||
MTU = "1300"
|
||||
)
|
||||
|
||||
// New vtun
|
||||
func New(local *string, remote *string, port *int, key *string) {
|
||||
os := runtime.GOOS
|
||||
if "linux" != os {
|
||||
log.Fatal("Only support linux!")
|
||||
return
|
||||
}
|
||||
hashKey := createHash(*key)
|
||||
// create tun
|
||||
config := water.Config{
|
||||
DeviceType: water.TAP,
|
||||
}
|
||||
config.Name = "vtun"
|
||||
iface, err := water.New(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if nil != err {
|
||||
log.Fatalln("Unable to allocate TUN interface:", err)
|
||||
}
|
||||
log.Println("Interface allocated:", iface.Name())
|
||||
// config tun
|
||||
configTun(local, iface)
|
||||
// start udp listener
|
||||
remoteAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%v", *remote, *port))
|
||||
if nil != err {
|
||||
log.Fatalln("Unable to resolve remote addr:", err)
|
||||
}
|
||||
localAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%v", *port))
|
||||
if nil != err {
|
||||
log.Fatalln("Unable to get UDP socket:", err)
|
||||
}
|
||||
conn, err := net.ListenUDP("udp", localAddr)
|
||||
if nil != err {
|
||||
log.Fatalln("Unable to listen on UDP socket:", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
// read data from remote and write data to tun
|
||||
go func() {
|
||||
buf := make([]byte, BufferSize)
|
||||
for {
|
||||
n, _, err := conn.ReadFromUDP(buf)
|
||||
if err != nil || n == 0 {
|
||||
break
|
||||
}
|
||||
b := buf[:n]
|
||||
// aes decrypt
|
||||
decrypt(&b, hashKey)
|
||||
iface.Write(b)
|
||||
}
|
||||
}()
|
||||
// read data from tun and write to remote
|
||||
packet := make([]byte, BufferSize)
|
||||
for {
|
||||
n, err := iface.Read(packet)
|
||||
if err != nil || n == 0 {
|
||||
break
|
||||
}
|
||||
b := packet[:n]
|
||||
// aes encrypt
|
||||
encrypt(&b, hashKey)
|
||||
conn.WriteToUDP(b, remoteAddr)
|
||||
}
|
||||
}
|
||||
|
||||
func configTun(local *string, iface *water.Interface) {
|
||||
execCmd("/sbin/ip", "link", "set", "dev", iface.Name(), "mtu", MTU)
|
||||
execCmd("/sbin/ip", "addr", "add", *local, "dev", iface.Name())
|
||||
execCmd("/sbin/ip", "link", "set", "dev", iface.Name(), "up")
|
||||
}
|
||||
|
||||
func execCmd(c string, args ...string) {
|
||||
cmd := exec.Command(c, args...)
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stdin = os.Stdin
|
||||
err := cmd.Run()
|
||||
if nil != err {
|
||||
log.Fatalln("Error running /sbin/ip:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func createHash(key string) []byte {
|
||||
hasher := md5.New()
|
||||
hasher.Write([]byte(key))
|
||||
return []byte(hex.EncodeToString(hasher.Sum(nil)))
|
||||
}
|
||||
|
||||
func encrypt(data *[]byte, key []byte) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
iv := key[:aes.BlockSize]
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
dest := make([]byte, len(*data))
|
||||
stream.XORKeyStream(dest, *data)
|
||||
data = nil
|
||||
data = &dest
|
||||
}
|
||||
|
||||
func decrypt(data *[]byte, key []byte) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
iv := key[:aes.BlockSize]
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
dest := make([]byte, len(*data))
|
||||
stream.XORKeyStream(dest, *data)
|
||||
data = nil
|
||||
data = &dest
|
||||
}
|
9
go.mod
Normal file
9
go.mod
Normal file
@ -0,0 +1,9 @@
|
||||
module vtun
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/marten-seemann/quic-conn v0.0.0-20191204020628-6e719687462b
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3
|
||||
)
|
46
go.sum
Normal file
46
go.sum
Normal file
@ -0,0 +1,46 @@
|
||||
github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE=
|
||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk=
|
||||
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/lucas-clemente/quic-go v0.14.0 h1:xmWt9+sRgvAAXmi2S9lrikUtNUPwxeOy400LD+I3Qw0=
|
||||
github.com/lucas-clemente/quic-go v0.14.0/go.mod h1:Vn3/Fb0/77b02SGhQk36KzOUmXgVpFfizUfW5WMaqyU=
|
||||
github.com/marten-seemann/chacha20 v0.2.0 h1:f40vqzzx+3GdOmzQoItkLX5WLvHgPgyYqFFIO5Gh4hQ=
|
||||
github.com/marten-seemann/chacha20 v0.2.0/go.mod h1:HSdjFau7GzYRj+ahFNwsO3ouVJr1HFkWoEwNDb4TMtE=
|
||||
github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
|
||||
github.com/marten-seemann/qtls v0.4.1 h1:YlT8QP3WCCvvok7MGEZkMldXbyqgr8oFg5/n8Gtbkks=
|
||||
github.com/marten-seemann/qtls v0.4.1/go.mod h1:pxVXcHHw1pNIt8Qo0pwSYQEoZ8yYOOPXTCZLQQunvRc=
|
||||
github.com/marten-seemann/quic-conn v0.0.0-20191204020628-6e719687462b h1:o3bbMw41/oEYaoqS5KugYhqAkO1QtqI+IPpi/SsGoME=
|
||||
github.com/marten-seemann/quic-conn v0.0.0-20191204020628-6e719687462b/go.mod h1:s6F5Us7rXwvhuJH4/E5AcncOlo2PV5DrIV2cciSuKq8=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8=
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 h1:Gv7RPwsi3eZ2Fgewe3CBsuOebPwO27PoXzRpJPsvSSM=
|
||||
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
27
main.go
Normal file
27
main.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
vtun "vtun/cmd"
|
||||
)
|
||||
|
||||
var (
|
||||
local = flag.String("l", "172.16.0.1/24", "Local tun interface IP/MASK like 172.16.0.1/24")
|
||||
remote = flag.String("r", "172.16.0.2", "Remote server external IP like 172.16.0.2")
|
||||
port = flag.Int("p", 2001, "UDP port")
|
||||
key = flag.String("k", "6da62287-979a-4eb4-a5ab-8b3d89da134b", "Encrypt key")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if "" == *local {
|
||||
flag.Usage()
|
||||
log.Fatalln("local ip is not specified")
|
||||
}
|
||||
if "" == *remote {
|
||||
flag.Usage()
|
||||
log.Fatalln("remote ip is not specified")
|
||||
}
|
||||
vtun.New(local, remote, port, key)
|
||||
}
|
Loading…
Reference in New Issue
Block a user