Compare commits

...

150 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
Snawoot
aab7d5ea92 Merge pull request #154 from Snawoot/deps_upd
Dependencies update
2025-09-22 20:03:45 +03:00
Vladislav Yarmak
ad623ba3d7 go mod tidy 2025-09-22 19:59:18 +03:00
Vladislav Yarmak
b6a68eb534 dependencies update 2025-09-22 19:59:01 +03:00
Snawoot
c1b059be3f Merge pull request #153 from Snawoot/api_hide_SNI
Hide SNI for API calls as well
2025-09-22 19:55:34 +03:00
Vladislav Yarmak
b74e0fd35a hide SNI for API calls as well 2025-09-22 19:38:50 +03:00
Snawoot
32079d234d Merge pull request #151 from Snawoot/resolver_fix
Resolver fix
2025-08-16 03:30:20 +03:00
Vladislav Yarmak
2d5002cd20 resolver fix 2025-08-16 03:29:29 +03:00
Vladislav Yarmak
4055473a06 fix readme formatting 2025-08-13 17:46:01 +03:00
Snawoot
8cd7f71d13 Merge pull request #150 from Snawoot/deps_upd
Dependencies update
2025-08-13 17:43:22 +03:00
Vladislav Yarmak
ccb11a0c6a fix readme formatting 2025-08-13 17:42:20 +03:00
Vladislav Yarmak
8dc4b32ce7 go mod tidy 2025-08-13 17:39:39 +03:00
Vladislav Yarmak
81bec4bcb0 deps update 2025-08-13 17:39:25 +03:00
Snawoot
a887dd0a88 Merge pull request #149 from Snawoot/compact_sdns
Lightweight secure DNS client
2025-08-13 17:37:27 +03:00
Vladislav Yarmak
ecc1159e1a proper retry dialer 2025-08-13 17:35:46 +03:00
Vladislav Yarmak
f361120f7e upd doc and CLI help 2025-08-13 17:11:05 +03:00
Vladislav Yarmak
ecabe00326 switch to compact secure DNS resolver 2025-08-13 16:57:38 +03:00
Snawoot
d55790c30d Merge pull request #146 from Snawoot/deps_upd
Dependencies update
2025-06-14 11:38:07 +03:00
Vladislav Yarmak
c0715b0244 go mod tidy 2025-06-14 11:35:16 +03:00
Vladislav Yarmak
1e2ff556c5 go mod update 2025-06-14 11:34:36 +03:00
Snawoot
a34396e149 Merge pull request #145 from Snawoot/fix_zgettunnels_method
Fix zgettunnels method
2025-06-14 11:20:00 +03:00
Vladislav Yarmak
1ecf989ea0 fix zgettunnels method 2025-06-14 11:18:30 +03:00
Snawoot
240c9a5194 Update README.md 2025-06-02 17:00:31 +03:00
Snawoot
d6f3871db1 Merge pull request #142 from Snawoot/dependabot/go_modules/github.com/refraction-networking/utls-1.7.0
Bump github.com/refraction-networking/utls from 1.6.7 to 1.7.0
2025-04-24 23:11:24 +03:00
Vladislav Yarmak
b0435c3929 deps update 2025-04-24 23:02:24 +03:00
dependabot[bot]
9d49f99cd3 Bump github.com/refraction-networking/utls from 1.6.7 to 1.7.0
Bumps [github.com/refraction-networking/utls](https://github.com/refraction-networking/utls) from 1.6.7 to 1.7.0.
- [Release notes](https://github.com/refraction-networking/utls/releases)
- [Commits](https://github.com/refraction-networking/utls/compare/v1.6.7...v1.7.0)

---
updated-dependencies:
- dependency-name: github.com/refraction-networking/utls
  dependency-version: 1.7.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-24 19:58:14 +00:00
Vladislav Yarmak
51a9f257e7 upd doc 2025-04-12 21:36:49 +03:00
Snawoot
5d3aa90a0f Merge pull request #141 from Snawoot/auto_user_agent
Discover fresh user-agent automatically
2025-04-12 21:34:07 +03:00
Vladislav Yarmak
f062f9310c get rid of google services dependencies 2025-04-12 21:09:20 +03:00
Vladislav Yarmak
c019e84bbe discover fresh user-agent automatically 2025-04-12 20:52:42 +03:00
Vladislav Yarmak
65fdac74bd bump user-agent version 2025-04-12 17:03:48 +03:00
Vladislav Yarmak
15fea1bf78 deps upd 2025-04-12 15:33:22 +03:00
Snawoot
1a526a6381 Merge pull request #140 from Snawoot/deps_upd
Dependencies update
2025-04-07 19:23:37 +03:00
Vladislav Yarmak
fcfc6212ee go mod tidy 2025-04-07 19:22:25 +03:00
Vladislav Yarmak
cf49895825 dependencies update 2025-04-07 19:21:53 +03:00
Vladislav Yarmak
becf27500b fix snap build 2025-03-28 18:53:05 +02:00
Vladislav Yarmak
b1671d4d19 upd doc 2025-02-24 20:13:31 +02:00
Vladislav Yarmak
2c22c3af35 bump snap version 2025-02-24 20:10:08 +02:00
Snawoot
55f8125044 Merge pull request #138 from Snawoot/deps_upd
Deps upd
2025-02-24 20:09:23 +02:00
Vladislav Yarmak
c3691b208b go mod tidy 2025-02-24 20:07:23 +02:00
Vladislav Yarmak
bfe19d9a85 deps update 2025-02-24 20:07:04 +02:00
Snawoot
3be0ad42f6 Merge pull request #137 from Snawoot/rotation_improvements
rotate credentials less frequently
2025-02-21 16:48:50 +02:00
Vladislav Yarmak
5e00cfb499 rotate credentials less frequently 2025-02-21 16:48:09 +02:00
Snawoot
ba52035f5a Merge pull request #136 from Snawoot/cred_rotation_fixes
credservice: allow rotation to be disabled
2025-02-19 23:40:53 +02:00
Vladislav Yarmak
091bc05a30 credservice: allow rotation to be disabled 2025-02-19 19:16:16 +02:00
Snawoot
ebba7bca60 Merge pull request #135 from Snawoot/deps_upd
Dependencies update
2025-02-19 19:06:25 +02:00
Vladislav Yarmak
99132778c9 go mod tidy 2025-02-19 15:16:16 +02:00
Vladislav Yarmak
02bfdea676 dependencies update 2025-02-19 15:15:42 +02:00
Snawoot
e2dbbb9ec3 Merge pull request #134 from Snawoot/deps_upd
Deps upd
2025-01-07 15:20:58 +02:00
Vladislav Yarmak
81e06c2828 go mod tidy 2025-01-07 15:10:34 +02:00
Vladislav Yarmak
440bad2860 dependencies update 2025-01-07 15:07:35 +02:00
Snawoot
f9d2e8985f Merge pull request #132 from Snawoot/dependabot/go_modules/golang.org/x/crypto-0.31.0
Bump golang.org/x/crypto from 0.28.0 to 0.31.0
2024-12-12 17:32:28 +02:00
dependabot[bot]
7775e5f54e Bump golang.org/x/crypto from 0.28.0 to 0.31.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.28.0 to 0.31.0.
- [Commits](https://github.com/golang/crypto/compare/v0.28.0...v0.31.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-12 05:28:00 +00:00
Snawoot
8479a86de6 Merge pull request #131 from Snawoot/dependabot/go_modules/github.com/quic-go/quic-go-0.48.2
Bump github.com/quic-go/quic-go from 0.48.1 to 0.48.2
2024-12-10 12:53:29 +02:00
dependabot[bot]
3fccf32f7b Bump github.com/quic-go/quic-go from 0.48.1 to 0.48.2
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.48.1 to 0.48.2.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.48.1...v0.48.2)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-10 10:43:41 +00:00
Vladislav Yarmak
332db446b4 bump snap version 2024-11-25 19:07:19 +02:00
Vladislav Yarmak
8020fba8f3 use timeout defaults as specified in doc 2024-11-25 19:07:03 +02:00
Snawoot
f659f26bad Merge pull request #130 from Snawoot/bump_timeout
Bump timeout
2024-11-25 19:05:42 +02:00
Vladislav Yarmak
ce356ce015 bump timeout 2024-11-25 19:05:05 +02:00
Snawoot
e8cd8ba0a8 Merge pull request #129 from Snawoot/improve_fbc
Add more fallback config endpoints
2024-11-25 19:03:44 +02:00
Vladislav Yarmak
191b1e7f51 Add more fallback config endpoints 2024-11-25 18:48:18 +02:00
Snawoot
6aa4fc334a Merge pull request #127 from Snawoot/upd_doc
upd doc
2024-11-05 22:02:53 +02:00
Vladislav Yarmak
124212a5e2 upd doc 2024-11-05 22:02:09 +02:00
Vladislav Yarmak
b120cb5462 bump snap version 2024-11-05 22:00:33 +02:00
Snawoot
972771b6af Merge pull request #126 from Snawoot/deps_upd
Dependencies update
2024-11-05 21:59:53 +02:00
Vladislav Yarmak
49b6ba9147 go mod tidy 2024-11-05 21:59:13 +02:00
Vladislav Yarmak
1e4c6684cc dependencies update 2024-11-05 21:58:26 +02:00
Snawoot
569bf1d39f Merge pull request #125 from Snawoot/try_hard
Retry init
2024-11-05 21:44:43 +02:00
Vladislav Yarmak
92fdd4fb72 retry init 2024-11-05 21:38:04 +02:00
Vladislav Yarmak
d4d37bb354 upd doc 2024-10-07 21:09:53 +03:00
Vladislav Yarmak
458fdf2d50 bump snap version 2024-10-07 21:08:05 +03:00
Snawoot
010ca056b3 Merge pull request #124 from Snawoot/upd
Update
2024-10-07 21:07:23 +03:00
Vladislav Yarmak
e28c186971 use latest stable go for container builder 2024-10-07 20:50:56 +03:00
Vladislav Yarmak
5de4f1a616 dependencies update 2024-10-07 20:50:16 +03:00
Vladislav Yarmak
1e13bae8b3 update user-agent 2024-10-07 20:48:42 +03:00
Vladislav Yarmak
0811bb6fa6 bump snap version 2024-04-17 14:00:27 +03:00
Vladislav Yarmak
1bfef0287f fix 2024-04-17 13:59:32 +03:00
Vladislav Yarmak
778339ddb2 upd docs 2024-04-17 13:48:27 +03:00
Snawoot
c8350cc731 Merge pull request #117 from Snawoot/upd_deps
Update dependencies
2024-04-17 13:46:32 +03:00
Vladislav Yarmak
5b0e1e33c6 bump go version 2024-04-17 13:45:00 +03:00
Vladislav Yarmak
7bc4cc57de go mod tidy 2024-04-17 13:43:13 +03:00
Vladislav Yarmak
3105cf04f1 update deps 2024-04-17 13:41:49 +03:00
Snawoot
69b582090c Merge pull request #116 from Snawoot/dependabot/go_modules/github.com/quic-go/quic-go-0.42.0
Bump github.com/quic-go/quic-go from 0.41.0 to 0.42.0
2024-04-17 13:34:06 +03:00
dependabot[bot]
9a91ec21ab Bump github.com/quic-go/quic-go from 0.41.0 to 0.42.0
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.41.0 to 0.42.0.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.41.0...v0.42.0)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-17 10:32:32 +00:00
Vladislav Yarmak
3d14c627bf bump snap version 2024-04-17 13:31:41 +03:00
Snawoot
f0ee8a0d23 Merge pull request #115 from Snawoot/cust_user_agent
Update default user-agent
2024-04-17 13:30:51 +03:00
Vladislav Yarmak
ca7c13f86a update default user-agent 2024-04-17 13:30:13 +03:00
Vladislav Yarmak
c5ddc5a5f1 bump snap version 2024-02-25 09:00:26 +02:00
Snawoot
8680aaf470 Merge pull request #114 from Snawoot/drop_go120
Drop go1.20 support
2024-02-25 01:16:46 +02:00
Vladislav Yarmak
36822781d1 drop go1.20 support 2024-02-25 01:15:39 +02:00
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
Vladislav Yarmak
7755ea54bd bump snap version 2023-05-22 12:30:46 +03:00
Snawoot
ff3d976d95 Merge pull request #82 from Ackater/patch-1
Bump hola api client version
2023-05-22 12:28:37 +03:00
Ackater
f5a2bcafbd Bump hola api client version 2023-05-22 01:28:00 -07:00
Vladislav Yarmak
3e28df5034 go1.20 support 2023-04-27 01:29:58 +03:00
Vladislav Yarmak
63c4b893d9 bump snap version 2023-03-28 11:43:38 +03:00
Snawoot
dac47f1e34 Merge pull request #80 from Snawoot/dependabot/go_modules/golang.org/x/net-0.7.0
Bump golang.org/x/net from 0.5.0 to 0.7.0
2023-03-28 11:35:14 +03:00
Vladislav Yarmak
1afd4fbf81 go mod tidy 2023-03-28 11:34:21 +03:00
Vladislav Yarmak
8dc0fa17fe update all dependencies 2023-03-28 11:33:33 +03:00
dependabot[bot]
40dbf436f0 Bump golang.org/x/net from 0.5.0 to 0.7.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.5.0 to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.5.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-28 08:28:57 +00:00
19 changed files with 791 additions and 364 deletions

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

@@ -0,0 +1,42 @@
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: Setup Go
uses: actions/setup-go@v4
with:
go-version: 'stable'
-
name: Read tag
id: tag
run: echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
-
name: Build
run: >-
make -j $(nproc) allplus
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: 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 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)'

View File

@@ -7,26 +7,7 @@ By default the application listens on 127.0.0.1:8080.
Application is capable to forward traffic via proxies in datacenters (flag `-proxy-type direct`, default) or via peer proxies on residental IPs (consumer ISP) in that country (flag `-proxy-type lum`).
---
: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
```
This alternative implementation ensures your internet connection is not shared with anyone else and everything is clean and safe.
## Features
@@ -162,17 +143,23 @@ 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) |
| init-retries | Number | number of attempts for initialization steps, zero for unlimited retry |
| init-retry-interval | Duration | delay between initialization retries (default 5s) |
| 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 |
| proxy | String | sets base proxy to use for all dial-outs. Format: `<http\|https\|socks5\|socks5h>://[login:password@]host[:port]` Examples: `http://user:password@192.168.1.1:3128`, `socks5://10.0.0.1:1080` |
| proxy-type | String | proxy type (Datacenter: direct) (Residential: lum) (default "direct") |
| 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) |
| resolver | String | comma-separated list of DNS/DoH/DoT resolvers used to lookup domain names blocked by Hola. Supported schemes are: `dns://`, `https://`, `tls://`, `tcp://`. (default `https://1.1.1.3/dns-query,https://8.8.8.8/dns-query,https://dns.google/dns-query,https://security.cloudflare-dns.com/dns-query,https://fidelity.vm-0.com/q,https://wikimedia-dns.org/dns-query,https://dns.adguard-dns.com/dns-query,https://dns.quad9.net/dns-query,https://doh.cleanbrowsing.org/doh/adult-filter/`) |
| rotate | Duration | rotate user ID once per given period (default 48h0m0s) |
| timeout | Duration | timeout for network operations (default 35s) |
| user-agent | String | value of User-Agent header in requests. Default: User-Agent of latest stable Chrome for Windows |
| 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)

