Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
G
gost
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nanahira
gost
Commits
e12fc6e1
Commit
e12fc6e1
authored
Aug 23, 2022
by
nanahira
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
https://github.com/ginuerzh/gost
parents
b3151cc7
81854a61
Pipeline
#16009
passed with stages
in 1 minute and 17 seconds
Changes
17
Pipelines
1
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
199 additions
and
204 deletions
+199
-204
Dockerfile
Dockerfile
+8
-6
Makefile
Makefile
+9
-1
README.md
README.md
+1
-1
README_en.md
README_en.md
+1
-1
cmd/gost/route.go
cmd/gost/route.go
+13
-0
go.mod
go.mod
+16
-14
go.sum
go.sum
+34
-45
gost.go
gost.go
+3
-1
handler.go
handler.go
+8
-0
http.go
http.go
+7
-2
http2.go
http2.go
+5
-1
quic.go
quic.go
+45
-75
selector.go
selector.go
+1
-1
server.go
server.go
+9
-2
snap/snapcraft.yaml
snap/snapcraft.yaml
+2
-2
sockopts_other.go
sockopts_other.go
+2
-1
tuntap_linux.go
tuntap_linux.go
+35
-51
No files found.
Dockerfile
View file @
e12fc6e1
FROM
golang:1-alpine as builder
FROM
golang:1.19-alpine as builder
# Convert TARGETPLATFORM to GOARCH format
# https://github.com/tonistiigi/xx
COPY
--from=tonistiigi/xx:golang / /
ARG
TARGETPLATFORM
RUN
apk add
--no-cache
musl-dev git gcc
RUN
apk add
--no-cache
musl-dev git gcc
...
@@ -8,9 +14,7 @@ WORKDIR /src
...
@@ -8,9 +14,7 @@ WORKDIR /src
ENV
GO111MODULE=on
ENV
GO111MODULE=on
RUN
cd
cmd/gost
\
RUN
cd
cmd/gost
&&
go
env
&&
go build
-v
&&
go
env
-w
GOPROXY
=
https://goproxy.cn,https://gocenter.io,https://goproxy.io,direct
\
&&
go build
-v
FROM
alpine:latest
FROM
alpine:latest
...
@@ -19,5 +23,3 @@ WORKDIR /bin/
...
@@ -19,5 +23,3 @@ WORKDIR /bin/
COPY
--from=builder /src/cmd/gost/gost .
COPY
--from=builder /src/cmd/gost/gost .
ENTRYPOINT
["/bin/gost"]
ENTRYPOINT
["/bin/gost"]
CMD
["-C", "/etc/gost/gost.json"]
Makefile
View file @
e12fc6e1
...
@@ -20,12 +20,14 @@ PLATFORM_LIST = \
...
@@ -20,12 +20,14 @@ PLATFORM_LIST = \
linux-mips64
\
linux-mips64
\
linux-mips64le
\
linux-mips64le
\
linux-s390x
\
linux-s390x
\
linux-riscv64
\
freebsd-386
\
freebsd-386
\
freebsd-amd64
freebsd-amd64
WINDOWS_ARCH_LIST
=
\
WINDOWS_ARCH_LIST
=
\
windows-386
\
windows-386
\
windows-amd64
windows-amd64
\
windows-arm64
all
:
linux-amd64 darwin-amd64 windows-amd64
#
Most used
all
:
linux-amd64 darwin-amd64 windows-amd64
#
Most used
...
@@ -74,6 +76,9 @@ linux-mips64le:
...
@@ -74,6 +76,9 @@ linux-mips64le:
linux-s390x
:
linux-s390x
:
GOARCH
=
s390x
GOOS
=
linux
$(GOBUILD)
-o
$(BINDIR)
/
$(NAME)
-
$@
$(GOFILES)
GOARCH
=
s390x
GOOS
=
linux
$(GOBUILD)
-o
$(BINDIR)
/
$(NAME)
-
$@
$(GOFILES)
linux-riscv64
:
GOARCH
=
riscv64
GOOS
=
linux
$(GOBUILD)
-o
$(BINDIR)
/
$(NAME)
-
$@
$(GOFILES)
freebsd-386
:
freebsd-386
:
GOARCH
=
386
GOOS
=
freebsd
$(GOBUILD)
-o
$(BINDIR)
/
$(NAME)
-
$@
$(GOFILES)
GOARCH
=
386
GOOS
=
freebsd
$(GOBUILD)
-o
$(BINDIR)
/
$(NAME)
-
$@
$(GOFILES)
...
@@ -86,6 +91,9 @@ windows-386:
...
@@ -86,6 +91,9 @@ windows-386:
windows-amd64
:
windows-amd64
:
GOARCH
=
amd64
GOOS
=
windows
$(GOBUILD)
-o
$(BINDIR)
/
$(NAME)
-
$@
.exe
$(GOFILES)
GOARCH
=
amd64
GOOS
=
windows
$(GOBUILD)
-o
$(BINDIR)
/
$(NAME)
-
$@
.exe
$(GOFILES)
windows-arm64
:
GOARCH
=
arm64
GOOS
=
windows
$(GOBUILD)
-o
$(BINDIR)
/
$(NAME)
-
$@
.exe
$(GOFILES)
gz_releases
=
$(
addsuffix
.gz,
$(PLATFORM_LIST)
)
gz_releases
=
$(
addsuffix
.gz,
$(PLATFORM_LIST)
)
zip_releases
=
$(
addsuffix
.zip,
$(WINDOWS_ARCH_LIST)
)
zip_releases
=
$(
addsuffix
.zip,
$(WINDOWS_ARCH_LIST)
)
...
...
README.md
View file @
e12fc6e1
...
@@ -58,7 +58,7 @@ go build
...
@@ -58,7 +58,7 @@ go build
#### Docker
#### Docker
```
bash
```
bash
docker
pull ginuerzh/gost
docker
run
--rm
ginuerzh/gost
-V
```
```
#### Homebrew
#### Homebrew
...
...
README_en.md
View file @
e12fc6e1
...
@@ -53,7 +53,7 @@ go build
...
@@ -53,7 +53,7 @@ go build
#### Docker
#### Docker
```
bash
```
bash
docker
pull ginuerzh/gost
docker
run
--rm
ginuerzh/gost
-V
```
```
#### Homebrew
#### Homebrew
...
...
cmd/gost/route.go
View file @
e12fc6e1
...
@@ -212,6 +212,12 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
...
@@ -212,6 +212,12 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
Timeout
:
timeout
,
Timeout
:
timeout
,
IdleTimeout
:
node
.
GetDuration
(
"idle"
),
IdleTimeout
:
node
.
GetDuration
(
"idle"
),
}
}
if
config
.
KeepAlive
{
config
.
KeepAlivePeriod
=
node
.
GetDuration
(
"ttl"
)
if
config
.
KeepAlivePeriod
==
0
{
config
.
KeepAlivePeriod
=
10
*
time
.
Second
}
}
if
cipher
:=
node
.
Get
(
"cipher"
);
cipher
!=
""
{
if
cipher
:=
node
.
Get
(
"cipher"
);
cipher
!=
""
{
sum
:=
sha256
.
Sum256
([]
byte
(
cipher
))
sum
:=
sha256
.
Sum256
([]
byte
(
cipher
))
...
@@ -458,6 +464,12 @@ func (r *route) GenRouters() ([]router, error) {
...
@@ -458,6 +464,12 @@ func (r *route) GenRouters() ([]router, error) {
Timeout
:
timeout
,
Timeout
:
timeout
,
IdleTimeout
:
node
.
GetDuration
(
"idle"
),
IdleTimeout
:
node
.
GetDuration
(
"idle"
),
}
}
if
config
.
KeepAlive
{
config
.
KeepAlivePeriod
=
node
.
GetDuration
(
"ttl"
)
if
config
.
KeepAlivePeriod
==
0
{
config
.
KeepAlivePeriod
=
10
*
time
.
Second
}
}
if
cipher
:=
node
.
Get
(
"cipher"
);
cipher
!=
""
{
if
cipher
:=
node
.
Get
(
"cipher"
);
cipher
!=
""
{
sum
:=
sha256
.
Sum256
([]
byte
(
cipher
))
sum
:=
sha256
.
Sum256
([]
byte
(
cipher
))
config
.
Key
=
sum
[
:
]
config
.
Key
=
sum
[
:
]
...
@@ -652,6 +664,7 @@ func (r *route) GenRouters() ([]router, error) {
...
@@ -652,6 +664,7 @@ func (r *route) GenRouters() ([]router, error) {
gost
.
IPsHandlerOption
(
ips
),
gost
.
IPsHandlerOption
(
ips
),
gost
.
TCPModeHandlerOption
(
node
.
GetBool
(
"tcp"
)),
gost
.
TCPModeHandlerOption
(
node
.
GetBool
(
"tcp"
)),
gost
.
IPRoutesHandlerOption
(
tunRoutes
...
),
gost
.
IPRoutesHandlerOption
(
tunRoutes
...
),
gost
.
ProxyAgentHandlerOption
(
node
.
Get
(
"proxyAgent"
)),
)
)
rt
:=
router
{
rt
:=
router
{
...
...
go.mod
View file @
e12fc6e1
module github.com/ginuerzh/gost
module github.com/ginuerzh/gost
go 1.17
go 1.18
replace github.com/templexxx/cpu v0.0.7 => github.com/templexxx/cpu v0.0.10-0.20211111114238-98168dcec14a
require (
require (
git.torproject.org/pluggable-transports/goptlib.git v1.2.0
git.torproject.org/pluggable-transports/goptlib.git v1.2.0
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/docker/libcontainer v2.2.1+incompatible
github.com/go-gost/gosocks4 v0.0.1
github.com/go-gost/gosocks4 v0.0.1
github.com/go-gost/gosocks5 v0.3.0
github.com/go-gost/gosocks5 v0.3.0
github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7
github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7
...
@@ -15,9 +16,8 @@ require (
...
@@ -15,9 +16,8 @@ require (
github.com/gobwas/glob v0.2.3
github.com/gobwas/glob v0.2.3
github.com/gorilla/websocket v1.4.2
github.com/gorilla/websocket v1.4.2
github.com/klauspost/compress v1.13.6
github.com/klauspost/compress v1.13.6
github.com/lucas-clemente/quic-go v0.2
6.0
github.com/lucas-clemente/quic-go v0.2
8.1
github.com/miekg/dns v1.1.47
github.com/miekg/dns v1.1.47
github.com/milosgajdos/tenus v0.0.3
github.com/ryanuber/go-glob v1.0.0
github.com/ryanuber/go-glob v1.0.0
github.com/shadowsocks/go-shadowsocks2 v0.1.5
github.com/shadowsocks/go-shadowsocks2 v0.1.5
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601
...
@@ -25,24 +25,26 @@ require (
...
@@ -25,24 +25,26 @@ require (
github.com/xtaci/kcp-go/v5 v5.6.1
github.com/xtaci/kcp-go/v5 v5.6.1
github.com/xtaci/smux v1.5.16
github.com/xtaci/smux v1.5.16
github.com/xtaci/tcpraw v1.2.25
github.com/xtaci/tcpraw v1.2.25
gitlab.com/yawning/obfs4.git v0.0.0-202
10511220700-e330d1b7024b
gitlab.com/yawning/obfs4.git v0.0.0-202
20204003609-77af0cba934d
golang.org/x/crypto v0.0.0-20220
321153916-2c7772ba3064
golang.org/x/crypto v0.0.0-20220
817201139-bc19a97f63c8
golang.org/x/net v0.0.0-20220
325170049-de3da57026de
golang.org/x/net v0.0.0-20220
812174116-3211cb980234
)
)
require (
require (
filippo.io/edwards25519 v1.0.0-rc.1.0.20210721174708-390f27c3be20 // indirect
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/cheekybits/genny v1.0.0 // indirect
github.com/cheekybits/genny v1.0.0 // indirect
github.com/coreos/go-iptables v0.6.0 // indirect
github.com/coreos/go-iptables v0.6.0 // indirect
github.com/dchest/siphash v1.2.2 // indirect
github.com/dchest/siphash v1.2.2 // indirect
github.com/fsnotify/fsnotify v1.5.
1
// indirect
github.com/fsnotify/fsnotify v1.5.
4
// indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/klauspost/reedsolomon v1.9.15 // indirect
github.com/klauspost/reedsolomon v1.9.15 // indirect
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
...
@@ -51,10 +53,10 @@ require (
...
@@ -51,10 +53,10 @@ require (
github.com/templexxx/xorsimd v0.4.1 // indirect
github.com/templexxx/xorsimd v0.4.1 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 // indirect
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
gitlab.com/yawning/edwards25519-extra.git v0.0.0-20211229043746-2f91fcc9fbdb // indirect
golang.org/x/sys v0.0.0-20220325203850-36772127a21f // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.10 // indirect
golang.org/x/tools v0.1.12 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
)
)
go.sum
View file @
e12fc6e1
This diff is collapsed.
Click to expand it.
gost.go
View file @
e12fc6e1
...
@@ -20,7 +20,7 @@ import (
...
@@ -20,7 +20,7 @@ import (
)
)
// Version is the gost version.
// Version is the gost version.
const
Version
=
"2.11.
2
"
const
Version
=
"2.11.
3
"
// Debug is a flag that enables the debug log.
// Debug is a flag that enables the debug log.
var
Debug
bool
var
Debug
bool
...
@@ -80,6 +80,8 @@ var (
...
@@ -80,6 +80,8 @@ var (
// DefaultUserAgent is the default HTTP User-Agent header used by HTTP and websocket.
// DefaultUserAgent is the default HTTP User-Agent header used by HTTP and websocket.
DefaultUserAgent
=
"Chrome/78.0.3904.106"
DefaultUserAgent
=
"Chrome/78.0.3904.106"
DefaultProxyAgent
=
"gost/"
+
Version
// DefaultMTU is the default mtu for tun/tap device
// DefaultMTU is the default mtu for tun/tap device
DefaultMTU
=
1350
DefaultMTU
=
1350
)
)
...
...
handler.go
View file @
e12fc6e1
...
@@ -42,6 +42,7 @@ type HandlerOptions struct {
...
@@ -42,6 +42,7 @@ type HandlerOptions struct {
IPs
[]
string
IPs
[]
string
TCPMode
bool
TCPMode
bool
IPRoutes
[]
IPRoute
IPRoutes
[]
IPRoute
ProxyAgent
string
}
}
// HandlerOption allows a common way to set handler options.
// HandlerOption allows a common way to set handler options.
...
@@ -211,6 +212,13 @@ func IPRoutesHandlerOption(routes ...IPRoute) HandlerOption {
...
@@ -211,6 +212,13 @@ func IPRoutesHandlerOption(routes ...IPRoute) HandlerOption {
}
}
}
}
// ProxyAgentHandlerOption sets the proxy agent for http handler.
func
ProxyAgentHandlerOption
(
agent
string
)
HandlerOption
{
return
func
(
opts
*
HandlerOptions
)
{
opts
.
ProxyAgent
=
agent
}
}
type
autoHandler
struct
{
type
autoHandler
struct
{
options
*
HandlerOptions
options
*
HandlerOptions
}
}
...
...
http.go
View file @
e12fc6e1
...
@@ -173,7 +173,12 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
...
@@ -173,7 +173,12 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
ProtoMinor
:
1
,
ProtoMinor
:
1
,
Header
:
http
.
Header
{},
Header
:
http
.
Header
{},
}
}
resp
.
Header
.
Add
(
"Proxy-Agent"
,
"gost/"
+
Version
)
proxyAgent
:=
DefaultProxyAgent
if
h
.
options
.
ProxyAgent
!=
""
{
proxyAgent
=
h
.
options
.
ProxyAgent
}
resp
.
Header
.
Add
(
"Proxy-Agent"
,
proxyAgent
)
if
!
Can
(
"tcp"
,
host
,
h
.
options
.
Whitelist
,
h
.
options
.
Blacklist
)
{
if
!
Can
(
"tcp"
,
host
,
h
.
options
.
Whitelist
,
h
.
options
.
Blacklist
)
{
log
.
Logf
(
"[http] %s - %s : Unauthorized to tcp connect to %s"
,
log
.
Logf
(
"[http] %s - %s : Unauthorized to tcp connect to %s"
,
...
@@ -287,7 +292,7 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
...
@@ -287,7 +292,7 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
if
req
.
Method
==
http
.
MethodConnect
{
if
req
.
Method
==
http
.
MethodConnect
{
b
:=
[]
byte
(
"HTTP/1.1 200 Connection established
\r\n
"
+
b
:=
[]
byte
(
"HTTP/1.1 200 Connection established
\r\n
"
+
"Proxy-Agent:
gost/"
+
Version
+
"
\r\n\r\n
"
)
"Proxy-Agent:
"
+
proxyAgent
+
"
\r\n\r\n
"
)
if
Debug
{
if
Debug
{
log
.
Logf
(
"[http] %s <- %s
\n
%s"
,
conn
.
RemoteAddr
(),
conn
.
LocalAddr
(),
string
(
b
))
log
.
Logf
(
"[http] %s <- %s
\n
%s"
,
conn
.
RemoteAddr
(),
conn
.
LocalAddr
(),
string
(
b
))
}
}
...
...
http2.go
View file @
e12fc6e1
...
@@ -365,7 +365,11 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
...
@@ -365,7 +365,11 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
log
.
Logf
(
"[http2] %s - %s
\n
%s"
,
r
.
RemoteAddr
,
laddr
,
string
(
dump
))
log
.
Logf
(
"[http2] %s - %s
\n
%s"
,
r
.
RemoteAddr
,
laddr
,
string
(
dump
))
}
}
w
.
Header
()
.
Set
(
"Proxy-Agent"
,
"gost/"
+
Version
)
proxyAgent
:=
DefaultProxyAgent
if
h
.
options
.
ProxyAgent
!=
""
{
proxyAgent
=
h
.
options
.
ProxyAgent
}
w
.
Header
()
.
Set
(
"Proxy-Agent"
,
proxyAgent
)
if
!
Can
(
"tcp"
,
host
,
h
.
options
.
Whitelist
,
h
.
options
.
Blacklist
)
{
if
!
Can
(
"tcp"
,
host
,
h
.
options
.
Whitelist
,
h
.
options
.
Blacklist
)
{
log
.
Logf
(
"[http2] %s - %s : Unauthorized to tcp connect to %s"
,
log
.
Logf
(
"[http2] %s - %s : Unauthorized to tcp connect to %s"
,
...
...
quic.go
View file @
e12fc6e1
...
@@ -17,8 +17,7 @@ import (
...
@@ -17,8 +17,7 @@ import (
)
)
type
quicSession
struct
{
type
quicSession
struct
{
conn
net
.
Conn
session
quic
.
EarlyConnection
session
quic
.
Session
}
}
func
(
session
*
quicSession
)
GetConn
()
(
*
quicConn
,
error
)
{
func
(
session
*
quicSession
)
GetConn
()
(
*
quicConn
,
error
)
{
...
@@ -60,100 +59,71 @@ func (tr *quicTransporter) Dial(addr string, options ...DialOption) (conn net.Co
...
@@ -60,100 +59,71 @@ func (tr *quicTransporter) Dial(addr string, options ...DialOption) (conn net.Co
option
(
opts
)
option
(
opts
)
}
}
udpAddr
,
err
:=
net
.
ResolveUDPAddr
(
"udp"
,
addr
)
if
err
!=
nil
{
return
nil
,
err
}
tr
.
sessionMutex
.
Lock
()
tr
.
sessionMutex
.
Lock
()
defer
tr
.
sessionMutex
.
Unlock
()
defer
tr
.
sessionMutex
.
Unlock
()
session
,
ok
:=
tr
.
sessions
[
addr
]
session
,
ok
:=
tr
.
sessions
[
addr
]
if
!
ok
{
if
!
ok
{
var
cc
*
net
.
UDP
Conn
var
pc
net
.
Packet
Conn
c
c
,
err
=
net
.
ListenUDP
(
"udp"
,
&
net
.
UDPAddr
{
IP
:
net
.
IPv4zero
,
Port
:
0
})
p
c
,
err
=
net
.
ListenUDP
(
"udp"
,
&
net
.
UDPAddr
{
IP
:
net
.
IPv4zero
,
Port
:
0
})
if
err
!=
nil
{
if
err
!=
nil
{
return
return
}
}
conn
=
cc
if
tr
.
config
!=
nil
&&
tr
.
config
.
Key
!=
nil
{
if
tr
.
config
!=
nil
&&
tr
.
config
.
Key
!=
nil
{
conn
=
&
quicCipherConn
{
UDPConn
:
c
c
,
key
:
tr
.
config
.
Key
}
pc
=
&
quicCipherConn
{
PacketConn
:
p
c
,
key
:
tr
.
config
.
Key
}
}
}
session
=
&
quicSession
{
conn
:
conn
}
session
,
err
=
tr
.
initSession
(
udpAddr
,
pc
)
tr
.
sessions
[
addr
]
=
session
}
return
session
.
conn
,
nil
}
func
(
tr
*
quicTransporter
)
Handshake
(
conn
net
.
Conn
,
options
...
HandshakeOption
)
(
net
.
Conn
,
error
)
{
opts
:=
&
HandshakeOptions
{}
for
_
,
option
:=
range
options
{
option
(
opts
)
}
config
:=
tr
.
config
if
opts
.
QUICConfig
!=
nil
{
config
=
opts
.
QUICConfig
}
if
config
.
TLSConfig
==
nil
{
config
.
TLSConfig
=
&
tls
.
Config
{
InsecureSkipVerify
:
true
}
}
tr
.
sessionMutex
.
Lock
()
defer
tr
.
sessionMutex
.
Unlock
()
timeout
:=
opts
.
Timeout
if
timeout
<=
0
{
timeout
=
HandshakeTimeout
}
conn
.
SetDeadline
(
time
.
Now
()
.
Add
(
timeout
))
defer
conn
.
SetDeadline
(
time
.
Time
{})
session
,
ok
:=
tr
.
sessions
[
opts
.
Addr
]
if
session
!=
nil
&&
session
.
conn
!=
conn
{
conn
.
Close
()
return
nil
,
errors
.
New
(
"quic: unrecognized connection"
)
}
if
!
ok
||
session
.
session
==
nil
{
s
,
err
:=
tr
.
initSession
(
opts
.
Addr
,
conn
,
config
)
if
err
!=
nil
{
if
err
!=
nil
{
conn
.
Close
()
pc
.
Close
()
delete
(
tr
.
sessions
,
opts
.
Addr
)
return
nil
,
err
return
nil
,
err
}
}
session
=
s
tr
.
sessions
[
addr
]
=
session
tr
.
sessions
[
opts
.
Addr
]
=
session
}
}
cc
,
err
:=
session
.
GetConn
()
conn
,
err
=
session
.
GetConn
()
if
err
!=
nil
{
if
err
!=
nil
{
session
.
Close
()
session
.
Close
()
delete
(
tr
.
sessions
,
opts
.
A
ddr
)
delete
(
tr
.
sessions
,
a
ddr
)
return
nil
,
err
return
nil
,
err
}
}
return
conn
,
nil
}
return
cc
,
nil
func
(
tr
*
quicTransporter
)
Handshake
(
conn
net
.
Conn
,
options
...
HandshakeOption
)
(
net
.
Conn
,
error
)
{
return
conn
,
nil
}
}
func
(
tr
*
quicTransporter
)
initSession
(
addr
string
,
conn
net
.
Conn
,
config
*
QUICConfig
)
(
*
quicSession
,
error
)
{
func
(
tr
*
quicTransporter
)
initSession
(
addr
net
.
Addr
,
conn
net
.
PacketConn
)
(
*
quicSession
,
error
)
{
udpConn
,
ok
:=
conn
.
(
net
.
PacketConn
)
config
:=
tr
.
config
if
!
ok
{
if
config
==
nil
{
return
nil
,
errors
.
New
(
"quic: wrong connection type"
)
config
=
&
QUICConfig
{}
}
}
udpAddr
,
err
:=
net
.
ResolveUDPAddr
(
"udp"
,
addr
)
if
config
.
TLSConfig
==
nil
{
if
err
!=
nil
{
config
.
TLSConfig
=
&
tls
.
Config
{
InsecureSkipVerify
:
true
}
return
nil
,
err
}
}
quicConfig
:=
&
quic
.
Config
{
quicConfig
:=
&
quic
.
Config
{
HandshakeIdleTimeout
:
config
.
Timeout
,
HandshakeIdleTimeout
:
config
.
Timeout
,
KeepAlive
:
config
.
KeepAlive
,
MaxIdleTimeout
:
config
.
IdleTimeout
,
KeepAlivePeriod
:
config
.
KeepAlivePeriod
,
Versions
:
[]
quic
.
VersionNumber
{
Versions
:
[]
quic
.
VersionNumber
{
quic
.
Version1
,
quic
.
Version1
,
quic
.
VersionDraft29
,
quic
.
VersionDraft29
,
},
},
MaxIdleTimeout
:
config
.
IdleTimeout
,
}
}
session
,
err
:=
quic
.
Dial
(
udpConn
,
udpAddr
,
addr
,
tlsConfigQUICALPN
(
config
.
TLSConfig
),
quicConfig
)
session
,
err
:=
quic
.
Dial
Early
(
conn
,
addr
,
addr
.
String
()
,
tlsConfigQUICALPN
(
config
.
TLSConfig
),
quicConfig
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Logf
(
"quic dial %s: %v"
,
addr
,
err
)
log
.
Logf
(
"quic dial %s: %v"
,
addr
,
err
)
return
nil
,
err
return
nil
,
err
}
}
return
&
quicSession
{
conn
:
conn
,
session
:
session
},
nil
return
&
quicSession
{
session
:
session
},
nil
}
}
func
(
tr
*
quicTransporter
)
Multiplex
()
bool
{
func
(
tr
*
quicTransporter
)
Multiplex
()
bool
{
...
@@ -162,15 +132,16 @@ func (tr *quicTransporter) Multiplex() bool {
...
@@ -162,15 +132,16 @@ func (tr *quicTransporter) Multiplex() bool {
// QUICConfig is the config for QUIC client and server
// QUICConfig is the config for QUIC client and server
type
QUICConfig
struct
{
type
QUICConfig
struct
{
TLSConfig
*
tls
.
Config
TLSConfig
*
tls
.
Config
Timeout
time
.
Duration
Timeout
time
.
Duration
KeepAlive
bool
KeepAlive
bool
IdleTimeout
time
.
Duration
KeepAlivePeriod
time
.
Duration
Key
[]
byte
IdleTimeout
time
.
Duration
Key
[]
byte
}
}
type
quicListener
struct
{
type
quicListener
struct
{
ln
quic
.
Listener
ln
quic
.
Early
Listener
connChan
chan
net
.
Conn
connChan
chan
net
.
Conn
errChan
chan
error
errChan
chan
error
}
}
...
@@ -182,7 +153,7 @@ func QUICListener(addr string, config *QUICConfig) (Listener, error) {
...
@@ -182,7 +153,7 @@ func QUICListener(addr string, config *QUICConfig) (Listener, error) {
}
}
quicConfig
:=
&
quic
.
Config
{
quicConfig
:=
&
quic
.
Config
{
HandshakeIdleTimeout
:
config
.
Timeout
,
HandshakeIdleTimeout
:
config
.
Timeout
,
KeepAlive
:
config
.
KeepAlive
,
KeepAlive
Period
:
config
.
KeepAlivePeriod
,
MaxIdleTimeout
:
config
.
IdleTimeout
,
MaxIdleTimeout
:
config
.
IdleTimeout
,
Versions
:
[]
quic
.
VersionNumber
{
Versions
:
[]
quic
.
VersionNumber
{
quic
.
Version1
,
quic
.
Version1
,
...
@@ -200,17 +171,16 @@ func QUICListener(addr string, config *QUICConfig) (Listener, error) {
...
@@ -200,17 +171,16 @@ func QUICListener(addr string, config *QUICConfig) (Listener, error) {
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
lconn
,
err
:
=
net
.
ListenUDP
(
"udp"
,
udpAddr
)
conn
,
err
=
net
.
ListenUDP
(
"udp"
,
udpAddr
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
conn
=
lconn
if
config
.
Key
!=
nil
{
if
config
.
Key
!=
nil
{
conn
=
&
quicCipherConn
{
UDPConn
:
l
conn
,
key
:
config
.
Key
}
conn
=
&
quicCipherConn
{
PacketConn
:
conn
,
key
:
config
.
Key
}
}
}
ln
,
err
:=
quic
.
Listen
(
conn
,
tlsConfigQUICALPN
(
tlsConfig
),
quicConfig
)
ln
,
err
:=
quic
.
Listen
Early
(
conn
,
tlsConfigQUICALPN
(
tlsConfig
),
quicConfig
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
...
@@ -238,7 +208,7 @@ func (l *quicListener) listenLoop() {
...
@@ -238,7 +208,7 @@ func (l *quicListener) listenLoop() {
}
}
}
}
func
(
l
*
quicListener
)
sessionLoop
(
session
quic
.
Sess
ion
)
{
func
(
l
*
quicListener
)
sessionLoop
(
session
quic
.
Connect
ion
)
{
log
.
Logf
(
"[quic] %s <-> %s"
,
session
.
RemoteAddr
(),
session
.
LocalAddr
())
log
.
Logf
(
"[quic] %s <-> %s"
,
session
.
RemoteAddr
(),
session
.
LocalAddr
())
defer
log
.
Logf
(
"[quic] %s >-< %s"
,
session
.
RemoteAddr
(),
session
.
LocalAddr
())
defer
log
.
Logf
(
"[quic] %s >-< %s"
,
session
.
RemoteAddr
(),
session
.
LocalAddr
())
...
@@ -295,12 +265,12 @@ func (c *quicConn) RemoteAddr() net.Addr {
...
@@ -295,12 +265,12 @@ func (c *quicConn) RemoteAddr() net.Addr {
}
}
type
quicCipherConn
struct
{
type
quicCipherConn
struct
{
*
net
.
UDP
Conn
net
.
Packet
Conn
key
[]
byte
key
[]
byte
}
}
func
(
conn
*
quicCipherConn
)
ReadFrom
(
data
[]
byte
)
(
n
int
,
addr
net
.
Addr
,
err
error
)
{
func
(
conn
*
quicCipherConn
)
ReadFrom
(
data
[]
byte
)
(
n
int
,
addr
net
.
Addr
,
err
error
)
{
n
,
addr
,
err
=
conn
.
UDP
Conn
.
ReadFrom
(
data
)
n
,
addr
,
err
=
conn
.
Packet
Conn
.
ReadFrom
(
data
)
if
err
!=
nil
{
if
err
!=
nil
{
return
return
}
}
...
@@ -320,7 +290,7 @@ func (conn *quicCipherConn) WriteTo(data []byte, addr net.Addr) (n int, err erro
...
@@ -320,7 +290,7 @@ func (conn *quicCipherConn) WriteTo(data []byte, addr net.Addr) (n int, err erro
return
return
}
}
_
,
err
=
conn
.
UDP
Conn
.
WriteTo
(
b
,
addr
)
_
,
err
=
conn
.
Packet
Conn
.
WriteTo
(
b
,
addr
)
if
err
!=
nil
{
if
err
!=
nil
{
return
return
}
}
...
...
selector.go
View file @
e12fc6e1
...
@@ -12,7 +12,7 @@ import (
...
@@ -12,7 +12,7 @@ import (
var
(
var
(
// ErrNoneAvailable indicates there is no node available.
// ErrNoneAvailable indicates there is no node available.
ErrNoneAvailable
=
errors
.
New
(
"none available"
)
ErrNoneAvailable
=
errors
.
New
(
"none
node
available"
)
)
)
// NodeSelector as a mechanism to pick nodes and mark their status.
// NodeSelector as a mechanism to pick nodes and mark their status.
...
...
server.go
View file @
e12fc6e1
...
@@ -103,7 +103,7 @@ type Listener interface {
...
@@ -103,7 +103,7 @@ type Listener interface {
}
}
func
transport
(
rw1
,
rw2
io
.
ReadWriter
)
error
{
func
transport
(
rw1
,
rw2
io
.
ReadWriter
)
error
{
errc
:=
make
(
chan
error
,
1
)
errc
:=
make
(
chan
error
,
2
)
go
func
()
{
go
func
()
{
errc
<-
copyBuffer
(
rw1
,
rw2
)
errc
<-
copyBuffer
(
rw1
,
rw2
)
}()
}()
...
@@ -113,10 +113,17 @@ func transport(rw1, rw2 io.ReadWriter) error {
...
@@ -113,10 +113,17 @@ func transport(rw1, rw2 io.ReadWriter) error {
}()
}()
err
:=
<-
errc
err
:=
<-
errc
err2
:=
<-
errc
if
err
!=
nil
&&
err
==
io
.
EOF
{
if
err
!=
nil
&&
err
==
io
.
EOF
{
err
=
nil
err
=
nil
}
}
return
err
if
err
!=
nil
{
return
err
}
if
err2
!=
nil
&&
err2
==
io
.
EOF
{
err2
=
nil
}
return
err2
}
}
func
copyBuffer
(
dst
io
.
Writer
,
src
io
.
Reader
)
error
{
func
copyBuffer
(
dst
io
.
Writer
,
src
io
.
Reader
)
error
{
...
...
snap/snapcraft.yaml
View file @
e12fc6e1
name
:
gost
name
:
gost
base
:
core20
base
:
core20
version
:
'
2.11.
2
'
version
:
'
2.11.
3
'
summary
:
A simple security tunnel written in golang
summary
:
A simple security tunnel written in golang
description
:
|
description
:
|
Project: https://github.com/ginuerzh/gost
Project: https://github.com/ginuerzh/gost
...
@@ -20,7 +20,7 @@ parts:
...
@@ -20,7 +20,7 @@ parts:
source
:
https://github.com/ginuerzh/gost
source
:
https://github.com/ginuerzh/gost
source-subdir
:
cmd/gost
source-subdir
:
cmd/gost
source-type
:
git
source-type
:
git
source-tag
:
v2.11.
2
source-tag
:
v2.11.
3
build-packages
:
build-packages
:
-
gcc
-
gcc
...
...
sockopts_other.go
View file @
e12fc6e1
//go:build !linux
//go:build !linux
// +build !linux
package
gost
package
gost
...
@@ -8,4 +9,4 @@ func setSocketMark(fd int, value int) (e error) {
...
@@ -8,4 +9,4 @@ func setSocketMark(fd int, value int) (e error) {
func
setSocketInterface
(
fd
int
,
value
string
)
(
e
error
)
{
func
setSocketInterface
(
fd
int
,
value
string
)
(
e
error
)
{
return
nil
return
nil
}
}
\ No newline at end of file
tuntap_linux.go
View file @
e12fc6e1
package
gost
package
gost
import
(
import
(
"errors"
"fmt"
"fmt"
"net"
"net"
"syscall"
"os/exec"
"strings"
"github.com/docker/libcontainer/netlink"
"github.com/go-log/log"
"github.com/go-log/log"
"github.com/milosgajdos/tenus"
"github.com/songgao/water"
"github.com/songgao/water"
)
)
func
createTun
(
cfg
TunConfig
)
(
conn
net
.
Conn
,
itf
*
net
.
Interface
,
err
error
)
{
func
createTun
(
cfg
TunConfig
)
(
conn
net
.
Conn
,
itf
*
net
.
Interface
,
err
error
)
{
ip
,
ipNet
,
err
:=
net
.
ParseCIDR
(
cfg
.
Addr
)
ip
,
_
,
err
:=
net
.
ParseCIDR
(
cfg
.
Addr
)
if
err
!=
nil
{
if
err
!=
nil
{
return
return
}
}
...
@@ -28,35 +26,21 @@ func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err error) {
...
@@ -28,35 +26,21 @@ func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err error) {
return
return
}
}
link
,
err
:=
tenus
.
NewLinkFrom
(
ifce
.
Name
())
if
err
!=
nil
{
return
}
mtu
:=
cfg
.
MTU
mtu
:=
cfg
.
MTU
if
mtu
<=
0
{
if
mtu
<=
0
{
mtu
=
DefaultMTU
mtu
=
DefaultMTU
}
}
cmd
:=
fmt
.
Sprintf
(
"ip link set dev %s mtu %d"
,
ifce
.
Name
(),
mtu
)
if
err
=
exeCmd
(
fmt
.
Sprintf
(
"ip link set dev %s mtu %d"
,
ifce
.
Name
(),
mtu
));
err
!=
nil
{
log
.
Log
(
"[tun]"
,
cmd
)
log
.
Log
(
err
)
if
er
:=
link
.
SetLinkMTU
(
mtu
);
er
!=
nil
{
err
=
fmt
.
Errorf
(
"%s: %v"
,
cmd
,
er
)
return
}
}
cmd
=
fmt
.
Sprintf
(
"ip address add %s dev %s"
,
cfg
.
Addr
,
ifce
.
Name
())
if
err
=
exeCmd
(
fmt
.
Sprintf
(
"ip address add %s dev %s"
,
cfg
.
Addr
,
ifce
.
Name
()));
err
!=
nil
{
log
.
Log
(
"[tun]"
,
cmd
)
log
.
Log
(
err
)
if
er
:=
link
.
SetLinkIp
(
ip
,
ipNet
);
er
!=
nil
{
err
=
fmt
.
Errorf
(
"%s: %v"
,
cmd
,
er
)
return
}
}
cmd
=
fmt
.
Sprintf
(
"ip link set dev %s up"
,
ifce
.
Name
())
if
err
=
exeCmd
(
fmt
.
Sprintf
(
"ip link set dev %s up"
,
ifce
.
Name
()));
err
!=
nil
{
log
.
Log
(
"[tun]"
,
cmd
)
log
.
Log
(
err
)
if
er
:=
link
.
SetLinkUp
();
er
!=
nil
{
err
=
fmt
.
Errorf
(
"%s: %v"
,
cmd
,
er
)
return
}
}
if
err
=
addTunRoutes
(
ifce
.
Name
(),
cfg
.
Routes
...
);
err
!=
nil
{
if
err
=
addTunRoutes
(
ifce
.
Name
(),
cfg
.
Routes
...
);
err
!=
nil
{
...
@@ -77,9 +61,8 @@ func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err error) {
...
@@ -77,9 +61,8 @@ func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err error) {
func
createTap
(
cfg
TapConfig
)
(
conn
net
.
Conn
,
itf
*
net
.
Interface
,
err
error
)
{
func
createTap
(
cfg
TapConfig
)
(
conn
net
.
Conn
,
itf
*
net
.
Interface
,
err
error
)
{
var
ip
net
.
IP
var
ip
net
.
IP
var
ipNet
*
net
.
IPNet
if
cfg
.
Addr
!=
""
{
if
cfg
.
Addr
!=
""
{
ip
,
ipNet
,
err
=
net
.
ParseCIDR
(
cfg
.
Addr
)
ip
,
_
,
err
=
net
.
ParseCIDR
(
cfg
.
Addr
)
if
err
!=
nil
{
if
err
!=
nil
{
return
return
}
}
...
@@ -95,37 +78,23 @@ func createTap(cfg TapConfig) (conn net.Conn, itf *net.Interface, err error) {
...
@@ -95,37 +78,23 @@ func createTap(cfg TapConfig) (conn net.Conn, itf *net.Interface, err error) {
return
return
}
}
link
,
err
:=
tenus
.
NewLinkFrom
(
ifce
.
Name
())
if
err
!=
nil
{
return
}
mtu
:=
cfg
.
MTU
mtu
:=
cfg
.
MTU
if
mtu
<=
0
{
if
mtu
<=
0
{
mtu
=
DefaultMTU
mtu
=
DefaultMTU
}
}
cmd
:=
fmt
.
Sprintf
(
"ip link set dev %s mtu %d"
,
ifce
.
Name
(),
mtu
)
if
err
=
exeCmd
(
fmt
.
Sprintf
(
"ip link set dev %s mtu %d"
,
ifce
.
Name
(),
mtu
));
err
!=
nil
{
log
.
Log
(
"[tap]"
,
cmd
)
log
.
Log
(
err
)
if
er
:=
link
.
SetLinkMTU
(
mtu
);
er
!=
nil
{
err
=
fmt
.
Errorf
(
"%s: %v"
,
cmd
,
er
)
return
}
}
if
cfg
.
Addr
!=
""
{
if
cfg
.
Addr
!=
""
{
cmd
=
fmt
.
Sprintf
(
"ip address add %s dev %s"
,
cfg
.
Addr
,
ifce
.
Name
())
if
err
=
exeCmd
(
fmt
.
Sprintf
(
"ip address add %s dev %s"
,
cfg
.
Addr
,
ifce
.
Name
()));
err
!=
nil
{
log
.
Log
(
"[tap]"
,
cmd
)
log
.
Log
(
err
)
if
er
:=
link
.
SetLinkIp
(
ip
,
ipNet
);
er
!=
nil
{
err
=
fmt
.
Errorf
(
"%s: %v"
,
cmd
,
er
)
return
}
}
}
}
cmd
=
fmt
.
Sprintf
(
"ip link set dev %s up"
,
ifce
.
Name
())
if
err
=
exeCmd
(
fmt
.
Sprintf
(
"ip link set dev %s up"
,
ifce
.
Name
()));
err
!=
nil
{
log
.
Log
(
"[tap]"
,
cmd
)
log
.
Log
(
err
)
if
er
:=
link
.
SetLinkUp
();
er
!=
nil
{
err
=
fmt
.
Errorf
(
"%s: %v"
,
cmd
,
er
)
return
}
}
if
err
=
addTapRoutes
(
ifce
.
Name
(),
cfg
.
Gateway
,
cfg
.
Routes
...
);
err
!=
nil
{
if
err
=
addTapRoutes
(
ifce
.
Name
(),
cfg
.
Gateway
,
cfg
.
Routes
...
);
err
!=
nil
{
...
@@ -151,8 +120,10 @@ func addTunRoutes(ifName string, routes ...IPRoute) error {
...
@@ -151,8 +120,10 @@ func addTunRoutes(ifName string, routes ...IPRoute) error {
}
}
cmd
:=
fmt
.
Sprintf
(
"ip route add %s dev %s"
,
route
.
Dest
.
String
(),
ifName
)
cmd
:=
fmt
.
Sprintf
(
"ip route add %s dev %s"
,
route
.
Dest
.
String
(),
ifName
)
log
.
Logf
(
"[tun] %s"
,
cmd
)
log
.
Logf
(
"[tun] %s"
,
cmd
)
if
err
:=
netlink
.
AddRoute
(
route
.
Dest
.
String
(),
""
,
""
,
ifName
);
err
!=
nil
&&
!
errors
.
Is
(
err
,
syscall
.
EEXIST
)
{
return
fmt
.
Errorf
(
"%s: %v"
,
cmd
,
err
)
args
:=
strings
.
Split
(
cmd
,
" "
)
if
er
:=
exec
.
Command
(
args
[
0
],
args
[
1
:
]
...
)
.
Run
();
er
!=
nil
{
log
.
Logf
(
"[tun] %s: %v"
,
cmd
,
er
)
}
}
}
}
return
nil
return
nil
...
@@ -165,9 +136,22 @@ func addTapRoutes(ifName string, gw string, routes ...string) error {
...
@@ -165,9 +136,22 @@ func addTapRoutes(ifName string, gw string, routes ...string) error {
}
}
cmd
:=
fmt
.
Sprintf
(
"ip route add %s via %s dev %s"
,
route
,
gw
,
ifName
)
cmd
:=
fmt
.
Sprintf
(
"ip route add %s via %s dev %s"
,
route
,
gw
,
ifName
)
log
.
Logf
(
"[tap] %s"
,
cmd
)
log
.
Logf
(
"[tap] %s"
,
cmd
)
if
err
:=
netlink
.
AddRoute
(
route
,
""
,
gw
,
ifName
);
err
!=
nil
{
return
fmt
.
Errorf
(
"%s: %v"
,
cmd
,
err
)
args
:=
strings
.
Split
(
cmd
,
" "
)
if
er
:=
exec
.
Command
(
args
[
0
],
args
[
1
:
]
...
)
.
Run
();
er
!=
nil
{
log
.
Logf
(
"[tap] %s: %v"
,
cmd
,
er
)
}
}
}
}
return
nil
return
nil
}
}
func
exeCmd
(
cmd
string
)
error
{
log
.
Log
(
cmd
)
args
:=
strings
.
Split
(
cmd
,
" "
)
if
err
:=
exec
.
Command
(
args
[
0
],
args
[
1
:
]
...
)
.
Run
();
err
!=
nil
{
return
fmt
.
Errorf
(
"%s: %v"
,
cmd
,
err
)
}
return
nil
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment