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