63
chromever.go Normal file
View File

@@ -0,0 +1,63 @@
package main
import (
"context"
"encoding/json"
"fmt"
"net"
"net/http"
"time"
)
type chromeVerResponse struct {
Versions [1]struct {
Version string `json:"version"`
} `json:"versions"`
}
const chromeVerURL = "https://versionhistory.googleapis.com/v1/chrome/platforms/win/channels/stable/versions?alt=json&orderBy=version+desc&pageSize=1&prettyPrint=false"
func GetChromeVer(ctx context.Context, dialer ContextDialer) (string, error) {
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,
}
req, err := http.NewRequestWithContext(ctx, "GET", chromeVerURL, nil)
if err != nil {
return "", fmt.Errorf("chrome browser version request construction failed: %w", err)
}
resp, err := httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("chrome browser version request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", fmt.Errorf("chrome browser version request failed: bad status code: %d", resp.StatusCode)
}
dec := json.NewDecoder(resp.Body)
var chromeVerResp chromeVerResponse
if err := dec.Decode(&chromeVerResp); err != nil {
return "", fmt.Errorf("unable to decode chrome browser version response: %w", err)
}
return chromeVerResp.Versions[0].Version, nil
}

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,
@@ -19,14 +20,13 @@ func CredService(interval, timeout time.Duration,
var mux sync.Mutex
var auth_header, user_uuid string
auth = func() (res string) {
(&mux).Lock()
res = auth_header
(&mux).Unlock()
return
mux.Lock()
defer mux.Unlock()
return auth_header
}
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 +43,10 @@ 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)
if interval <= 0 {
return
}
go func() {
var (
err error
@@ -57,7 +59,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)
@@ -74,10 +76,9 @@ func CredService(interval, timeout time.Duration,
logger.Critical("All rotation attempts failed.")
continue
}
(&mux).Lock()
auth_header = basic_auth_header(LOGIN_PREFIX+user_uuid,
tuns.AgentKey)
(&mux).Unlock()
mux.Lock()
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("chrome web store: 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
}

44
go.mod
View File

@@ -1,39 +1,23 @@
module github.com/Snawoot/hola-proxy
go 1.19
go 1.24.4
require (
github.com/AdguardTeam/dnsproxy v0.46.6
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e
github.com/google/uuid v1.3.0
github.com/miekg/dns v1.1.50
golang.org/x/net v0.5.0
github.com/cenkalti/backoff/v4 v4.3.0
github.com/google/uuid v1.6.0
github.com/hashicorp/go-multierror v1.1.1
github.com/ncruces/go-dns v1.2.7
github.com/refraction-networking/utls v1.8.0
golang.org/x/net v0.44.0
)
require (
github.com/AdguardTeam/golibs v0.11.4 // 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.5 // indirect
github.com/ameshkov/dnsstamps v1.0.3 // indirect
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 // indirect
github.com/bluele/gcache v0.0.2 // indirect
github.com/cenkalti/backoff/v4 v4.2.0 // 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-20230131232505-5a9e8f65f08f // indirect
github.com/jessevdk/go-flags v1.5.0 // indirect
github.com/lucas-clemente/quic-go v0.31.1 // indirect
github.com/marten-seemann/qpack v0.3.0 // indirect
github.com/marten-seemann/qtls-go1-18 v0.1.4 // indirect
github.com/marten-seemann/qtls-go1-19 v0.1.2 // indirect
github.com/onsi/ginkgo/v2 v2.8.0 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/exp v0.0.0-20230203172020-98cc5a0785f9 // indirect
golang.org/x/mod v0.7.0 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/text v0.6.0 // indirect
golang.org/x/tools v0.5.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
golang.org/x/crypto v0.42.0 // indirect
golang.org/x/sys v0.36.0 // indirect
)
retract [v0.0.0-0, v1.18.3]

157
go.sum
View File

@@ -1,134 +1,27 @@
github.com/AdguardTeam/dnsproxy v0.46.5 h1:TiJZhwaIDDaKkqEfJ9AD9aroFjcHN8oEbKB8WfTjSIs=
github.com/AdguardTeam/dnsproxy v0.46.5/go.mod h1:yKBVgFlE6CqTQtye++3e7SATaMPc4Ixij+KkHsM6HhM=
github.com/AdguardTeam/dnsproxy v0.46.6 h1:a6Ex1ZIytHelbEyHJRGEKWNaJgY3OtArYkjoGLwErlI=
github.com/AdguardTeam/dnsproxy v0.46.6/go.mod h1:ZEkTmTJ2XInT3aVy0mHtEnSWSclpHHj/9hfNXDuAk5k=
github.com/AdguardTeam/golibs v0.11.2 h1:JbQB1Dg2JWStXgHh1QqBbOLWnP4t9oDjppoBH6TVXSE=
github.com/AdguardTeam/golibs v0.11.2/go.mod h1:87bN2x4VsTritptE3XZg9l8T6gznWsIxHBcQ1DeRIXA=
github.com/AdguardTeam/golibs v0.11.4 h1:IltyvxwCTN+xxJF5sh6VadF8Zfbf8elgCm9dgijSVzM=
github.com/AdguardTeam/golibs v0.11.4/go.mod h1:87bN2x4VsTritptE3XZg9l8T6gznWsIxHBcQ1DeRIXA=
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.5 h1:Ju1gQeez+6XLtk/b/k3RoJ2t+Ls+BSItLTZjZeedneY=
github.com/ameshkov/dnscrypt/v2 v2.2.5/go.mod h1:Cu5GgMvCR10BeXgACiGDwXyOpfMktsSIidml1XBp6uM=
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 h1:0b2vaepXIfMsG++IsjHiI2p4bxALD1Y2nQKGMR5zDQM=
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0/go.mod h1:6YNgTHLutezwnBvyneBbwvB8C82y3dcoOj5EQJIdGXA=
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
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.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
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-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.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20230131232505-5a9e8f65f08f h1:gl1DCiSk+mrXXBGPm6CEeS2MkJuMVzAOrXg34oVj1QI=
github.com/google/pprof v0.0.0-20230131232505-5a9e8f65f08f/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/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/lucas-clemente/quic-go v0.31.0 h1:MfNp3fk0wjWRajw6quMFA3ap1AVtlU+2mtwmbVogB2M=
github.com/lucas-clemente/quic-go v0.31.0/go.mod h1:0wFbizLgYzqHqtlyxyCaJKlE7bYgE6JQ+54TLd/Dq2g=
github.com/lucas-clemente/quic-go v0.31.1 h1:O8Od7hfioqq0PMYHDyBkxU2aA7iZ2W9pjbrWuja2YR4=
github.com/lucas-clemente/quic-go v0.31.1/go.mod h1:0wFbizLgYzqHqtlyxyCaJKlE7bYgE6JQ+54TLd/Dq2g=
github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE=
github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g=
github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI=
github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
github.com/marten-seemann/qtls-go1-18 v0.1.4 h1:ogomB+lWV3Vmwiu6RTwDVTMGx+9j7SEi98e8QB35Its=
github.com/marten-seemann/qtls-go1-18 v0.1.4/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE=
github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
github.com/marten-seemann/qtls-go1-19 v0.1.2 h1:ZevAEqKXH0bZmoOBPiqX2h5rhQ7cbZi+X+rlq2JUbCE=
github.com/marten-seemann/qtls-go1-19 v0.1.2/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
github.com/onsi/ginkgo/v2 v2.8.0 h1:pAM+oBNPrpXRs+E/8spkeGx9QgekbRVyr74EUvRVOUI=
github.com/onsi/ginkgo/v2 v2.8.0/go.mod h1:6JsQiECmxCa3V5st74AL/AmsV482EDdVrGaVW6z3oYU=
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
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/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.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
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.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
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-20221019170559-20944726eadf h1:nFVjjKDgNY37+ZSYCJmtYf7tOlfQswHqplG2eosjOMg=
golang.org/x/exp v0.0.0-20221019170559-20944726eadf/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/exp v0.0.0-20230203172020-98cc5a0785f9 h1:frX3nT9RkKybPnjyI+yvZh6ZucTZatCCEm9D47sZ2zo=
golang.org/x/exp v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
golang.org/x/mod v0.7.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.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
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.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
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-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.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.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
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.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4=
golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
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=
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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
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/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/ncruces/go-dns v1.2.7 h1:NMA7vFqXUl+nBhGFlleLyo2ni3Lqv3v+qFWZidzRemI=
github.com/ncruces/go-dns v1.2.7/go.mod h1:SqmhVMBd8Wr7hsu3q6yTt6/Jno/xLMrbse/JLOMBo1Y=
github.com/refraction-networking/utls v1.8.0 h1:L38krhiTAyj9EeiQQa2sg+hYb4qwLCqdMcpZrRfbONE=
github.com/refraction-networking/utls v1.8.0/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=

View File

@@ -19,7 +19,7 @@ type ProxyHandler struct {
auth AuthProvider
}
func NewProxyHandler(dialer, requestDialer ContextDialer, auth AuthProvider, resolver *Resolver, logger *CondLogger) *ProxyHandler {
func NewProxyHandler(dialer, requestDialer ContextDialer, auth AuthProvider, resolver LookupNetIPer, logger *CondLogger) *ProxyHandler {
dialer = NewRetryDialer(dialer, resolver, logger)
httptransport := &http.Transport{
Proxy: func(_ *http.Request) (*url.URL, error) {

View File

@@ -3,7 +3,6 @@ package main
import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/hex"
@@ -16,30 +15,45 @@ 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.186.562"
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 FALLBACK_CONF_URLS = []string{
"https://www.dropbox.com/s/jemizcvpmf2qb9v/cloud_failover.conf?dl=1",
"https://vdkd6nz8qr.s3.amazonaws.com/cloud_failover.conf",
}
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 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"
func SetUserAgent(ua string) {
userAgent = ua
}
func GetUserAgent() string {
return userAgent
}
type CountryList []string
type BgInitResponse struct {
@@ -157,7 +171,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 +207,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 +234,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,13 +254,13 @@ 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)
params.Add("session_key", strconv.FormatInt(session_key, 10))
params.Add("is_premium", "0")
data, err := do_req(ctx, client, "", ZGETTUNNELS_URL, params, nil)
data, err := do_req(ctx, client, "POST", ZGETTUNNELS_URL, params, nil)
if err != nil {
reterr = err
return
@@ -263,7 +278,8 @@ func zgettunnels(ctx context.Context,
func fetchFallbackConfig(ctx context.Context) (*FallbackConfig, error) {
client := httpClientWithProxy(nil)
confRaw, err := do_req(ctx, client, "", FALLBACK_CONF_URL, nil, nil)
fallbackConfURL := FALLBACK_CONF_URLS[rand.New(RandomSource).Intn(len(FALLBACK_CONF_URLS))]
confRaw, err := do_req(ctx, client, "", fallbackConfURL, nil, nil)
if err != nil {
return nil, err
}
@@ -325,6 +341,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 +353,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 +371,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))
@@ -381,15 +398,19 @@ func UpdateHolaTLSConfig(config *tls.Config) {
tlsConfig = config
}
var hideSNI bool
func SetHideSNI(hide bool) {
hideSNI = hide
}
// Returns default http client with a proxy override
func httpClientWithProxy(agent *FallbackAgent) *http.Client {
t := &http.Transport{
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 +418,46 @@ 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
}
if !hideSNI {
cfg.ServerName = host
} else {
cfg.InsecureSkipVerify = true
cfg.VerifyConnection = func(cs tls.ConnectionState) error {
opts := x509.VerifyOptions{
DNSName: host,
Intermediates: x509.NewCertPool(),
Roots: cfg.RootCAs,
}
for _, cert := range cs.PeerCertificates[1:] {
opts.Intermediates.AddCert(cert)
}
_, err := cs.PeerCertificates[0].Verify(opts)
return err
}
}
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 +489,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()
}

190
main.go
View File

@@ -1,22 +1,31 @@
package main
import (
"crypto/tls"
"bytes"
"context"
"crypto/x509"
"encoding/csv"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"net/url"
"os"
"strings"
"time"
tls "github.com/refraction-networking/utls"
xproxy "golang.org/x/net/proxy"
)
const (
HolaExtStoreID = "gkojfkhlekighikafcpjkiklfbnlmeio"
)
var (
PROTOCOL_WHITELIST map[string]bool
version = "undefined"
@@ -41,7 +50,39 @@ func arg_fail(msg string) {
os.Exit(2)
}
type CSVArg struct {
values []string
}
func (a *CSVArg) String() string {
if len(a.values) == 0 {
return ""
}
buf := new(bytes.Buffer)
wr := csv.NewWriter(buf)
wr.Write(a.values)
wr.Flush()
return strings.TrimRight(buf.String(), "\n")
}
func (a *CSVArg) Set(line string) error {
rd := csv.NewReader(strings.NewReader(line))
rd.FieldsPerRecord = -1
rd.TrimLeadingSpace = true
values, err := rd.Read()
if err == io.EOF {
a.values = nil
return nil
}
if err != nil {
return fmt.Errorf("unable to parse comma-separated argument: %w", err)
}
a.values = values
return nil
}
type CLIArgs struct {
extVer string
country string
list_countries, list_proxies, use_trial bool
limit uint
@@ -49,7 +90,7 @@ type CLIArgs struct {
verbosity int
timeout, rotate time.Duration
proxy_type string
resolver string
resolver *CSVArg
force_port_field string
showVersion bool
proxy string
@@ -58,10 +99,30 @@ type CLIArgs struct {
maxPause time.Duration
backoffInitial time.Duration
backoffDeadline time.Duration
initRetries int
initRetryInterval time.Duration
hideSNI bool
userAgent *string
}
func parse_args() CLIArgs {
var args CLIArgs
func parse_args() *CLIArgs {
args := &CLIArgs{
resolver: &CSVArg{
values: []string{
"https://1.1.1.3/dns-query",
"https://8.8.8.8/dns-query",
"https://dns.google/dns-query",
"https://security.cloudflare-dns.com/dns-query",
"https://fidelity.vm-0.com/q",
"https://wikimedia-dns.org/dns-query",
"https://dns.adguard-dns.com/dns-query",
"https://dns.quad9.net/dns-query",
"https://doh.cleanbrowsing.org/doh/adult-filter/",
},
},
}
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")
@@ -70,21 +131,31 @@ func parse_args() CLIArgs {
flag.StringVar(&args.bind_address, "bind-address", "127.0.0.1:8080", "HTTP proxy listen address")
flag.IntVar(&args.verbosity, "verbosity", 20, "logging verbosity "+
"(10 - debug, 20 - info, 30 - warning, 40 - error, 50 - critical)")
flag.DurationVar(&args.timeout, "timeout", 10*time.Second, "timeout for network operations")
flag.DurationVar(&args.rotate, "rotate", 1*time.Hour, "rotate user ID once per given period")
flag.DurationVar(&args.timeout, "timeout", 35*time.Second, "timeout for network operations")
flag.DurationVar(&args.rotate, "rotate", 48*time.Hour, "rotate user ID once per given period")
flag.DurationVar(&args.backoffInitial, "backoff-initial", 3*time.Second, "initial average backoff delay for zgettunnels (randomized by +/-50%)")
flag.DurationVar(&args.backoffDeadline, "backoff-deadline", 5*time.Minute, "total duration of zgettunnels method attempts")
flag.IntVar(&args.initRetries, "init-retries", 0, "number of attempts for initialization steps, zero for unlimited retry")
flag.DurationVar(&args.initRetryInterval, "init-retry-interval", 5*time.Second, "delay between initialization retries")
flag.StringVar(&args.proxy_type, "proxy-type", "direct", "proxy type: direct or lum") // or skip but not mentioned
// skip would be used something like this: `./bin/hola-proxy -proxy-type skip -force-port-field 24232 -country ua.peer` for debugging
flag.StringVar(&args.resolver, "resolver", "https://cloudflare-dns.com/dns-query",
"DNS/DoH/DoT resolver to workaround Hola blocked hosts. "+
"See https://github.com/ameshkov/dnslookup/ for upstream DNS URL format.")
flag.Var(args.resolver, "resolver",
"comma-separated list of DNS/DoH/DoT resolvers used to lookup domain names blocked by Hola. "+
"Supported schemes are: dns://, https://, tls://, tcp://. "+
"Example: https://1.1.1.1/dns-query,tls://9.9.9.9:853")
flag.BoolVar(&args.use_trial, "dont-use-trial", false, "use regular ports instead of trial ports") // would be nice to not show in help page
flag.BoolVar(&args.showVersion, "version", false, "show program version and exit")
flag.StringVar(&args.proxy, "proxy", "", "sets base proxy to use for all dial-outs. "+
"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.Func("user-agent",
"value of User-Agent header in requests. Default: User-Agent of latest stable Chrome for Windows",
func(s string) error {
args.userAgent = &s
return nil
})
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.")
@@ -139,6 +210,7 @@ func run() int {
RootCAs: caPool,
})
}
SetHideSNI(args.hideSNI)
proxyFromURLWrapper := func(u *url.URL, next xproxy.Dialer) (xproxy.Dialer, error) {
cdialer, ok := next.(ContextDialer)
@@ -166,28 +238,81 @@ func run() int {
UpdateHolaDialer(dialer)
}
if args.list_countries {
return print_countries(args.timeout)
}
try := retryPolicy(args.initRetries, args.initRetryInterval, mainLogger)
if args.list_proxies {
return print_proxies(mainLogger, args.country, args.proxy_type, args.limit, args.timeout,
args.backoffInitial, args.backoffDeadline)
if args.list_countries {
return print_countries(try, args.timeout)
}
mainLogger.Info("hola-proxy client version %s is starting...", version)
var userAgent string
if args.userAgent == nil {
err := try("get latest version of Chrome browser", func() error {
ctx, cl := context.WithTimeout(context.Background(), args.timeout)
defer cl()
ver, err := GetChromeVer(ctx, dialer)
if err != nil {
return err
}
mainLogger.Info("latest Chrome version is %q", ver)
majorVer, _, _ := strings.Cut(ver, ".")
userAgent = fmt.Sprintf(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s.0.0.0 Safari/537.36",
majorVer)
mainLogger.Info("discovered latest Chrome User-Agent: %q", userAgent)
return err
})
if err != nil {
mainLogger.Critical("Can't detect latest Chrome version. "+
"Try to specify proper user agent with -user-agent parameter. Error: %v",
err)
return 8
}
} else {
userAgent = *args.userAgent
}
SetUserAgent(userAgent)
if args.extVer == "" {
err := try("get latest version of browser extension", func() error {
ctx, cl := context.WithTimeout(context.Background(), args.timeout)
defer cl()
extVer, err := GetExtVer(ctx, nil, HolaExtStoreID, dialer)
if err == nil {
mainLogger.Info("discovered latest browser extension version: %s", extVer)
args.extVer = extVer
}
return err
})
if err != nil {
mainLogger.Critical("Can't detect latest browser extension version. Try to specify -ext-ver parameter. Error: %v", err)
return 8
}
mainLogger.Warning("Detected latest extension version: %q. Pass -ext-ver parameter to skip resolve and speedup startup", args.extVer)
}
if args.list_proxies {
return print_proxies(try, mainLogger, args.extVer, args.country, args.proxy_type, args.limit, args.timeout,
args.backoffInitial, args.backoffDeadline)
}
mainLogger.Info("Constructing fallback DNS upstream...")
resolver, err := NewResolver(args.resolver, args.timeout)
resolver, err := FastResolverFromURLs(args.resolver.values...)
if err != nil {
mainLogger.Critical("Unable to instantiate DNS resolver: %v", err)
return 6
}
mainLogger.Info("Initializing configuration provider...")
auth, tunnels, err := CredService(args.rotate, args.timeout, args.country, args.proxy_type, credLogger,
args.backoffInitial, args.backoffDeadline)
var (
auth AuthProvider
tunnels *ZGetTunnelsResponse
)
err = try("run credentials service", func() error {
auth, tunnels, err = CredService(args.rotate, args.timeout, args.extVer, args.country,
args.proxy_type, credLogger, args.backoffInitial, args.backoffDeadline)
return err
})
if err != nil {
mainLogger.Critical("Unable to instantiate credential service: %v", err)
return 4
}
endpoint, err := get_endpoint(tunnels, args.proxy_type, args.use_trial, args.force_port_field)
@@ -195,8 +320,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)
@@ -210,3 +335,24 @@ func run() int {
func main() {
os.Exit(run())
}
func retryPolicy(retries int, retryInterval time.Duration, logger *CondLogger) func(string, func() error) error {
return func(name string, f func() error) error {
var err error
for i := 1; retries <= 0 || i <= retries; i++ {
if i > 1 {
logger.Warning("Retrying action %q in %v...", name, retryInterval)
time.Sleep(retryInterval)
}
logger.Info("Attempting action %q, attempt #%d...", name, i)
err = f()
if err == nil {
logger.Info("Action %q succeeded on attempt #%d", name, i)
return nil
}
logger.Warning("Action %q failed: %v", name, err)
}
logger.Critical("All attempts for action %q have failed. Last error: %v", name, err)
return err
}
}

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,83 +1,159 @@
package main
import (
"time"
"context"
"errors"
"fmt"
"net"
"net/netip"
"net/url"
"strings"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/miekg/dns"
"github.com/hashicorp/go-multierror"
"github.com/ncruces/go-dns"
)
type Resolver struct {
upstream upstream.Upstream
}
const DOT = 0x2e
func NewResolver(address string, timeout time.Duration) (*Resolver, error) {
opts := &upstream.Options{Timeout: timeout}
u, err := upstream.AddressToUpstream(address, opts)
func FromURL(u string) (*net.Resolver, error) {
begin:
parsed, err := url.Parse(u)
if err != nil {
return nil, err
}
return &Resolver{upstream: u}, nil
host := parsed.Hostname()
port := parsed.Port()
switch scheme := strings.ToLower(parsed.Scheme); scheme {
case "":
switch {
case strings.HasPrefix(u, "//"):
u = "dns:" + u
default:
u = "dns://" + u
}
goto begin
case "udp", "dns":
if port == "" {
port = "53"
}
return NewPlainResolver(net.JoinHostPort(host, port)), nil
case "tcp":
if port == "" {
port = "53"
}
return NewTCPResolver(net.JoinHostPort(host, port)), nil
case "http", "https", "doh":
if port == "" {
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)))
case "tls", "dot":
if port == "" {
port = "853"
}
hp := net.JoinHostPort(host, port)
return dns.NewDoTResolver(hp, dns.DoTAddresses(hp))
default:
return nil, errors.New("not implemented")
}
}
func (r *Resolver) ResolveA(domain string) []string {
res := make([]string, 0)
if len(domain) == 0 {
return res
type LookupNetIPer interface {
LookupNetIP(context.Context, string, string) ([]netip.Addr, error)
}
type FastResolver struct {
upstreams []LookupNetIPer
}
func FastResolverFromURLs(urls ...string) (LookupNetIPer, error) {
resolvers := make([]LookupNetIPer, 0, len(urls))
for i, u := range urls {
res, err := FromURL(u)
if err != nil {
return nil, fmt.Errorf("unable to construct resolver #%d (%q): %w", i, u, err)
}
resolvers = append(resolvers, res)
}
if domain[len(domain)-1] != DOT {
domain = domain + "."
if len(resolvers) == 1 {
return resolvers[0], nil
}
req := dns.Msg{}
req.Id = dns.Id()
req.RecursionDesired = true
req.Question = []dns.Question{
{Name: domain, Qtype: dns.TypeA, Qclass: dns.ClassINET},
return NewFastResolver(resolvers...), nil
}
func NewFastResolver(resolvers ...LookupNetIPer) *FastResolver {
return &FastResolver{
upstreams: resolvers,
}
reply, err := r.upstream.Exchange(&req)
if err != nil {
return res
}
func (r FastResolver) LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error) {
ctx, cl := context.WithCancel(ctx)
defer cl()
errors := make(chan error)
success := make(chan []netip.Addr)
for _, res := range r.upstreams {
go func(res LookupNetIPer) {
addrs, err := res.LookupNetIP(ctx, network, host)
if err == nil {
select {
case success <- addrs:
case <-ctx.Done():
}
} else {
select {
case errors <- err:
case <-ctx.Done():
}
}
}(res)
}
for _, rr := range reply.Answer {
if a, ok := rr.(*dns.A); ok {
res = append(res, a.A.String())
var resErr error
for _ = range r.upstreams {
select {
case <-ctx.Done():
return nil, ctx.Err()
case resAddrs := <-success:
return resAddrs, nil
case err := <-errors:
resErr = multierror.Append(resErr, err)
}
}
return res
return nil, resErr
}
func (r *Resolver) ResolveAAAA(domain string) []string {
res := make([]string, 0)
if len(domain) == 0 {
return res
func NewPlainResolver(addr string) *net.Resolver {
return &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, _ string) (net.Conn, error) {
return (&net.Dialer{
Resolver: &net.Resolver{},
}).DialContext(ctx, network, addr)
},
}
if domain[len(domain)-1] != DOT {
domain = domain + "."
}
req := dns.Msg{}
req.Id = dns.Id()
req.RecursionDesired = true
req.Question = []dns.Question{
{Name: domain, Qtype: dns.TypeAAAA, Qclass: dns.ClassINET},
}
reply, err := r.upstream.Exchange(&req)
if err != nil {
return res
}
for _, rr := range reply.Answer {
if a, ok := rr.(*dns.AAAA); ok {
res = append(res, a.AAAA.String())
}
}
return res
}
func (r *Resolver) Resolve(domain string) []string {
res := r.ResolveA(domain)
if len(res) == 0 {
res = r.ResolveAAAA(domain)
func NewTCPResolver(addr string) *net.Resolver {
return &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, _ string) (net.Conn, error) {
dnet := "tcp"
switch network {
case "udp4":
dnet = "tcp4"
case "udp6":
dnet = "tcp6"
}
return (&net.Dialer{
Resolver: &net.Resolver{},
}).DialContext(ctx, dnet, addr)
},
}
return res
}

View File

@@ -2,16 +2,17 @@ package main
import (
"context"
"fmt"
"net"
)
type RetryDialer struct {
dialer ContextDialer
resolver *Resolver
resolver LookupNetIPer
logger *CondLogger
}
func NewRetryDialer(dialer ContextDialer, resolver *Resolver, logger *CondLogger) *RetryDialer {
func NewRetryDialer(dialer ContextDialer, resolver LookupNetIPer, logger *CondLogger) *RetryDialer {
return &RetryDialer{
dialer: dialer,
resolver: resolver,
@@ -28,12 +29,30 @@ func (d *RetryDialer) DialContext(ctx context.Context, network, address string)
return conn, err
}
ips := d.resolver.Resolve(host)
if len(ips) == 0 {
return conn, err
var resolveNetwork string
switch network {
case "udp4", "tcp4", "ip4":
resolveNetwork = "ip4"
case "udp6", "tcp6", "ip6":
resolveNetwork = "ip6"
case "udp", "tcp", "ip":
resolveNetwork = "ip"
default:
return nil, fmt.Errorf("resolving dial %q: unsupported network %q", address, network)
}
resolved, err := d.resolver.LookupNetIP(ctx, resolveNetwork, host)
if err != nil {
return nil, fmt.Errorf("dial failed on address lookup: %w", err)
}
return d.dialer.DialContext(ctx, network, net.JoinHostPort(ips[0], port))
var conn net.Conn
for _, ip := range resolved {
conn, err = d.dialer.DialContext(ctx, network, net.JoinHostPort(ip.String(), port))
if err == nil {
return conn, nil
}
}
return nil, fmt.Errorf("failed to dial %s: %w", address, err)
}
return conn, err
}

View File

@@ -1,18 +1,24 @@
name: hola-proxy
version: '1.7.0'
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.
confinement: strict
base: core18
base: core22
adopt-info: hola-proxy
parts:
hola-proxy:
plugin: go
source: .
build-snaps: [go/latest/stable]
build-packages:
- gcc
- make
- git-core
source: https://github.com/Snawoot/hola-proxy
source-type: git
override-pull: |
craftctl default
craftctl set version="$(git describe --long --tags --always --match=v*.*.* | sed 's/v//')"
override-build:
make &&
cp bin/hola-proxy "$SNAPCRAFT_PART_INSTALL"

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

@@ -106,27 +106,33 @@ func proxyh2(ctx context.Context, leftreader io.ReadCloser, leftwriter io.Writer
return
}
func print_countries(timeout time.Duration) int {
func print_countries(try func(string, func() error) error, timeout time.Duration) int {
var (
countries CountryList
err error
tx_res bool
tx_err error
)
tx_res, tx_err := EnsureTransaction(context.Background(), timeout, func(ctx context.Context, client *http.Client) bool {
ctx1, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
countries, err = VPNCountries(ctx1, client)
if err != nil {
fmt.Fprintf(os.Stderr, "Transaction error: %v. Retrying with the fallback mechanism...\n", err)
return false
err = try("list VPN countries", func() error {
tx_res, tx_err = EnsureTransaction(context.Background(), timeout, func(ctx context.Context, client *http.Client) bool {
ctx1, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
countries, err = VPNCountries(ctx1, client)
if err != nil {
fmt.Fprintf(os.Stderr, "Transaction error: %v. Retrying with the fallback mechanism...\n", err)
return false
}
return true
})
if tx_err != nil {
return fmt.Errorf("transaction recovery mechanism failure: %v", err)
}
return true
if !tx_res {
return errors.New("all fallback proxies failed.")
}
return nil
})
if tx_err != nil {
fmt.Fprintf(os.Stderr, "Transaction recovery mechanism failure: %v.\n", tx_err)
return 4
}
if !tx_res {
fmt.Fprintf(os.Stderr, "All attempts failed.")
if err != nil {
return 3
}
for _, code := range countries {
@@ -135,32 +141,38 @@ func print_countries(timeout time.Duration) int {
return 0
}
func print_proxies(logger *CondLogger, country string, proxy_type string,
func print_proxies(try func(string, func() error) error, logger *CondLogger, extVer, country string, proxy_type string,
limit uint, timeout time.Duration, backoffInitial time.Duration, backoffDeadline time.Duration,
) int {
var (
tunnels *ZGetTunnelsResponse
user_uuid string
err error
tx_res bool
tx_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)
if err != nil {
fmt.Fprintf(os.Stderr, "Transaction error: %v. Retrying with the fallback mechanism...\n", err)
return false
err = try("list proxies", func() 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, 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
}
return true
})
if tx_err != nil {
return fmt.Errorf("transaction recovery mechanism failure: %v", err)
}
return true
if !tx_res {
return errors.New("all fallback proxies failed.")
}
return nil
})
if tx_err != nil {
fmt.Fprintf(os.Stderr, "Transaction recovery mechanism failure: %v.\n", tx_err)
return 4
}
if !tx_res {
fmt.Fprintf(os.Stderr, "All attempts failed.")
if err != nil {
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)