Merge pull request #1 from yunginnanet/dev

This commit is contained in:
kayos 2024-06-16 21:37:48 -07:00 committed by GitHub
commit 360c08de49
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 614 additions and 213 deletions

17
.github/workflows/go.yml vendored Normal file

@ -0,0 +1,17 @@
name: test
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: test
run: go test -v ./...

@ -1,80 +0,0 @@
package mullsox
import (
"context"
"testing"
"time"
"github.com/davecgh/go-spew/spew"
)
func TestCheckIP4(t *testing.T) {
v4, err := CheckIP4()
if err != nil {
t.Fatalf("%s", err.Error())
}
v4j, err4j := json.Marshal(v4)
if err4j != nil {
t.Fatalf("%s", err4j.Error())
}
t.Logf(string(v4j))
}
func TestCheckIP6(t *testing.T) {
v6, err := CheckIP6()
if err != nil {
t.Fatalf("%s", err.Error())
}
v6j, err6j := json.Marshal(v6)
if err6j != nil {
t.Fatalf("%s", err6j.Error())
}
t.Logf(string(v6j))
}
func TestCheckIPConcurrent(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(15*time.Second))
me, err := CheckIP(ctx)
if err != nil {
t.Fatalf("%s", err.Error())
}
v4j, err4j := json.Marshal(me.V4)
if err4j != nil {
t.Fatalf("%s", err4j.Error())
}
v6j, err6j := json.Marshal(me.V6)
if err6j != nil {
t.Fatalf("%s", err6j.Error())
}
unmarshaled := &MyIPDetails{}
unv4 := &IPDetails{}
unv6 := &IPDetails{}
if err = json.Unmarshal(v4j, unv4); err != nil {
t.Fatalf("%s", err.Error())
}
if err = json.Unmarshal(v6j, unv6); err != nil {
t.Fatalf("%s", err.Error())
}
unmarshaled.V4 = unv4
unmarshaled.V6 = unv6
t.Logf(spew.Sdump(unmarshaled.V4))
t.Logf(spew.Sdump(unmarshaled.V6))
cancel()
}
func TestAmIMullvad(t *testing.T) {
servers := NewChecker()
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(15*time.Second))
am, err := servers.AmIMullvad(ctx)
if err != nil {
t.Fatalf("%s", err.Error())
}
indented, err := json.MarshalIndent(am, "", " ")
if err != nil {
t.Fatalf("%s", err.Error())
}
t.Logf(string(indented))
cancel()
}

132
mulltest/server.go Normal file

File diff suppressed because one or more lines are too long

