Compare commits

..

48 Commits

Author SHA1 Message Date
Snawoot
1d81ddd083 Merge pull request #113 from Snawoot/utls
uTLS
2024-02-25 00:58:41 +02:00
Vladislav Yarmak
37401b39f8 utls: even more fixes 2024-02-25 00:56:37 +02:00
Vladislav Yarmak
d4e86ad2b4 utls: final updates and fixes 2024-02-25 00:40:33 +02:00
Vladislav Yarmak
fc9e85dba0 final fixes for utls impl. 2024-02-25 00:01:11 +02:00
Vladislav Yarmak
bbd2ea4048 uTLS for API HTTP client 2024-02-24 23:35:52 +02:00
Vladislav Yarmak
6d65d22a84 use uTLS for upstream proxy connection 2024-02-24 22:57:15 +02:00
Vladislav Yarmak
2be66ef0d1 bump snap version 2023-12-26 10:42:58 +02:00
Snawoot
7ed761c0c3 Merge pull request #111 from Snawoot/dependabot/go_modules/golang.org/x/crypto-0.17.0
Bump golang.org/x/crypto from 0.15.0 to 0.17.0
2023-12-26 10:41:58 +02:00
Vladislav Yarmak
fa21f85414 go mod tidy 2023-12-26 10:40:59 +02:00
Vladislav Yarmak
6940495771 update all deps 2023-12-26 10:40:38 +02:00
dependabot[bot]
7864816161 Bump golang.org/x/crypto from 0.15.0 to 0.17.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.15.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.15.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-26 08:03:31 +00:00
Vladislav Yarmak
838463b771 bump snap version 2023-12-01 14:40:30 +02:00
Snawoot
2ff8391919 Merge pull request #110 from Snawoot/cust_user_agent
Customizable User-Agent
2023-12-01 14:39:40 +02:00
Vladislav Yarmak
54fa9a4831 upd doc 2023-12-01 14:39:14 +02:00
Vladislav Yarmak
679ac56806 customizable User-Agent 2023-12-01 14:36:30 +02:00
Vladislav Yarmak
47721e844a fix go version for compat build 2023-11-12 15:17:46 +02:00
Snawoot
fa8ea7356f Merge pull request #108 from Snawoot/windows_compat
ci: compat with old windows
2023-11-12 15:06:11 +02:00
Vladislav Yarmak
c54c588b17 ci: compat with old windows 2023-11-12 15:02:06 +02:00
Vladislav Yarmak
ad9ecc60ff bump snap version 2023-11-12 02:45:24 +02:00
Snawoot
527ab8a74a Merge pull request #107 from Snawoot/dep_upd
Update and tidy deps
2023-11-12 02:44:18 +02:00
Vladislav Yarmak
613c7778da update and tidy deps 2023-11-12 02:42:57 +02:00
Vladislav Yarmak
c0d5a118be workaround checkout action bug 2023-10-09 01:16:21 +03:00
Vladislav Yarmak
652a7ab662 more trimpath for reproducibility 2023-10-08 15:23:28 +03:00
Vladislav Yarmak
1b1ea6db4f new CI 2023-10-07 20:24:22 +03:00
Vladislav Yarmak
32fc635666 reproducible build 2023-10-06 15:02:05 +03:00
Vladislav Yarmak
71de713376 add telegram community link 2023-10-02 18:04:10 +03:00
Snawoot
39a9ba0bd3 Merge pull request #102 from Snawoot/docker-crosscompile
docker: crosscompile
2023-09-30 15:58:17 +03:00
Vladislav Yarmak
77bfe7907b docker: crosscompile 2023-09-30 15:57:43 +03:00
Vladislav Yarmak
ba18da688b upd golang version for docker 2023-09-06 13:33:11 +03:00
Vladislav Yarmak
4af6fdf9ef bump snap version 2023-09-06 13:18:15 +03:00
Snawoot
b841678722 Merge pull request #99 from Snawoot/old_windows
use older golang for windows build for a while
2023-09-06 13:15:47 +03:00
Vladislav Yarmak
5c7b550983 use older golang for windows build for a while 2023-09-06 13:13:57 +03:00
Snawoot
203ed79b2b Merge pull request #98 from Snawoot/fix_auth
Fix auth
2023-09-06 13:10:26 +03:00
Vladislav Yarmak
ce330f66a7 upd dependencies 2023-09-06 13:05:17 +03:00
Vladislav Yarmak
e82da1cb7b fix auth 2023-09-06 13:04:06 +03:00
Vladislav Yarmak
257fbe70a7 upd doc 2023-07-28 13:04:44 +03:00
Vladislav Yarmak
c9e2a2d5df bump snap version 2023-07-28 01:18:06 +03:00
Snawoot
98784aada9 Merge pull request #91 from Snawoot/optional-sni-hide
option to disable SNI hide
2023-07-28 01:17:13 +03:00
Vladislav Yarmak
518098ac2b option to disable SNI hide 2023-07-28 01:15:48 +03:00
Vladislav Yarmak
60eee4ad84 bump snap version 2023-05-30 21:45:32 +03:00
Snawoot
223105b010 Merge pull request #87 from Snawoot/fix_store_xml_parsing
Improve chrome web store XML parsing
2023-05-30 21:45:13 +03:00
Vladislav Yarmak
b93ba7718c improve chrome web store XML parsing 2023-05-30 21:43:36 +03:00
Vladislav Yarmak
8660c52f26 bump snap version 2023-05-29 00:59:18 +03:00
Snawoot
a003e75cb4 Merge pull request #85 from Snawoot/resolver_ext_ver
Auto-resolve ext_ver
2023-05-29 00:58:25 +03:00
Vladislav Yarmak
173fbd5d98 resolve ext_ver 2023-05-29 00:53:00 +03:00
Vladislav Yarmak
4d182dedd9 bump snap version 2023-05-28 16:43:50 +03:00
Snawoot
6501950752 Merge pull request #84 from Snawoot/fix/ext_ver_quickfix
Customizable ext_ver param
2023-05-28 16:43:18 +03:00
Vladislav Yarmak
9118ac4fae fix ext_ver param 2023-05-28 16:38:26 +03:00
15 changed files with 430 additions and 152 deletions

