Compare commits

..

168 Commits

Author SHA1 Message Date
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
Vladislav Yarmak
618010d407 bump snap version 2023-02-08 19:33:09 +02:00
Snawoot
501246d7a2 Merge pull request #78 from Snawoot/tunnels_exp_backoff
Tunnels exp backoff
2023-02-08 19:30:47 +02:00
Vladislav Yarmak
34a8addcd5 upd doc 2023-02-08 19:19:29 +02:00
Vladislav Yarmak
b88a0f3edf tunnels exp backoff 2023-02-08 19:19:29 +02:00
Vladislav Yarmak
8e19a9ce57 bump snap version 2023-02-07 19:38:26 +02:00
Snawoot
bab7fafd27 Merge pull request #77 from Snawoot/adjustable_pause
upd doc
2023-02-07 19:37:15 +02:00
Vladislav Yarmak
ed35d9abac upd doc 2023-02-07 19:35:42 +02:00
Snawoot
37a685bda7 Merge pull request #76 from Snawoot/adjustable_pause
adjustable pause
2023-02-07 19:33:22 +02:00
Vladislav Yarmak
4f01c96d19 adjustable pause 2023-02-07 19:32:49 +02:00
Vladislav Yarmak
2e5fce3cd4 bump snap version 2023-02-04 14:36:03 +02:00
Snawoot
a465e24dc5 Merge pull request #75 from Snawoot/bix_netbsd_build
Fix NetBSD build
2023-02-04 14:32:13 +02:00
Vladislav Yarmak
ed3f67b2fb fix NetBSD build 2023-02-04 14:30:38 +02:00
Vladislav Yarmak
2228571412 bump snap version 2023-02-04 13:27:45 +02:00
Snawoot
34588f46e7 Merge pull request #74 from Snawoot/mod_upgrade
Modules upgrade
2023-02-04 13:24:01 +02:00
Vladislav Yarmak
c47d582556 mod upgrade 2023-02-04 13:20:00 +02:00
Vladislav Yarmak
478249d7a8 Dockerfile: fixed golang version 2023-02-02 01:03:26 +02:00
Vladislav Yarmak
ff5b462c25 bump snap version 2023-02-02 00:54:56 +02:00
Vladislav Yarmak
7355e3a76e upd doc 2023-02-02 00:54:24 +02:00
Snawoot
d030f47c59 Merge pull request #72 from Snawoot/fix_tunnels_api
fix tunnels API client
2023-02-02 00:51:34 +02:00
Vladislav Yarmak
73e6bca7a3 extend CSPRNG to support math/rand.Source64 interface 2023-02-02 00:26:36 +02:00
Vladislav Yarmak
4b8cb56ff5 fix tunnels API client 2023-02-02 00:26:36 +02:00
Vladislav Yarmak
c413ef95b1 goimports -w 2023-02-01 20:16:05 +02:00
Vladislav Yarmak
adddc10149 go mod tidy 2022-10-22 10:49:56 +03:00
Vladislav Yarmak
0f13b7635e bump snap version 2022-10-21 21:29:45 +03:00
Snawoot
2ee621310d Merge pull request #69 from Snawoot/go119
fix build with go1.19
2022-10-21 21:28:35 +03:00
Vladislav Yarmak
1d3a61339f fix build with go1.19 2022-10-21 21:28:05 +03:00
Vladislav Yarmak
6aa3494d71 enable stale bot 2022-07-01 20:09:58 +03:00
Vladislav Yarmak
068a2d5b83 bump snap version 2022-06-25 15:39:20 +03:00
Snawoot
fadff8c38f Merge pull request #65 from Snawoot/libs_upgrade
libs upgrade
2022-06-25 15:37:46 +03:00
Vladislav Yarmak
bd1a37b3d3 libs upgrade 2022-06-25 15:36:19 +03:00
Vladislav Yarmak
7d891ac613 bump snap version 2021-07-18 00:56:27 +03:00
Snawoot
458efb37ba Merge pull request #51 from Snawoot/cafile
add cafile option
2021-07-18 00:55:21 +03:00
Vladislav Yarmak
26990c6130 upd doc 2021-07-18 00:53:23 +03:00
Vladislav Yarmak
880631670e add cafile option 2021-07-18 00:52:27 +03:00
Vladislav Yarmak
27381ce5ff makefile: add arm64 to default build 2021-07-17 20:24:21 +03:00
Vladislav Yarmak
5050e96484 makefile: add arm64 and mips 2021-07-17 19:54:52 +03:00
Vladislav Yarmak
30295224ee bump snap version 2021-07-15 23:11:09 +03:00
Vladislav Yarmak
4d4348686c holaapi: update reported client version 2021-07-15 23:10:29 +03:00
Vladislav Yarmak
86b7fece9b bump snap version 2021-07-02 23:41:28 +03:00
Vladislav Yarmak
608da0baa9 remove mentions of unknown proxy types 2021-07-02 23:38:40 +03:00
Vladislav Yarmak
0c36dee0b7 remove dockerhub hooks 2021-06-09 21:46:34 +03:00
Vladislav Yarmak
f2fdeea039 ci: docker 2021-06-09 19:39:22 +03:00
Snawoot
f5da736ca1 Update README.md 2021-05-02 13:04:36 +03:00
Vladislav Yarmak
dd0eaa7611 bump snap version 2021-05-01 17:58:42 +03:00
Snawoot
882bca34bc Merge pull request #45 from Snawoot/fix_http
Fixed plain HTTP request
2021-05-01 17:57:30 +03:00
Vladislav Yarmak
70faaec848 fixed plain HTTP request 2021-05-01 17:55:12 +03:00
Snawoot
4728548594 Merge pull request #43 from aarivex/patch-2
Update README.md
2021-04-01 02:10:13 +03:00
Vladislav Yarmak
2c555adb35 amend chmod notice 2021-04-01 02:09:06 +03:00
Canathan
9fee5905bb Update README.md
Add chmod command section for the linux binary.
2021-03-30 04:57:44 +02:00
Vladislav Yarmak
19fd0c9d52 add android build target 2021-03-28 18:44:12 +03:00
Vladislav Yarmak
a3e1bd0901 bump snap version 2021-03-24 00:39:08 +02:00
Snawoot
882b6381db Merge pull request #42 from Snawoot/base_proxy
Base proxy support
2021-03-24 00:37:39 +02:00
Vladislav Yarmak
9d686e3f70 update help and docs 2021-03-24 00:33:38 +02:00
Vladislav Yarmak
1f44e7548d use proxy stack for list modes 2021-03-23 23:58:28 +02:00
Vladislav Yarmak
910f76065f embed proxy stack into hola api client 2021-03-23 23:36:04 +02:00
Vladislav Yarmak
18dd1776be http(s) proxy support 2021-03-23 23:22:09 +02:00
Vladislav Yarmak
1c98b33978 socks proxy support 2021-03-23 22:30:03 +02:00
21 changed files with 917 additions and 172 deletions

