mirror of
https://github.com/Snawoot/hola-proxy.git
synced 2026-04-09 18:08:35 +00:00
138 lines
3.4 KiB
Go
138 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"context"
|
|
"net"
|
|
"sync"
|
|
"io"
|
|
"os"
|
|
"time"
|
|
"encoding/base64"
|
|
"encoding/csv"
|
|
"errors"
|
|
"strings"
|
|
"strconv"
|
|
"net/http"
|
|
)
|
|
|
|
func basic_auth_header(login, password string) string {
|
|
return "basic " + base64.StdEncoding.EncodeToString(
|
|
[]byte(login + ":" + password))
|
|
}
|
|
|
|
func proxy(ctx context.Context, left, right net.Conn) {
|
|
wg := sync.WaitGroup{}
|
|
cpy := func (dst, src net.Conn) {
|
|
defer wg.Done()
|
|
io.Copy(dst, src)
|
|
dst.Close()
|
|
}
|
|
wg.Add(2)
|
|
go cpy(left, right)
|
|
go cpy(right, left)
|
|
groupdone := make(chan struct{})
|
|
go func() {
|
|
wg.Wait()
|
|
groupdone <-struct{}{}
|
|
}()
|
|
select {
|
|
case <-ctx.Done():
|
|
left.Close()
|
|
right.Close()
|
|
case <-groupdone:
|
|
return
|
|
}
|
|
<-groupdone
|
|
return
|
|
}
|
|
|
|
func print_countries(timeout time.Duration) int {
|
|
ctx, _ := context.WithTimeout(context.Background(), timeout)
|
|
countries, err := VPNCountries(ctx)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
return 3
|
|
}
|
|
for _, code := range countries {
|
|
fmt.Printf("%v - %v\n", code, ISO3166[strings.ToUpper(code)])
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func print_proxies(country string, limit uint, timeout time.Duration) int {
|
|
ctx, _ := context.WithTimeout(context.Background(), timeout)
|
|
tunnels, user_uuid, err := Tunnels(ctx, country, limit)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
return 3
|
|
}
|
|
wr := csv.NewWriter(os.Stdout)
|
|
login := LOGIN_PREFIX + user_uuid
|
|
password := tunnels.AgentKey
|
|
fmt.Println("Login:", login)
|
|
fmt.Println("Password:", password)
|
|
fmt.Println("Proxy-Authorization:",
|
|
basic_auth_header(login, password))
|
|
fmt.Println("")
|
|
wr.Write([]string{"Host", "IP address", "Direct port", "Peer port", "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),
|
|
tunnels.Vendor[host]})
|
|
}
|
|
}
|
|
wr.Flush()
|
|
return 0
|
|
}
|
|
|
|
func get_endpoint(tunnels *ZGetTunnelsResponse, typ string) (string, error) {
|
|
var hostname string
|
|
for k, _ := range tunnels.IPList {
|
|
hostname = k
|
|
break
|
|
}
|
|
if hostname == "" {
|
|
return "", errors.New("No tunnels found in API response")
|
|
}
|
|
var port uint16
|
|
if typ == "direct" {
|
|
port = tunnels.Port.Direct
|
|
} else if typ == "peer" {
|
|
port = tunnels.Port.Peer
|
|
} else {
|
|
return "", errors.New("Unsupported port type")
|
|
}
|
|
return net.JoinHostPort(hostname, strconv.FormatUint(uint64(port), 10)), nil
|
|
}
|
|
|
|
// Hop-by-hop headers. These are removed when sent to the backend.
|
|
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
|
|
var hopHeaders = []string{
|
|
"Connection",
|
|
"Keep-Alive",
|
|
"Proxy-Authenticate",
|
|
"Te", // canonicalized version of "TE"
|
|
"Trailers",
|
|
"Transfer-Encoding",
|
|
"Upgrade",
|
|
}
|
|
|
|
func copyHeader(dst, src http.Header) {
|
|
for k, vv := range src {
|
|
for _, v := range vv {
|
|
dst.Add(k, v)
|
|
}
|
|
}
|
|
}
|
|
|
|
func delHopHeaders(header http.Header) {
|
|
for _, h := range hopHeaders {
|
|
header.Del(h)
|
|
}
|
|
}
|
|
|