Compare commits

..

17 Commits

Author SHA1 Message Date
Snawoot
a95a6519aa Merge pull request #14 from rany2/master
Fix #13 and enhancements
2021-03-06 21:00:42 +02:00
rany
5774d898d2 update country list from readme 2021-03-06 20:13:43 +02:00
rany
8a3b18e784 update readme 2021-03-06 20:13:01 +02:00
rany
3ebfea6b86 switch back default port 2021-03-06 20:09:56 +02:00
rany
92b7a509e9 remove binary 2021-03-06 20:07:11 +02:00
rany
d4b8306cd4 Fix #13 and enhacements
* Add `-use-trial` to use trial ports.
* Mention Hola and Trial ports in `-list-proxies`
* Add GB to `-list-countries` if UK is present. This is what extension does.
* Add `lum` proxy-type to use residential ips
* Change `peer` and `lum` behavior to also modify the country to `country_code`.peer and `country_code`.pool_lum_`country_code`._shared. This lets them work properly
* Above means that `list-proxies` behavior will change based on `-proxy-type` now(The port isn't the only thing that matters)
2021-03-06 20:03:01 +02:00
Vladislav Yarmak
335894d533 add IPFS mirror 2020-10-24 20:23:54 +03:00
Vladislav Yarmak
d95706046d update readme 2020-08-10 00:50:26 +03:00
Vladislav Yarmak
6fecb99728 add endpoint info to log 2020-05-18 02:00:56 +03:00
Snawoot
0d0cbca13e Merge pull request #3 from Snawoot/readme_upd
doc update
2020-04-20 22:37:57 +03:00
Vladislav Yarmak
3462113454 doc update 2020-04-20 22:34:58 +03:00
Vladislav Yarmak
db9499a936 snap: add required plugs 2020-04-20 22:18:34 +03:00
Vladislav Yarmak
1052329228 add snap build spec 2020-04-20 21:29:45 +03:00
Vladislav Yarmak
94addea5d4 single-layer docker image 2020-04-18 14:04:43 +03:00
Vladislav Yarmak
56a10f2a32 fix docker example 2020-04-18 12:44:40 +03:00
Snawoot
801178a7de Merge pull request #2 from Snawoot/docker
add docker support
2020-04-18 12:33:59 +03:00
Vladislav Yarmak
6d627de3d7 add docker support 2020-04-18 12:30:26 +03:00
11 changed files with 173 additions and 33 deletions

1
.dockerignore Normal file
View File

@@ -0,0 +1 @@
bin/

4
.gitignore vendored
View File

@@ -14,3 +14,7 @@
# Dependency directories (remove the comment below to include it)
# vendor/
bin/
*.snap
# hola-proxy binary
hola-proxy

17
Dockerfile Normal file
View File

@@ -0,0 +1,17 @@
FROM golang AS build
WORKDIR /go/src/github.com/Snawoot/hola-proxy
COPY . .
RUN CGO_ENABLED=0 go build -a -tags netgo -ldflags '-s -w -extldflags "-static"'
ADD https://curl.haxx.se/ca/cacert.pem /certs.crt
RUN chmod 0644 /certs.crt
FROM scratch AS arrange
COPY --from=build /go/src/github.com/Snawoot/hola-proxy/hola-proxy /
COPY --from=build /certs.crt /etc/ssl/certs/ca-certificates.crt
FROM scratch
COPY --from=arrange / /
USER 9999:9999
EXPOSE 8080/tcp
ENTRYPOINT ["/hola-proxy", "-bind-address", "0.0.0.0:8080"]

View File

@@ -1,9 +1,32 @@
# hola-proxy
[![hola-proxy](https://snapcraft.io//hola-proxy/badge.svg)](https://snapcraft.io/hola-proxy)
Standalone Hola proxy client. Just run it and it'll start plain HTTP proxy server forwarding traffic via Hola proxies of your choice. By default application listens port 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 peer`).
---
:heart: :heart: :heart:
You can say thanks to the author by donations to these wallets:
- ETH: `0xB71250010e8beC90C5f9ddF408251eBA9dD7320e`
- BTC:
- Legacy: `1N89PRvG1CSsUk9sxKwBwudN6TjTPQ1N8a`
- Segwit: `bc1qc0hcyxc000qf0ketv4r44ld7dlgmmu73rtlntw`
---
## Mirrors
IPFS git mirror:
```
git clone https://ipfs.io/ipns/k51qzi5uqu5dkrgx0hozpy1tlggw5o0whtquyrjlc6pprhvbmczr6qtj4ocrv0 hola-proxy
```
## Features
* Cross-platform (Windows/Mac OS/Linux/Android (via shell)/\*BSD)
@@ -12,14 +35,39 @@ Application is capable to forward traffic via proxies in datacenters (flag `-pro
## Installation
#### Binary download
Pre-built binaries available on [releases](https://github.com/Snawoot/hola-proxy/releases/latest) page.
#### From source
Alternatively, you may install hola-proxy from source. Run within source directory
```
go install
```
#### Docker
Docker image is available as well. Here is an example for running proxy via DE as a background service:
```sh
docker run -d \
--security-opt no-new-privileges \
-p 127.0.0.1:8080:8080 \
--restart unless-stopped \
--name hola-proxy \
yarmak/hola-proxy -country de
```
#### Snap Store
[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/hola-proxy)
```bash
sudo snap install hola-proxy
```
## Usage
List available countries:
@@ -42,8 +90,10 @@ dk - Denmark
es - Spain
fi - Finland
fr - France
gb - United Kingdom (Great Britain)
gr - Greece
hk - Hong Kong
hr - Croatia
hu - Hungary
id - Indonesia
ie - Ireland
@@ -77,21 +127,21 @@ $ ~/go/bin/hola-proxy -country de
Or run proxy on residental IP:
```
$ ~/go/bin/hola-proxy -country de -proxy-type peer
$ ~/go/bin/hola-proxy -country de -proxy-type lum
```
Also it is possible to export proxy addresses and credentials:
```
$ ~/go/bin/hola-proxy -country de -list-proxies -limit 3
Login: user-uuid-f4c2c3a8657640048e7243a807867d52
Password: e194c4f457e0
Proxy-Authorization: basic dXNlci11dWlkLWY0YzJjM2E4NjU3NjQwMDQ4ZTcyNDNhODA3ODY3ZDUyOmUxOTRjNGY0NTdlMA==
Login: user-uuid-0a67c797b3214cbdb432b089c4b801cd
Password: cd123c465901
Proxy-Authorization: basic dXNlci11dWlkLTBhNjdjNzk3YjMyMTRjYmRiNDMyYjA4OWM0YjgwMWNkOmNkMTIzYzQ2NTkwMQ==
Host,IP address,Direct port,Peer port,Vendor
zagent90.hola.org,185.72.246.203,22222,22223,nqhost
zagent249.hola.org,165.22.80.107,22222,22223,digitalocean
zagent248.hola.org,165.22.65.3,22222,22223,digitalocean
host,ip_address,direct,peer,hola,trial,trial_peer,vendor
zagent783.hola.org,165.22.22.6,22222,22223,22224,22225,22226,digitalocean
zagent830.hola.org,104.248.24.64,22222,22223,22224,22225,22226,digitalocean
zagent248.hola.org,165.22.65.3,22222,22223,22224,22225,22226,digitalocean
```
## Synopsis
@@ -110,14 +160,15 @@ Usage of /home/user/go/bin/hola-proxy:
-list-proxies
output proxy list and exit
-proxy-type string
proxy type: direct or peer (default "direct")
proxy type: direct or peer or 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)
-use-trial
use trial ports instead of regular ports
-verbosity int
logging verbosity (10 - debug, 20 - info, 30 - warning, 40 - error, 50 - critical) (default 20)
```

View File

@@ -11,6 +11,7 @@ const API_CALL_ATTEMPTS = 3
func CredService(interval, timeout time.Duration,
country string,
proxytype string,
logger *CondLogger) (auth AuthProvider,
tunnels *ZGetTunnelsResponse,
err error) {
@@ -25,7 +26,7 @@ func CredService(interval, timeout time.Duration,
for i := 0; i < API_CALL_ATTEMPTS ; i++ {
ctx, _ := context.WithTimeout(context.Background(), timeout)
tunnels, user_uuid, err = Tunnels(ctx, country, DEFAULT_LIST_LIMIT)
tunnels, user_uuid, err = Tunnels(ctx, country, proxytype, DEFAULT_LIST_LIMIT)
if err == nil {
break
}
@@ -49,7 +50,7 @@ func CredService(interval, timeout time.Duration,
logger.Info("Rotating credentials...")
for i := 0; i < API_CALL_ATTEMPTS ; i++ {
ctx, _ := context.WithTimeout(context.Background(), timeout)
tuns, user_uuid, err = Tunnels(ctx, country, DEFAULT_LIST_LIMIT)
tuns, user_uuid, err = Tunnels(ctx, country, proxytype, DEFAULT_LIST_LIMIT)
if err == nil {
break
}

1
go.mod
View File

@@ -4,6 +4,7 @@ go 1.13
require (
github.com/AdguardTeam/dnsproxy v0.25.0
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e
github.com/google/uuid v1.1.1
github.com/miekg/dns v1.1.29
)

2
go.sum
View File

@@ -11,6 +11,8 @@ github.com/ameshkov/dnscrypt v1.1.0/go.mod h1:ikduAxNLCTEfd1AaCgpIA5TgroIVQ8JY3V
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/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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

View File

@@ -11,10 +11,11 @@ import (
"bytes"
"strconv"
"math/rand"
"github.com/campoy/unique"
)
const USER_AGENT = "Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"
const EXT_VER = "1.164.641"
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/"
@@ -96,6 +97,13 @@ func VPNCountries(ctx context.Context) (res CountryList, err error) {
return nil, err
}
err = json.Unmarshal(data, &res)
for _, a := range res {
if a == "uk" {
res = append(res, "gb")
}
}
less := func(i, j int) bool { return res[i] < res[j] }
unique.Slice(&res, less)
return
}
@@ -118,10 +126,17 @@ func zgettunnels(ctx context.Context,
user_uuid string,
session_key int64,
country string,
proxy_type string,
limit uint) (res *ZGetTunnelsResponse, reterr error) {
var tunnels ZGetTunnelsResponse
params := make(url.Values)
params.Add("country", country)
if proxy_type == "lum" {
params.Add("country", country + ".pool_lum_" + country + "_shared")
} else if proxy_type == "peer" {
params.Add("country", country + ".peer")
} else {
params.Add("country", country)
}
params.Add("limit", strconv.FormatInt(int64(limit), 10))
params.Add("ping_id", strconv.FormatFloat(rand.Float64(), 'f', -1, 64))
params.Add("ext_ver", EXT_VER)
@@ -142,6 +157,7 @@ func zgettunnels(ctx context.Context,
func Tunnels(ctx context.Context,
country string,
proxy_type string,
limit uint) (res *ZGetTunnelsResponse, user_uuid string, reterr error) {
u := uuid.New()
user_uuid = hex.EncodeToString(u[:])
@@ -150,6 +166,6 @@ func Tunnels(ctx context.Context,
reterr = err
return
}
res, reterr = zgettunnels(ctx, user_uuid, initres.Key, country, limit)
res, reterr = zgettunnels(ctx, user_uuid, initres.Key, country, proxy_type, limit)
return
}

32
main.go
View File

@@ -36,7 +36,7 @@ func arg_fail(msg string) {
type CLIArgs struct {
country string
list_countries, list_proxies bool
list_countries, list_proxies, use_trial bool
limit uint
bind_address string
verbosity int
@@ -57,27 +57,31 @@ func parse_args() CLIArgs {
"(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")
flag.StringVar(&args.proxy_type, "proxy-type", "direct", "proxy type: direct or peer or lum")
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, "use-trial", false, "use trial ports instead of regular ports")
flag.Parse()
if args.country == "" {
arg_fail("Country can't be empty string.")
}
if args.proxy_type == "" {
arg_fail("Proxy type can't be an empty string.")
}
if args.list_countries && args.list_proxies {
arg_fail("list-countries and list-proxies flags are mutually exclusive")
}
return args
}
func main() {
func run() int {
args := parse_args()
if args.list_countries {
os.Exit(print_countries(args.timeout))
return print_countries(args.timeout)
}
if args.list_proxies {
os.Exit(print_proxies(args.country, args.limit, args.timeout))
return print_proxies(args.country, args.proxy_type, args.limit, args.timeout)
}
logWriter := NewLogWriter(os.Stderr)
@@ -96,22 +100,30 @@ func main() {
resolver, err := NewResolver(args.resolver, args.timeout)
if err != nil {
mainLogger.Critical("Unable to instantiate DNS resolver: %v", err)
os.Exit(6)
return 6
}
mainLogger.Info("Initializing configuration provider...")
auth, tunnels, err := CredService(args.rotate, args.timeout, args.country, credLogger)
auth, tunnels, err := CredService(args.rotate, args.timeout, args.country, args.proxy_type, credLogger)
if err != nil {
mainLogger.Critical("Unable to instantiate credential service: %v", err)
os.Exit(4)
logWriter.Close()
return 4
}
endpoint, err := get_endpoint(tunnels, args.proxy_type)
endpoint, err := get_endpoint(tunnels, args.proxy_type, args.use_trial)
if err != nil {
mainLogger.Critical("Unable to determine proxy endpoint: %v", err)
os.Exit(5)
logWriter.Close()
return 5
}
mainLogger.Info("Endpoint: %s", endpoint)
mainLogger.Info("Starting proxy server...")
handler := NewProxyHandler(endpoint, auth, resolver, proxyLogger)
err = http.ListenAndServe(args.bind_address, handler)
mainLogger.Critical("Server terminated with a reason: %v", err)
mainLogger.Info("Shutting down...")
return 0
}
func main() {
os.Exit(run())
}

24
snapcraft.yaml Normal file
View File

@@ -0,0 +1,24 @@
name: hola-proxy
version: '1.1.2'
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
parts:
hola-proxy:
plugin: go
go-importpath: github.com/Snawoot/hola-proxy
source: https://github.com/Snawoot/hola-proxy
source-type: git
build-packages:
- gcc
apps:
hola-proxy:
command: bin/hola-proxy
plugs:
- network
- network-bind

View File

@@ -62,9 +62,9 @@ func print_countries(timeout time.Duration) int {
return 0
}
func print_proxies(country string, limit uint, timeout time.Duration) int {
func print_proxies(country string, proxy_type string, limit uint, timeout time.Duration) int {
ctx, _ := context.WithTimeout(context.Background(), timeout)
tunnels, user_uuid, err := Tunnels(ctx, country, limit)
tunnels, user_uuid, err := Tunnels(ctx, country, proxy_type, limit)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
return 3
@@ -77,13 +77,16 @@ func print_proxies(country string, limit uint, timeout time.Duration) int {
fmt.Println("Proxy-Authorization:",
basic_auth_header(login, password))
fmt.Println("")
wr.Write([]string{"Host", "IP address", "Direct port", "Peer port", "Vendor"})
wr.Write([]string{"host", "ip_address", "direct", "peer", "hola", "trial", "trial_peer", "vendor"})
for host, ip := range tunnels.IPList {
if (PROTOCOL_WHITELIST[tunnels.Protocol[host]]) {
wr.Write([]string{host,
ip,
strconv.FormatUint(uint64(tunnels.Port.Direct), 10),
strconv.FormatUint(uint64(tunnels.Port.Peer), 10),
strconv.FormatUint(uint64(tunnels.Port.Hola), 10),
strconv.FormatUint(uint64(tunnels.Port.Trial), 10),
strconv.FormatUint(uint64(tunnels.Port.TrialPeer), 10),
tunnels.Vendor[host]})
}
}
@@ -91,7 +94,7 @@ func print_proxies(country string, limit uint, timeout time.Duration) int {
return 0
}
func get_endpoint(tunnels *ZGetTunnelsResponse, typ string) (string, error) {
func get_endpoint(tunnels *ZGetTunnelsResponse, typ string, trial bool) (string, error) {
var hostname string
for k, _ := range tunnels.IPList {
hostname = k
@@ -102,9 +105,17 @@ func get_endpoint(tunnels *ZGetTunnelsResponse, typ string) (string, error) {
}
var port uint16
if typ == "direct" {
port = tunnels.Port.Direct
} else if typ == "peer" {
port = tunnels.Port.Peer
if trial {
port = tunnels.Port.Trial
} else {
port = tunnels.Port.Direct
}
} else if typ == "peer" || typ == "lum" {
if trial {
port = tunnels.Port.TrialPeer
} else {
port = tunnels.Port.Peer
}
} else {
return "", errors.New("Unsupported port type")
}