17
.github/stale.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

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

62
.github/workflows/docker-ci.yml vendored Normal file
View File

@@ -0,0 +1,62 @@
name: docker-ci
on:
push:
tags:
- 'v*.*.*'
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
-
name: Find Git Tag
id: tagger
uses: jimschubert/query-tag-action@v2
with:
include: 'v*'
exclude: '*-rc*'
commit-ish: 'HEAD'
skip-unshallow: 'true'
abbrev: 7
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
# 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@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
-
name: Login to DockerHub
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@v5
with:
context: .
platforms: linux/amd64,linux/arm64,linux/386,linux/arm/v7
push: true
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 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,26 +1,38 @@
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)'
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
src = $(wildcard *.go)
src = $(wildcard *.go */*.go */*/*.go) go.mod go.sum
native: bin-native
all: bin-linux-amd64 bin-linux-386 bin-linux-arm \
all: 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-windows-amd64 bin-windows-386 bin-windows-arm
allplus: all \
bin-android-arm bin-android-arm64
bin-native: $(OUTSUFFIX)
bin-linux-amd64: $(OUTSUFFIX).linux-amd64
bin-linux-386: $(OUTSUFFIX).linux-386
bin-linux-arm: $(OUTSUFFIX).linux-arm
bin-linux-arm64: $(OUTSUFFIX).linux-arm64
bin-linux-mips: $(OUTSUFFIX).linux-mips
bin-linux-mipsle: $(OUTSUFFIX).linux-mipsle
bin-linux-mips64: $(OUTSUFFIX).linux-mips64
bin-linux-mips64le: $(OUTSUFFIX).linux-mips64le
bin-freebsd-amd64: $(OUTSUFFIX).freebsd-amd64
bin-freebsd-386: $(OUTSUFFIX).freebsd-386
bin-freebsd-arm: $(OUTSUFFIX).freebsd-arm
@@ -33,6 +45,8 @@ bin-darwin-arm64: $(OUTSUFFIX).darwin-arm64
bin-windows-amd64: $(OUTSUFFIX).windows-amd64.exe
bin-windows-386: $(OUTSUFFIX).windows-386.exe
bin-windows-arm: $(OUTSUFFIX).windows-arm.exe
bin-android-arm: $(OUTSUFFIX).android-arm
bin-android-arm64: $(OUTSUFFIX).android-arm64
$(OUTSUFFIX): $(src)
$(GO) build $(LDFLAGS_NATIVE) -o $@
@@ -46,6 +60,21 @@ $(OUTSUFFIX).linux-386: $(src)
$(OUTSUFFIX).linux-arm: $(src)
CGO_ENABLED=0 GOOS=linux GOARCH=arm $(GO) build $(BUILDOPTS) $(LDFLAGS) -o $@
$(OUTSUFFIX).linux-arm64: $(src)
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(GO) build $(BUILDOPTS) $(LDFLAGS) -o $@
$(OUTSUFFIX).linux-mips: $(src)
CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat $(GO) build $(BUILDOPTS) $(LDFLAGS) -o $@
$(OUTSUFFIX).linux-mips64: $(src)
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 GOMIPS=softfloat $(GO) build $(BUILDOPTS) $(LDFLAGS) -o $@
$(OUTSUFFIX).linux-mipsle: $(src)
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle GOMIPS=softfloat $(GO) build $(BUILDOPTS) $(LDFLAGS) -o $@
$(OUTSUFFIX).linux-mips64le: $(src)
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le GOMIPS=softfloat $(GO) build $(BUILDOPTS) $(LDFLAGS) -o $@
$(OUTSUFFIX).freebsd-amd64: $(src)
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 $(GO) build $(BUILDOPTS) $(LDFLAGS) -o $@
@@ -82,6 +111,12 @@ $(OUTSUFFIX).windows-386.exe: $(src)
$(OUTSUFFIX).windows-arm.exe: $(src)
CGO_ENABLED=0 GOOS=windows GOARCH=arm GOARM=7 $(GO) 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 $@
$(OUTSUFFIX).android-arm64: $(src)
CC=$(NDK_CC_ARM64) CGO_ENABLED=1 GOOS=android GOARCH=arm64 $(GO) build $(LDFLAGS_NATIVE) -o $@
clean:
rm -f bin/*
@@ -99,9 +134,21 @@ install:
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-windows-amd64 \
bin-windows-386
bin-windows-386 \
bin-windows-arm \
bin-android-arm \
bin-android-arm64

View File

@@ -5,7 +5,7 @@
Standalone Hola proxy client. Just run it and it'll start a plain HTTP proxy server forwarding traffic through Hola proxies of your choice.
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 pool` or `-proxy-type lum`).
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`).
---
@@ -41,6 +41,12 @@ git clone https://ipfs.io/ipns/k51qzi5uqu5dkrgx0hozpy1tlggw5o0whtquyrjlc6pprhvbm
Pre-built binaries are available [here](https://github.com/Snawoot/hola-proxy/releases/latest).
Don't forget to make file executable on Unix-like systems (Linux, MacOS, \*BSD, Android). For your convenience rename downloaded file to `hola-proxy` and run within directory where you placed it:
```sh
chmod +x hola-proxy
```
#### Build from source
Alternatively, you may install hola-proxy from source. Run the following within the source directory:
@@ -150,15 +156,29 @@ zagent248.hola.org,165.22.65.3,22222,22223,22224,22225,22226,digitalocean
| Argument | Type | Description |
| -------- | ---- | ----------- |
| backoff-deadline | Duration | total duration of zgettunnels method attempts (default 5m0s) |
| backoff-initial | Duration | initial average backoff delay for zgettunnels (randomized by +/-50%) (default 3s) |
| bind-address | String | HTTP proxy address to listen to (default "127.0.0.1:8080") |
| 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-type | String | proxy type (Datacenter: direct, virt) (Residential: peer, lum, pool) (default "direct") |
| 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) |
| timeout | Duration | timeout for network operations (default 10s) |
| 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 "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36") |
| 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,22 +10,24 @@ import (
const DEFAULT_LIST_LIMIT = 3
func CredService(interval, timeout time.Duration,
extVer string,
country string,
proxytype string,
logger *CondLogger) (auth AuthProvider,
tunnels *ZGetTunnelsResponse,
err error) {
logger *CondLogger,
backoffInitial time.Duration,
backoffDeadline time.Duration,
) (auth AuthProvider, tunnels *ZGetTunnelsResponse, err error) {
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, client, country, proxytype, DEFAULT_LIST_LIMIT)
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)
return false
@@ -41,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
@@ -55,7 +59,8 @@ 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, client, country, proxytype, DEFAULT_LIST_LIMIT)
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)
return false
@@ -71,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.")
}
}()

View File

@@ -10,6 +10,7 @@ type secureRandomSource struct{}
var RandomSource secureRandomSource
var int63Limit = big.NewInt(0).Lsh(big.NewInt(1), 63)
var int64Limit = big.NewInt(0).Lsh(big.NewInt(1), 64)
func (_ secureRandomSource) Seed(_ int64) {
}
@@ -21,3 +22,11 @@ func (_ secureRandomSource) Int63() int64 {
}
return randNum.Int64()
}
func (_ secureRandomSource) Uint64() uint64 {
randNum, err := crand.Int(crand.Reader, int64Limit)
if err != nil {
panic(err)
}
return randNum.Uint64()
}

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
}

37
go.mod
View File

@@ -1,10 +1,39 @@
module github.com/Snawoot/hola-proxy
go 1.13
go 1.23.5
toolchain go1.23.6
require (
github.com/AdguardTeam/dnsproxy v0.25.0
github.com/AdguardTeam/dnsproxy v0.75.0
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e
github.com/google/uuid v1.1.1
github.com/miekg/dns v1.1.29
github.com/cenkalti/backoff/v4 v4.3.0
github.com/google/uuid v1.6.0
github.com/miekg/dns v1.1.63
github.com/refraction-networking/utls v1.6.7
golang.org/x/net v0.35.0
)
require (
github.com/AdguardTeam/golibs v0.32.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.3.0 // indirect
github.com/ameshkov/dnsstamps v1.0.3 // indirect
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/cloudflare/circl v1.6.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/onsi/ginkgo/v2 v2.22.2 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.50.0 // indirect
go.uber.org/mock v0.5.0 // indirect
golang.org/x/crypto v0.35.0 // indirect
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect
golang.org/x/mod v0.23.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect
golang.org/x/tools v0.30.0 // indirect
)

124
go.sum
View File

@@ -1,64 +1,76 @@
github.com/AdguardTeam/dnsproxy v0.25.0 h1:BTUPrrwB01GeQW5d2Xx4pH5HOFXcZxN1MTeNXXuy6vQ=
github.com/AdguardTeam/dnsproxy v0.25.0/go.mod h1:z2EljVLJQXFGZcP9pWABftXm9UxpLNqls7H6bMcIvEY=
github.com/AdguardTeam/golibs v0.4.0 h1:4VX6LoOqFe9p9Gf55BeD8BvJD6M6RDYmgEiHrENE9KU=
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
github.com/AdguardTeam/dnsproxy v0.75.0 h1:v8/Oq/xPYzNoALR7SEUZEIbKmjnPcXLVhJLFVbrozEc=
github.com/AdguardTeam/dnsproxy v0.75.0/go.mod h1:O2qoXwF4BUBFui7OMUiWSYwapEDcYxKWeur4+jfy9nM=
github.com/AdguardTeam/golibs v0.32.1 h1:Ajf6Q0k+A9zjFbj8HOzNAbHImrV4JtbT0vwy02D6VeI=
github.com/AdguardTeam/golibs v0.32.1/go.mod h1:dXRLSsnJQDxOfQVl0ochy1bfk4NgnJQGQdR1YPJdwcw=
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 v1.1.0 h1:2vAt5dD6ZmqlAxEAfzRcLBnkvdf8NI46Kn9InSwQbSI=
github.com/ameshkov/dnscrypt v1.1.0/go.mod h1:ikduAxNLCTEfd1AaCgpIA5TgroIVQ8JY3Vb095fiFJg=
github.com/ameshkov/dnsstamps v1.0.1 h1:LhGvgWDzhNJh+kBQd/AfUlq1vfVe109huiXw4JhnPug=
github.com/ameshkov/dnsstamps v1.0.1/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
github.com/beefsack/go-rate v0.0.0-20180408011153-efa7637bb9b6/go.mod h1:6YNgTHLutezwnBvyneBbwvB8C82y3dcoOj5EQJIdGXA=
github.com/ameshkov/dnscrypt/v2 v2.3.0 h1:pDXDF7eFa6Lw+04C0hoMh8kCAQM8NwUdFEllSP2zNLs=
github.com/ameshkov/dnscrypt/v2 v2.3.0/go.mod h1:N5hDwgx2cNb4Ay7AhvOSKst+eUiOZ/vbKRO9qMpQttE=
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.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
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-test/deep v1.0.5/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/joomcode/errorx v1.0.1 h1:CalpDWz14ZHd68fIqluJasJosAewpz2TFaJALrUxjrk=
github.com/joomcode/errorx v1.0.1/go.mod h1:kgco15ekB6cs+4Xjzo7SPeXzx38PbJzBwbnu9qfVNHQ=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc=
github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
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.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
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/sparrc/go-ping v0.0.0-20190613174326-4e5b6552494c/go.mod h1:eMyUVp6f/5jnzM+3zahzl7q6UXLbgSc3MKg/+ow9QW0=
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=
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-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8 h1:fpnn/HnJONpIu6hkXi1u/7rR0NzilgWr4T0JmWkEitk=
golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
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-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.50.0 h1:3H/ld1pa3CYhkcc20TPIyG1bNsdhn9qZBGN3b9/UyUo=
github.com/quic-go/quic-go v0.50.0/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E=
github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4=
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=
google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -3,6 +3,7 @@ package main
import (
"fmt"
"net/http"
"net/url"
"strings"
"time"
)
@@ -15,20 +16,28 @@ type ProxyHandler struct {
logger *CondLogger
dialer ContextDialer
httptransport http.RoundTripper
auth AuthProvider
}
func NewProxyHandler(dialer ContextDialer, resolver *Resolver, logger *CondLogger) *ProxyHandler {
func NewProxyHandler(dialer, requestDialer ContextDialer, auth AuthProvider, resolver *Resolver, logger *CondLogger) *ProxyHandler {
dialer = NewRetryDialer(dialer, resolver, logger)
httptransport := &http.Transport{
Proxy: func(_ *http.Request) (*url.URL, error) {
return &url.URL{
Scheme: "http",
Host: "void",
}, nil
},
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
DialContext: dialer.DialContext,
DialContext: requestDialer.DialContext,
}
return &ProxyHandler{
logger: logger,
dialer: dialer,
auth: auth,
httptransport: httptransport,
}
}
@@ -74,6 +83,8 @@ func (s *ProxyHandler) HandleRequest(wr http.ResponseWriter, req *http.Request)
req.URL.Scheme = "http" // We can't access :scheme pseudo-header, so assume http
req.URL.Host = req.Host
}
delHopHeaders(req.Header)
req.Header.Add("Proxy-Authorization", s.auth())
resp, err := s.httptransport.RoundTrip(req)
if err != nil {
s.logger.Error("HTTP fetch error: %v", err)

View File

@@ -3,6 +3,7 @@ package main
import (
"bytes"
"context"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/json"
@@ -14,27 +15,44 @@ 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/89.0.4389.72 Safari/537.36"
const EXT_VER = "1.181.350"
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/129.0.0.0 Safari/537.36"
func SetUserAgent(ua string) {
userAgent = ua
}
func GetUserAgent() string {
return userAgent
}
type CountryList []string
@@ -153,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
@@ -189,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)
@@ -216,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) {
@@ -235,7 +254,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)
@@ -246,13 +265,21 @@ func zgettunnels(ctx context.Context,
reterr = err
return
}
reterr = json.Unmarshal(data, &tunnels)
err = json.Unmarshal(data, &tunnels)
if err != nil {
return nil, fmt.Errorf("unable to unmashal zgettunnels response: %w", err)
}
if len(tunnels.IPList) == 0 {
return nil, EmptyResponseError
}
res = &tunnels
return
}
func fetchFallbackConfig(ctx context.Context) (*FallbackConfig, error) {
confRaw, err := do_req(ctx, &http.Client{}, "", FALLBACK_CONF_URL, nil, nil)
client := httpClientWithProxy(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
}
@@ -312,56 +339,120 @@ 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) (res *ZGetTunnelsResponse, user_uuid string, reterr error) {
limit uint,
timeout time.Duration,
backoffInitial time.Duration,
backoffDeadline time.Duration,
) (res *ZGetTunnelsResponse, user_uuid string, reterr error) {
u := uuid.New()
user_uuid = hex.EncodeToString(u[:])
initres, err := background_init(ctx, client, user_uuid)
ctx1, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
initres, err := background_init(ctx1, client, extVer, user_uuid)
if err != nil {
reterr = err
return
}
res, reterr = zgettunnels(ctx, client, user_uuid, initres.Key, country, proxy_type, limit)
var bo backoff.BackOff = &backoff.ExponentialBackOff{
InitialInterval: backoffInitial,
RandomizationFactor: 0.5,
Multiplier: 1.5,
MaxInterval: 10 * time.Minute,
MaxElapsedTime: backoffDeadline,
Stop: backoff.Stop,
Clock: backoff.SystemClock,
}
bo = backoff.WithContext(bo, ctx)
err = backoff.RetryNotify(func() error {
ctx1, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
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))
})
if err != nil {
logger.Error("All attempts failed: %v", err)
return nil, "", err
}
return
}
var baseDialer ContextDialer = &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}
var tlsConfig *tls.Config
func UpdateHolaDialer(dialer ContextDialer) {
baseDialer = dialer
}
func UpdateHolaTLSConfig(config *tls.Config) {
tlsConfig = config
}
// 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,
}
var dialer ContextDialer = &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
var dialer ContextDialer = baseDialer
var rootCAs *x509.CertPool
if tlsConfig != nil {
rootCAs = tlsConfig.RootCAs
}
if agent != nil {
dialer = NewProxyDialer(agent.NetAddr(), agent.Hostname(), 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,
}
}
func EnsureTransaction(baseCtx context.Context, txnTimeout time.Duration, txn func(context.Context, *http.Client) bool) (bool, error) {
func EnsureTransaction(ctx context.Context, getFBTimeout time.Duration, txn func(context.Context, *http.Client) bool) (bool, error) {
client := httpClientWithProxy(nil)
defer client.CloseIdleConnections()
ctx, cancel := context.WithTimeout(baseCtx, txnTimeout)
defer cancel()
if txn(ctx, client) {
return true, nil
}
// Fallback needed
fbc, err := GetFallbackProxies(baseCtx)
getFBCtx, cancel := context.WithTimeout(ctx, getFBTimeout)
defer cancel()
fbc, err := GetFallbackProxies(getFBCtx)
if err != nil {
return false, err
}
@@ -369,10 +460,6 @@ func EnsureTransaction(baseCtx context.Context, txnTimeout time.Duration, txn fu
for _, agent := range fbc.Agents {
client = httpClientWithProxy(&agent)
defer client.CloseIdleConnections()
ctx, cancel = context.WithTimeout(baseCtx, txnTimeout)
defer cancel()
if txn(ctx, client) {
return true, nil
}
@@ -380,3 +467,12 @@ func EnsureTransaction(baseCtx context.Context, txnTimeout time.Duration, txn fu
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()
}

View File

@@ -1,2 +0,0 @@
#!/bin/bash
docker build --build-arg GIT_DESC="$(git describe)" -f "$DOCKERFILE_PATH" -t "$IMAGE_NAME" .

168
main.go
View File

@@ -1,13 +1,25 @@
package main
import (
"context"
"crypto/x509"
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"net/url"
"os"
"time"
tls "github.com/refraction-networking/utls"
xproxy "golang.org/x/net/proxy"
)
const (
HolaExtStoreID = "gkojfkhlekighikafcpjkiklfbnlmeio"
)
var (
@@ -35,6 +47,7 @@ func arg_fail(msg string) {
}
type CLIArgs struct {
extVer string
country string
list_countries, list_proxies, use_trial bool
limit uint
@@ -45,10 +58,22 @@ type CLIArgs struct {
resolver string
force_port_field string
showVersion bool
proxy string
caFile string
minPause time.Duration
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
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")
@@ -57,15 +82,25 @@ 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.StringVar(&args.proxy_type, "proxy-type", "direct", "proxy type: direct or peer or lum or virt or pool") // or skip but not mentioned
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.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.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.")
@@ -86,13 +121,6 @@ func run() int {
return 0
}
if args.list_countries {
return print_countries(args.timeout)
}
if args.list_proxies {
return print_proxies(args.country, args.proxy_type, args.limit, args.timeout)
}
logWriter := NewLogWriter(os.Stderr)
defer logWriter.Close()
@@ -105,33 +133,112 @@ func run() int {
proxyLogger := NewCondLogger(log.New(logWriter, "PROXY : ",
log.LstdFlags|log.Lshortfile),
args.verbosity)
var dialer ContextDialer = &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}
var caPool *x509.CertPool
if args.caFile != "" {
caPool = x509.NewCertPool()
certs, err := ioutil.ReadFile(args.caFile)
if err != nil {
mainLogger.Error("Can't load CA file: %v", err)
return 15
}
if ok := caPool.AppendCertsFromPEM(certs); !ok {
mainLogger.Error("Can't load certificates from CA file")
return 15
}
UpdateHolaTLSConfig(&tls.Config{
RootCAs: caPool,
})
}
proxyFromURLWrapper := func(u *url.URL, next xproxy.Dialer) (xproxy.Dialer, error) {
cdialer, ok := next.(ContextDialer)
if !ok {
return nil, errors.New("only context dialers are accepted")
}
return ProxyDialerFromURL(u, caPool, cdialer)
}
if args.proxy != "" {
xproxy.RegisterDialerType("http", proxyFromURLWrapper)
xproxy.RegisterDialerType("https", proxyFromURLWrapper)
proxyURL, err := url.Parse(args.proxy)
if err != nil {
mainLogger.Critical("Unable to parse base proxy URL: %v", err)
return 6
}
pxDialer, err := xproxy.FromURL(proxyURL, dialer)
if err != nil {
mainLogger.Critical("Unable to instantiate base proxy dialer: %v", err)
return 7
}
dialer = pxDialer.(ContextDialer)
UpdateHolaDialer(dialer)
}
SetUserAgent(args.userAgent)
try := retryPolicy(args.initRetries, args.initRetryInterval, mainLogger)
if args.list_countries {
return print_countries(try, args.timeout)
}
mainLogger.Info("hola-proxy client version %s is starting...", version)
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)
args.extVer = extVer
return err
})
if err != nil {
mainLogger.Critical("Can't detect latest API 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)
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)
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)
logWriter.Close()
return 4
}
endpoint, err := get_endpoint(tunnels, args.proxy_type, args.use_trial, args.force_port_field)
if err != nil {
mainLogger.Critical("Unable to determine proxy endpoint: %v", err)
logWriter.Close()
return 5
}
var dialer ContextDialer = NewProxyDialer(endpoint.NetAddr(), endpoint.TLSName, auth, &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
})
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(dialer, resolver, proxyLogger)
handler := NewProxyHandler(handlerDialer, requestDialer, auth, resolver, proxyLogger)
mainLogger.Info("Init complete.")
err = http.ListenAndServe(args.bind_address, handler)
mainLogger.Critical("Server terminated with a reason: %v", err)
@@ -142,3 +249,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
}
}

77
plaintext.go Normal file
View File

@@ -0,0 +1,77 @@
package main
import (
"context"
"crypto/x509"
"errors"
"net"
tls "github.com/refraction-networking/utls"
)
type PlaintextDialer struct {
fixedAddress string
tlsServerName string
next ContextDialer
caPool *x509.CertPool
hideSNI bool
}
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,
}
}
func (d *PlaintextDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
switch network {
case "tcp", "tcp4", "tcp6":
default:
return nil, errors.New("bad network specified for DialContext: only tcp is supported")
}
conn, err := d.next.DialContext(ctx, "tcp", d.fixedAddress)
if err != nil {
return nil, err
}
if d.tlsServerName != "" {
// Custom cert verification logic:
// DO NOT send SNI extension of TLS ClientHello
// DO peer certificate verification against specified 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{
DNSName: d.tlsServerName,
Intermediates: x509.NewCertPool(),
Roots: d.caPool,
}
for _, cert := range cs.PeerCertificates[1:] {
opts.Intermediates.AddCert(cert)
}
_, 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
}
func (d *PlaintextDialer) Dial(network, address string) (net.Conn, error) {
return d.DialContext(context.Background(), network, address)
}

View File

@@ -1,9 +1,10 @@
package main
import (
"time"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/miekg/dns"
"time"
)
type Resolver struct {
@@ -13,7 +14,7 @@ type Resolver struct {
const DOT = 0x2e
func NewResolver(address string, timeout time.Duration) (*Resolver, error) {
opts := upstream.Options{Timeout: timeout}
opts := &upstream.Options{Timeout: timeout}
u, err := upstream.AddressToUpstream(address, opts)
if err != nil {
return nil, err

View File

@@ -37,3 +37,7 @@ func (d *RetryDialer) DialContext(ctx context.Context, network, address string)
}
return conn, err
}
func (d *RetryDialer) Dial(network, address string) (net.Conn, error) {
return d.DialContext(context.Background(), network, address)
}

View File

@@ -1,5 +1,5 @@
name: hola-proxy
version: '1.4.6'
version: '1.15.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,13 +4,17 @@ import (
"bufio"
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/http/httputil"
"net/url"
"strings"
tls "github.com/refraction-networking/utls"
)
const (
@@ -21,7 +25,12 @@ const (
var UpstreamBlockedError = errors.New("blocked by upstream")
type Dialer interface {
Dial(network, address string) (net.Conn, error)
}
type ContextDialer interface {
Dialer
DialContext(ctx context.Context, network, address string) (net.Conn, error)
}
@@ -30,17 +39,54 @@ type ProxyDialer struct {
tlsServerName string
auth AuthProvider
next ContextDialer
caPool *x509.CertPool
hideSNI bool
}
func NewProxyDialer(address, tlsServerName string, 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,
}
}
func ProxyDialerFromURL(u *url.URL, caPool *x509.CertPool, next ContextDialer) (*ProxyDialer, error) {
host := u.Hostname()
port := u.Port()
tlsServerName := ""
var auth AuthProvider = nil
switch strings.ToLower(u.Scheme) {
case "http":
if port == "" {
port = "80"
}
case "https":
if port == "" {
port = "443"
}
tlsServerName = host
default:
return nil, errors.New("unsupported proxy type")
}
address := net.JoinHostPort(host, port)
if u.User != nil {
username := u.User.Username()
password, _ := u.User.Password()
authHeader := basic_auth_header(username, password)
auth = func() string {
return authHeader
}
}
return NewProxyDialer(address, tlsServerName, caPool, auth, false, next), nil
}
func (d *ProxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
switch network {
case "tcp", "tcp4", "tcp6":
@@ -57,13 +103,18 @@ 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{
DNSName: d.tlsServerName,
Intermediates: x509.NewCertPool(),
Roots: d.caPool,
}
for _, cert := range cs.PeerCertificates[1:] {
opts.Intermediates.AddCert(cert)
@@ -71,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{
@@ -110,12 +161,16 @@ func (d *ProxyDialer) DialContext(ctx context.Context, network, address string)
proxyResp.Header.Get("X-Hola-Error") == "Forbidden Host" {
return nil, UpstreamBlockedError
}
return nil, errors.New("Bad response from upstream proxy server")
return nil, errors.New(fmt.Sprintf("bad response from upstream proxy server: %s", proxyResp.Status))
}
return conn, nil
}
func (d *ProxyDialer) Dial(network, address string) (net.Conn, error) {
return d.DialContext(context.Background(), network, address)
}
func readResponse(r io.Reader, req *http.Request) (*http.Response, error) {
endOfResponse := []byte("\r\n\r\n")
buf := &bytes.Buffer{}

View File

@@ -8,6 +8,7 @@ import (
"errors"
"fmt"
"io"
"math/rand"
"net"
"net/http"
"net/url"
@@ -105,25 +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 {
countries, err = VPNCountries(ctx, 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 {
@@ -132,30 +141,38 @@ func print_countries(timeout time.Duration) int {
return 0
}
func print_proxies(country string, proxy_type string, limit uint, timeout time.Duration) int {
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, client, country, proxy_type, limit)
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)
@@ -292,3 +309,11 @@ func copyBody(wr io.Writer, body io.Reader) {
}
}
}
func RandRange(low, hi int64) int64 {
if low >= hi {
panic("RandRange: low boundary is greater or equal to high boundary")
}
delta := hi - low
return low + rand.New(RandomSource).Int63n(delta+1)
}