Skip to content

Commit

Permalink
Implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mtojek committed Mar 4, 2019
1 parent a490e7d commit 433c674
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# IDEA
*.iml
.idea/
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
build: clean-code install

clean-code:
go get golang.org/x/tools/cmd/goimports && goimports -w .
gofmt -s -w .
go get golang.org/x/lint/golint && golint -set_exit_status ./...

install:
go get -v github.com/mtojek/ohlavpn

47 changes: 47 additions & 0 deletions ipapi/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package ipapi

import (
"encoding/json"
"fmt"
"net/http"
)

const baseUri = "http://ip-api.com/json"

type IPApi struct{}

type GeoIPData struct {
As string
City string
Country string
ISP string
Org string
RegionName string
Zip string
}

func (g *GeoIPData) String() string {
return fmt.Sprintf("%s\t%s\t%s\t%s\t\t%s\t%s\t%s", g.As, g.City, g.Country, g.ISP, g.Org, g.RegionName,
g.Zip)
}

func NewIPApi() *IPApi {
return new(IPApi)
}

func (api *IPApi) GeoIP(ip string) (*GeoIPData, error) {
response, err := http.Get(baseUri + "/" + ip)
if err != nil {
return nil, err
}

defer response.Body.Close()
var r GeoIPData

err = json.NewDecoder(response.Body).Decode(&r)
if err != nil {
return nil, err
}

return &r, nil
}
54 changes: 54 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package main

import (
"flag"
"fmt"
"log"

"github.com/mtojek/ohlavpn/ipapi"
"github.com/mtojek/ohlavpn/vpn"
)

func main() {
var countryCode string
var limit int
var geoIP bool

flag.StringVar(&countryCode, "c", "us", "country code")
flag.IntVar(&limit, "l", 5, "proxy server limit")
flag.BoolVar(&geoIP, "g", false, "check GeoIP data")
flag.Parse()

ipApiClient := ipapi.NewIPApi()
vpnClient := vpn.NewClient()
err := vpnClient.Initialize()
if err != nil {
log.Fatalf("Error occurred while initializing VPN API vpnClient: %v", err)
}

tunnels, err := vpnClient.FindTunnels(countryCode, limit)
if err != nil {
log.Fatalf("Error occurred while finding VPN tunnels: %v", err)
}

if len(tunnels.Servers) == 0 {
log.Fatal("No proxy servers found")
}

fmt.Printf("Login: %s, Password: %s\n\n", tunnels.Login, tunnels.Password)

for _, tunnel := range tunnels.Servers {
fmt.Print(tunnel.String())

if geoIP {
geoIPData, err := ipApiClient.GeoIP(tunnel.Host)
if err != nil {
fmt.Printf("\terror checking GeoIP data: %v", err)
} else {
fmt.Printf("\t%v", geoIPData.String())
}
}

fmt.Println()
}
}
131 changes: 131 additions & 0 deletions vpn/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package vpn

import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"

"github.com/google/uuid"
)

const (
baseUri = "https://client.hola.org/client_cgi"

browser = "chrome"
extVer = "1.125.157"
rmtVer = "1.2.676"
)

type Client struct {
uuid string
key string
}

type Tunnels struct {
Login string
Password string

Servers []TunnelSettings
}

type TunnelSettings struct {
Host string
Port string
Proto string
}

func (ts *TunnelSettings) String() string {
return fmt.Sprintf("%s\t%s:%s", ts.Proto, ts.Host, ts.Port)
}

type initializeResponse struct {
Key int
}

type zGetTunnelsResponse struct {
Ztun map[string][]string
IPList map[string]string `json:"ip_list"`
Protocol map[string]string
AgentKey string `json:"agent_key"`
}

func NewClient() *Client {
return &Client{
uuid: strings.Replace(uuid.New().String(), "-", "", -1),
}
}

func (c *Client) Initialize() error {
response, err := http.PostForm(baseUri+"/background_init", url.Values{
"login": []string{"1"},
"flags": []string{"0"},
"ver": []string{extVer},
"uuid": []string{c.uuid},
})
if err != nil {
return err
}

defer response.Body.Close()
var r initializeResponse

err = json.NewDecoder(response.Body).Decode(&r)
if err != nil {
return err
}

c.key = fmt.Sprintf("%d", r.Key)
return nil
}

func (c *Client) FindTunnels(countryCode string, limit int) (*Tunnels, error) {
u := baseUri + "/zgettunnels?" + "uuid=" + c.uuid + "&session_key=" + c.key +
"&country=" + countryCode + "&rmt_ver=" + rmtVer + "&ext_ver=" + extVer + "&browser=" + browser +
"&product=cws" + "&lccgi=1" + fmt.Sprintf("&limit=%d", limit)
response, err := http.Get(u)
defer response.Body.Close()
var r zGetTunnelsResponse

err = json.NewDecoder(response.Body).Decode(&r)
if err != nil {
return nil, err
}

tunnels := &Tunnels{
Login: c.uuid,
Password: r.AgentKey,
Servers: []TunnelSettings{},
}

proxyEndpoints, ok := r.Ztun[countryCode]
if ok {
for _, endpoint := range proxyEndpoints {
endpointSplit := strings.SplitN(endpoint, " ", 2)
hostPort := endpointSplit[1]

hostPortSplit := strings.SplitN(hostPort, ":", 2)
hostname := hostPortSplit[0]
port := hostPortSplit[1]

ipAddress, foundIpAddress := r.IPList[hostname]
if !foundIpAddress {
return nil, fmt.Errorf("IP address not found (hostname: %s)", hostname)
}

protocol, foundProtocol := r.Protocol[hostname]
if !foundProtocol {
return nil, fmt.Errorf("protocol not found (hostname: %s)", hostname)
}

tunnels.Servers = append(tunnels.Servers, TunnelSettings{
Host: ipAddress,
Port: port,
Proto: protocol,
})
}
}

return tunnels, nil
}

0 comments on commit 433c674

Please sign in to comment.