From b4e45d4861edb8e19d8094fc6d11e57a14b58878 Mon Sep 17 00:00:00 2001 From: godstanis Date: Thu, 2 Jan 2025 17:50:50 +0300 Subject: [PATCH] Add interface wrappers and tests --- .gitignore | 1 + go.mod | 49 ++-- go.sum | 118 +++++---- main.go | 1 + pkg/client/client.go | 52 ++-- pkg/client/client_test.go | 173 +++++++++++++ pkg/client/interfaces.go | 31 +++ pkg/client/metrics_test.go | 47 ++++ pkg/client/mocks/client_mocks.go | 421 +++++++++++++++++++++++++++++++ 9 files changed, 802 insertions(+), 91 deletions(-) create mode 100644 .gitignore create mode 100644 pkg/client/client_test.go create mode 100644 pkg/client/interfaces.go create mode 100644 pkg/client/metrics_test.go create mode 100644 pkg/client/mocks/client_mocks.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/go.mod b/go.mod index d482528..d61b8d9 100644 --- a/go.mod +++ b/go.mod @@ -3,60 +3,61 @@ module github.com/goxray/tun go 1.23.3 require ( - github.com/goxray/core v0.0.0-20241217043310-fb75955c8e9b - github.com/jackpal/gateway v1.0.15 - github.com/lilendian0x00/xray-knife v1.6.14-0.20241211194505-363c66ecace3 + github.com/goxray/core v0.0.1 + github.com/jackpal/gateway v1.0.16 + github.com/lilendian0x00/xray-knife/v2 v2.14.21 + github.com/stretchr/testify v1.10.0 github.com/xtls/xray-core v1.8.24 + go.uber.org/mock v0.5.0 ) require ( - github.com/andybalholm/brotli v1.1.0 // indirect - github.com/cloudflare/circl v1.4.0 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect + github.com/cloudflare/circl v1.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect github.com/eycorsican/go-tun2socks v1.16.11 // indirect - github.com/fatih/color v1.17.0 // indirect + github.com/fatih/color v1.18.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect - github.com/google/btree v1.1.2 // indirect - github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/klauspost/compress v1.17.8 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/klauspost/compress v1.17.11 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/onsi/ginkgo/v2 v2.19.0 // indirect - github.com/pires/go-proxyproto v0.7.0 // indirect + github.com/onsi/ginkgo/v2 v2.22.2 // indirect + github.com/pires/go-proxyproto v0.8.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/quic-go/quic-go v0.48.2 // indirect github.com/refraction-networking/utls v1.6.7 // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect - github.com/sagernet/sing v0.4.1 // indirect + github.com/sagernet/sing v0.5.1 // indirect github.com/sagernet/sing-shadowsocks v0.2.7 // indirect github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 // indirect github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/stretchr/testify v1.10.0 // indirect github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect github.com/vishvananda/netlink v1.3.0 // indirect - github.com/vishvananda/netns v0.0.4 // indirect - github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d // indirect - go.uber.org/mock v0.4.0 // indirect + github.com/vishvananda/netns v0.0.5 // indirect + github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect golang.org/x/crypto v0.31.0 // indirect - golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect - golang.org/x/mod v0.18.0 // indirect + golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect + golang.org/x/mod v0.22.0 // indirect golang.org/x/net v0.33.0 // indirect + golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect - golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.22.0 // indirect + golang.org/x/time v0.8.0 // indirect + golang.org/x/tools v0.28.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect - google.golang.org/grpc v1.66.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241230172942-26aa7a208def // indirect + google.golang.org/grpc v1.69.2 // indirect + google.golang.org/protobuf v1.36.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 // indirect lukechampine.com/blake3 v1.3.0 // indirect diff --git a/go.sum b/go.sum index 47903e9..067b594 100644 --- a/go.sum +++ b/go.sum @@ -10,15 +10,15 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJSGpevP+8Pk5bANX7fJacO2w04aqLiC5I= github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM= -github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= -github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.4.0 h1:BV7h5MgrktNzytKmWjpOtdYrf0lkkbF8YMlBGPhJQrY= -github.com/cloudflare/circl v1.4.0/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= +github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys= +github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -29,8 +29,8 @@ github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fp github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eycorsican/go-tun2socks v1.16.11 h1:+hJDNgisrYaGEqoSxhdikMgMJ4Ilfwm/IZDrWRrbaH8= github.com/eycorsican/go-tun2socks v1.16.11/go.mod h1:wgB2BFT8ZaPKyKOQ/5dljMG/YIow+AIXyq4KBwJ5sGQ= -github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= -github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= @@ -40,8 +40,10 @@ github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3 github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -53,9 +55,11 @@ github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/ github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -63,33 +67,35 @@ github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+u github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g= -github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/goxray/core v0.0.0-20241217043310-fb75955c8e9b h1:zm360v9CFN/nfnZkV2U8zoGXBA1bc+ZNKwstk61miX4= -github.com/goxray/core v0.0.0-20241217043310-fb75955c8e9b/go.mod h1:oU090gFSBZjhwx2Ts+zBMPWOb+RKXDz6jZ1uHNJ3js8= +github.com/goxray/core v0.0.1 h1:z52fMtMQz5iU5d6Zo2U3pxYyL0qWU3XeemKQE9f8shg= +github.com/goxray/core v0.0.1/go.mod h1:zuVBEc3ZAJ2cZU8/fiv+EjkS3K7amkln4dyZCpP7CeY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/jackpal/gateway v1.0.15 h1:yb4Gltgr8ApHWWnSyybnDL1vURbqw7ooo7IIL5VZSeg= -github.com/jackpal/gateway v1.0.15/go.mod h1:dbyEDcDhHUh9EmjB9ung81elMUZfG0SoNc2TfTbcj4c= +github.com/jackpal/gateway v1.0.16 h1:mTBRuHSW8qviVqX7kXnxKevqlfS/OA01ys6k6fxSX7w= +github.com/jackpal/gateway v1.0.16/go.mod h1:IOn1OUbso/cGYmnCBZbCEqhNCLSz0xxdtIpUpri5/nA= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lilendian0x00/xray-knife v1.6.14-0.20241211194505-363c66ecace3 h1:Vxe7i413Cc9nyIXht3lX4dKksdk2gN1XG33Zutqyo2E= -github.com/lilendian0x00/xray-knife v1.6.14-0.20241211194505-363c66ecace3/go.mod h1:cjMdIWKJSdLCHOd+6TncUjwCc4QetcQtdtkA0usHqI4= +github.com/lilendian0x00/xray-knife/v2 v2.14.21 h1:PZ0Fd//u9srX8yHQFBOkihUVxGASBV306188PCd2kxc= +github.com/lilendian0x00/xray-knife/v2 v2.14.21/go.mod h1:VcjPtAbsz2OxSC1u+rbgaL9pSFaS/jQRIG/BAglX2iE= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -105,15 +111,15 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= +github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs= -github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4= +github.com/pires/go-proxyproto v0.8.0 h1:5unRmEAPbHXHuLjDg01CxJWf91cw3lKHc/0xzKpXEe0= +github.com/pires/go-proxyproto v0.8.0/go.mod h1:iknsfgnH8EkjrMeMyvfKByp9TiBZCKZM0jx2xmKqnVY= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -130,8 +136,8 @@ github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5D github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sagernet/sing v0.4.1 h1:zVlpE+7k7AFoC2pv6ReqLf0PIHjihL/jsBl5k05PQFk= -github.com/sagernet/sing v0.4.1/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls= +github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y= +github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8= github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE= github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 h1:emzAzMZ1L9iaKCTxdy3Em8Wv4ChIAGnfiz18Cda70g4= @@ -178,15 +184,28 @@ github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49u github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk= github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs= -github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= -github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d h1:+B97uD9uHLgAAulhigmys4BVwZZypzK7gPN3WtpgRJg= -github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE= +github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= +github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 h1:g1Cj7d+my6k/HHxLAyxPwyX8i7FGRr6ulBDMkBzg2BM= +github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463/go.mod h1:BjIOLmkEEtAgloAiVUcYj0Mt+YU00JARZw8AEU0IwAg= github.com/xtls/xray-core v1.8.24 h1:Y2NumdlnJ9C9gvh1Ivs2+73ui5XQgB70wZXYCiI9DyY= github.com/xtls/xray-core v1.8.24/go.mod h1:cWIOI6iBBOsB0HHU9PGhaiBhaMPfiktUjwA0IWolWJc= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= +go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= +go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= +go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= @@ -197,13 +216,13 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg= -golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= +golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= -golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -234,7 +253,6 @@ golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= @@ -245,14 +263,14 @@ golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= -golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4= @@ -269,16 +287,16 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241230172942-26aa7a208def h1:4P81qv5JXI/sDNae2ClVx88cgDDA6DPilADkG9tYKz8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241230172942-26aa7a208def/go.mod h1:bdAgzvd4kFrpykc5/AC2eLUiegK9T/qxZHD4hXYf/ho= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= -google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= +google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= diff --git a/main.go b/main.go index 4fe6456..df609e6 100644 --- a/main.go +++ b/main.go @@ -45,6 +45,7 @@ func main() { log.Fatal(err) } + slog.Info("Connected to VPN server") <-sigterm slog.Info("Received term signal, disconnecting...") if err = vpn.Disconnect(context.Background()); err != nil { diff --git a/pkg/client/client.go b/pkg/client/client.go index aa556e0..36ed939 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -14,10 +14,10 @@ import ( "github.com/goxray/core/network/route" "github.com/goxray/core/network/tun" - tun2socks "github.com/goxray/core/pipe2socks" + "github.com/goxray/core/pipe2socks" "github.com/jackpal/gateway" - "github.com/lilendian0x00/xray-knife/xray" + "github.com/lilendian0x00/xray-knife/v2/xray" xapplog "github.com/xtls/xray-core/app/log" xcommlog "github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/core" @@ -96,9 +96,11 @@ func (c *Config) apply(new *Config) { type Client struct { cfg Config - xInst *core.Instance + xInst runnable xCfg *xray.GeneralConfig tunnel io.ReadWriteCloser + pipe pipe + routes ipTable tunnelStopped chan error stopTunnel func() @@ -122,6 +124,16 @@ func NewClient() (*Client, error) { return nil, fmt.Errorf("discover gateway: %w", err) } + p, err := pipe2socks.NewPipe(pipe2socks.DefaultOpts) + if err != nil { + return nil, fmt.Errorf("tun2socks new pipe: %w", err) + } + + r, err := route.New() + if err != nil { + return nil, fmt.Errorf("route new: %w", err) + } + return &Client{ cfg: Config{ GatewayIP: &gatewayIP, @@ -131,6 +143,8 @@ func NewClient() (*Client, error) { Logger: slog.New(slog.NewTextHandler(os.Stdout, nil)), }, tunnelStopped: make(chan error), + pipe: p, + routes: r, }, nil } @@ -174,7 +188,7 @@ func (c *Client) Connect(link string) error { if err != nil { c.cfg.Logger.Error("xray core creation failed", "err", err, "xray_config", c.xCfg) - return fmt.Errorf("create xray core instance: %v", err) + return fmt.Errorf("create xray core instance: %w", err) } c.cfg.Logger.Debug("xray core instance created", "xray_config", c.xCfg) @@ -182,31 +196,31 @@ func (c *Client) Connect(link string) error { if err = c.xInst.Start(); err != nil { c.cfg.Logger.Error("xray core instance startup failed", "err", err) - return fmt.Errorf("start xray core instance: %v", err) + return fmt.Errorf("start xray core instance: %w", err) } time.Sleep(100 * time.Millisecond) // Sometimes XRay instance should have a bit more time to set up. c.cfg.Logger.Debug("xray core instance started") c.cfg.Logger.Debug("Setting up TUN device") // Create TUN and route all traffic to it. - c.tunnel, err = setupTunnel(c.cfg.TUNAddress, c.cfg.TUNAddress.IP, c.cfg.RoutesToTUN) + c.tunnel, err = c.setupTunnel() if err != nil { c.cfg.Logger.Error("TUN creation failed", "err", err) - return fmt.Errorf("setup TUN device: %v", err) + return fmt.Errorf("setup TUN device: %w", err) } c.tunnel = newReaderMetrics(c.tunnel) c.cfg.Logger.Debug("TUN device created") c.cfg.Logger.Debug("adding routes for TUN device") // Set XRay remote address to be routed through the default gateway, so that we don't get a loop. - _ = route.Delete(c.xrayToGatewayRoute()) // In case previous run failed. + _ = c.routes.Delete(c.xrayToGatewayRoute()) // In case previous run failed. c.cfg.Logger.Debug("deleted dangling routes") - err = route.Add(c.xrayToGatewayRoute()) + err = c.routes.Add(c.xrayToGatewayRoute()) if err != nil { c.cfg.Logger.Error("routing xray server IP to default route failed", "err", err, "route", c.xrayToGatewayRoute()) - return fmt.Errorf("add xray server route exception: %v", err) + return fmt.Errorf("add xray server route exception: %w", err) } c.cfg.Logger.Debug("routing xray server IP to default route") @@ -216,7 +230,7 @@ func (c *Client) Connect(link string) error { ctx, c.stopTunnel = context.WithCancel(context.Background()) go func() { wg.Done() - c.tunnelStopped <- tun2socks.Copy(ctx, c.tunnel, c.cfg.InboundProxy.String(), nil) + c.tunnelStopped <- c.pipe.Copy(ctx, c.tunnel, c.cfg.InboundProxy.String()) c.cfg.Logger.Debug("tunnel pipe closed", "err", err) }() wg.Wait() @@ -230,8 +244,12 @@ func (c *Client) Connect(link string) error { // It will block till all resources are done processing or // context is cancelled (method also enforces timeout of disconnectTimeout) func (c *Client) Disconnect(ctx context.Context) error { + if c.stopTunnel == nil { + return nil // not connected + } + c.stopTunnel() - err := errors.Join(c.xInst.Close(), c.tunnel.Close(), route.Delete(c.xrayToGatewayRoute())) + err := errors.Join(c.xInst.Close(), c.tunnel.Close(), c.routes.Delete(c.xrayToGatewayRoute())) // Waiting till the tunnel actually done with processing connections. ctx, cancel := context.WithTimeout(ctx, disconnectTimeout) @@ -283,7 +301,7 @@ func (c *Client) xrayToGatewayRoute() route.Opts { func (c *Client) createXrayProxy(link string) (*core.Instance, *xray.GeneralConfig, error) { protocol, err := xray.ParseXrayConfig(link) if err != nil { - return nil, nil, fmt.Errorf("parse xray config link: %w", err) + return nil, nil, fmt.Errorf("parse config link: %w", err) } // Make the inbound for local proxy. @@ -302,7 +320,7 @@ func (c *Client) createXrayProxy(link string) (*core.Instance, *xray.GeneralConf inst, err := svc.MakeXrayInstance(protocol) if err != nil { - return nil, nil, fmt.Errorf("make xray instance: %w", err) + return nil, nil, fmt.Errorf("make instance: %w", err) } cfg := protocol.ConvertToGeneralConfig() @@ -328,17 +346,17 @@ func xRayLogLevel(h slog.Handler) xcommlog.Severity { } // setupTunnel creates new TUN interface in the system and routes all traffic to it. -func setupTunnel(l *net.IPNet, gw net.IP, rerouteToTun []*route.Addr) (*tun.Interface, error) { +func (c *Client) setupTunnel() (*tun.Interface, error) { ifc, err := tun.New("", 1500) if err != nil { return nil, fmt.Errorf("create tun: %w", err) } - if err = ifc.Up(l, gw); err != nil { + if err = ifc.Up(c.cfg.TUNAddress, c.cfg.TUNAddress.IP); err != nil { return nil, fmt.Errorf("setup interface: %w", err) } - if err = route.Add(route.Opts{IfName: ifc.Name(), Routes: rerouteToTun}); err != nil { + if err = c.routes.Add(route.Opts{IfName: ifc.Name(), Routes: c.cfg.RoutesToTUN}); err != nil { return nil, fmt.Errorf("add route: %w", err) } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go new file mode 100644 index 0000000..6e602da --- /dev/null +++ b/pkg/client/client_test.go @@ -0,0 +1,173 @@ +package client + +import ( + "context" + "errors" + "io" + "log/slog" + "net" + "os" + "testing" + "time" + + "github.com/goxray/core/network/route" + "github.com/lilendian0x00/xray-knife/v2/xray" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + "github.com/goxray/tun/pkg/client/mocks" +) + +func TestConnect_InvalidLink(t *testing.T) { + cl := Client{ + cfg: Config{Logger: slog.New(slog.NewTextHandler(os.Stdout, nil))}, + } + + err := cl.Connect("invalid_link") + require.ErrorContains(t, err, "parse config link: invalid protocol") +} + +func TestDisconnect_NonConnected(t *testing.T) { + cl := newTestClient(nil, nil, nil, nil, nil) + require.NoError(t, cl.Disconnect(context.Background())) +} + +func TestDisconnect_CtxTimeout(t *testing.T) { + tests := []struct { + name string + stopTunFunc func(stopped chan error) + setupMocks func(*Client, *mocks.Mockrunnable, *mocks.Mockpipe, *mocks.MockipTable, *mocks.MockioReadWriteCloser) + assert func(ctx context.Context, cl *Client, t *testing.T) + }{ + { + name: "ok", + stopTunFunc: func(stopped chan error) { + stopped <- nil + }, + setupMocks: func(cl *Client, r *mocks.Mockrunnable, _ *mocks.Mockpipe, ip *mocks.MockipTable, rwc *mocks.MockioReadWriteCloser) { + r.EXPECT().Close().Return(nil) + rwc.EXPECT().Close().Return(nil) + mockSuccessDisconnectIP(t, cl, ip) + }, + assert: func(ctx context.Context, cl *Client, t *testing.T) { + require.NoError(t, cl.Disconnect(context.Background())) + }, + }, + { + name: "ctx timeout", + stopTunFunc: func(stopped chan error) {}, + setupMocks: func(cl *Client, r *mocks.Mockrunnable, _ *mocks.Mockpipe, ip *mocks.MockipTable, rwc *mocks.MockioReadWriteCloser) { + r.EXPECT().Close().Return(nil) + rwc.EXPECT().Close().Return(nil) + mockSuccessDisconnectIP(t, cl, ip) + }, + assert: func(ctx context.Context, cl *Client, t *testing.T) { + require.ErrorIs(t, cl.Disconnect(ctx), context.DeadlineExceeded) + }, + }, + { + name: "error from instance", + stopTunFunc: func(stopped chan error) { + stopped <- nil + }, + setupMocks: func(cl *Client, r *mocks.Mockrunnable, _ *mocks.Mockpipe, ip *mocks.MockipTable, rwc *mocks.MockioReadWriteCloser) { + r.EXPECT().Close().Return(errors.New("instance close err")) + rwc.EXPECT().Close().Return(nil) + mockSuccessDisconnectIP(t, cl, ip) + }, + assert: func(ctx context.Context, cl *Client, t *testing.T) { + require.ErrorContains(t, cl.Disconnect(ctx), "instance close err") + }, + }, + { + name: "error from tun", + stopTunFunc: func(stopped chan error) { + stopped <- nil + }, + setupMocks: func(cl *Client, r *mocks.Mockrunnable, _ *mocks.Mockpipe, ip *mocks.MockipTable, rwc *mocks.MockioReadWriteCloser) { + r.EXPECT().Close().Return(nil) + rwc.EXPECT().Close().Return(errors.New("tun close err")) + mockSuccessDisconnectIP(t, cl, ip) + }, + assert: func(ctx context.Context, cl *Client, t *testing.T) { + require.ErrorContains(t, cl.Disconnect(ctx), "tun close err") + }, + }, + { + name: "error from everything", + stopTunFunc: func(stopped chan error) { + stopped <- errors.New("stop err") + }, + setupMocks: func(cl *Client, r *mocks.Mockrunnable, _ *mocks.Mockpipe, ip *mocks.MockipTable, rwc *mocks.MockioReadWriteCloser) { + r.EXPECT().Close().Return(errors.New("instance close err")) + rwc.EXPECT().Close().Return(errors.New("tun close err")) + mockSuccessDisconnectIP(t, cl, ip) + }, + assert: func(ctx context.Context, cl *Client, t *testing.T) { + err := cl.Disconnect(ctx) + require.ErrorContains(t, err, "tun close err") + require.ErrorContains(t, err, "instance close err") + require.ErrorContains(t, err, "stop err") + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + require.NotNil(t, test.setupMocks) + + xInstMock := mocks.NewMockrunnable(gomock.NewController(t)) + pipeMock := mocks.NewMockpipe(gomock.NewController(t)) + routesMock := mocks.NewMockipTable(gomock.NewController(t)) + tunMock := mocks.NewMockioReadWriteCloser(gomock.NewController(t)) + + cl := newTestClient(xInstMock, tunMock, routesMock, pipeMock, test.stopTunFunc) + test.setupMocks(cl, xInstMock, pipeMock, routesMock, tunMock) + + ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*10) + defer cancel() + + test.assert(ctx, cl, t) + }) + } +} + +func newTestClient(xInst runnable, tun io.ReadWriteCloser, routes ipTable, pipe pipe, stopTunnel func(chan error)) *Client { + expGateway := &net.IP{127, 0, 0, 2} + expProxy := &Proxy{IP: net.IP{127, 0, 0, 1}, Port: 10234} + expGeneralConfig := &xray.GeneralConfig{Address: "127.0.0.3"} + + cl := &Client{ + cfg: Config{ + Logger: slog.New(slog.NewTextHandler(os.Stdout, nil)), + InboundProxy: expProxy, + GatewayIP: expGateway, + }, + tunnelStopped: make(chan error), + xInst: xInst, + tunnel: tun, + routes: routes, + pipe: pipe, + xCfg: expGeneralConfig, + } + if stopTunnel != nil { + cl.stopTunnel = func() { + go func() { + stopTunnel(cl.tunnelStopped) + }() + } + } + + return cl +} + +func mockSuccessDisconnectIP(t *testing.T, cl *Client, ip *mocks.MockipTable) { + ip.EXPECT().Delete(gomock.Any()).DoAndReturn(func(opts route.Opts) error { + require.Empty(t, opts.IfName) + require.Equal(t, *cl.cfg.GatewayIP, opts.Gateway) + require.Contains(t, opts.Routes, route.MustParseAddr(cl.xCfg.Address+"/32")) + require.Len(t, opts.Routes, 1) + + return nil + }) +} diff --git a/pkg/client/interfaces.go b/pkg/client/interfaces.go new file mode 100644 index 0000000..0b0337a --- /dev/null +++ b/pkg/client/interfaces.go @@ -0,0 +1,31 @@ +//go:generate mockgen -destination=mocks/client_mocks.go -source=interfaces.go -package=mocks -typed + +package client + +import ( + "context" + "io" + + "github.com/goxray/core/network/route" + xcommon "github.com/xtls/xray-core/common" +) + +type pipe interface { + Copy(ctx context.Context, pipe io.ReadWriteCloser, socks5 string) error +} + +type ipTable interface { + // Add adds route to ip table. + Add(options route.Opts) error + // Delete deletes route from ip table. + Delete(options route.Opts) error +} + +type runnable interface { + xcommon.Runnable +} + +//nolint:unused +type ioReadWriteCloser interface { + io.ReadWriteCloser +} diff --git a/pkg/client/metrics_test.go b/pkg/client/metrics_test.go new file mode 100644 index 0000000..d93e206 --- /dev/null +++ b/pkg/client/metrics_test.go @@ -0,0 +1,47 @@ +package client + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + "github.com/goxray/tun/pkg/client/mocks" +) + +func TestMetrics(t *testing.T) { + var ioMockBuf []byte + ioMock := mocks.NewMockioReadWriteCloser(gomock.NewController(t)) + ioMock.EXPECT().Close().Return(nil) + ioMock.EXPECT().Write(gomock.Any()).DoAndReturn(func(buf []byte) (int, error) { + ioMockBuf = append(buf, []byte("test")...) + return len(buf), nil + }).AnyTimes() + ioMock.EXPECT().Read(gomock.Any()).DoAndReturn(func(buf []byte) (int, error) { + copy(buf, ioMockBuf) + n := len(ioMockBuf) + ioMockBuf = []byte{} + return n, nil + }).AnyTimes() + + rwc := newReaderMetrics(ioMock) + + sumRead, sumWrite := 0, 0 + for i := 0; i < 10; i++ { + data := []byte(fmt.Sprintf("data: %d", i)) + n, err := rwc.Write(data) + require.NoError(t, err) + require.Equal(t, len(data), n) + sumWrite += len(data) + + buf := make([]byte, len(data)+10) + n, err = rwc.Read(buf) + require.NoError(t, err) + sumRead += n + } + + require.NoError(t, rwc.Close()) + require.Equal(t, sumRead, rwc.BytesRead()) + require.Equal(t, sumWrite, rwc.BytesWritten()) +} diff --git a/pkg/client/mocks/client_mocks.go b/pkg/client/mocks/client_mocks.go new file mode 100644 index 0000000..72b0011 --- /dev/null +++ b/pkg/client/mocks/client_mocks.go @@ -0,0 +1,421 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: interfaces.go +// +// Generated by this command: +// +// mockgen -destination=mocks/client_mocks.go -source=interfaces.go -package=mocks -typed +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + io "io" + reflect "reflect" + + route "github.com/goxray/core/network/route" + gomock "go.uber.org/mock/gomock" +) + +// Mockpipe is a mock of pipe interface. +type Mockpipe struct { + ctrl *gomock.Controller + recorder *MockpipeMockRecorder + isgomock struct{} +} + +// MockpipeMockRecorder is the mock recorder for Mockpipe. +type MockpipeMockRecorder struct { + mock *Mockpipe +} + +// NewMockpipe creates a new mock instance. +func NewMockpipe(ctrl *gomock.Controller) *Mockpipe { + mock := &Mockpipe{ctrl: ctrl} + mock.recorder = &MockpipeMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *Mockpipe) EXPECT() *MockpipeMockRecorder { + return m.recorder +} + +// Copy mocks base method. +func (m *Mockpipe) Copy(ctx context.Context, pipe io.ReadWriteCloser, socks5 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Copy", ctx, pipe, socks5) + ret0, _ := ret[0].(error) + return ret0 +} + +// Copy indicates an expected call of Copy. +func (mr *MockpipeMockRecorder) Copy(ctx, pipe, socks5 any) *MockpipeCopyCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Copy", reflect.TypeOf((*Mockpipe)(nil).Copy), ctx, pipe, socks5) + return &MockpipeCopyCall{Call: call} +} + +// MockpipeCopyCall wrap *gomock.Call +type MockpipeCopyCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockpipeCopyCall) Return(arg0 error) *MockpipeCopyCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockpipeCopyCall) Do(f func(context.Context, io.ReadWriteCloser, string) error) *MockpipeCopyCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockpipeCopyCall) DoAndReturn(f func(context.Context, io.ReadWriteCloser, string) error) *MockpipeCopyCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// MockipTable is a mock of ipTable interface. +type MockipTable struct { + ctrl *gomock.Controller + recorder *MockipTableMockRecorder + isgomock struct{} +} + +// MockipTableMockRecorder is the mock recorder for MockipTable. +type MockipTableMockRecorder struct { + mock *MockipTable +} + +// NewMockipTable creates a new mock instance. +func NewMockipTable(ctrl *gomock.Controller) *MockipTable { + mock := &MockipTable{ctrl: ctrl} + mock.recorder = &MockipTableMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockipTable) EXPECT() *MockipTableMockRecorder { + return m.recorder +} + +// Add mocks base method. +func (m *MockipTable) Add(options route.Opts) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Add", options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Add indicates an expected call of Add. +func (mr *MockipTableMockRecorder) Add(options any) *MockipTableAddCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Add", reflect.TypeOf((*MockipTable)(nil).Add), options) + return &MockipTableAddCall{Call: call} +} + +// MockipTableAddCall wrap *gomock.Call +type MockipTableAddCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockipTableAddCall) Return(arg0 error) *MockipTableAddCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockipTableAddCall) Do(f func(route.Opts) error) *MockipTableAddCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockipTableAddCall) DoAndReturn(f func(route.Opts) error) *MockipTableAddCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Delete mocks base method. +func (m *MockipTable) Delete(options route.Opts) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockipTableMockRecorder) Delete(options any) *MockipTableDeleteCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockipTable)(nil).Delete), options) + return &MockipTableDeleteCall{Call: call} +} + +// MockipTableDeleteCall wrap *gomock.Call +type MockipTableDeleteCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockipTableDeleteCall) Return(arg0 error) *MockipTableDeleteCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockipTableDeleteCall) Do(f func(route.Opts) error) *MockipTableDeleteCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockipTableDeleteCall) DoAndReturn(f func(route.Opts) error) *MockipTableDeleteCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Mockrunnable is a mock of runnable interface. +type Mockrunnable struct { + ctrl *gomock.Controller + recorder *MockrunnableMockRecorder + isgomock struct{} +} + +// MockrunnableMockRecorder is the mock recorder for Mockrunnable. +type MockrunnableMockRecorder struct { + mock *Mockrunnable +} + +// NewMockrunnable creates a new mock instance. +func NewMockrunnable(ctrl *gomock.Controller) *Mockrunnable { + mock := &Mockrunnable{ctrl: ctrl} + mock.recorder = &MockrunnableMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *Mockrunnable) EXPECT() *MockrunnableMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *Mockrunnable) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockrunnableMockRecorder) Close() *MockrunnableCloseCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*Mockrunnable)(nil).Close)) + return &MockrunnableCloseCall{Call: call} +} + +// MockrunnableCloseCall wrap *gomock.Call +type MockrunnableCloseCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockrunnableCloseCall) Return(arg0 error) *MockrunnableCloseCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockrunnableCloseCall) Do(f func() error) *MockrunnableCloseCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockrunnableCloseCall) DoAndReturn(f func() error) *MockrunnableCloseCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Start mocks base method. +func (m *Mockrunnable) Start() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Start") + ret0, _ := ret[0].(error) + return ret0 +} + +// Start indicates an expected call of Start. +func (mr *MockrunnableMockRecorder) Start() *MockrunnableStartCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*Mockrunnable)(nil).Start)) + return &MockrunnableStartCall{Call: call} +} + +// MockrunnableStartCall wrap *gomock.Call +type MockrunnableStartCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockrunnableStartCall) Return(arg0 error) *MockrunnableStartCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockrunnableStartCall) Do(f func() error) *MockrunnableStartCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockrunnableStartCall) DoAndReturn(f func() error) *MockrunnableStartCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// MockioReadWriteCloser is a mock of ioReadWriteCloser interface. +type MockioReadWriteCloser struct { + ctrl *gomock.Controller + recorder *MockioReadWriteCloserMockRecorder + isgomock struct{} +} + +// MockioReadWriteCloserMockRecorder is the mock recorder for MockioReadWriteCloser. +type MockioReadWriteCloserMockRecorder struct { + mock *MockioReadWriteCloser +} + +// NewMockioReadWriteCloser creates a new mock instance. +func NewMockioReadWriteCloser(ctrl *gomock.Controller) *MockioReadWriteCloser { + mock := &MockioReadWriteCloser{ctrl: ctrl} + mock.recorder = &MockioReadWriteCloserMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockioReadWriteCloser) EXPECT() *MockioReadWriteCloserMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockioReadWriteCloser) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockioReadWriteCloserMockRecorder) Close() *MockioReadWriteCloserCloseCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockioReadWriteCloser)(nil).Close)) + return &MockioReadWriteCloserCloseCall{Call: call} +} + +// MockioReadWriteCloserCloseCall wrap *gomock.Call +type MockioReadWriteCloserCloseCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockioReadWriteCloserCloseCall) Return(arg0 error) *MockioReadWriteCloserCloseCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockioReadWriteCloserCloseCall) Do(f func() error) *MockioReadWriteCloserCloseCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockioReadWriteCloserCloseCall) DoAndReturn(f func() error) *MockioReadWriteCloserCloseCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Read mocks base method. +func (m *MockioReadWriteCloser) Read(p []byte) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Read", p) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Read indicates an expected call of Read. +func (mr *MockioReadWriteCloserMockRecorder) Read(p any) *MockioReadWriteCloserReadCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Read", reflect.TypeOf((*MockioReadWriteCloser)(nil).Read), p) + return &MockioReadWriteCloserReadCall{Call: call} +} + +// MockioReadWriteCloserReadCall wrap *gomock.Call +type MockioReadWriteCloserReadCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockioReadWriteCloserReadCall) Return(n int, err error) *MockioReadWriteCloserReadCall { + c.Call = c.Call.Return(n, err) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockioReadWriteCloserReadCall) Do(f func([]byte) (int, error)) *MockioReadWriteCloserReadCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockioReadWriteCloserReadCall) DoAndReturn(f func([]byte) (int, error)) *MockioReadWriteCloserReadCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Write mocks base method. +func (m *MockioReadWriteCloser) Write(p []byte) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Write", p) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Write indicates an expected call of Write. +func (mr *MockioReadWriteCloserMockRecorder) Write(p any) *MockioReadWriteCloserWriteCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockioReadWriteCloser)(nil).Write), p) + return &MockioReadWriteCloserWriteCall{Call: call} +} + +// MockioReadWriteCloserWriteCall wrap *gomock.Call +type MockioReadWriteCloserWriteCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockioReadWriteCloserWriteCall) Return(n int, err error) *MockioReadWriteCloserWriteCall { + c.Call = c.Call.Return(n, err) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockioReadWriteCloserWriteCall) Do(f func([]byte) (int, error)) *MockioReadWriteCloserWriteCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockioReadWriteCloserWriteCall) DoAndReturn(f func([]byte) (int, error)) *MockioReadWriteCloserWriteCall { + c.Call = c.Call.DoAndReturn(f) + return c +}