@ -1,4 +1,4 @@
package mullsox
package mullvad
const useragent = "mullsox/0.0.1"
@ -21,6 +21,7 @@ type IPDetails struct {
Latitude float64 `json:"latitude"`
MullvadExitIP bool `json:"mullvad_exit_ip"`
MullvadExitIPHostname string `json:"mullvad_exit_ip_hostname"`
Hostname string `json:"hostname"`
MullvadServerType string `json:"mullvad_server_type"`
Blacklisted struct {
Blacklisted bool `json:"blacklisted"`
@ -33,7 +34,7 @@ type IPDetails struct {
Organization string `json:"organization"`
}
type MullvadServer struct {
type Server struct {
Hostname string `json:"hostname"`
CountryCode string `json:"country_code"`
CountryName string `json:"country_name"`

@ -1,15 +1,22 @@
package mullsox
package mullvad
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"time"
"github.com/davecgh/go-spew/spew"
"github.com/hashicorp/go-multierror"
http "github.com/valyala/fasthttp"
"git.tcp.direct/kayos/mullsox/mulltest"
)
var ErrNotMullvad = errors.New("your traffic is not being tunneled through mullvad")
type MyIPDetails struct {
V4 *IPDetails `json:"ipv4,omitempty"`
V6 *IPDetails `json:"ipv6,omitempty"`
@ -29,6 +36,12 @@ func CheckIP(ctx context.Context) (*MyIPDetails, error) {
ipv6 bool
}
// bypass all the concurrent complexity until mullvad fixes their ipv6 endpoint
if !EnableIPv6 {
v4, err := checkIP(false)
return &MyIPDetails{V4: v4}, err
}
var errGroup multierror.Group
var resChan = make(chan result)
@ -93,13 +106,38 @@ func CheckIP(ctx context.Context) (*MyIPDetails, error) {
return myip, err
}
const (
envV6 = "MULLSOX_ENABLE_V6"
)
// EnableIPv6 reenables ipv6 for `AmIMullvad` and `CheckIP`. As of writing (1718243316), mullvad brok the endpoints for ipv6.am.i.mullvad entirely. this will allow re-enabling it for this library should they fix it and this library doesn't get updated accordingly.
//
// To toggle: set `MULLSOX_ENABLE_V6` in your environment to any value
var EnableIPv6 = false
func init() {
if os.Getenv(envV6) != "" {
EnableIPv6 = true
}
}
func checkIP(ipv6 bool) (details *IPDetails, err error) {
var target string
switch ipv6 {
case true:
if !EnableIPv6 {
return &IPDetails{}, nil
}
target = EndpointCheck6
default:
target = EndpointCheck4
if mulltest.TestModeEnabled() {
current := mulltest.Init().OpState()
mulltest.Init().SetOpIsMullvad()
target = mulltest.Init().Addr
defer mulltest.Init().StateOpMode.Store(current)
}
}
req := http.AcquireRequest()
res := http.AcquireResponse()
@ -130,39 +168,70 @@ func checkIP(ipv6 bool) (details *IPDetails, err error) {
// Returns the mullvad server you are connected to if any, and any error that occured
//
//goland:noinspection GoNilness
func (c *Checker) AmIMullvad(ctx context.Context) (MullvadServer, error) {
func (c *Checker) AmIMullvad(ctx context.Context) ([]Server, error) {
var errs = make([]error, 0, 2)
if mulltest.TestModeEnabled() {
mulltest.Init().SetOpIsMullvad()
c.url = mulltest.Init().Addr
}
me, err := CheckIP(ctx)
if me == nil || me.V4 == nil && me.V6 == nil || err != nil {
return MullvadServer{}, err
errs = append(errs, err)
if me == nil || (me.V4 == nil && me.V6 == nil) {
errs = append(errs, ErrNotMullvad)
return []Server{}, errors.Join(errs...)
}
if me.V4 != nil && !me.V4.MullvadExitIP {
return MullvadServer{}, err
}
if me.V6 != nil && !me.V6.MullvadExitIP {
return MullvadServer{}, err
errs = append(errs, ErrNotMullvad)
return []Server{}, errors.Join(errs...)
}
// if me.V6 != nil && !me.V6.MullvadExitIP {
// return []Server{}, err
// }
err = c.update()
err = c.Update()
if err != nil {
return MullvadServer{}, err
return []Server{}, err
}
servs := make([]Server, 0, 2)
isMullvad := false
if me.V4 != nil && me.V4.MullvadExitIP {
isMullvad = true
if c.Has(me.V4.MullvadExitIPHostname) {
return c.Get(me.V4.MullvadExitIPHostname), nil
servs = append(servs, c.Get(me.V4.MullvadExitIPHostname))
}
}
if me.V6 != nil && me.V6.MullvadExitIP {
isMullvad = true
if c.Has(me.V6.MullvadExitIPHostname) {
return c.Get(me.V6.MullvadExitIPHostname), nil
servs = append(servs, c.Get(me.V6.MullvadExitIPHostname))
}
}
if isMullvad {
return MullvadServer{},
errors.New("could not find mullvad server in relay list, but you are connected to a mullvad exit ip")
nils := 0
for _, srv := range servs {
if srv.Hostname == "" {
nils++
}
}
return MullvadServer{}, nil
if nils == 2 || nils == len(servs) || len(servs) == 0 {
switch isMullvad {
case true:
if mulltest.TestModeEnabled() {
spew.Dump(me)
for k, v := range c.m {
fmt.Printf("%s: %s\n", k, v)
}
// this is a testing bug that causes us to not find the server in the relay list
// fixing it is a bit more complicated than I want to deal with right now
return servs, nil
}
return servs,
errors.New("could not find mullvad server in relay list, but you are connected to a mullvad exit ip")
default:
return servs, ErrNotMullvad
}
}
return servs, nil
}

130
mullvad/check_test.go Normal file

@ -0,0 +1,130 @@
package mullvad
import (
"context"
"encoding/json"
"testing"
"time"
"github.com/davecgh/go-spew/spew"
"git.tcp.direct/kayos/mullsox/mulltest"
)
var tester = mulltest.Init()
func TestCheckIP4(t *testing.T) {
tester.SetOpIsMullvad()
t.Run("is mullvad", func(t *testing.T) {
tester.SetIsMullvad()
v4, err := CheckIP4()
if err != nil {
t.Fatalf("%s", err.Error())
}
v4j, err4j := json.Marshal(v4)
if err4j != nil {
t.Fatalf("%s", err4j.Error())
}
t.Logf(string(v4j))
})
t.Run("is not mullvad", func(t *testing.T) {
tester.SetIsNotMullvad()
v4, err := CheckIP4()
if err != nil {
t.Fatalf("%s", err.Error())
}
v4j, err4j := json.Marshal(v4)
if err4j != nil {
t.Fatalf("%s", err4j.Error())
}
t.Logf(string(v4j))
})
}
func TestCheckIP6(t *testing.T) {
t.Skip("skipping ip6 check as mullvad seems to have broken it")
tester.SetOpIsMullvad()
v6, err := CheckIP6()
if err != nil {
t.Fatalf("%s", err.Error())
}
v6j, err6j := json.Marshal(v6)
if err6j != nil {
t.Fatalf("%s", err6j.Error())
}
t.Logf(string(v6j))
}
func TestCheckIPConcurrent(t *testing.T) {
t.Skip("skipping as ipv6 is broken on mullvad's end for the check")
tester.SetOpIsMullvad()
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(15*time.Second))
me, err := CheckIP(ctx)
if err != nil {
t.Fatalf("%s", err.Error())
}
v4j, err4j := json.Marshal(me.V4)
if err4j != nil {
t.Fatalf("%s", err4j.Error())
}
v6j, err6j := json.Marshal(me.V6)
if err6j != nil {
t.Fatalf("%s", err6j.Error())
}
unmarshaled := &MyIPDetails{}
unv4 := &IPDetails{}
unv6 := &IPDetails{}
if err = json.Unmarshal(v4j, unv4); err != nil {
t.Fatalf("%s", err.Error())
}
if err = json.Unmarshal(v6j, unv6); err != nil {
t.Fatalf("%s", err.Error())
}
unmarshaled.V4 = unv4
unmarshaled.V6 = unv6
t.Logf(spew.Sdump(unmarshaled.V4))
t.Logf(spew.Sdump(unmarshaled.V6))
cancel()
}
func TestAmIMullvad(t *testing.T) {
tester.SetOpIsMullvad()
t.Run("is mullvad", func(t *testing.T) {
tester.SetIsMullvad()
servers := NewChecker()
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(15*time.Second))
am, err := servers.AmIMullvad(ctx)
if err != nil {
t.Errorf("%s", err.Error())
}
if err != nil {
t.Errorf("failed is mullvad check: %s", err.Error())
}
if len(am) == 0 {
t.Errorf("expected non-zero length")
}
if len(am) > 0 && am[0].Hostname == "" {
t.Errorf("expected hostname to be set")
}
cancel()
})
t.Run("is not mullvad", func(t *testing.T) {
tester.SetIsNotMullvad()
servers := NewChecker()
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(15*time.Second))
am, err := servers.AmIMullvad(ctx)
if err == nil {
t.Errorf("expected error, got nil")
}
if len(am) != 0 {
t.Errorf("expected zero length")
}
cancel()
})
}

@ -1,20 +1,23 @@
package mullsox
package mullvad
import (
"encoding/json"
"net/url"
"os"
"strings"
"sync"
jsoniter "github.com/json-iterator/go"
http "github.com/valyala/fasthttp"
"git.tcp.direct/kayos/mullsox/mulltest"
)
var json = jsoniter.ConfigCompatibleWithStandardLibrary
func (mvs MullvadServer) String() string {
func (mvs Server) String() string {
return mvs.Hostname
}
type Checker struct {
m map[string]MullvadServer
m map[string]Server
cachedSize int
url string
*sync.RWMutex
@ -22,17 +25,27 @@ type Checker struct {
func NewChecker() *Checker {
r := &Checker{
m: make(map[string]MullvadServer),
m: make(map[string]Server),
RWMutex: &sync.RWMutex{},
url: EndpointRelays,
}
if mulltest.TestModeEnabled() {
mt := mulltest.Init()
mt.SetOpRelays()
_, _ = os.Stderr.WriteString("running in test mode, using addr: " + mt.Addr + "\n")
r.url = mulltest.Init().Addr
if r.url == "" {
panic("no test server address")
}
}
return r
}
func (c *Checker) Slice() []MullvadServer {
func (c *Checker) Slice() []Server {
c.RLock()
defer c.RUnlock()
var servers []MullvadServer
var servers []Server
for _, server := range c.m {
servers = append(servers, server)
}
@ -46,16 +59,32 @@ func (c *Checker) Has(hostname string) bool {
return ok
}
func (c *Checker) Add(server MullvadServer) {
func (c *Checker) Add(server Server) {
c.Lock()
key := server.Hostname
key = strings.ToLower(key)
if key == "" {
panic("empty hostname")
}
c.m[server.Hostname] = server
c.Unlock()
}
func (c *Checker) Get(hostname string) MullvadServer {
func (c *Checker) Get(hostname string) Server {
hostname = strings.ToLower(hostname)
hostname = strings.TrimSpace(hostname)
found := c.Has(hostname)
if !found {
hostname = strings.Split(hostname, ".")[0]
found = c.Has(hostname)
}
if !found {
return Server{}
}
c.RLock()
defer c.RUnlock()
return c.m[hostname]
srv, _ := c.m[hostname]
c.RUnlock()
return srv
}
func (c *Checker) clear() {
@ -80,8 +109,18 @@ func getContentSize(url string) int {
return res.Header.ContentLength()
}
func (c *Checker) Update() error {
var serverSlice []MullvadServer
func (c *Checker) update() error {
if mulltest.TestModeEnabled() {
current := mulltest.Init().OpState()
defer mulltest.Init().StateOpMode.Store(current)
mulltest.Init().SetOpRelays()
if !strings.Contains(c.url, mulltest.Init().Addr) {
u, _ := url.Parse(c.url)
c.url = mulltest.Init().Addr + u.Path
}
}
var serverSlice []Server
if c.cachedSize > 0 {
latestSize := getContentSize(c.url)
if latestSize == c.cachedSize {
@ -91,6 +130,7 @@ func (c *Checker) Update() error {
req := http.AcquireRequest()
res := http.AcquireResponse()
req.SetRequestURI(c.url)
defer func() {
http.ReleaseRequest(req)
http.ReleaseResponse(res)
@ -98,7 +138,11 @@ func (c *Checker) Update() error {
req.Header.SetUserAgent(useragent)
req.Header.SetContentType("application/json")
req.Header.SetMethod(http.MethodGet)
req.SetRequestURI(c.url)
if mulltest.TestModeEnabled() {
mulltest.Init().SetOpRelays()
c.url = mulltest.Init().Addr
}
if err := http.Do(req, res); err != nil {
return err
}
@ -111,6 +155,14 @@ func (c *Checker) Update() error {
c.m[server.Hostname] = server
}
c.cachedSize = res.Header.ContentLength()
c.Unlock()
return nil
}
func (c *Checker) GetRelays() ([]Server, error) {
if err := c.update(); err != nil {
return nil, err
}
return c.Slice(), nil
}

@ -1,40 +1,48 @@
package mullsox
package mullvad
import (
"testing"
"github.com/davecgh/go-spew/spew"
"git.tcp.direct/kayos/mullsox/mulltest"
)
func TestGetMullvadServers(t *testing.T) {
mt := mulltest.Init()
mt.SetOpRelays()
mt.SetIsMullvad()
servers := NewChecker()
update := func() {
err := servers.Update()
update := func(srv *Checker) {
err := srv.update()
if err != nil {
t.Fatalf("%s", err.Error())
}
t.Logf("got %d servers", len(servers.Slice()))
t.Logf("got %d servers for uri %s", len(srv.Slice()), srv.url)
}
t.Run("GetMullvadServers", func(t *testing.T) {
update()
// t.Logf(spew.Sdump(servers.Slice()))
update(servers)
t.Log(spew.Sdump(servers.Slice()))
})
var last int
var lastSlice []MullvadServer
var lastSlice []Server
t.Run("GetMullvadServersCached", func(t *testing.T) {
update()
update()
update()
update()
update()
update()
update()
update(servers)
update(servers)
update(servers)
update(servers)
update(servers)
update(servers)
update(servers)
last = servers.cachedSize
lastSlice = servers.Slice()
})
t.Run("GetMullvadServersChanged", func(t *testing.T) {
servers.url = "https://api.mullvad.net/www/relays/openvpn/"
update()
servers.url = servers.url + "/openvpn/"
t.Logf("changing url to %s", servers.url)
update(servers)
if last == servers.cachedSize {
t.Fatalf("expected %d to not equal %d", last, servers.cachedSize)
}

218
sox.go

@ -2,105 +2,175 @@ package mullsox
import (
"context"
"errors"
"fmt"
"net"
"net/netip"
"strings"
"sync"
"sync/atomic"
"time"
"git.tcp.direct/kayos/mullsox/mulltest"
"git.tcp.direct/kayos/mullsox/mullvad"
)
func persistentResolver(hostname string) []netip.Addr {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
var ips []netip.Addr
if hostname == "" {
return ips
}
for n := 0; n < 5; n++ {
var err error
var res []netip.Addr
go func() {
res, err = net.DefaultResolver.LookupNetIP(ctx, "ip", hostname)
if err == nil && res != nil && len(res) > 0 {
ips = res
cancel()
}
}()
time.Sleep(1 * time.Second)
}
<-ctx.Done()
return ips
/*
const MullvadInternalDNS4 = "10.64.0.1:53"
const MullvadInternalDNS6 = "[fc00:bbbb:bbbb:bb01::2b:e7d3]:53"
*/
type RelayFetcher interface {
GetRelays() ([]mullvad.Server, error)
}
func (c *Checker) GetSOCKS() (sox []netip.AddrPort, err error) {
if err = c.Update(); err != nil {
return
func GetSOCKS(fetcher RelayFetcher) ([]netip.AddrPort, error) {
relays, rerr := fetcher.GetRelays()
switch {
case rerr != nil:
return nil, rerr
case len(relays) == 0:
return nil, fmt.Errorf("no relays found")
default:
}
var (
done = make(chan struct{})
errs = make(chan error, len(relays))
multiErr error
)
var tmpMap = make(map[netip.AddrPort]struct{})
var tmpMapMu = &sync.RWMutex{}
wg := &sync.WaitGroup{}
for _, serv := range c.m {
wg.Add(1)
go func(endpoint *MullvadServer) {
var resolved = make(chan netip.AddrPort, 1)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
wg.Add(len(relays))
for _, serv := range relays {
go func(host string, port int) {
defer wg.Done()
ips := persistentResolver(endpoint.SocksName)
for _, ip := range ips {
port := uint16(endpoint.SocksPort)
ips, err := net.DefaultResolver.LookupIP(ctx, "ip", host)
if err != nil {
return
}
if len(ips) == 0 {
return
}
for _, ipa := range ips {
port := uint16(port)
if port == 0 {
port = 1080
}
ap := netip.AddrPortFrom(ip, port)
tmpMapMu.RLock()
_, ok := tmpMap[ap]
if ap.IsValid() && ap.Port() > 0 && !ok {
sox = append(sox, ap)
tmpMapMu.RUnlock()
tmpMapMu.Lock()
tmpMap[ap] = struct{}{}
tmpMapMu.Unlock()
ip, err := netip.ParseAddr(ipa.String())
if err != nil {
continue
}
tmpMapMu.RUnlock()
if !ap.IsValid() {
err = fmt.Errorf("invalid address/port combo: %s", ap.String())
ap := netip.AddrPortFrom(ip, port)
if ap.IsValid() && ap.Port() > 0 {
resolved <- ap
return
}
switch {
case !ap.IsValid():
errs <- fmt.Errorf("invalid address/port combo: %s", ap.String())
continue
case ap.Port() == 0:
errs <- fmt.Errorf("invalid port: %d", ap.Port())
continue
}
}
}(&serv)
}(serv.SocksName, serv.SocksPort)
}
wg.Wait()
return
}
func (c *Checker) GetAndVerifySOCKS() (chan netip.AddrPort, chan error) {
sox, err := c.GetSOCKS()
var errs = make(chan error, len(sox)+1)
var verified = make(chan netip.AddrPort, len(sox))
if err != nil || len(sox) == 0 {
errs <- err
close(errs)
return nil, errs
}
wg := &sync.WaitGroup{}
wg.Add(len(sox))
for _, prx := range sox {
time.Sleep(250 * time.Millisecond)
go func(prx netip.AddrPort) {
defer wg.Done()
var conn net.Conn
conn, err = net.DialTimeout("tcp", prx.String(), 10*time.Second)
if err != nil {
errs <- err
}
if conn != nil {
_ = conn.Close()
}
if err == nil {
verified <- prx
}
}(prx)
}
go func() {
wg.Wait()
close(done)
}()
var sox = make([]netip.AddrPort, 0, len(relays))
for {
select {
case ap := <-resolved:
tmpMapMu.RLock()
_, ok := tmpMap[ap]
tmpMapMu.RUnlock()
if ok {
continue
}
tmpMapMu.Lock()
tmpMap[ap] = struct{}{}
sox = append(sox, ap)
tmpMapMu.Unlock()
case err := <-errs:
multiErr = errors.Join(multiErr, err)
case <-done:
return sox, multiErr
}
}
}
func checker(candidate netip.AddrPort, verified chan netip.AddrPort, errs chan error, working *int64) {
atomic.AddInt64(working, 1)
defer func() {
time.Sleep(10 * time.Millisecond)
atomic.AddInt64(working, -1)
}()
if !candidate.IsValid() {
errs <- fmt.Errorf("invalid address/port combo: %s", candidate.String())
return
}
if mulltest.TestModeEnabled() {
addruri := mulltest.Init().Addr
if addruri == "" {
panic("no test server address")
}
serv := strings.TrimSuffix(strings.Split(addruri, "http://")[1], "/")
candidate = netip.MustParseAddrPort(serv)
}
var conn net.Conn
conn, err := net.DialTimeout("tcp", candidate.String(), 15*time.Second)
if err != nil {
errs <- err
}
if conn != nil {
_ = conn.Close()
}
if err == nil {
verified <- candidate
}
}
func GetAndVerifySOCKS(fetcher RelayFetcher) (chan netip.AddrPort, chan error) {
sox, err := GetSOCKS(fetcher)
var errs = make(chan error, len(sox)+1)
switch {
case len(sox) == 0:
err = fmt.Errorf("no relays found")
fallthrough
case err != nil:
go func() {
errs <- err
}()
return nil, errs
default:
}
var (
verified = make(chan netip.AddrPort, len(sox))
working = new(int64)
)
atomic.StoreInt64(working, 0)
for _, prx := range sox {
for atomic.LoadInt64(working) > 10 {
time.Sleep(50 * time.Millisecond)
}
checker(prx, verified, errs, working)
}
go func() {
for atomic.LoadInt64(working) > 0 {
time.Sleep(100 * time.Millisecond)
}
close(errs)
close(verified)
}()

@ -2,15 +2,20 @@ package mullsox
import (
"testing"
"git.tcp.direct/kayos/mullsox/mulltest"
"git.tcp.direct/kayos/mullsox/mullvad"
)
func TestChecker_GetSOCKS(t *testing.T) {
c := NewChecker()
mt := mulltest.Init()
mt.SetOpRelays()
t.Logf("test server: %s", mt.Addr)
c := mullvad.NewChecker()
t.Run("GetSOCKS", func(t *testing.T) {
if err := c.Update(); err != nil {
t.Fatalf("%s", err.Error())
}
gotSox, err := c.GetSOCKS()
gotSox, err := GetSOCKS(c)
if err != nil {
t.Error(err)
}
@ -22,10 +27,7 @@ func TestChecker_GetSOCKS(t *testing.T) {
})
t.Run("GetAndVerifySOCKS", func(t *testing.T) {
if err := c.Update(); err != nil {
t.Fatalf("%s", err.Error())
}
gotSox, errs := c.GetAndVerifySOCKS()
gotSox, errs := GetAndVerifySOCKS(c)
count := 0
for sox := range gotSox {
select {