add tun device support (#420)
This commit is contained in:
parent
5414768920
commit
b11ce8a71c
@ -372,6 +372,8 @@ func (r *route) GenRouters() ([]router, error) {
|
|||||||
ln, err = gost.Obfs4Listener(node.Addr)
|
ln, err = gost.Obfs4Listener(node.Addr)
|
||||||
case "ohttp":
|
case "ohttp":
|
||||||
ln, err = gost.ObfsHTTPListener(node.Addr)
|
ln, err = gost.ObfsHTTPListener(node.Addr)
|
||||||
|
case "tun":
|
||||||
|
ln, err = gost.TunListener(node.Addr)
|
||||||
default:
|
default:
|
||||||
ln, err = gost.TCPListener(node.Addr)
|
ln, err = gost.TCPListener(node.Addr)
|
||||||
}
|
}
|
||||||
@ -409,6 +411,13 @@ func (r *route) GenRouters() ([]router, error) {
|
|||||||
handler = gost.ShadowUDPdHandler()
|
handler = gost.ShadowUDPdHandler()
|
||||||
case "sni":
|
case "sni":
|
||||||
handler = gost.SNIHandler()
|
handler = gost.SNIHandler()
|
||||||
|
case "tun":
|
||||||
|
cfg := gost.TunConfig{
|
||||||
|
Name: node.Get("name"),
|
||||||
|
Addr: node.Get("net"),
|
||||||
|
MTU: node.GetInt("mtu"),
|
||||||
|
}
|
||||||
|
handler = gost.TunHandler(node.Remote, gost.TunConfigHandlerOption(cfg))
|
||||||
default:
|
default:
|
||||||
// start from 2.5, if remote is not empty, then we assume that it is a forward tunnel.
|
// start from 2.5, if remote is not empty, then we assume that it is a forward tunnel.
|
||||||
if node.Remote != "" {
|
if node.Remote != "" {
|
||||||
|
1
go.mod
1
go.mod
@ -31,6 +31,7 @@ require (
|
|||||||
github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735
|
github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735
|
||||||
github.com/shadowsocks/go-shadowsocks2 v0.0.11
|
github.com/shadowsocks/go-shadowsocks2 v0.0.11
|
||||||
github.com/shadowsocks/shadowsocks-go v0.0.0-20170121203516-97a5c71f80ba
|
github.com/shadowsocks/shadowsocks-go v0.0.0-20170121203516-97a5c71f80ba
|
||||||
|
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b
|
||||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
|
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
|
||||||
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect
|
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect
|
||||||
github.com/tjfoc/gmsm v1.0.1 // indirect
|
github.com/tjfoc/gmsm v1.0.1 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -65,6 +65,8 @@ github.com/shadowsocks/go-shadowsocks2 v0.0.11 h1:dXloqEhYnZV40jblWTK8kWeC0Eb+dg
|
|||||||
github.com/shadowsocks/go-shadowsocks2 v0.0.11/go.mod h1:R+KWaoIwRRhnpw6XV+dZil0XHi64Hc1D7hXUyXTjUzQ=
|
github.com/shadowsocks/go-shadowsocks2 v0.0.11/go.mod h1:R+KWaoIwRRhnpw6XV+dZil0XHi64Hc1D7hXUyXTjUzQ=
|
||||||
github.com/shadowsocks/shadowsocks-go v0.0.0-20170121203516-97a5c71f80ba h1:tJgNXb3S+RkB4kNPi6N5OmEWe3m+Y3Qs6LUMiNDAONM=
|
github.com/shadowsocks/shadowsocks-go v0.0.0-20170121203516-97a5c71f80ba h1:tJgNXb3S+RkB4kNPi6N5OmEWe3m+Y3Qs6LUMiNDAONM=
|
||||||
github.com/shadowsocks/shadowsocks-go v0.0.0-20170121203516-97a5c71f80ba/go.mod h1:mttDPaeLm87u74HMrP+n2tugXvIKWcwff/cqSX0lehY=
|
github.com/shadowsocks/shadowsocks-go v0.0.0-20170121203516-97a5c71f80ba/go.mod h1:mttDPaeLm87u74HMrP+n2tugXvIKWcwff/cqSX0lehY=
|
||||||
|
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b h1:+y4hCMc/WKsDbAPsOQZgBSaSZ26uh2afyaWeVg/3s/c=
|
||||||
|
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
||||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
|
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
|
||||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
|
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
|
||||||
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b h1:mnG1fcsIB1d/3vbkBak2MM0u+vhGhlQwpeimUi7QncM=
|
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b h1:mnG1fcsIB1d/3vbkBak2MM0u+vhGhlQwpeimUi7QncM=
|
||||||
|
8
gost.go
8
gost.go
@ -20,14 +20,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Version is the gost version.
|
// Version is the gost version.
|
||||||
const Version = "2.8.2"
|
const Version = "2.9.0-dev"
|
||||||
|
|
||||||
// Debug is a flag that enables the debug log.
|
// Debug is a flag that enables the debug log.
|
||||||
var Debug bool
|
var Debug bool
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tinyBufferSize = 128
|
tinyBufferSize = 512
|
||||||
smallBufferSize = 1 * 1024 // 1KB small buffer
|
smallBufferSize = 2 * 1024 // 2KB small buffer
|
||||||
mediumBufferSize = 8 * 1024 // 8KB medium buffer
|
mediumBufferSize = 8 * 1024 // 8KB medium buffer
|
||||||
largeBufferSize = 32 * 1024 // 32KB large buffer
|
largeBufferSize = 32 * 1024 // 32KB large buffer
|
||||||
)
|
)
|
||||||
@ -77,6 +77,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"
|
||||||
|
|
||||||
|
DefaultMTU = 1350 // default mtu for tun device
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetLogger sets a new logger for internal log system.
|
// SetLogger sets a new logger for internal log system.
|
||||||
|
@ -40,6 +40,7 @@ type HandlerOptions struct {
|
|||||||
Node Node
|
Node Node
|
||||||
Host string
|
Host string
|
||||||
IPs []string
|
IPs []string
|
||||||
|
TunConfig TunConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandlerOption allows a common way to set handler options.
|
// HandlerOption allows a common way to set handler options.
|
||||||
@ -195,6 +196,13 @@ func IPsHandlerOption(ips []string) HandlerOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TunConfigHandlerOption sets the config for tun device.
|
||||||
|
func TunConfigHandlerOption(cfg TunConfig) HandlerOption {
|
||||||
|
return func(opts *HandlerOptions) {
|
||||||
|
opts.TunConfig = cfg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type autoHandler struct {
|
type autoHandler struct {
|
||||||
options *HandlerOptions
|
options *HandlerOptions
|
||||||
}
|
}
|
||||||
|
2
node.go
2
node.go
@ -82,6 +82,7 @@ func ParseNode(s string) (node Node, err error) {
|
|||||||
case "tcp", "udp": // started from v2.1, tcp and udp are for local port forwarding
|
case "tcp", "udp": // started from v2.1, tcp and udp are for local port forwarding
|
||||||
case "rtcp", "rudp": // rtcp and rudp are for remote port forwarding
|
case "rtcp", "rudp": // rtcp and rudp are for remote port forwarding
|
||||||
case "ohttp": // obfs-http
|
case "ohttp": // obfs-http
|
||||||
|
case "tun": //tun device
|
||||||
default:
|
default:
|
||||||
node.Transport = "tcp"
|
node.Transport = "tcp"
|
||||||
}
|
}
|
||||||
@ -93,6 +94,7 @@ func ParseNode(s string) (node Node, err error) {
|
|||||||
case "tcp", "udp", "rtcp", "rudp": // port forwarding
|
case "tcp", "udp", "rtcp", "rudp": // port forwarding
|
||||||
case "direct", "remote", "forward": // forwarding
|
case "direct", "remote", "forward": // forwarding
|
||||||
case "redirect": // TCP transparent proxy
|
case "redirect": // TCP transparent proxy
|
||||||
|
case "tun": // tun device
|
||||||
default:
|
default:
|
||||||
node.Protocol = ""
|
node.Protocol = ""
|
||||||
}
|
}
|
||||||
|
@ -81,14 +81,6 @@ func (s *Server) Serve(h Handler, opts ...ServerOption) error {
|
|||||||
}
|
}
|
||||||
tempDelay = 0
|
tempDelay = 0
|
||||||
|
|
||||||
/*
|
|
||||||
if s.options.Bypass.Contains(conn.RemoteAddr().String()) {
|
|
||||||
log.Log("[bypass]", conn.RemoteAddr())
|
|
||||||
conn.Close()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
go h.Handle(conn)
|
go h.Handle(conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
341
tun.go
Normal file
341
tun.go
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
package gost
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-log/log"
|
||||||
|
"github.com/shadowsocks/go-shadowsocks2/core"
|
||||||
|
"github.com/songgao/water"
|
||||||
|
"golang.org/x/net/ipv4"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TunConfig struct {
|
||||||
|
Name string
|
||||||
|
Addr string
|
||||||
|
MTU int
|
||||||
|
Routes []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type tunHandler struct {
|
||||||
|
raddr string
|
||||||
|
options *HandlerOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// TunHandler creates a handler for tun tunnel.
|
||||||
|
func TunHandler(raddr string, opts ...HandlerOption) Handler {
|
||||||
|
h := &tunHandler{
|
||||||
|
raddr: raddr,
|
||||||
|
options: &HandlerOptions{},
|
||||||
|
}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(h.options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *tunHandler) Init(options ...HandlerOption) {
|
||||||
|
if h.options == nil {
|
||||||
|
h.options = &HandlerOptions{}
|
||||||
|
}
|
||||||
|
for _, opt := range options {
|
||||||
|
opt(h.options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *tunHandler) Handle(conn net.Conn) {
|
||||||
|
defer os.Exit(0)
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
uc, ok := conn.(net.PacketConn)
|
||||||
|
if !ok {
|
||||||
|
log.Log("[tun] wrong connection type, must be PacketConn")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tc, err := h.createTun()
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[tun] %s create tun: %v", conn.LocalAddr(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer tc.Close()
|
||||||
|
|
||||||
|
log.Logf("[tun] %s - %s: tun creation successful", tc.LocalAddr(), conn.LocalAddr())
|
||||||
|
|
||||||
|
var raddr net.Addr
|
||||||
|
if h.raddr != "" {
|
||||||
|
raddr, err = net.ResolveUDPAddr("udp", h.raddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[tun] %s - %s remote addr: %v", tc.LocalAddr(), conn.LocalAddr(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(h.options.Users) > 0 && h.options.Users[0] != nil {
|
||||||
|
passwd, _ := h.options.Users[0].Password()
|
||||||
|
cipher, err := core.PickCipher(h.options.Users[0].Username(), nil, passwd)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[tun] %s - %s cipher: %v", tc.LocalAddr(), conn.LocalAddr(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uc = cipher.PacketConn(uc)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.transportTun(tc, uc, raddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *tunHandler) createTun() (conn net.Conn, err error) {
|
||||||
|
cfg := h.options.TunConfig
|
||||||
|
|
||||||
|
ip, _, err := net.ParseCIDR(cfg.Addr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ifce, err := water.New(water.Config{
|
||||||
|
DeviceType: water.TUN,
|
||||||
|
PlatformSpecificParams: water.PlatformSpecificParams{
|
||||||
|
Name: cfg.Name,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setup := func(args ...string) error {
|
||||||
|
cmd := exec.Command("/sbin/ip", args...)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
mtu := cfg.MTU
|
||||||
|
if mtu <= 0 {
|
||||||
|
mtu = DefaultMTU
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = setup("link", "set", "dev", ifce.Name(), "mtu", strconv.Itoa(mtu)); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = setup("addr", "add", cfg.Addr, "dev", ifce.Name()); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = setup("link", "set", "dev", ifce.Name(), "up"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tc := &tunConn{
|
||||||
|
ifce: ifce,
|
||||||
|
addr: &net.IPAddr{IP: ip},
|
||||||
|
}
|
||||||
|
return tc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *tunHandler) transportTun(tun net.Conn, conn net.PacketConn, raddr net.Addr) error {
|
||||||
|
var routes sync.Map
|
||||||
|
errc := make(chan error, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
err := func() error {
|
||||||
|
b := sPool.Get().([]byte)
|
||||||
|
defer sPool.Put(b)
|
||||||
|
|
||||||
|
n, err := tun.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
header, err := ipv4.ParseHeader(b[:n])
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[tun] %s: %v", tun.LocalAddr(), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if header.Version != ipv4.Version {
|
||||||
|
log.Logf("[tun] %s: v%d ignored, only support ipv4",
|
||||||
|
tun.LocalAddr(), header.Version)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := raddr
|
||||||
|
if v, ok := routes.Load(header.Dst.String()); ok {
|
||||||
|
addr = v.(net.Addr)
|
||||||
|
}
|
||||||
|
if addr == nil {
|
||||||
|
log.Logf("[tun] %s: no address to forward for %s -> %s",
|
||||||
|
tun.LocalAddr(), header.Src, header.Dst)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if Debug {
|
||||||
|
log.Logf("[tun] %s >>> %s: %s -> %s %d/%d %x %x %d",
|
||||||
|
tun.LocalAddr(), addr, header.Src, header.Dst,
|
||||||
|
header.Len, header.TotalLen, header.ID, header.Flags, header.Protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := conn.WriteTo(b[:n], addr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
errc <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
err := func() error {
|
||||||
|
b := sPool.Get().([]byte)
|
||||||
|
defer mPool.Put(b)
|
||||||
|
|
||||||
|
n, addr, err := conn.ReadFrom(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
header, err := ipv4.ParseHeader(b[:n])
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[tun] %s <- %s: %v", tun.LocalAddr(), addr, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if header.Version != ipv4.Version {
|
||||||
|
log.Logf("[tun] %s <- %s: v%d ignored, only support ipv4",
|
||||||
|
tun.LocalAddr(), addr, header.Version)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if Debug {
|
||||||
|
log.Logf("[tun] %s <<< %s: %s -> %s %d/%d %x %x %d",
|
||||||
|
tun.LocalAddr(), addr, header.Src, header.Dst,
|
||||||
|
header.Len, header.TotalLen, header.ID, header.Flags, header.Protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
if actual, loaded := routes.LoadOrStore(header.Src.String(), addr); loaded {
|
||||||
|
if actual.(net.Addr).String() != addr.String() {
|
||||||
|
log.Logf("[tun] %s <- %s: unexpected address mapping %s -> %s(actual %s)",
|
||||||
|
tun.LocalAddr(), addr, header.Dst.String(), addr, actual.(net.Addr).String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := tun.Write(b[:n]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
errc <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := <-errc
|
||||||
|
if err != nil && err == io.EOF {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
log.Logf("[tun] %s - %s: %v", tun.LocalAddr(), conn.LocalAddr(), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type tunConn struct {
|
||||||
|
ifce *water.Interface
|
||||||
|
addr net.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunConn) Read(b []byte) (n int, err error) {
|
||||||
|
return c.ifce.Read(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunConn) Write(b []byte) (n int, err error) {
|
||||||
|
return c.ifce.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunConn) Close() (err error) {
|
||||||
|
return c.ifce.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunConn) LocalAddr() net.Addr {
|
||||||
|
return c.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunConn) RemoteAddr() net.Addr {
|
||||||
|
return &net.IPAddr{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunConn) SetDeadline(t time.Time) error {
|
||||||
|
return &net.OpError{Op: "set", Net: "tun", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunConn) SetReadDeadline(t time.Time) error {
|
||||||
|
return &net.OpError{Op: "set", Net: "tun", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunConn) SetWriteDeadline(t time.Time) error {
|
||||||
|
return &net.OpError{Op: "set", Net: "tun", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
||||||
|
}
|
||||||
|
|
||||||
|
type tunListener struct {
|
||||||
|
conn *net.UDPConn
|
||||||
|
accepted, closed chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TunListener creates a listener for tun tunnel.
|
||||||
|
func TunListener(addr string) (Listener, error) {
|
||||||
|
laddr, err := net.ResolveUDPAddr("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn, err := net.ListenUDP("udp", laddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tunListener{
|
||||||
|
conn: conn,
|
||||||
|
accepted: make(chan struct{}),
|
||||||
|
closed: make(chan struct{}),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tunListener) Accept() (net.Conn, error) {
|
||||||
|
select {
|
||||||
|
case <-l.accepted:
|
||||||
|
default:
|
||||||
|
close(l.accepted)
|
||||||
|
return l.conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-l.closed:
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("accept on closed listener")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tunListener) Addr() net.Addr {
|
||||||
|
return l.conn.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tunListener) Close() error {
|
||||||
|
select {
|
||||||
|
case <-l.closed:
|
||||||
|
return errors.New("listener has been closed")
|
||||||
|
default:
|
||||||
|
close(l.closed)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user