Compare commits

..

5 Commits

Author SHA1 Message Date
Quentin McGaw
1114981914 wip 2024-11-07 19:55:02 +00:00
Quentin McGaw
4ef0df04aa chore(routing): remove redundant rule ip rule in error messages 2024-11-07 19:50:46 +00:00
Quentin McGaw
937c667ca8 hotfix(perfectprivacy): fix formatting from previous commit 2024-10-27 17:20:30 +00:00
Christoph Kehl
3c45f57aaa fix(perfectprivacy): update openvpn expired certificates (#2542) 2024-10-27 11:45:25 +01:00
Quentin McGaw
30640eefe2 chore(deps): upgrade dns to v2.0.0-cr7 2024-10-25 14:01:29 +00:00
20 changed files with 383 additions and 400 deletions

45
go.mod
View File

@@ -3,15 +3,14 @@ module github.com/qdm12/gluetun
go 1.23
require (
github.com/breml/rootcerts v0.2.17
github.com/fatih/color v1.17.0
github.com/breml/rootcerts v0.2.18
github.com/fatih/color v1.18.0
github.com/golang/mock v1.6.0
github.com/klauspost/compress v1.17.9
github.com/klauspost/pgzip v1.2.6
github.com/pelletier/go-toml/v2 v2.2.2
github.com/qdm12/dns/v2 v2.0.0-rc6
github.com/qdm12/goservices v0.1.0
github.com/qdm12/gosettings v0.4.2
github.com/qdm12/dns/v2 v2.0.0-rc7
github.com/qdm12/gosettings v0.4.3
github.com/qdm12/goshutdown v0.3.0
github.com/qdm12/gosplash v0.2.0
github.com/qdm12/gotree v0.3.0
@@ -21,10 +20,10 @@ require (
github.com/ulikunitz/xz v0.5.11
github.com/vishvananda/netlink v1.2.1
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
golang.org/x/net v0.28.0
golang.org/x/sys v0.24.0
golang.org/x/text v0.17.0
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
golang.org/x/net v0.30.0
golang.org/x/sys v0.26.0
golang.org/x/text v0.19.0
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
gopkg.in/ini.v1 v1.67.0
@@ -32,32 +31,32 @@ require (
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mdlayher/genetlink v1.3.2 // indirect
github.com/mdlayher/netlink v1.7.2 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/miekg/dns v1.1.55 // indirect
github.com/miekg/dns v1.1.62 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.60.1 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/qdm12/goservices v0.1.0 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
golang.org/x/tools v0.26.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
google.golang.org/protobuf v1.33.0 // indirect
google.golang.org/protobuf v1.35.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
kernel.org/pub/linux/libs/security/libcap/cap v1.2.69 // indirect
kernel.org/pub/linux/libs/security/libcap/psx v1.2.69 // indirect
kernel.org/pub/linux/libs/security/libcap/cap v1.2.70 // indirect
kernel.org/pub/linux/libs/security/libcap/psx v1.2.70 // indirect
)

98
go.sum
View File

@@ -1,24 +1,18 @@
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/breml/rootcerts v0.2.17 h1:0/M2BE2Apw0qEJCXDOkaiu7d5Sx5ObNfe1BkImJ4u1I=
github.com/breml/rootcerts v0.2.17/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/breml/rootcerts v0.2.18 h1:KjZaNT7AX/akUjzpStuwTMQs42YHlPyc6NmdwShVba0=
github.com/breml/rootcerts v0.2.18/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
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=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
@@ -36,36 +30,36 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo=
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/qdm12/dns/v2 v2.0.0-rc6 h1:h5KpuqZ3IMoSbz2a0OkHzIVc9/jk2vuIm9RoKJuaI78=
github.com/qdm12/dns/v2 v2.0.0-rc6/go.mod h1:Oh34IJIG55BgHoACOf+cgZCgDiFuiJZ6r6gQW58FN+k=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc=
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/qdm12/dns/v2 v2.0.0-rc7 h1:noFoWunMfFuJeIpcyTJsdS9BU7jRxxKrBV5xN2qjPHI=
github.com/qdm12/dns/v2 v2.0.0-rc7/go.mod h1:VaF02KWEL7xNV4oKfG4N9nEv/kR6bqyIcBReCV5NJhw=
github.com/qdm12/goservices v0.1.0 h1:9sODefm/yuIGS7ynCkEnNlMTAYn9GzPhtcK4F69JWvc=
github.com/qdm12/goservices v0.1.0/go.mod h1:/JOFsAnHFiSjyoXxa5FlfX903h20K5u/3rLzCjYVMck=
github.com/qdm12/gosettings v0.4.2 h1:Gb39NScPr7OQV+oy0o1OD7A121udITDJuUGa7ljDF58=
github.com/qdm12/gosettings v0.4.2/go.mod h1:CPrt2YC4UsURTrslmhxocVhMCW03lIrqdH2hzIf5prg=
github.com/qdm12/gosettings v0.4.3 h1:oGAjiKVtml9oHVlPQo6H3yk6TmtWpVYicNeGFcM7AP8=
github.com/qdm12/gosettings v0.4.3/go.mod h1:CPrt2YC4UsURTrslmhxocVhMCW03lIrqdH2hzIf5prg=
github.com/qdm12/goshutdown v0.3.0 h1:pqBpJkdwlZlfTEx4QHtS8u8CXx6pG0fVo6S1N0MpSEM=
github.com/qdm12/goshutdown v0.3.0/go.mod h1:EqZ46No00kCTZ5qzdd3qIzY6ayhMt24QI8Mh8LVQYmM=
github.com/qdm12/gosplash v0.2.0 h1:DOxCEizbW6ZG+FgpH2oK1atT6bM8MHL9GZ2ywSS4zZY=
@@ -78,8 +72,8 @@ github.com/qdm12/ss-server v0.6.0 h1:OaOdCIBXx0z3DGHPT6Th0v88vGa3MtAS4oRgUsDHGZE
github.com/qdm12/ss-server v0.6.0/go.mod h1:0BO/zEmtTiLDlmQEcjtoHTC+w+cWxwItjBuGP6TWM78=
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/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -101,19 +95,18 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
@@ -127,23 +120,22 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.2.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.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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=
@@ -151,10 +143,8 @@ golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uI
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -165,7 +155,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 h1:TbRPT0HtzFP3Cno1zZo7yPzEEnfu8EjLfl6IU9VfqkQ=
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259/go.mod h1:AVgIgHMwK63XvmAzWG9vLQ41YnVHN0du0tEC46fI7yY=
kernel.org/pub/linux/libs/security/libcap/cap v1.2.69 h1:N0m3tKYbkRMmDobh/47ngz+AWeV7PcfXMDi8xu3Vrag=
kernel.org/pub/linux/libs/security/libcap/cap v1.2.69/go.mod h1:Tk5Ip2TuxaWGpccL7//rAsLRH6RQ/jfqTGxuN/+i/FQ=
kernel.org/pub/linux/libs/security/libcap/psx v1.2.69 h1:IdrOs1ZgwGw5CI+BH6GgVVlOt+LAXoPyh7enr8lfaXs=
kernel.org/pub/linux/libs/security/libcap/psx v1.2.69/go.mod h1:+l6Ee2F59XiJ2I6WR5ObpC1utCQJZ/VLsEbQCD8RG24=
kernel.org/pub/linux/libs/security/libcap/cap v1.2.70 h1:QnLPkuDWWbD5C+3DUA2IUXai5TK6w2zff+MAGccqdsw=
kernel.org/pub/linux/libs/security/libcap/cap v1.2.70/go.mod h1:/iBwcj9nbLejQitYvUm9caurITQ6WyNHibJk6Q9fiS4=
kernel.org/pub/linux/libs/security/libcap/psx v1.2.70 h1:HsB2G/rEQiYyo1bGoQqHZ/Bvd6x1rERQTNdPr1FyWjI=
kernel.org/pub/linux/libs/security/libcap/psx v1.2.70/go.mod h1:+l6Ee2F59XiJ2I6WR5ObpC1utCQJZ/VLsEbQCD8RG24=

View File

@@ -54,6 +54,7 @@ func (p PortForwarding) Validate(vpnProvider string) (err error) {
providers.PrivateInternetAccess,
providers.Privatevpn,
providers.Protonvpn,
providers.Mullvad,
}
if err = validate.IsOneOf(providerSelected, validProviders...); err != nil {
return fmt.Errorf("%w: %w", ErrPortForwardingEnabled, err)

View File

@@ -22,7 +22,7 @@ func (s Shadowsocks) validate() (err error) {
return s.Settings.Validate()
}
func (s *Shadowsocks) Copy() (copied Shadowsocks) {
func (s *Shadowsocks) copy() (copied Shadowsocks) {
return Shadowsocks{
Enabled: gosettings.CopyPointer(s.Enabled),
Settings: s.Settings.Copy(),
@@ -32,7 +32,7 @@ func (s *Shadowsocks) Copy() (copied Shadowsocks) {
// overrideWith overrides fields of the receiver
// settings object with any field set in the other
// settings.
func (s *Shadowsocks) OverrideWith(other Shadowsocks) {
func (s *Shadowsocks) overrideWith(other Shadowsocks) {
s.Enabled = gosettings.OverrideWithPointer(s.Enabled, other.Enabled)
s.Settings.OverrideWith(other.Settings)
}

View File

@@ -6,8 +6,8 @@ import (
"net/http"
"time"
"github.com/qdm12/dns/v2/pkg/dot"
"github.com/qdm12/dns/v2/pkg/middlewares/filter/mapfilter"
"github.com/qdm12/dns/v2/pkg/server"
"github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/dns/state"
@@ -18,7 +18,7 @@ import (
type Loop struct {
statusManager *loopstate.State
state *state.State
server *dot.Server
server *server.Server
filter *mapfilter.Filter
resolvConf string
client *http.Client

View File

@@ -10,6 +10,7 @@ import (
filtermiddleware "github.com/qdm12/dns/v2/pkg/middlewares/filter"
"github.com/qdm12/dns/v2/pkg/middlewares/filter/mapfilter"
"github.com/qdm12/dns/v2/pkg/provider"
"github.com/qdm12/dns/v2/pkg/server"
"github.com/qdm12/gluetun/internal/configuration/settings"
)
@@ -23,53 +24,52 @@ func (l *Loop) SetSettings(ctx context.Context, settings settings.DNS) (
func buildDoTSettings(settings settings.DNS,
filter *mapfilter.Filter, logger Logger) (
dotSettings dot.ServerSettings, err error,
serverSettings server.Settings, err error,
) {
var middlewares []dot.Middleware
serverSettings.Logger = logger
var dotSettings dot.Settings
dotSettings.Warner = logger
providersData := provider.NewProviders()
dotSettings.UpstreamResolvers = make([]provider.Provider, len(settings.DoT.Providers))
for i := range settings.DoT.Providers {
var err error
dotSettings.UpstreamResolvers[i], err = providersData.Get(settings.DoT.Providers[i])
if err != nil {
panic(err) // this should already had been checked
}
}
dotSettings.IPVersion = "ipv4"
if *settings.DoT.IPv6 {
dotSettings.IPVersion = "ipv6"
}
serverSettings.Dialer, err = dot.New(dotSettings)
if err != nil {
return server.Settings{}, fmt.Errorf("creating DNS over TLS dialer: %w", err)
}
if *settings.DoT.Caching {
lruCache, err := lru.New(lru.Settings{})
if err != nil {
return dot.ServerSettings{}, fmt.Errorf("creating LRU cache: %w", err)
return server.Settings{}, fmt.Errorf("creating LRU cache: %w", err)
}
cacheMiddleware, err := cachemiddleware.New(cachemiddleware.Settings{
Cache: lruCache,
})
if err != nil {
return dot.ServerSettings{}, fmt.Errorf("creating cache middleware: %w", err)
return server.Settings{}, fmt.Errorf("creating cache middleware: %w", err)
}
middlewares = append(middlewares, cacheMiddleware)
serverSettings.Middlewares = append(serverSettings.Middlewares, cacheMiddleware)
}
filterMiddleware, err := filtermiddleware.New(filtermiddleware.Settings{
Filter: filter,
})
if err != nil {
return dot.ServerSettings{}, fmt.Errorf("creating filter middleware: %w", err)
return server.Settings{}, fmt.Errorf("creating filter middleware: %w", err)
}
middlewares = append(middlewares, filterMiddleware)
serverSettings.Middlewares = append(serverSettings.Middlewares, filterMiddleware)
providersData := provider.NewProviders()
providers := make([]provider.Provider, len(settings.DoT.Providers))
for i := range settings.DoT.Providers {
var err error
providers[i], err = providersData.Get(settings.DoT.Providers[i])
if err != nil {
panic(err) // this should already had been checked
}
}
ipVersion := "ipv4"
if *settings.DoT.IPv6 {
ipVersion = "ipv6"
}
return dot.ServerSettings{
Resolver: dot.ResolverSettings{
UpstreamResolvers: providers,
IPVersion: ipVersion,
Warner: logger,
},
Middlewares: middlewares,
Logger: logger,
}, nil
return serverSettings, nil
}

View File

@@ -6,8 +6,8 @@ import (
"fmt"
"github.com/qdm12/dns/v2/pkg/check"
"github.com/qdm12/dns/v2/pkg/dot"
"github.com/qdm12/dns/v2/pkg/nameserver"
"github.com/qdm12/dns/v2/pkg/server"
)
var errUpdateBlockLists = errors.New("cannot update filter block lists")
@@ -25,12 +25,12 @@ func (l *Loop) setupServer(ctx context.Context) (runError <-chan error, err erro
return nil, fmt.Errorf("building DoT settings: %w", err)
}
server, err := dot.NewServer(dotSettings)
server, err := server.New(dotSettings)
if err != nil {
return nil, fmt.Errorf("creating DoT server: %w", err)
}
runError, err = server.Start()
runError, err = server.Start(ctx)
if err != nil {
return nil, fmt.Errorf("starting server: %w", err)
}

View File

@@ -18,22 +18,15 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
}
for ctx.Err() == nil {
runCtx, runCancel := context.WithCancel(ctx)
settings := l.state.GetSettings()
server, err := New(settings.ListeningAddress, l.logger,
server := New(runCtx, settings.ListeningAddress, l.logger,
*settings.Stealth, *settings.Log, *settings.User,
*settings.Password, settings.ReadHeaderTimeout, settings.ReadTimeout)
if err != nil {
l.statusManager.SetStatus(constants.Crashed)
l.logAndWait(ctx, err)
continue
}
errorCh, err := server.Start(ctx)
if err != nil {
l.statusManager.SetStatus(constants.Crashed)
l.logAndWait(ctx, err)
continue
}
errorCh := make(chan error)
go server.Run(runCtx, errorCh)
// TODO stable timer, check Shadowsocks
if l.userTrigger {
@@ -48,23 +41,31 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
for stayHere {
select {
case <-ctx.Done():
_ = server.Stop()
runCancel()
<-errorCh
close(errorCh)
return
case <-l.start:
l.userTrigger = true
l.logger.Info("starting")
_ = server.Stop()
runCancel()
<-errorCh
close(errorCh)
stayHere = false
case <-l.stop:
l.userTrigger = true
l.logger.Info("stopping")
_ = server.Stop()
runCancel()
<-errorCh
// Do not close errorCh or this for loop won't work
l.stopped <- struct{}{}
case err := <-errorCh:
close(errorCh)
l.statusManager.SetStatus(constants.Crashed)
l.logAndWait(ctx, err)
stayHere = false
}
}
runCancel() // repetition for linter only
}
}

View File

@@ -2,81 +2,57 @@ package httpproxy
import (
"context"
"fmt"
"net/http"
"sync"
"time"
"github.com/qdm12/goservices"
"github.com/qdm12/goservices/httpserver"
)
type Server struct {
httpServer *httpserver.Server
handlerCtx context.Context //nolint:containedctx
handlerCancel context.CancelFunc
handlerWg *sync.WaitGroup
// Server settings
httpServerSettings httpserver.Settings
// Handler settings
logger Logger
stealth bool
verbose bool
username string
password string
address string
handler http.Handler
logger infoErrorer
internalWG *sync.WaitGroup
readHeaderTimeout time.Duration
readTimeout time.Duration
}
func ptrTo[T any](x T) *T { return &x }
func New(address string, logger Logger,
func New(ctx context.Context, address string, logger Logger,
stealth, verbose bool, username, password string,
readHeaderTimeout, readTimeout time.Duration,
) (server *Server, err error) {
) *Server {
wg := &sync.WaitGroup{}
return &Server{
handlerWg: &sync.WaitGroup{},
httpServerSettings: httpserver.Settings{
// Handler is set when calling Start and reset when Stop is called
Handler: nil,
Name: ptrTo("proxy"),
Address: ptrTo(address),
ReadTimeout: readTimeout,
ReadHeaderTimeout: readHeaderTimeout,
Logger: logger,
},
address: address,
handler: newHandler(ctx, wg, logger, stealth, verbose, username, password),
logger: logger,
stealth: stealth,
verbose: verbose,
username: username,
password: password,
}, nil
internalWG: wg,
readHeaderTimeout: readHeaderTimeout,
readTimeout: readTimeout,
}
}
func (s *Server) Start(ctx context.Context) (
runError <-chan error, err error,
) {
if s.httpServer != nil {
return nil, fmt.Errorf("%w", goservices.ErrAlreadyStarted)
func (s *Server) Run(ctx context.Context, errorCh chan<- error) {
server := http.Server{
Addr: s.address,
Handler: s.handler,
ReadHeaderTimeout: s.readHeaderTimeout,
ReadTimeout: s.readTimeout,
}
s.handlerCtx, s.handlerCancel = context.WithCancel(context.Background())
s.httpServerSettings.Handler = newHandler(s.handlerCtx, s.handlerWg,
s.logger, s.stealth, s.verbose, s.username, s.password)
s.httpServer, err = httpserver.New(s.httpServerSettings)
if err != nil {
return nil, fmt.Errorf("creating http server: %w", err)
go func() {
<-ctx.Done()
const shutdownGraceDuration = 100 * time.Millisecond
shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownGraceDuration)
defer cancel()
if err := server.Shutdown(shutdownCtx); err != nil {
s.logger.Error("failed shutting down: " + err.Error())
}
}()
s.logger.Info("listening on " + s.address)
err := server.ListenAndServe()
s.internalWG.Wait()
if err != nil && ctx.Err() == nil {
errorCh <- err
} else {
errorCh <- nil
}
return s.httpServer.Start(ctx)
}
func (s *Server) Stop() (err error) {
if s.httpServer == nil {
return fmt.Errorf("%w", goservices.ErrAlreadyStopped)
}
s.handlerCancel()
err = s.httpServer.Stop()
s.handlerWg.Wait()
s.httpServer = nil // signal the server is down
return err
}

View File

@@ -0,0 +1,23 @@
package mullvad
import (
"context"
"github.com/qdm12/gluetun/internal/provider/utils"
)
// PortForward obtains a VPN server side port forwarded from ProtonVPN gateway.
func (p *Provider) PortForward(_ context.Context, objects utils.PortForwardObjects) (
port uint16, err error) {
objects.Logger.Debug("mullvad: port forward")
port = 10000
return port, nil
}
func (p *Provider) KeepPortForward(ctx context.Context,
objects utils.PortForwardObjects) (err error) {
objects.Logger.Debug("mullvad: keeping port forward")
<-ctx.Done()
objects.Logger.Debug("mullvad: keeping port forward exiting")
return nil
}

View File

@@ -21,8 +21,8 @@ func (p *Provider) OpenVPNConfig(connection models.Connection,
MssFix: 1450,
Ping: 5,
CAs: []string{"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"}, //nolint:lll
Cert: "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", //nolint:lll
Key: "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", //nolint:lll
Cert: "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", //nolint:lll
Key: "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", //nolint:lll
TLSCrypt: "d10a8e2641f5834f6c5e04a6ee9a798553d338fa2836ef2a91057c1f6174a3a12b36f16d1110b20e42ae94d3bd579213e9c3770be6c74804348dddba876945a5a3ab7660f9436f85f331641f6efc81315f0d12b2766a9f15c10a53cf9ba32dc80f03b5f15a6cc6987bda795dbe83443ec81f3d5e161cd47fab6b1f125b3adeee1eae33370d018594e0ff6b25b815228d27371b32c82a95f4929d3abb5fa36e57bf1f42353542568fbb8233f4645f05820275f79570cb8bbcf8010fc5d20f07d031a8227d45daf7349e34158c91a3d4e5add19cfa02f683f87609f6525fa0594016d11abf2de649f83ad54edd3e74e032e34b1bca685b8499916826d9aee11c13", //nolint:lll
TLSCipher: "TLS_CHACHA20_POLY1305_SHA256:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS_AES_256_GCM_SHA384:TLS-RSA-WITH-AES-256-CBC-SHA", //nolint:lll
TunMTU: 1500,

View File

@@ -26,7 +26,7 @@ func (r *Routing) addIPRule(src, dst netip.Prefix, table, priority int) error {
}
if err := r.netLinker.RuleAdd(rule); err != nil {
return fmt.Errorf("adding rule %s: %w", rule, err)
return fmt.Errorf("adding %s: %w", rule, err)
}
return nil
}

View File

@@ -80,7 +80,7 @@ func Test_Routing_addIPRule(t *testing.T) {
ruleToAdd: makeIPRule(makeNetipPrefix(1), makeNetipPrefix(2), 99, 99),
err: errDummy,
},
err: errors.New("adding rule ip rule 99: from 1.1.1.0/24 to 2.2.2.0/24 table 99: dummy error"),
err: errors.New("adding ip rule 99: from 1.1.1.0/24 to 2.2.2.0/24 table 99: dummy error"),
},
"add rule success": {
src: makeNetipPrefix(1),

View File

@@ -2,11 +2,13 @@ package shadowsocks
import (
"context"
"sync"
"time"
"github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/models"
shadowsockslib "github.com/qdm12/ss-server/pkg/tcpudp"
)
type Loop struct {
@@ -14,110 +16,11 @@ type Loop struct {
// Other objects
logger Logger
// Internal channels and locks
refreshing bool
refresh chan struct{}
changed chan models.LoopStatus
loopLock sync.Mutex
running chan models.LoopStatus
stop, stopped chan struct{}
start chan struct{}
backoffTime time.Duration
runCancel context.CancelFunc
runDone <-chan struct{}
}
const defaultBackoffTime = 10 * time.Second
func NewLoop(settings settings.Shadowsocks, logger Logger) *Loop {
return &Loop{
state: state{
status: constants.Stopped,
settings: settings,
},
logger: logger,
refresh: make(chan struct{}, 1), // capacity of 1 to handle crash auto-restart
changed: make(chan models.LoopStatus),
backoffTime: defaultBackoffTime,
}
}
func (l *Loop) Start(ctx context.Context) (runError <-chan error, err error) {
runCtx, runCancel := context.WithCancel(context.Background())
l.runCancel = runCancel
ready := make(chan struct{})
done := make(chan struct{})
l.runDone = done
go l.run(runCtx, ready, done)
<-ready
return nil, nil //nolint:nilnil
}
func (l *Loop) run(ctx context.Context, ready, done chan<- struct{}) {
defer close(done)
close(ready)
for ctx.Err() == nil {
// What if update and crash at the same time ish?
settings := l.GetSettings()
var service *service
var runError <-chan error
var err error
if *settings.Enabled {
service = newService(settings.Settings, l.logger)
runError, err = service.Start(ctx)
if err != nil {
runErrorCh := make(chan error, 1)
runError = runErrorCh
runErrorCh <- err
} else if l.refreshing {
l.changed <- constants.Running
} else { // auto-restart due to crash
l.state.setStatusWithLock(constants.Running)
l.backoffTime = defaultBackoffTime
}
} else {
if l.refreshing {
l.changed <- constants.Stopped
} else { // auto-restart due to crash
l.state.setStatusWithLock(constants.Stopped)
l.backoffTime = defaultBackoffTime
}
}
l.refreshing = false
select {
case <-l.refresh:
l.refreshing = true
if service != nil {
err = service.Stop()
if err != nil {
l.logger.Error("stopping service: " + err.Error())
}
}
case err = <-runError:
if l.refreshing {
l.changed <- constants.Crashed
} else {
l.state.setStatusWithLock(constants.Crashed)
}
l.logAndWait(ctx, err)
case <-ctx.Done():
if service != nil {
err = service.Stop()
if err != nil {
l.logger.Error("stopping service: " + err.Error())
}
}
return
}
}
}
func (l *Loop) Stop() (err error) {
l.runCancel()
<-l.runDone
return nil
}
func (l *Loop) logAndWait(ctx context.Context, err error) {
@@ -130,7 +33,113 @@ func (l *Loop) logAndWait(ctx context.Context, err error) {
select {
case <-timer.C:
case <-ctx.Done():
_ = timer.Stop()
case <-l.refresh: // user-triggered refresh
if !timer.Stop() {
<-timer.C
}
}
}
const defaultBackoffTime = 10 * time.Second
func NewLoop(settings settings.Shadowsocks, logger Logger) *Loop {
return &Loop{
state: state{
status: constants.Stopped,
settings: settings,
},
logger: logger,
start: make(chan struct{}),
running: make(chan models.LoopStatus),
stop: make(chan struct{}),
stopped: make(chan struct{}),
backoffTime: defaultBackoffTime,
}
}
func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
defer close(done)
crashed := false
if *l.GetSettings().Enabled {
go func() {
_, _ = l.SetStatus(ctx, constants.Running)
}()
}
select {
case <-l.start:
case <-ctx.Done():
return
}
for ctx.Err() == nil {
settings := l.GetSettings()
server, err := shadowsockslib.NewServer(settings.Settings, l.logger)
if err != nil {
crashed = true
l.logAndWait(ctx, err)
continue
}
shadowsocksCtx, shadowsocksCancel := context.WithCancel(ctx)
waitError := make(chan error)
go func() {
waitError <- server.Listen(shadowsocksCtx)
}()
if err != nil {
crashed = true
shadowsocksCancel()
l.logAndWait(ctx, err)
continue
}
isStableTimer := time.NewTimer(time.Second)
stayHere := true
for stayHere {
select {
case <-ctx.Done():
shadowsocksCancel()
<-waitError
close(waitError)
return
case <-isStableTimer.C:
if !crashed {
l.running <- constants.Running
crashed = false
} else {
l.backoffTime = defaultBackoffTime
l.state.setStatusWithLock(constants.Running)
}
case <-l.start:
l.logger.Info("starting")
shadowsocksCancel()
<-waitError
close(waitError)
stayHere = false
case <-l.stop:
l.logger.Info("stopping")
shadowsocksCancel()
<-waitError
close(waitError)
l.stopped <- struct{}{}
case err := <-waitError: // unexpected error
shadowsocksCancel()
close(waitError)
if ctx.Err() != nil {
return
}
l.state.setStatusWithLock(constants.Crashed)
l.logAndWait(ctx, err)
crashed = true
stayHere = false
}
}
shadowsocksCancel() // repetition for linter only
if !isStableTimer.Stop() {
<-isStableTimer.C
}
}
}

View File

@@ -1,14 +0,0 @@
package shadowsocks
import "context"
type noopService struct{}
func (n *noopService) Start(_ context.Context) (
runError <-chan error, err error) {
return nil, nil
}
func (n *noopService) Stop() (err error) {
return nil
}

View File

@@ -1,67 +0,0 @@
package shadowsocks
import (
"context"
"fmt"
"time"
"github.com/qdm12/ss-server/pkg/tcpudp"
)
type service struct {
// Injected settings
settings tcpudp.Settings
logger Logger
// Internal fields
cancel context.CancelFunc
done <-chan struct{}
}
func newService(settings tcpudp.Settings,
logger Logger) *service {
return &service{
settings: settings,
logger: logger,
}
}
func (s *service) Start(ctx context.Context) (runError <-chan error, err error) {
server, err := tcpudp.NewServer(s.settings, s.logger)
if err != nil {
return nil, fmt.Errorf("creating server: %w", err)
}
shadowsocksCtx, shadowsocksCancel := context.WithCancel(context.Background())
s.cancel = shadowsocksCancel
runErrorCh := make(chan error)
done := make(chan struct{})
s.done = done
go func() {
defer close(done)
err = server.Listen(shadowsocksCtx)
if shadowsocksCtx.Err() == nil {
runErrorCh <- fmt.Errorf("listening: %w", err)
}
}()
const minStabilityTime = 100 * time.Millisecond
isStableTimer := time.NewTimer(minStabilityTime)
select {
case <-isStableTimer.C:
case err = <-runErrorCh:
return nil, fmt.Errorf("server became unstable within %s: %w",
minStabilityTime, err)
case <-ctx.Done():
shadowsocksCancel()
<-done
return nil, ctx.Err()
}
return runErrorCh, nil
}
func (s *service) Stop() (err error) {
s.cancel()
<-s.done
return nil
}

View File

@@ -1,10 +1,14 @@
package shadowsocks
import (
"context"
"errors"
"fmt"
"reflect"
"sync"
"github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/models"
)
@@ -21,34 +25,95 @@ func (s *state) setStatusWithLock(status models.LoopStatus) {
s.status = status
}
// GetStatus returns the status of the loop for informative purposes.
// In no case it should be used programmatically to avoid any
// TOCTOU race conditions.
func (l *Loop) GetStatus() (status models.LoopStatus) {
l.state.statusMu.RLock()
defer l.state.statusMu.RUnlock()
return l.state.status
}
var ErrInvalidStatus = errors.New("invalid status")
func (l *Loop) SetStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error,
) {
l.state.statusMu.Lock()
defer l.state.statusMu.Unlock()
existingStatus := l.state.status
switch status {
case constants.Running:
switch existingStatus {
case constants.Starting, constants.Running, constants.Stopping, constants.Crashed:
return fmt.Sprintf("already %s", existingStatus), nil
}
l.loopLock.Lock()
defer l.loopLock.Unlock()
l.state.status = constants.Starting
l.state.statusMu.Unlock()
l.start <- struct{}{}
newStatus := constants.Starting // for canceled context
select {
case <-ctx.Done():
case newStatus = <-l.running:
}
l.state.statusMu.Lock()
l.state.status = newStatus
return newStatus.String(), nil
case constants.Stopped:
switch existingStatus {
case constants.Stopped, constants.Stopping, constants.Starting, constants.Crashed:
return fmt.Sprintf("already %s", existingStatus), nil
}
l.loopLock.Lock()
defer l.loopLock.Unlock()
l.state.status = constants.Stopping
l.state.statusMu.Unlock()
l.stop <- struct{}{}
newStatus := constants.Stopping // for canceled context
select {
case <-ctx.Done():
case <-l.stopped:
newStatus = constants.Stopped
}
l.state.statusMu.Lock()
l.state.status = newStatus
return status.String(), nil
default:
return "", fmt.Errorf("%w: %s: it can only be one of: %s, %s",
ErrInvalidStatus, status, constants.Running, constants.Stopped)
}
}
func (l *Loop) GetSettings() (settings settings.Shadowsocks) {
l.state.settingsMu.RLock()
defer l.state.settingsMu.RUnlock()
return l.state.settings
}
func (l *Loop) UpdateSettings(updateSettings settings.Shadowsocks) (outcome string) {
func (l *Loop) SetSettings(ctx context.Context, settings settings.Shadowsocks) (
outcome string,
) {
l.state.settingsMu.Lock()
previousSettings := l.state.settings.Copy()
l.state.settings.OverrideWith(updateSettings)
settingsUnchanged := reflect.DeepEqual(previousSettings, l.state.settings)
l.state.settingsMu.Unlock()
settingsUnchanged := reflect.DeepEqual(settings, l.state.settings)
if settingsUnchanged {
l.state.settingsMu.Unlock()
return "settings left unchanged"
}
l.refresh <- struct{}{}
newStatus := <-l.changed
l.state.statusMu.Lock()
l.state.status = newStatus
l.state.statusMu.Unlock()
return "settings updated (service " + newStatus.String() + ")"
newEnabled := *settings.Enabled
previousEnabled := *l.state.settings.Enabled
l.state.settings = settings
l.state.settingsMu.Unlock()
// Either restart or set changed status
switch {
case !newEnabled && !previousEnabled:
case newEnabled && previousEnabled:
_, _ = l.SetStatus(ctx, constants.Stopped)
_, _ = l.SetStatus(ctx, constants.Running)
case newEnabled && !previousEnabled:
_, _ = l.SetStatus(ctx, constants.Running)
case !newEnabled && previousEnabled:
_, _ = l.SetStatus(ctx, constants.Stopped)
}
return "settings updated"
}

View File

@@ -118,5 +118,5 @@ func Test_netlink_Wireguard_addRule(t *testing.T) {
_ = nilCleanup() // in case it succeeds
}
require.Error(t, err)
assert.EqualError(t, err, "adding rule ip rule 10000: from all to all table 999: file exists")
assert.EqualError(t, err, "adding ip rule 10000: from all to all table 999: file exists")
}

View File

@@ -16,7 +16,7 @@ func (w *Wireguard) addRule(rulePriority int, firewallMark uint32,
rule.Table = int(firewallMark)
rule.Family = family
if err := w.netlink.RuleAdd(rule); err != nil {
return nil, fmt.Errorf("adding rule %s: %w", rule, err)
return nil, fmt.Errorf("adding %s: %w", rule, err)
}
cleanup = func() error {

View File

@@ -45,7 +45,7 @@ func Test_Wireguard_addRule(t *testing.T) {
Family: family,
},
ruleAddErr: errDummy,
err: errors.New("adding rule ip rule 987: from all to all table 456: dummy"),
err: errors.New("adding ip rule 987: from all to all table 456: dummy"),
},
"rule delete error": {
expectedRule: netlink.Rule{