Compare commits

...

4 Commits

Author SHA1 Message Date
Vladislav Yarmak
518606be42 retract all versions 2026-03-09 13:58:39 +02:00
Vladislav Yarmak
25958fd032 upd readme 2025-09-30 22:12:06 +03:00
Snawoot
822530392d Merge pull request #155 from Snawoot/resolver_fixes
Resolver fixes
2025-09-24 01:03:01 +03:00
Vladislav Yarmak
971530e7ce resolver fixes 2025-09-24 01:02:09 +03:00
3 changed files with 51 additions and 51 deletions

View File

@@ -9,27 +9,6 @@ Application is capable to forward traffic via proxies in datacenters (flag `-pro
This alternative implementation ensures your internet connection is not shared with anyone else and everything is clean and safe. This alternative implementation ensures your internet connection is not shared with anyone else and everything is clean and safe.
---
:heart: :heart: :heart:
You can say thanks to the author by donations to these wallets:
- ETH: `0xB71250010e8beC90C5f9ddF408251eBA9dD7320e`
- BTC:
- Legacy: `1N89PRvG1CSsUk9sxKwBwudN6TjTPQ1N8a`
- Segwit: `bc1qc0hcyxc000qf0ketv4r44ld7dlgmmu73rtlntw`
---
## Mirrors
IPFS git mirror:
```
git clone https://ipfs.io/ipns/k51qzi5uqu5dkrgx0hozpy1tlggw5o0whtquyrjlc6pprhvbmczr6qtj4ocrv0 hola-proxy
```
## Features ## Features
* Cross-platform (Windows/Mac OS/Linux/Android (via shell)/\*BSD) * Cross-platform (Windows/Mac OS/Linux/Android (via shell)/\*BSD)

2
go.mod
View File

@@ -19,3 +19,5 @@ require (
golang.org/x/crypto v0.42.0 // indirect golang.org/x/crypto v0.42.0 // indirect
golang.org/x/sys v0.36.0 // indirect golang.org/x/sys v0.36.0 // indirect
) )
retract [v0.0.0-0, v1.18.3]

View File

@@ -14,14 +14,23 @@ import (
) )
func FromURL(u string) (*net.Resolver, error) { func FromURL(u string) (*net.Resolver, error) {
begin:
parsed, err := url.Parse(u) parsed, err := url.Parse(u)
if err != nil { if err != nil {
return nil, err return nil, err
} }
host := parsed.Hostname() host := parsed.Hostname()
port := parsed.Port() port := parsed.Port()
switch strings.ToLower(parsed.Scheme) { switch scheme := strings.ToLower(parsed.Scheme); scheme {
case "", "dns": case "":
switch {
case strings.HasPrefix(u, "//"):
u = "dns:" + u
default:
u = "dns://" + u
}
goto begin
case "udp", "dns":
if port == "" { if port == "" {
port = "53" port = "53"
} }
@@ -31,12 +40,20 @@ func FromURL(u string) (*net.Resolver, error) {
port = "53" port = "53"
} }
return NewTCPResolver(net.JoinHostPort(host, port)), nil return NewTCPResolver(net.JoinHostPort(host, port)), nil
case "http", "https": case "http", "https", "doh":
if port == "" { if port == "" {
port = "443" if scheme == "http" {
port = "80"
} else {
port = "443"
}
}
if scheme == "doh" {
parsed.Scheme = "https"
u = parsed.String()
} }
return dns.NewDoHResolver(u, dns.DoHAddresses(net.JoinHostPort(host, port))) return dns.NewDoHResolver(u, dns.DoHAddresses(net.JoinHostPort(host, port)))
case "tls": case "tls", "dot":
if port == "" { if port == "" {
port = "853" port = "853"
} }
@@ -55,12 +72,7 @@ type FastResolver struct {
upstreams []LookupNetIPer upstreams []LookupNetIPer
} }
type lookupReply struct { func FastResolverFromURLs(urls ...string) (LookupNetIPer, error) {
addrs []netip.Addr
err error
}
func FastResolverFromURLs(urls ...string) (*FastResolver, error) {
resolvers := make([]LookupNetIPer, 0, len(urls)) resolvers := make([]LookupNetIPer, 0, len(urls))
for i, u := range urls { for i, u := range urls {
res, err := FromURL(u) res, err := FromURL(u)
@@ -69,6 +81,9 @@ func FastResolverFromURLs(urls ...string) (*FastResolver, error) {
} }
resolvers = append(resolvers, res) resolvers = append(resolvers, res)
} }
if len(resolvers) == 1 {
return resolvers[0], nil
}
return NewFastResolver(resolvers...), nil return NewFastResolver(resolvers...), nil
} }
@@ -80,34 +95,38 @@ func NewFastResolver(resolvers ...LookupNetIPer) *FastResolver {
func (r FastResolver) LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error) { func (r FastResolver) LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error) {
ctx, cl := context.WithCancel(ctx) ctx, cl := context.WithCancel(ctx)
drain := make(chan lookupReply, len(r.upstreams)) defer cl()
errors := make(chan error)
success := make(chan []netip.Addr)
for _, res := range r.upstreams { for _, res := range r.upstreams {
go func(res LookupNetIPer) { go func(res LookupNetIPer) {
addrs, err := res.LookupNetIP(ctx, network, host) addrs, err := res.LookupNetIP(ctx, network, host)
drain <- lookupReply{addrs, err} if err == nil {
select {
case success <- addrs:
case <-ctx.Done():
}
} else {
select {
case errors <- err:
case <-ctx.Done():
}
}
}(res) }(res)
} }
i := 0
var resAddrs []netip.Addr
var resErr error var resErr error
for ; i < len(r.upstreams); i++ { for _ = range r.upstreams {
pair := <-drain select {
if pair.err != nil { case <-ctx.Done():
resErr = multierror.Append(resErr, pair.err) return nil, ctx.Err()
} else { case resAddrs := <-success:
cl() return resAddrs, nil
resAddrs = pair.addrs case err := <-errors:
resErr = nil resErr = multierror.Append(resErr, err)
break
} }
} }
go func() { return nil, resErr
for i = i + 1; i < len(r.upstreams); i++ {
<-drain
}
}()
return resAddrs, resErr
} }
func NewPlainResolver(addr string) *net.Resolver { func NewPlainResolver(addr string) *net.Resolver {