61
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,61 @@
name: build
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
-
name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
-
name: Read tag
id: tag
run: echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
-
name: Setup Go
uses: actions/setup-go@v4
with:
go-version: 'stable'
-
name: Build
run: >-
make -j $(nproc)
bin-linux-amd64 bin-linux-386 bin-linux-arm bin-linux-arm64
bin-linux-mips bin-linux-mipsle bin-linux-mips64 bin-linux-mips64le
bin-freebsd-amd64 bin-freebsd-386 bin-freebsd-arm
bin-netbsd-amd64 bin-netbsd-386
bin-openbsd-amd64 bin-openbsd-386
bin-darwin-amd64 bin-darwin-arm64
bin-android-arm bin-android-arm64
NDK_CC_ARM64="$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang"
NDK_CC_ARM="$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi21-clang"
VERSION=${{steps.tag.outputs.tag}}
-
name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '~1.20'
-
name: Build
run: >-
make -j $(nproc)
bin-windows-amd64 bin-windows-386 bin-windows-arm
VERSION=${{steps.tag.outputs.tag}}
GO120=go
-
name: Release
uses: softprops/action-gh-release@v1
with:
files: bin/*
fail_on_unmatched_files: true
generate_release_notes: true

View File

@@ -2,10 +2,8 @@ name: docker-ci
on:
push:
branches:
- 'master'
release:
types: [published]
tags:
- 'v*.*.*'
jobs:
docker:
@@ -13,7 +11,7 @@ jobs:
steps:
-
name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
fetch-depth: 0
-
@@ -26,33 +24,39 @@ jobs:
commit-ish: 'HEAD'
skip-unshallow: 'true'
abbrev: 7
-
name: Determine image tag type
uses: haya14busa/action-cond@v1
id: imgtag
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
cond: ${{ github.event_name == 'release' }}
if_true: ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:${{ github.event.release.tag_name }},${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:latest
if_false: ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:latest
# list of Docker images to use as base name for tags
images: |
${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}
# generate Docker tags based on the following events/attributes
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
-
name: Login to DockerHub
uses: docker/login-action@v1
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
id: docker_build
uses: docker/build-push-action@v2
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64,linux/386,linux/arm/v7
push: true
tags: ${{ steps.imgtag.outputs.value }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: 'GIT_DESC=${{steps.tagger.outputs.tag}}'

View File

@@ -1,10 +1,11 @@
FROM golang:1.19 AS build
FROM --platform=$BUILDPLATFORM golang:1.21 AS build
ARG GIT_DESC=undefined
WORKDIR /go/src/github.com/Snawoot/hola-proxy
COPY . .
RUN CGO_ENABLED=0 go build -a -tags netgo -ldflags '-s -w -extldflags "-static" -X main.version='"$GIT_DESC"
ARG TARGETOS TARGETARCH
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -a -tags netgo -ldflags '-s -w -extldflags "-static" -X main.version='"$GIT_DESC"
ADD https://curl.haxx.se/ca/cacert.pem /certs.crt
RUN chmod 0644 /certs.crt

View File

@@ -1,7 +1,7 @@
PROGNAME = hola-proxy
OUTSUFFIX = bin/$(PROGNAME)
VERSION := $(shell git describe)
BUILDOPTS = -a -tags netgo
BUILDOPTS = -a -tags netgo -trimpath -asmflags -trimpath
LDFLAGS = -ldflags '-s -w -extldflags "-static" -X main.version=$(VERSION)'
LDFLAGS_NATIVE = -ldflags '-s -w -X main.version=$(VERSION)'
@@ -9,6 +9,7 @@ NDK_CC_ARM = $(abspath ../../ndk-toolchain-arm/bin/arm-linux-androideabi-gcc)
NDK_CC_ARM64 = $(abspath ../../ndk-toolchain-arm64/bin/aarch64-linux-android21-clang)
GO := go
GO120 := /usr/lib64/go/1.20/bin/go
src = $(wildcard *.go */*.go */*/*.go) go.mod go.sum
@@ -103,13 +104,13 @@ $(OUTSUFFIX).darwin-arm64: $(src)
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 $(GO) build $(BUILDOPTS) $(LDFLAGS) -o $@
$(OUTSUFFIX).windows-amd64.exe: $(src)
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 $(GO) build $(BUILDOPTS) $(LDFLAGS) -o $@
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 $(GO120) build $(BUILDOPTS) $(LDFLAGS) -o $@
$(OUTSUFFIX).windows-386.exe: $(src)
CGO_ENABLED=0 GOOS=windows GOARCH=386 $(GO) build $(BUILDOPTS) $(LDFLAGS) -o $@
CGO_ENABLED=0 GOOS=windows GOARCH=386 $(GO120) build $(BUILDOPTS) $(LDFLAGS) -o $@
$(OUTSUFFIX).windows-arm.exe: $(src)
CGO_ENABLED=0 GOOS=windows GOARCH=arm GOARM=7 $(GO) build $(BUILDOPTS) $(LDFLAGS) -o $@
CGO_ENABLED=0 GOOS=windows GOARCH=arm GOARM=7 $(GO120) build $(BUILDOPTS) $(LDFLAGS) -o $@
$(OUTSUFFIX).android-arm: $(src)
CC=$(NDK_CC_ARM) CGO_ENABLED=1 GOOS=android GOARCH=arm GOARM=7 $(GO) build $(LDFLAGS_NATIVE) -o $@

View File

@@ -162,7 +162,9 @@ zagent248.hola.org,165.22.65.3,22222,22223,22224,22225,22226,digitalocean
| cafile | String | use custom CA certificate bundle file |
| country | String | desired proxy location (default "us") |
| dont-use-trial | - | use regular ports instead of trial ports |
| ext-ver | String | extension version to mimic in requests. Can be obtained from https://chrome.google.com/webstore/detail/hola-vpn-the-website-unbl/gkojfkhlekighikafcpjkiklfbnlmeio (default "999.999.999") |
| force-port-field | Number | force specific port field/num (example 24232 or lum) |
| hide-SNI | Boolean | hide SNI in TLS sessions with proxy server (default true) |
| limit | Unsigned Integer (Number) | amount of proxies in retrieved list (default 3) |
| list-countries | String | list available countries and exit |
| list-proxies | - | output proxy list and exit |
@@ -171,8 +173,10 @@ zagent248.hola.org,165.22.65.3,22222,22223,22224,22225,22226,digitalocean
| resolver | String | DNS/DoH/DoT resolver to workaround Hola blocked hosts. See https://github.com/ameshkov/dnslookup/ for upstream DNS URL format. (default "https://cloudflare-dns.com/dns-query") |
| rotate | Duration | rotate user ID once per given period (default 1h0m0s) |
| timeout | Duration | timeout for network operations (default 35s) |
| user-agent | String | value of User-Agent header in requests (default "Mozilla/5.0 (X11; Linux x86\_64; rv:109.0) Gecko/20100101 Firefox/118.0") |
| verbosity | Number | logging verbosity (10 - debug, 20 - info, 30 - warning, 40 - error, 50 - critical) (default 20) |
## See also
* [Project wiki](https://github.com/Snawoot/hola-proxy/wiki)
* [Community in Telegram](https://t.me/alternative_proxy)

View File

@@ -10,6 +10,7 @@ import (
const DEFAULT_LIST_LIMIT = 3
func CredService(interval, timeout time.Duration,
extVer string,
country string,
proxytype string,
logger *CondLogger,
@@ -26,7 +27,7 @@ func CredService(interval, timeout time.Duration,
}
tx_res, tx_err := EnsureTransaction(context.Background(), timeout, func(ctx context.Context, client *http.Client) bool {
tunnels, user_uuid, err = Tunnels(ctx, logger, client, country, proxytype,
tunnels, user_uuid, err = Tunnels(ctx, logger, client, extVer, country, proxytype,
DEFAULT_LIST_LIMIT, timeout, backoffInitial, backoffDeadline)
if err != nil {
logger.Error("Configuration bootstrap error: %v. Retrying with the fallback mechanism...", err)
@@ -43,8 +44,7 @@ func CredService(interval, timeout time.Duration,
logger.Critical("All attempts failed.")
return
}
auth_header = basic_auth_header(LOGIN_PREFIX+user_uuid,
tunnels.AgentKey)
auth_header = basic_auth_header(TemplateLogin(user_uuid), tunnels.AgentKey)
go func() {
var (
err error
@@ -57,7 +57,7 @@ func CredService(interval, timeout time.Duration,
<-ticker.C
logger.Info("Rotating credentials...")
tx_res, tx_err := EnsureTransaction(context.Background(), timeout, func(ctx context.Context, client *http.Client) bool {
tuns, user_uuid, err = Tunnels(ctx, logger, client, country, proxytype,
tuns, user_uuid, err = Tunnels(ctx, logger, client, extVer, country, proxytype,
DEFAULT_LIST_LIMIT, timeout, backoffInitial, backoffDeadline)
if err != nil {
logger.Error("Credential rotation error: %v. Retrying with the fallback mechanism...", err)
@@ -75,8 +75,7 @@ func CredService(interval, timeout time.Duration,
continue
}
(&mux).Lock()
auth_header = basic_auth_header(LOGIN_PREFIX+user_uuid,
tuns.AgentKey)
auth_header = basic_auth_header(TemplateLogin(user_uuid), tuns.AgentKey)
(&mux).Unlock()
logger.Info("Credentials rotated successfully.")
}

107
extver.go Normal file
View File

@@ -0,0 +1,107 @@
package main
import (
"context"
"encoding/xml"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/url"
"time"
)
var (
defaultProdVersion = "113.0"
)
var (
ErrNoVerData = errors.New("no version data returned")
)
type StoreExtUpdateResponse struct {
XMLName xml.Name `xml:"gupdate"`
App *struct {
AppID string `xml:"appid,attr"`
Status string `xml:"status,attr"`
UpdateCheck *struct {
Version string `xml:"version,attr"`
Status string `xml:"status,attr"`
} `xml:"updatecheck"`
} `xml:"app"`
}
func GetExtVer(ctx context.Context,
prodVersion *string,
id string,
dialer ContextDialer,
) (string, error) {
if prodVersion == nil {
prodVersion = &defaultProdVersion
}
if dialer == nil {
dialer = &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}
}
transport := &http.Transport{
DialContext: dialer.DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
defer transport.CloseIdleConnections()
httpClient := &http.Client{
Transport: transport,
}
reqURL := (&url.URL{
Scheme: "https",
Host: "clients2.google.com",
Path: "/service/update2/crx",
RawQuery: url.Values{
"prodversion": {*prodVersion},
"acceptformat": {"crx2,crx3"},
"x": {url.Values{
"id": {id},
"uc": {""},
}.Encode()},
}.Encode(),
}).String()
req, err := http.NewRequestWithContext(ctx, "GET", reqURL, nil)
if err != nil {
return "", fmt.Errorf("chrome web store request construction failed: %w", err)
}
resp, err := httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("chrome web store request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", fmt.Errorf("bad status code: %d", resp.StatusCode)
}
reader := io.LimitReader(resp.Body, 64*1024)
var respData *StoreExtUpdateResponse
dec := xml.NewDecoder(reader)
err = dec.Decode(&respData)
if err != nil {
return "", fmt.Errorf("unmarshaling of chrome web store response failed: %w", err)
}
if respData != nil && respData.App != nil &&
respData.App.UpdateCheck != nil && respData.App.UpdateCheck.Version != "" {
return respData.App.UpdateCheck.Version, nil
}
return "", ErrNoVerData
}

43
go.mod
View File

@@ -1,34 +1,37 @@
module github.com/Snawoot/hola-proxy
go 1.20
go 1.21.7
require (
github.com/AdguardTeam/dnsproxy v0.49.1
github.com/AdguardTeam/dnsproxy v0.65.1
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e
github.com/cenkalti/backoff/v4 v4.2.1
github.com/google/uuid v1.3.0
github.com/miekg/dns v1.1.53
golang.org/x/net v0.9.0
github.com/google/uuid v1.6.0
github.com/miekg/dns v1.1.58
github.com/refraction-networking/utls v1.6.3
golang.org/x/net v0.21.0
)
require (
github.com/AdguardTeam/golibs v0.13.0 // indirect
github.com/AdguardTeam/golibs v0.20.1 // indirect
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
github.com/ameshkov/dnscrypt/v2 v2.2.6 // indirect
github.com/ameshkov/dnscrypt/v2 v2.2.7 // indirect
github.com/ameshkov/dnsstamps v1.0.3 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/google/pprof v0.0.0-20230111200839-76d1ae5aea2b // indirect
github.com/onsi/ginkgo/v2 v2.7.0 // indirect
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/google/pprof v0.0.0-20240224134209-9dc27345a773 // indirect
github.com/klauspost/compress v1.17.7 // indirect
github.com/onsi/ginkgo/v2 v2.15.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-19 v0.2.1 // indirect
github.com/quic-go/qtls-go1-20 v0.1.1 // indirect
github.com/quic-go/quic-go v0.33.0 // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/exp v0.0.0-20230306221820-f0f767cdffd6 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.6.0 // indirect
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
github.com/quic-go/quic-go v0.41.0 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.18.0 // indirect
)

151
go.sum
View File

@@ -1,90 +1,103 @@
github.com/AdguardTeam/dnsproxy v0.49.1 h1:JpStBK05uCgA3ldleaNLRmIwE9V7vRg7/kVJQSdnQYg=
github.com/AdguardTeam/dnsproxy v0.49.1/go.mod h1:Y7g7jRTd/u7+KJ/QvnGI2PCE8vnisp6EsW47/Sz0DZw=
github.com/AdguardTeam/golibs v0.13.0 h1:hVBeNQXT/BgcjKz/4FMpFGvEYqXiXDJG+b5XpGCUOLk=
github.com/AdguardTeam/golibs v0.13.0/go.mod h1:rIglKDHdLvFT1UbhumBLHO9S4cvWS9MEyT1njommI/Y=
github.com/AdguardTeam/dnsproxy v0.61.0 h1:A5tmOpPw9c1kw5L4RKrOPzscRZuzpLaikwXLDsibQnY=
github.com/AdguardTeam/dnsproxy v0.61.0/go.mod h1:IdmXdkpc+m+S2EajJkVZDZm//yQ4mQm2FCOugQpc/N8=
github.com/AdguardTeam/dnsproxy v0.65.1 h1:BY+SCRky0aWB7w8/aQXMCzoSFGlMMOyrO6HktaE+1Po=
github.com/AdguardTeam/dnsproxy v0.65.1/go.mod h1:8NQTTNZY+qR9O1Fzgz3WQv30knfSgms68SRlzSnX74A=
github.com/AdguardTeam/golibs v0.18.2 h1:fI5Kw5tnIXLmiT/oiZrSpudl88aW3IeLMG4JpEH/5Gs=
github.com/AdguardTeam/golibs v0.18.2/go.mod h1:3WunclLLfrVAq7fYQRhd6f168FHOEMssnipVXCxDL/w=
github.com/AdguardTeam/golibs v0.20.1 h1:ol8qLjWGZhU9paMMwN+OLWVTUigGsXa29iVTyd62VKY=
github.com/AdguardTeam/golibs v0.20.1/go.mod h1:bgcMgRviCKyU6mkrX+RtT/OsKPFzyppelfRsksMG3KU=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV291OopO93Bwf9fQLQeLyt33VJRUg5VJ30us=
github.com/ameshkov/dnscrypt/v2 v2.2.6 h1:rE7AFbPWebq7me7RVS66Cipd1m7ef1yf2+C8QzjQXXE=
github.com/ameshkov/dnscrypt/v2 v2.2.6/go.mod h1:qPWhwz6FdSmuK7W4sMyvogrez4MWdtzosdqlr0Rg3ow=
github.com/ameshkov/dnscrypt/v2 v2.2.7 h1:aEitLIR8HcxVodZ79mgRcCiC0A0I5kZPBuWGFwwulAw=
github.com/ameshkov/dnscrypt/v2 v2.2.7/go.mod h1:qPWhwz6FdSmuK7W4sMyvogrez4MWdtzosdqlr0Rg3ow=
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e h1:V9a67dfYqPLAvzk5hMQOXYJlZ4SLIXgyKIE+ZiHzgGQ=
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
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/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
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.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/pprof v0.0.0-20230111200839-76d1ae5aea2b h1:8htHrh2bw9c7Idkb7YNac+ZpTqLMjRpI+FWu51ltaQc=
github.com/google/pprof v0.0.0-20230111200839-76d1ae5aea2b/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow=
github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/pprof v0.0.0-20231212022811-ec68065c825e h1:bwOy7hAFd0C91URzMIEBfr6BAz29yk7Qj0cy6S7DJlU=
github.com/google/pprof v0.0.0-20231212022811-ec68065c825e/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/pprof v0.0.0-20240224134209-9dc27345a773 h1:7Z7G0BHsvjTilR9nPGwohzCWsl2bKt9/IgvOVF7fljo=
github.com/google/pprof v0.0.0-20240224134209-9dc27345a773/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
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/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A=
github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk=
github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA=
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1Q=
github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k=
github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA=
github.com/refraction-networking/utls v1.6.3 h1:MFOfRN35sSx6K5AZNIoESsBuBxS2LCgRilRIdHb6fDc=
github.com/refraction-networking/utls v1.6.3/go.mod h1:yil9+7qSl+gBwJqztoQseO6Pr3h62pQoY1lXiNR/FPs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
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.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/exp v0.0.0-20230306221820-f0f767cdffd6 h1:3p+wVC0x0TCIPgd3LCQlpgVlEtjziEC5v42w7+B8t8M=
golang.org/x/exp v0.0.0-20230306221820-f0f767cdffd6/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
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.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
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.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4=
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -3,7 +3,6 @@ package main
import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/hex"
@@ -16,30 +15,41 @@ import (
"net/http"
"net/url"
"strconv"
"strings"
"sync"
"text/template"
"time"
"github.com/campoy/unique"
"github.com/cenkalti/backoff/v4"
"github.com/google/uuid"
tls "github.com/refraction-networking/utls"
)
const USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36"
const EXT_VER = "1.210.946"
const EXT_BROWSER = "chrome"
const PRODUCT = "cws"
const CCGI_URL = "https://client.hola.org/client_cgi/"
const VPN_COUNTRIES_URL = CCGI_URL + "vpn_countries.json"
const BG_INIT_URL = CCGI_URL + "background_init"
const ZGETTUNNELS_URL = CCGI_URL + "zgettunnels"
const LOGIN_PREFIX = "user-uuid-"
const FALLBACK_CONF_URL = "https://www.dropbox.com/s/jemizcvpmf2qb9v/cloud_failover.conf?dl=1"
const AGENT_SUFFIX = ".hola.org"
var LOGIN_TEMPLATE = template.Must(template.New("LOGIN_TEMPLATE").Parse("user-uuid-{{.uuid}}-is_prem-{{.prem}}"))
var TemporaryBanError = errors.New("temporary ban detected")
var PermanentBanError = errors.New("permanent ban detected")
var EmptyResponseError = errors.New("empty response")
var userAgent = "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0"
func SetUserAgent(ua string) {
userAgent = ua
}
func GetUserAgent() string {
return userAgent
}
type CountryList []string
type BgInitResponse struct {
@@ -157,7 +167,7 @@ func do_req(ctx context.Context, client *http.Client, method, url string, query,
if query != nil {
req.URL.RawQuery = query.Encode()
}
req.Header.Set("User-Agent", USER_AGENT)
req.Header.Set("User-Agent", userAgent)
resp, err := client.Do(req)
if err != nil {
return nil, err
@@ -193,10 +203,10 @@ func VPNCountries(ctx context.Context, client *http.Client) (res CountryList, er
return
}
func background_init(ctx context.Context, client *http.Client, user_uuid string) (res BgInitResponse, reterr error) {
func background_init(ctx context.Context, client *http.Client, extVer, user_uuid string) (res BgInitResponse, reterr error) {
post_data := make(url.Values)
post_data.Add("login", "1")
post_data.Add("ver", EXT_VER)
post_data.Add("ver", extVer)
qs := make(url.Values)
qs.Add("uuid", user_uuid)
resp, err := do_req(ctx, client, "POST", BG_INIT_URL, qs, post_data)
@@ -220,6 +230,7 @@ func zgettunnels(ctx context.Context,
client *http.Client,
user_uuid string,
session_key int64,
extVer string,
country string,
proxy_type string,
limit uint) (res *ZGetTunnelsResponse, reterr error) {
@@ -239,7 +250,7 @@ func zgettunnels(ctx context.Context,
}
params.Add("limit", strconv.FormatInt(int64(limit), 10))
params.Add("ping_id", strconv.FormatFloat(rand.New(RandomSource).Float64(), 'f', -1, 64))
params.Add("ext_ver", EXT_VER)
params.Add("ext_ver", extVer)
params.Add("browser", EXT_BROWSER)
params.Add("product", PRODUCT)
params.Add("uuid", user_uuid)
@@ -325,6 +336,7 @@ func GetFallbackProxies(ctx context.Context) (*FallbackConfig, error) {
func Tunnels(ctx context.Context,
logger *CondLogger,
client *http.Client,
extVer string,
country string,
proxy_type string,
limit uint,
@@ -336,7 +348,7 @@ func Tunnels(ctx context.Context,
user_uuid = hex.EncodeToString(u[:])
ctx1, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
initres, err := background_init(ctx1, client, user_uuid)
initres, err := background_init(ctx1, client, extVer, user_uuid)
if err != nil {
reterr = err
return
@@ -354,7 +366,7 @@ func Tunnels(ctx context.Context,
err = backoff.RetryNotify(func() error {
ctx1, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
res, reterr = zgettunnels(ctx1, client, user_uuid, initres.Key, country, proxy_type, limit)
res, reterr = zgettunnels(ctx1, client, user_uuid, initres.Key, extVer, country, proxy_type, limit)
return reterr
}, bo, func(err error, dur time.Duration) {
logger.Info("zgettunnels error: %v; will retry after %v", err, dur.Truncate(time.Millisecond))
@@ -387,9 +399,7 @@ func httpClientWithProxy(agent *FallbackAgent) *http.Client {
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: tlsConfig,
}
var dialer ContextDialer = baseDialer
var rootCAs *x509.CertPool
@@ -397,9 +407,30 @@ func httpClientWithProxy(agent *FallbackAgent) *http.Client {
rootCAs = tlsConfig.RootCAs
}
if agent != nil {
dialer = NewProxyDialer(agent.NetAddr(), agent.Hostname(), rootCAs, nil, dialer)
dialer = NewProxyDialer(agent.NetAddr(), agent.Hostname(), rootCAs, nil, true, dialer)
}
t.DialContext = dialer.DialContext
t.DialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, fmt.Errorf("hostname extraction error: %w", err)
}
conn, err := dialer.DialContext(ctx, network, addr)
if err != nil {
return nil, fmt.Errorf("can't prepare underlying connection for TLS session: %w", err)
}
var cfg tls.Config
if tlsConfig != nil {
cfg = *tlsConfig
}
cfg.ServerName = host
tlsConn := tls.UClient(conn, &cfg, tls.HelloAndroid_11_OkHttp)
if err := tlsConn.HandshakeContext(ctx); err != nil {
conn.Close()
return nil, fmt.Errorf("UClient handshake failed: %w", err)
}
return tlsConn, nil
}
return &http.Client{
Transport: t,
}
@@ -431,3 +462,12 @@ func EnsureTransaction(ctx context.Context, getFBTimeout time.Duration, txn func
return false, nil
}
func TemplateLogin(user_uuid string) string {
var b strings.Builder
LOGIN_TEMPLATE.Execute(&b, map[string]string{
"uuid": user_uuid,
"prem": "0",
})
return b.String()
}

38
main.go
View File

@@ -1,7 +1,7 @@
package main
import (
"crypto/tls"
"context"
"crypto/x509"
"errors"
"flag"
@@ -14,9 +14,14 @@ import (
"os"
"time"
tls "github.com/refraction-networking/utls"
xproxy "golang.org/x/net/proxy"
)
const (
HolaExtStoreID = "gkojfkhlekighikafcpjkiklfbnlmeio"
)
var (
PROTOCOL_WHITELIST map[string]bool
version = "undefined"
@@ -42,6 +47,7 @@ func arg_fail(msg string) {
}
type CLIArgs struct {
extVer string
country string
list_countries, list_proxies, use_trial bool
limit uint
@@ -58,10 +64,14 @@ type CLIArgs struct {
maxPause time.Duration
backoffInitial time.Duration
backoffDeadline time.Duration
hideSNI bool
userAgent string
}
func parse_args() CLIArgs {
var args CLIArgs
flag.StringVar(&args.extVer, "ext-ver", "", "extension version to mimic in requests. "+
"Can be obtained from https://chrome.google.com/webstore/detail/hola-vpn-the-website-unbl/gkojfkhlekighikafcpjkiklfbnlmeio")
flag.StringVar(&args.force_port_field, "force-port-field", "", "force specific port field/num (example 24232 or lum)") // would be nice to not show in help page
flag.StringVar(&args.country, "country", "us", "desired proxy location")
flag.BoolVar(&args.list_countries, "list-countries", false, "list available countries and exit")
@@ -85,6 +95,8 @@ func parse_args() CLIArgs {
"Format: <http|https|socks5|socks5h>://[login:password@]host[:port] "+
"Examples: http://user:password@192.168.1.1:3128, socks5://10.0.0.1:1080")
flag.StringVar(&args.caFile, "cafile", "", "use custom CA certificate bundle file")
flag.StringVar(&args.userAgent, "user-agent", GetUserAgent(), "value of User-Agent header in requests")
flag.BoolVar(&args.hideSNI, "hide-SNI", true, "hide SNI in TLS sessions with proxy server")
flag.Parse()
if args.country == "" {
arg_fail("Country can't be empty string.")
@@ -166,12 +178,26 @@ func run() int {
UpdateHolaDialer(dialer)
}
SetUserAgent(args.userAgent)
if args.list_countries {
return print_countries(args.timeout)
}
if args.extVer == "" {
ctx, cl := context.WithTimeout(context.Background(), args.timeout)
defer cl()
extVer, err := GetExtVer(ctx, nil, HolaExtStoreID, dialer)
if err != nil {
mainLogger.Critical("Can't detect latest API version. Try to specify -ext-ver parameter. Error: %v", err)
return 8
}
args.extVer = extVer
mainLogger.Warning("Detected latest extension version: %q. Pass -ext-ver parameter to skip resolve and speedup startup", args.extVer)
cl()
}
if args.list_proxies {
return print_proxies(mainLogger, args.country, args.proxy_type, args.limit, args.timeout,
return print_proxies(mainLogger, args.extVer, args.country, args.proxy_type, args.limit, args.timeout,
args.backoffInitial, args.backoffDeadline)
}
@@ -184,8 +210,8 @@ func run() int {
}
mainLogger.Info("Initializing configuration provider...")
auth, tunnels, err := CredService(args.rotate, args.timeout, args.country, args.proxy_type, credLogger,
args.backoffInitial, args.backoffDeadline)
auth, tunnels, err := CredService(args.rotate, args.timeout, args.extVer, args.country,
args.proxy_type, credLogger, args.backoffInitial, args.backoffDeadline)
if err != nil {
mainLogger.Critical("Unable to instantiate credential service: %v", err)
return 4
@@ -195,8 +221,8 @@ func run() int {
mainLogger.Critical("Unable to determine proxy endpoint: %v", err)
return 5
}
handlerDialer := NewProxyDialer(endpoint.NetAddr(), endpoint.TLSName, caPool, auth, dialer)
requestDialer := NewPlaintextDialer(endpoint.NetAddr(), endpoint.TLSName, caPool, dialer)
handlerDialer := NewProxyDialer(endpoint.NetAddr(), endpoint.TLSName, caPool, auth, args.hideSNI, dialer)
requestDialer := NewPlaintextDialer(endpoint.NetAddr(), endpoint.TLSName, caPool, args.hideSNI, dialer)
mainLogger.Info("Endpoint: %s", endpoint.URL().String())
mainLogger.Info("Starting proxy server...")
handler := NewProxyHandler(handlerDialer, requestDialer, auth, resolver, proxyLogger)

View File

@@ -2,10 +2,11 @@ package main
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"net"
tls "github.com/refraction-networking/utls"
)
type PlaintextDialer struct {
@@ -13,14 +14,16 @@ type PlaintextDialer struct {
tlsServerName string
next ContextDialer
caPool *x509.CertPool
hideSNI bool
}
func NewPlaintextDialer(address, tlsServerName string, caPool *x509.CertPool, next ContextDialer) *PlaintextDialer {
func NewPlaintextDialer(address, tlsServerName string, caPool *x509.CertPool, hideSNI bool, next ContextDialer) *PlaintextDialer {
return &PlaintextDialer{
fixedAddress: address,
tlsServerName: tlsServerName,
next: next,
caPool: caPool,
hideSNI: hideSNI,
}
}
@@ -40,8 +43,12 @@ func (d *PlaintextDialer) DialContext(ctx context.Context, network, address stri
// Custom cert verification logic:
// DO NOT send SNI extension of TLS ClientHello
// DO peer certificate verification against specified servername
conn = tls.Client(conn, &tls.Config{
ServerName: "",
sni := d.tlsServerName
if d.hideSNI {
sni = ""
}
tlsConn := tls.UClient(conn, &tls.Config{
ServerName: sni,
InsecureSkipVerify: true,
VerifyConnection: func(cs tls.ConnectionState) error {
opts := x509.VerifyOptions{
@@ -55,7 +62,12 @@ func (d *PlaintextDialer) DialContext(ctx context.Context, network, address stri
_, err := cs.PeerCertificates[0].Verify(opts)
return err
},
})
}, tls.HelloAndroid_11_OkHttp)
if err := tlsConn.HandshakeContext(ctx); err != nil {
conn.Close()
return nil, err
}
return tlsConn, nil
}
return conn, nil
}

View File

@@ -1,5 +1,5 @@
name: hola-proxy
version: '1.7.2'
version: '1.12.1'
summary: Standalone Hola proxy client.
description: |
Standalone Hola proxy client. Just run it and it'll start plain HTTP proxy server forwarding traffic via Hola proxies of your choice.

View File

@@ -4,7 +4,6 @@ import (
"bufio"
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
@@ -14,6 +13,8 @@ import (
"net/http/httputil"
"net/url"
"strings"
tls "github.com/refraction-networking/utls"
)
const (
@@ -39,15 +40,17 @@ type ProxyDialer struct {
auth AuthProvider
next ContextDialer
caPool *x509.CertPool
hideSNI bool
}
func NewProxyDialer(address, tlsServerName string, caPool *x509.CertPool, auth AuthProvider, nextDialer ContextDialer) *ProxyDialer {
func NewProxyDialer(address, tlsServerName string, caPool *x509.CertPool, auth AuthProvider, hideSNI bool, nextDialer ContextDialer) *ProxyDialer {
return &ProxyDialer{
address: address,
tlsServerName: tlsServerName,
auth: auth,
next: nextDialer,
caPool: caPool,
hideSNI: hideSNI,
}
}
@@ -81,7 +84,7 @@ func ProxyDialerFromURL(u *url.URL, caPool *x509.CertPool, next ContextDialer) (
return authHeader
}
}
return NewProxyDialer(address, tlsServerName, caPool, auth, next), nil
return NewProxyDialer(address, tlsServerName, caPool, auth, false, next), nil
}
func (d *ProxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
@@ -100,8 +103,12 @@ func (d *ProxyDialer) DialContext(ctx context.Context, network, address string)
// Custom cert verification logic:
// DO NOT send SNI extension of TLS ClientHello
// DO peer certificate verification against specified servername
conn = tls.Client(conn, &tls.Config{
ServerName: "",
sni := d.tlsServerName
if d.hideSNI {
sni = ""
}
conn = tls.UClient(conn, &tls.Config{
ServerName: sni,
InsecureSkipVerify: true,
VerifyConnection: func(cs tls.ConnectionState) error {
opts := x509.VerifyOptions{
@@ -115,7 +122,7 @@ func (d *ProxyDialer) DialContext(ctx context.Context, network, address string)
_, err := cs.PeerCertificates[0].Verify(opts)
return err
},
})
}, tls.HelloAndroid_11_OkHttp)
}
req := &http.Request{

View File

@@ -135,7 +135,7 @@ func print_countries(timeout time.Duration) int {
return 0
}
func print_proxies(logger *CondLogger, country string, proxy_type string,
func print_proxies(logger *CondLogger, extVer, country string, proxy_type string,
limit uint, timeout time.Duration, backoffInitial time.Duration, backoffDeadline time.Duration,
) int {
var (
@@ -144,7 +144,7 @@ func print_proxies(logger *CondLogger, country string, proxy_type string,
err error
)
tx_res, tx_err := EnsureTransaction(context.Background(), timeout, func(ctx context.Context, client *http.Client) bool {
tunnels, user_uuid, err = Tunnels(ctx, logger, client, country, proxy_type, limit, timeout, backoffInitial, backoffDeadline)
tunnels, user_uuid, err = Tunnels(ctx, logger, client, extVer, country, proxy_type, limit, timeout, backoffInitial, backoffDeadline)
if err != nil {
fmt.Fprintf(os.Stderr, "Transaction error: %v. Retrying with the fallback mechanism...\n", err)
return false
@@ -160,7 +160,7 @@ func print_proxies(logger *CondLogger, country string, proxy_type string,
return 3
}
wr := csv.NewWriter(os.Stdout)
login := LOGIN_PREFIX + user_uuid
login := TemplateLogin(user_uuid)
password := tunnels.AgentKey
fmt.Println("Login:", login)
fmt.Println("Password:", password)