Merge pull request 'daemonize' (#14) from daemonize into develop
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #14
This commit is contained in:
commit
55c9a1d9a1
@ -7,13 +7,12 @@ import (
|
||||
"mpbl3p/crypto/sharedkey"
|
||||
"mpbl3p/proxy"
|
||||
"mpbl3p/tcp"
|
||||
"mpbl3p/tun"
|
||||
"mpbl3p/udp"
|
||||
"mpbl3p/udp/congestion"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (c Configuration) Build() (*proxy.Proxy, error) {
|
||||
func (c Configuration) Build(source proxy.Source, sink proxy.Sink) (*proxy.Proxy, error) {
|
||||
p := proxy.NewProxy(0)
|
||||
|
||||
var g func() proxy.MacGenerator
|
||||
@ -41,17 +40,8 @@ func (c Configuration) Build() (*proxy.Proxy, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if c.Host.InterfaceName == "" {
|
||||
c.Host.InterfaceName = "nc%d"
|
||||
}
|
||||
|
||||
ss, err := tun.NewTun(c.Host.InterfaceName, 1500)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.Source = ss
|
||||
p.Sink = ss
|
||||
p.Source = source
|
||||
p.Sink = sink
|
||||
|
||||
for _, peer := range c.Peers {
|
||||
switch peer.Method {
|
||||
|
@ -38,10 +38,9 @@ type Configuration struct {
|
||||
}
|
||||
|
||||
type Host struct {
|
||||
InterfaceName string
|
||||
|
||||
Crypto string `validate:"required,oneof=None Blake2s"`
|
||||
SharedKey string `validate:"required_if=Crypto Blake2s"`
|
||||
MTU uint `validate:"required,min=576"`
|
||||
}
|
||||
|
||||
type Peer struct {
|
||||
|
41
flags/flags.go
Normal file
41
flags/flags.go
Normal file
@ -0,0 +1,41 @@
|
||||
package flags
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
goflags "github.com/jessevdk/go-flags"
|
||||
"os"
|
||||
)
|
||||
|
||||
var PrintedHelpErr = goflags.ErrHelp
|
||||
var NotEnoughArgs = errors.New("not enough arguments")
|
||||
|
||||
type Options struct {
|
||||
Foreground bool `short:"f" long:"foreground" description:"Run in the foreground"`
|
||||
ConfigFile string `short:"c" long:"config" description:"Configuration file location" value-name:"FILE"`
|
||||
PidFile string `short:"p" long:"pid" description:"PID file location"`
|
||||
|
||||
Positional struct {
|
||||
InterfaceName string `required:"yes" positional-arg-name:"INTERFACE-NAME" description:"Interface name"`
|
||||
} `positional-args:"yes"`
|
||||
}
|
||||
|
||||
func ParseFlags() (*Options, error) {
|
||||
o := new(Options)
|
||||
parser := goflags.NewParser(o, goflags.Default)
|
||||
|
||||
_, err := parser.Parse()
|
||||
if err != nil {
|
||||
parser.WriteHelp(os.Stdout)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if o.ConfigFile == "" {
|
||||
o.ConfigFile = fmt.Sprintf(DefaultConfigFile, o.Positional.InterfaceName)
|
||||
}
|
||||
if o.PidFile == "" {
|
||||
o.PidFile = fmt.Sprintf(DefaultPidFile, o.Positional.InterfaceName)
|
||||
}
|
||||
|
||||
return o, nil
|
||||
}
|
4
flags/locs_freebsd.go
Normal file
4
flags/locs_freebsd.go
Normal file
@ -0,0 +1,4 @@
|
||||
package flags
|
||||
|
||||
const DefaultConfigFile = "/usr/local/etc/netcombiner/%s"
|
||||
const DefaultPidFile = "/var/run/netcombiner/%s.pid"
|
4
flags/locs_linux.go
Normal file
4
flags/locs_linux.go
Normal file
@ -0,0 +1,4 @@
|
||||
package flags
|
||||
|
||||
const DefaultConfigFile = "/etc/netcombiner/%s"
|
||||
const DefaultPidFile = "/var/run/netcombiner/%s.pid"
|
6
go.mod
6
go.mod
@ -3,10 +3,12 @@ module mpbl3p
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/JakeHillion/taptun v0.0.0-20210320133200-cf0ef75b1bff
|
||||
github.com/go-playground/validator/v10 v10.4.1
|
||||
github.com/jessevdk/go-flags v1.5.0
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897 // indirect
|
||||
golang.zx2c4.com/wireguard v0.0.0-20201118132417-da19db415a58
|
||||
gopkg.in/ini.v1 v1.62.0
|
||||
)
|
||||
|
27
go.sum
27
go.sum
@ -1,7 +1,3 @@
|
||||
github.com/JakeHillion/taptun v0.0.0-20160424131934-bbbd335672ab h1:/UB98lLA11PJZOqhdzqeITMTMz6eiTjti9Z9kYq1SWQ=
|
||||
github.com/JakeHillion/taptun v0.0.0-20160424131934-bbbd335672ab/go.mod h1:8WBFCKR7ZdT+WVtgyiSPJf6gqXiNZUvfglN8vwkoyBE=
|
||||
github.com/JakeHillion/taptun v0.0.0-20210320133200-cf0ef75b1bff h1:O+wiKpOHS2BidwDz6ZuR3dVQNsrD55raE9mY4yub6Wc=
|
||||
github.com/JakeHillion/taptun v0.0.0-20210320133200-cf0ef75b1bff/go.mod h1:8WBFCKR7ZdT+WVtgyiSPJf6gqXiNZUvfglN8vwkoyBE=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
@ -14,6 +10,8 @@ github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7a
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
@ -28,17 +26,34 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897 h1:KrsHThm5nFk34YtATK1LsThyGhGbGe1olrte/HInHvs=
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201117222635-ba5294a509c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg=
|
||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20201118132417-da19db415a58 h1:HiPOx0boQr3qv0HkZ4fGLtTXJ5tmkbv0d8UmkNcxdv0=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20201118132417-da19db415a58/go.mod h1:Dz+cq5bnrai9EpgYj4GDof/+qaGzbRWbeaAOs1bUYa0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
||||
|
129
main.go
129
main.go
@ -1,43 +1,150 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"mpbl3p/config"
|
||||
"mpbl3p/flags"
|
||||
"mpbl3p/tun"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
ENV_NC_TUN_FD = "NC_TUN_FD"
|
||||
ENV_NC_CONFIG_PATH = "NC_CONFIG_PATH"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(log.Ldate | log.Ltime | log.Llongfile)
|
||||
|
||||
if _, exists := os.LookupEnv(ENV_NC_TUN_FD); !exists {
|
||||
// we are the parent process
|
||||
// 1) process arguments
|
||||
// 2) validate config
|
||||
// 2) create a tun adapter
|
||||
// 3) spawn a child
|
||||
// 4) exit
|
||||
|
||||
o, err := flags.ParseFlags()
|
||||
if err != nil {
|
||||
if errors.Is(err, flags.PrintedHelpErr) {
|
||||
return
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
log.Println("loading config...")
|
||||
|
||||
c, err := config.LoadConfig(o.ConfigFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
log.Println("creating tun adapter...")
|
||||
t, err := tun.NewTun(o.Positional.InterfaceName, int(c.Host.MTU))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if o.Foreground {
|
||||
if err := os.Setenv(ENV_NC_TUN_FD, fmt.Sprintf("%d", t.File().Fd())); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := os.Setenv(ENV_NC_CONFIG_PATH, o.ConfigFile); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Println("switching to foreground")
|
||||
goto FOREGROUND
|
||||
}
|
||||
|
||||
files := make([]*os.File, 4)
|
||||
files[0], _ = os.Open(os.DevNull) // stdin
|
||||
files[1], _ = os.Open(os.DevNull) // stderr
|
||||
files[2], _ = os.Open(os.DevNull) // stdout
|
||||
files[3] = t.File()
|
||||
|
||||
env := os.Environ()
|
||||
env = append(env, fmt.Sprintf("%s=3", ENV_NC_TUN_FD))
|
||||
env = append(env, fmt.Sprintf("%s=%s", ENV_NC_CONFIG_PATH, o.ConfigFile))
|
||||
|
||||
attr := os.ProcAttr{
|
||||
Env: env,
|
||||
Files: files,
|
||||
}
|
||||
|
||||
path, err := os.Executable()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
process, err := os.StartProcess(
|
||||
path,
|
||||
os.Args,
|
||||
&attr,
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pidFile, err := os.Create(o.PidFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if _, err := fmt.Fprintf(pidFile, "%d", process.Pid); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_ = process.Release()
|
||||
return
|
||||
}
|
||||
|
||||
// we are the child process
|
||||
// 1) recreate tun adapter from file descriptor
|
||||
// 2) launch proxy
|
||||
|
||||
FOREGROUND:
|
||||
|
||||
log.Println("loading config...")
|
||||
|
||||
var configLoc string
|
||||
if v, ok := os.LookupEnv("CONFIG_LOC"); ok {
|
||||
configLoc = v
|
||||
} else {
|
||||
configLoc = "config.ini"
|
||||
}
|
||||
|
||||
c, err := config.LoadConfig(configLoc)
|
||||
c, err := config.LoadConfig(os.Getenv(ENV_NC_CONFIG_PATH))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
log.Println("connecting tun adapter...")
|
||||
tunFd, err := strconv.ParseUint(os.Getenv(ENV_NC_TUN_FD), 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
t, err := tun.NewFromFile(uintptr(tunFd), int(c.Host.MTU))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := t.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Println("building config...")
|
||||
p, err := c.Build()
|
||||
p, err := c.Build(t, t)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
log.Println("starting...")
|
||||
log.Println("starting proxy...")
|
||||
p.Start()
|
||||
|
||||
log.Println("running")
|
||||
log.Println("proxy started")
|
||||
|
||||
signals := make(chan os.Signal)
|
||||
signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)
|
||||
|
||||
<-signals
|
||||
log.Println("exiting...")
|
||||
}
|
||||
|
39
tun/tun.go
39
tun/tun.go
@ -1,7 +1,7 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"github.com/JakeHillion/taptun"
|
||||
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||
"io"
|
||||
"log"
|
||||
"mpbl3p/proxy"
|
||||
@ -13,32 +13,42 @@ import (
|
||||
)
|
||||
|
||||
type SourceSink struct {
|
||||
tun *taptun.Tun
|
||||
bufferSize int
|
||||
tun wgtun.Device
|
||||
mtu int
|
||||
|
||||
up bool
|
||||
upMu sync.Mutex
|
||||
}
|
||||
|
||||
func NewTun(namingScheme string, bufferSize int) (ss *SourceSink, err error) {
|
||||
ss = &SourceSink{}
|
||||
func NewTun(name string, mtu int) (t wgtun.Device, err error) {
|
||||
return wgtun.CreateTUN(name, mtu)
|
||||
}
|
||||
|
||||
ss.tun, err = taptun.NewTun(namingScheme)
|
||||
func NewFromFile(fd uintptr, mtu int) (ss *SourceSink, err error) {
|
||||
ss = new(SourceSink)
|
||||
|
||||
file := os.NewFile(fd, "")
|
||||
ss.tun, err = wgtun.CreateTUNFromFile(file, mtu)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ss.bufferSize = bufferSize
|
||||
ss.mtu = mtu
|
||||
|
||||
ss.upMu.Lock()
|
||||
go func() {
|
||||
defer ss.upMu.Unlock()
|
||||
|
||||
for {
|
||||
iface, err := net.InterfaceByName(ss.tun.String())
|
||||
tunName, err := ss.tun.Name()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
iface, err := net.InterfaceByName(tunName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if strings.Contains(iface.Flags.String(), "up") {
|
||||
log.Println("tun is up")
|
||||
ss.up = true
|
||||
@ -51,15 +61,22 @@ func NewTun(namingScheme string, bufferSize int) (ss *SourceSink, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (t *SourceSink) Close() error {
|
||||
t.upMu.Lock()
|
||||
t.up = false
|
||||
|
||||
return t.tun.Close()
|
||||
}
|
||||
|
||||
func (t *SourceSink) Source() (proxy.Packet, error) {
|
||||
if !t.up {
|
||||
t.upMu.Lock()
|
||||
t.upMu.Unlock()
|
||||
}
|
||||
|
||||
buf := make([]byte, t.bufferSize)
|
||||
buf := make([]byte, t.mtu)
|
||||
|
||||
read, err := t.tun.Read(buf)
|
||||
read, err := t.tun.Read(buf, 4)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -79,7 +96,7 @@ func (t *SourceSink) Sink(packet proxy.Packet) error {
|
||||
t.upMu.Unlock()
|
||||
}
|
||||
|
||||
_, err := t.tun.Write(packet.Contents())
|
||||
_, err := t.tun.Write(packet.Contents(), 4)
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case *os.PathError:
|
||||
|
Loading…
Reference in New Issue
Block a user