mirror of
https://github.com/ICKelin/gtun.git
synced 2025-09-26 19:11:15 +08:00
feature: use tproxy and multi forward(alpha)
This commit is contained in:
@@ -15,3 +15,6 @@
|
||||
|
||||
2018.08.30
|
||||
Refactor code.
|
||||
|
||||
2021.05.13
|
||||
use tproxy for traffic redirect, support multi forwards eg: CN, US
|
@@ -1,18 +0,0 @@
|
||||
name="us-node-1-1"
|
||||
istap=false
|
||||
|
||||
[server]
|
||||
listen=":9623"
|
||||
auth_key="gtun-cs-token"
|
||||
nameservers=["8.8.8.8", "8.8.4.4"]
|
||||
#route_url="http://www.ipdeny.com/ipblocks/data/countries/us.zone"
|
||||
|
||||
[dhcp]
|
||||
cidr="100.64.240.1/24"
|
||||
gateway="100.64.240.1"
|
||||
nameserver="8.8.8.8"
|
||||
|
||||
[log]
|
||||
level="debug"
|
||||
path="log.log"
|
||||
days=3
|
8
Dockerfiles/gtund/gtund.yaml
Normal file
8
Dockerfiles/gtund/gtund.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
server:
|
||||
listen: ":9098"
|
||||
authKey: "rewrite with your auth key"
|
||||
|
||||
log:
|
||||
days: 5
|
||||
level: "info"
|
||||
path: "gtund.log"
|
@@ -1,2 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
/gtund -c /gtund.conf
|
||||
/gtund -c /gtund.yaml
|
||||
|
8
NEWS
8
NEWS
@@ -1,8 +0,0 @@
|
||||
- Plugins System
|
||||
Writting plugin extention such as dns plugin
|
||||
|
||||
- app
|
||||
To controller ip, domain and reverse configuration
|
||||
|
||||
- TUN/TAP device DNAT to local port
|
||||
Userland Conntrack Flow
|
44
README-EN.md
44
README-EN.md
@@ -1,32 +1,14 @@
|
||||
[](https://travis-ci.org/ICKelin/gtun)
|
||||
### gtun
|
||||
Gtun is a game or ip accelator written in golang. Currently only support mac os and linux.
|
||||
|
||||
### Build
|
||||
|
||||
```
|
||||
|
||||
./makefile.sh
|
||||
|
||||
```
|
||||
|
||||
More information, reference.travils.yml
|
||||
|
||||
### example
|
||||
|
||||
- ip accelator
|
||||
|
||||

|
||||
|
||||
- tunnel
|
||||
|
||||

|
||||
|
||||
### thanks
|
||||
[songgao/water](https://github.com/songgao/water)
|
||||
|
||||
### more
|
||||
[tun/tap vpn](https://github.com/ICKelin/article/issues/9)
|
||||
|
||||
any [issues](https://github.com/ICKelin/gtun/issues/new) are welcome
|
||||
## gtun
|
||||
<a href="">
|
||||
<img src="https://img.shields.io/badge/-Go-000?&logo=go">
|
||||
</a>
|
||||
<a href="https://goreportcard.com/report/github.com/ICKelin/gtun" rel="nofollow">
|
||||
<img src="https://goreportcard.com/badge/github.com/ICKelin/gtun" alt="go report">
|
||||
</a>
|
||||
|
||||
<a href="https://travis-ci.org/ICKelin/gtun" rel="nofollow">
|
||||
<img src="https://travis-ci.org/ICKelin/gtun.svg?branch=master" alt="Build Status">
|
||||
</a>
|
||||
<a href="https://github.com/ICKelin/gtun/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
|
||||
</a>
|
@@ -1,8 +0,0 @@
|
||||
[client]
|
||||
server = "192.168.31.65:9399"
|
||||
auth="gtun-cs-token"
|
||||
|
||||
[log]
|
||||
level="debug"
|
||||
path="log.log"
|
||||
days=3
|
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name":"US",
|
||||
"god_config":{
|
||||
"god_hb_interval": 3,
|
||||
"god_conn_timeout":10,
|
||||
"god_addr": "127.0.0.1:9623",
|
||||
"must": false,
|
||||
"token": "gtun-sg-token"
|
||||
}
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
name="us-node-1-1"
|
||||
|
||||
[server]
|
||||
listen=":9623"
|
||||
auth_key="gtun-cs-token"
|
||||
nameservers=["8.8.8.8", "8.8.4.4"]
|
||||
|
||||
[dhcp]
|
||||
cidr="100.64.240.1/24"
|
||||
gateway="100.64.240.1"
|
||||
nameserver="8.8.8.8"
|
||||
|
||||
[log]
|
||||
level="debug"
|
||||
path="log.log"
|
||||
days=3
|
@@ -1,96 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
MAX_PAYLOAD = 1<<16 - 1
|
||||
)
|
||||
|
||||
const (
|
||||
CODE_SUCCESS = 10000
|
||||
CODE_REGISTER_FAIL = 10001
|
||||
CODE_FAIL = 99999
|
||||
)
|
||||
|
||||
var version = "1.1.0"
|
||||
|
||||
func Version() string {
|
||||
return version
|
||||
}
|
||||
|
||||
type ResponseBody struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func Response(data interface{}, err error) []byte {
|
||||
g2s := &ResponseBody{}
|
||||
|
||||
if err != nil {
|
||||
g2s.Code = CODE_FAIL
|
||||
g2s.Message = err.Error()
|
||||
g2s.Data = data
|
||||
} else {
|
||||
g2s.Code = CODE_SUCCESS
|
||||
g2s.Message = "success"
|
||||
g2s.Data = data
|
||||
}
|
||||
|
||||
bytes, _ := json.Marshal(g2s)
|
||||
return bytes
|
||||
}
|
||||
|
||||
func Encode(cmd byte, payload []byte) ([]byte, error) {
|
||||
buff := make([]byte, 0)
|
||||
|
||||
if len(payload) > MAX_PAYLOAD {
|
||||
return nil, fmt.Errorf("too big payload")
|
||||
}
|
||||
|
||||
plen := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(plen, uint16(len(payload))+1)
|
||||
buff = append(buff, plen...)
|
||||
buff = append(buff, cmd)
|
||||
buff = append(buff, payload...)
|
||||
|
||||
return buff, nil
|
||||
}
|
||||
|
||||
func Decode(conn net.Conn) (byte, []byte, error) {
|
||||
plen := make([]byte, 2)
|
||||
conn.SetReadDeadline(time.Now().Add(time.Second * 10))
|
||||
_, err := io.ReadFull(conn, plen)
|
||||
conn.SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
payloadlength := binary.BigEndian.Uint16(plen)
|
||||
if payloadlength > 65535 {
|
||||
return 0, nil, fmt.Errorf("too big ippkt size %d", payloadlength)
|
||||
}
|
||||
|
||||
resp := make([]byte, payloadlength)
|
||||
nr, err := io.ReadFull(conn, resp)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if nr < 1 {
|
||||
return 0, nil, fmt.Errorf("invalid pkt")
|
||||
}
|
||||
|
||||
if nr != int(payloadlength) {
|
||||
return resp[0], resp[1:nr], fmt.Errorf("invalid payloadlength %d %d", nr, int(payloadlength))
|
||||
}
|
||||
|
||||
return resp[0], resp[1:nr], nil
|
||||
}
|
40
common/cs.go
40
common/cs.go
@@ -1,40 +0,0 @@
|
||||
package common
|
||||
|
||||
// S => gtund(gtun server)
|
||||
// C => gtun(gtun client)
|
||||
const (
|
||||
C2C_DATA = byte(0x00)
|
||||
|
||||
C2S_DATA = byte(0x01)
|
||||
S2C_DATA = byte(0x02)
|
||||
|
||||
C2S_HEARTBEAT = byte(0x03)
|
||||
S2C_HEARTBEAT = byte(0x04)
|
||||
|
||||
C2S_AUTHORIZE = byte(0x05)
|
||||
S2C_AUTHORIZE = byte(0x06)
|
||||
)
|
||||
|
||||
var os = map[string]int{
|
||||
"linux": 1,
|
||||
"darwin": 2,
|
||||
"windows": 3,
|
||||
}
|
||||
|
||||
func OSID(goos string) int {
|
||||
return os[goos]
|
||||
}
|
||||
|
||||
type C2SAuthorize struct {
|
||||
Version string `json:"version"`
|
||||
OS int `json:"os"`
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
type S2CAuthorize struct {
|
||||
Status string `json:"status"`
|
||||
AccessIP string `json:"access_ip"`
|
||||
Nameservers []string `json:"nameservers"`
|
||||
Gateway string `json:"gateway"`
|
||||
RouteScriptUrl string `json:"route_script_url"`
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
[client]
|
||||
server = "192.168.1.2:9091"
|
||||
auth="gtun-cs-token"
|
||||
|
||||
[registry]
|
||||
addr="http://127.0.0.1:9093"
|
||||
token="gtun-cr-token"
|
||||
must=false
|
||||
|
20
etc/gtun.yaml
Normal file
20
etc/gtun.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
forwards:
|
||||
US:
|
||||
server: "127.0.0.1:9098"
|
||||
authKey: "rewrite with your auth key"
|
||||
tcp:
|
||||
listenAddr: ":8098"
|
||||
udp:
|
||||
listenAddr: ":8098"
|
||||
CN:
|
||||
server: "127.0.0.1:9097"
|
||||
authKey: "rewrite with your auth key"
|
||||
tcp:
|
||||
listenAddr: ":8097"
|
||||
udp:
|
||||
listenAddr: ":8097"
|
||||
|
||||
logs:
|
||||
days: 5
|
||||
level: "info"
|
||||
path: "gtund.log"
|
8
etc/gtund.yaml
Normal file
8
etc/gtund.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
server:
|
||||
listen: ":9098"
|
||||
authKey: "rewrite with your auth key"
|
||||
|
||||
log:
|
||||
days: 5
|
||||
level: "info"
|
||||
path: "gtund.log"
|
1
go.mod
1
go.mod
@@ -24,4 +24,5 @@ require (
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 // indirect
|
||||
github.com/xtaci/smux v2.0.1+incompatible
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
)
|
||||
|
1
go.sum
1
go.sum
@@ -318,6 +318,7 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
@@ -8,11 +8,10 @@ import (
|
||||
"github.com/hashicorp/yamux"
|
||||
)
|
||||
|
||||
var defaultRegion = "US"
|
||||
|
||||
type ClientConfig struct {
|
||||
ServerAddr string `toml:"server"`
|
||||
AuthKey string `toml:"auth"`
|
||||
Region string
|
||||
ServerAddr string
|
||||
AuthKey string
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
@@ -31,7 +30,7 @@ func (client *Client) Run() {
|
||||
for {
|
||||
conn, err := net.DialTimeout("tcp", client.cfg.ServerAddr, time.Second*10)
|
||||
if err != nil {
|
||||
logs.Error("connect to server fail: %v", err)
|
||||
logs.Error("connect to %s fail: %v", client.cfg.ServerAddr, err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
@@ -43,14 +42,14 @@ func (client *Client) Run() {
|
||||
continue
|
||||
}
|
||||
|
||||
sess := newSession(mux, defaultRegion)
|
||||
client.sessionMgr.AddSession(defaultRegion, sess)
|
||||
sess := newSession(mux, client.cfg.Region)
|
||||
client.sessionMgr.AddSession(client.cfg.Region, sess)
|
||||
select {
|
||||
case <-sess.conn.CloseChan():
|
||||
break
|
||||
}
|
||||
|
||||
client.sessionMgr.DeleteSession(defaultRegion)
|
||||
client.sessionMgr.DeleteSession(client.cfg.Region)
|
||||
logs.Warn("reconnect")
|
||||
}
|
||||
}
|
||||
|
@@ -3,33 +3,38 @@ package gtun
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/pelletier/go-toml"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ClientConfig *ClientConfig `toml:"client"`
|
||||
TCPForward TCPForwardConfig `toml:"tcpforward"`
|
||||
UDPForward UDPForwardConfig `toml:"udpforward"`
|
||||
Log Log `toml:"log"`
|
||||
Forwards map[string]ForwardConfig `yaml:"forwards"`
|
||||
Log Log `yaml:"log"`
|
||||
}
|
||||
|
||||
type Log struct {
|
||||
Days int64 `toml:"days"`
|
||||
Level string `toml:"level"`
|
||||
Path string `toml:"path"`
|
||||
type ForwardConfig struct {
|
||||
ServerAddr string `yaml:"server"`
|
||||
AuthKey string `yaml:"authKey"`
|
||||
TCPForward TCPForwardConfig `yaml:"tcp"`
|
||||
UDPForward UDPForwardConfig `yaml:"udp"`
|
||||
}
|
||||
|
||||
type TCPForwardConfig struct {
|
||||
ListenAddr string `toml:"listen"`
|
||||
ReadTimeout int `toml:"readTimeout"`
|
||||
WriteTimeout int `toml:"writeTimeout"`
|
||||
ListenAddr string `yaml:"listen"`
|
||||
ReadTimeout int `yaml:"readTimeout"`
|
||||
WriteTimeout int `yaml:"writeTimeout"`
|
||||
}
|
||||
|
||||
type UDPForwardConfig struct {
|
||||
ListenAddr string `toml:"listen"`
|
||||
ReadTimeout int `toml:"readTimeout"`
|
||||
WriteTimeout int `toml:"writeTimeout"`
|
||||
SessionTimeout int `toml:"sessionTimeout"`
|
||||
ListenAddr string `yaml:"listen"`
|
||||
ReadTimeout int `yaml:"readTimeout"`
|
||||
WriteTimeout int `yaml:"writeTimeout"`
|
||||
SessionTimeout int `yaml:"sessionTimeout"`
|
||||
}
|
||||
|
||||
type Log struct {
|
||||
Days int64 `yaml:"days"`
|
||||
Level string `yaml:"level"`
|
||||
Path string `yaml:"path"`
|
||||
}
|
||||
|
||||
func ParseConfig(path string) (*Config, error) {
|
||||
@@ -43,6 +48,6 @@ func ParseConfig(path string) (*Config, error) {
|
||||
|
||||
func parseConfig(content []byte) (*Config, error) {
|
||||
conf := Config{}
|
||||
err := toml.Unmarshal(content, &conf)
|
||||
err := yaml.Unmarshal(content, &conf)
|
||||
return &conf, err
|
||||
}
|
||||
|
16
gtun/main.go
16
gtun/main.go
@@ -18,7 +18,8 @@ func Main() {
|
||||
}
|
||||
logs.Init(conf.Log.Path, conf.Log.Level, conf.Log.Days)
|
||||
|
||||
tcpfw := NewTCPForward(conf.TCPForward)
|
||||
for region, cfg := range conf.Forwards {
|
||||
tcpfw := NewTCPForward(region, cfg.TCPForward)
|
||||
lis, err := tcpfw.Listen()
|
||||
if err != nil {
|
||||
logs.Error("listen tproxy tcp fail: %v", err)
|
||||
@@ -27,7 +28,7 @@ func Main() {
|
||||
|
||||
go tcpfw.Serve(lis)
|
||||
|
||||
udpfw := NewUDPForward(conf.UDPForward)
|
||||
udpfw := NewUDPForward(region, cfg.UDPForward)
|
||||
udpConn, err := udpfw.Listen()
|
||||
if err != nil {
|
||||
logs.Error("listen tproxy udp fail: %v", err)
|
||||
@@ -36,6 +37,13 @@ func Main() {
|
||||
|
||||
go udpfw.Serve(udpConn)
|
||||
|
||||
client := NewClient(conf.ClientConfig)
|
||||
client.Run()
|
||||
client := NewClient(&ClientConfig{
|
||||
ServerAddr: cfg.ServerAddr,
|
||||
AuthKey: cfg.AuthKey,
|
||||
Region: region,
|
||||
})
|
||||
go client.Run()
|
||||
}
|
||||
|
||||
select {}
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@ var (
|
||||
)
|
||||
|
||||
type TCPForward struct {
|
||||
region string
|
||||
listenAddr string
|
||||
// writeTimeout defines the tcp connection write timeout in second
|
||||
// default value set to 10 seconds
|
||||
@@ -30,7 +31,7 @@ type TCPForward struct {
|
||||
sessMgr *SessionManager
|
||||
}
|
||||
|
||||
func NewTCPForward(cfg TCPForwardConfig) *TCPForward {
|
||||
func NewTCPForward(region string, cfg TCPForwardConfig) *TCPForward {
|
||||
tcpReadTimeout := cfg.ReadTimeout
|
||||
if tcpReadTimeout <= 0 {
|
||||
tcpReadTimeout = defaultTCPTimeout
|
||||
@@ -41,6 +42,7 @@ func NewTCPForward(cfg TCPForwardConfig) *TCPForward {
|
||||
tcpWriteTimeout = int(defaultTCPTimeout)
|
||||
}
|
||||
return &TCPForward{
|
||||
region: region,
|
||||
listenAddr: cfg.ListenAddr,
|
||||
writeTimeout: time.Duration(tcpWriteTimeout) * time.Second,
|
||||
readTimeout: time.Duration(tcpReadTimeout) * time.Second,
|
||||
@@ -89,7 +91,7 @@ func (f *TCPForward) forwardTCP(conn net.Conn) {
|
||||
dip, dport, _ := net.SplitHostPort(conn.LocalAddr().String())
|
||||
sip, sport, _ := net.SplitHostPort(conn.RemoteAddr().String())
|
||||
|
||||
sess := f.sessMgr.GetSession(defaultRegion)
|
||||
sess := f.sessMgr.GetSession(f.region)
|
||||
if sess == nil {
|
||||
logs.Error("no route to host: %s", dip)
|
||||
return
|
||||
|
@@ -29,6 +29,7 @@ type udpSession struct {
|
||||
}
|
||||
|
||||
type UDPForward struct {
|
||||
region string
|
||||
listenAddr string
|
||||
sessionTimeout int
|
||||
readTimeout time.Duration
|
||||
@@ -45,7 +46,7 @@ type UDPForward struct {
|
||||
udpsessLock sync.Mutex
|
||||
}
|
||||
|
||||
func NewUDPForward(cfg UDPForwardConfig) *UDPForward {
|
||||
func NewUDPForward(region string, cfg UDPForwardConfig) *UDPForward {
|
||||
readTimeout := cfg.ReadTimeout
|
||||
if readTimeout <= 0 {
|
||||
readTimeout = defaultUDPTimeout
|
||||
@@ -62,6 +63,7 @@ func NewUDPForward(cfg UDPForwardConfig) *UDPForward {
|
||||
}
|
||||
|
||||
return &UDPForward{
|
||||
region: region,
|
||||
listenAddr: cfg.ListenAddr,
|
||||
readTimeout: time.Duration(readTimeout) * time.Second,
|
||||
writeTimeout: time.Duration(writeTimeout) * time.Second,
|
||||
@@ -154,7 +156,7 @@ func (f *UDPForward) Serve(lconn *net.UDPConn) error {
|
||||
f.udpsessLock.Unlock()
|
||||
} else {
|
||||
f.udpsessLock.Unlock()
|
||||
sess := f.sessMgr.GetSession(defaultRegion)
|
||||
sess := f.sessMgr.GetSession(f.region)
|
||||
if sess == nil {
|
||||
logs.Error("no route to host: %s", dip)
|
||||
continue
|
||||
|
@@ -4,18 +4,18 @@ import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/pelletier/go-toml"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ServerConfig ServerConfig `toml:"server"` // tcp server configuration
|
||||
Log Log `toml:"log"`
|
||||
ServerConfig ServerConfig `yaml:"server"`
|
||||
Log Log `yaml:"log"`
|
||||
}
|
||||
|
||||
type Log struct {
|
||||
Days int64 `toml:"days"`
|
||||
Level string `toml:"level"`
|
||||
Path string `toml:"path"`
|
||||
Days int64 `yaml:"days"`
|
||||
Level string `yaml:"level"`
|
||||
Path string `yaml:"path"`
|
||||
}
|
||||
|
||||
func ParseConfig(path string) (*Config, error) {
|
||||
@@ -29,7 +29,7 @@ func ParseConfig(path string) (*Config, error) {
|
||||
|
||||
func parseConfig(content []byte) (*Config, error) {
|
||||
var c Config
|
||||
err := toml.Unmarshal(content, &c)
|
||||
err := yaml.Unmarshal(content, &c)
|
||||
return &c, err
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,7 @@ var (
|
||||
|
||||
type ServerConfig struct {
|
||||
Listen string `toml:"listen"`
|
||||
AuthKey string `toml:"auth_key"`
|
||||
AuthKey string `toml:"authKey"`
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
|
11
makefile.sh
11
makefile.sh
@@ -7,18 +7,9 @@ mkdir -p bin/gtund
|
||||
mkdir -p bin/gtund/log
|
||||
|
||||
GOOS=linux go build -o bin/gtund/gtund cmd/gtund/*.go
|
||||
cp etc/gtund.conf bin/gtund/
|
||||
cp etc/gtund.yaml bin/gtund/
|
||||
|
||||
cd cmd/gtun
|
||||
echo "building gtun_cli_darwin...."
|
||||
GOOS=darwin go build -o ../../bin/gtun/gtun-darwin_amd64
|
||||
echo "builded gtun_cli_darwin...."
|
||||
|
||||
echo "building gtun_cli_linux...."
|
||||
GOOS=linux go build -o ../../bin/gtun/gtun-linux_amd64
|
||||
echo "builded gtun_cli_linux...."
|
||||
|
||||
echo "building gtun_cli_win...."
|
||||
|
||||
GOOS=windows go build -o ../../bin/gtun/gtun-windows_amd64.exe
|
||||
echo "builded gtun_cli_win...."
|
BIN
qrcode.jpg
BIN
qrcode.jpg
Binary file not shown.
Before Width: | Height: | Size: 27 KiB |
Reference in New Issue
Block a user