Compare commits

...

13 Commits

Author SHA1 Message Date
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
9 changed files with 154 additions and 25 deletions

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

@@ -0,0 +1,58 @@
name: docker-ci
on:
push:
branches:
- 'master'
release:
types: [published]
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
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: Determine image tag type
uses: haya14busa/action-cond@v1
id: imgtag
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
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
-
name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64,linux/arm64,linux/386,linux/arm/v7
push: true
tags: ${{ steps.imgtag.outputs.value }}
build-args: 'GIT_DESC=${{steps.tagger.outputs.tag}}'

View File

@@ -13,7 +13,8 @@ GO := go
src = $(wildcard *.go)
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 \
@@ -27,6 +28,11 @@ 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
@@ -54,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 $@
@@ -113,6 +134,11 @@ 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 \

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`).
---
@@ -157,6 +157,7 @@ zagent248.hola.org,165.22.65.3,22222,22223,22224,22225,22226,digitalocean
| Argument | Type | Description |
| -------- | ---- | ----------- |
| 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 |
| force-port-field | Number | force specific port field/num (example 24232 or lum) |
@@ -164,8 +165,12 @@ zagent248.hola.org,165.22.65.3,22222,22223,22224,22225,22226,digitalocean
| 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, virt) (Residential: peer, lum, pool) (default "direct") |
| 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) |
| 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)

View File

@@ -3,6 +3,8 @@ package main
import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/json"
@@ -21,8 +23,8 @@ import (
"github.com/google/uuid"
)
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 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/"
@@ -333,10 +335,16 @@ var baseDialer ContextDialer = &net.Dialer{
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{
@@ -345,10 +353,15 @@ func httpClientWithProxy(agent *FallbackAgent) *http.Client {
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: tlsConfig,
}
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, dialer)
}
t.DialContext = dialer.DialContext
return &http.Client{

View File

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

47
main.go
View File

@@ -1,9 +1,12 @@
package main
import (
"crypto/tls"
"crypto/x509"
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
@@ -50,6 +53,7 @@ type CLIArgs struct {
force_port_field string
showVersion bool
proxy string
caFile string
}
func parse_args() CLIArgs {
@@ -64,7 +68,7 @@ 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 or lum or virt or pool") // or skip but not mentioned
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. "+
@@ -74,6 +78,7 @@ func parse_args() CLIArgs {
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.Parse()
if args.country == "" {
arg_fail("Country can't be empty string.")
@@ -87,15 +92,6 @@ func parse_args() CLIArgs {
return args
}
func proxyFromURLWrapper(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, cdialer)
}
func run() int {
args := parse_args()
if args.showVersion {
@@ -120,6 +116,33 @@ func run() int {
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)
@@ -163,8 +186,8 @@ func run() int {
mainLogger.Critical("Unable to determine proxy endpoint: %v", err)
return 5
}
handlerDialer := NewProxyDialer(endpoint.NetAddr(), endpoint.TLSName, auth, dialer)
requestDialer := NewPlaintextDialer(endpoint.NetAddr(), endpoint.TLSName, dialer)
handlerDialer := NewProxyDialer(endpoint.NetAddr(), endpoint.TLSName, caPool, auth, dialer)
requestDialer := NewPlaintextDialer(endpoint.NetAddr(), endpoint.TLSName, caPool, dialer)
mainLogger.Info("Endpoint: %s", endpoint.URL().String())
mainLogger.Info("Starting proxy server...")
handler := NewProxyHandler(handlerDialer, requestDialer, auth, resolver, proxyLogger)

View File

@@ -12,13 +12,15 @@ type PlaintextDialer struct {
fixedAddress string
tlsServerName string
next ContextDialer
caPool *x509.CertPool
}
func NewPlaintextDialer(address, tlsServerName string, next ContextDialer) *PlaintextDialer {
func NewPlaintextDialer(address, tlsServerName string, caPool *x509.CertPool, next ContextDialer) *PlaintextDialer {
return &PlaintextDialer{
fixedAddress: address,
tlsServerName: tlsServerName,
next: next,
caPool: caPool,
}
}
@@ -45,6 +47,7 @@ func (d *PlaintextDialer) DialContext(ctx context.Context, network, address stri
opts := x509.VerifyOptions{
DNSName: d.tlsServerName,
Intermediates: x509.NewCertPool(),
Roots: d.caPool,
}
for _, cert := range cs.PeerCertificates[1:] {
opts.Intermediates.AddCert(cert)

View File

@@ -1,5 +1,5 @@
name: hola-proxy
version: '1.5.1'
version: '1.5.4'
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

@@ -38,18 +38,20 @@ type ProxyDialer struct {
tlsServerName string
auth AuthProvider
next ContextDialer
caPool *x509.CertPool
}
func NewProxyDialer(address, tlsServerName string, auth AuthProvider, nextDialer ContextDialer) *ProxyDialer {
func NewProxyDialer(address, tlsServerName string, caPool *x509.CertPool, auth AuthProvider, nextDialer ContextDialer) *ProxyDialer {
return &ProxyDialer{
address: address,
tlsServerName: tlsServerName,
auth: auth,
next: nextDialer,
caPool: caPool,
}
}
func ProxyDialerFromURL(u *url.URL, next ContextDialer) (*ProxyDialer, error) {
func ProxyDialerFromURL(u *url.URL, caPool *x509.CertPool, next ContextDialer) (*ProxyDialer, error) {
host := u.Hostname()
port := u.Port()
tlsServerName := ""
@@ -79,7 +81,7 @@ func ProxyDialerFromURL(u *url.URL, next ContextDialer) (*ProxyDialer, error) {
return authHeader
}
}
return NewProxyDialer(address, tlsServerName, auth, next), nil
return NewProxyDialer(address, tlsServerName, caPool, auth, next), nil
}
func (d *ProxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
@@ -105,6 +107,7 @@ func (d *ProxyDialer) DialContext(ctx context.Context, network, address string)
opts := x509.VerifyOptions{
DNSName: d.tlsServerName,
Intermediates: x509.NewCertPool(),
Roots: d.caPool,
}
for _, cert := range cs.PeerCertificates[1:] {
opts.Intermediates.AddCert(cert)