-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
246 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,7 @@ | |
|
||
# Output of the go coverage tool, specifically when used with LiteIDE | ||
*.out | ||
|
||
# IDEA | ||
*.iml | ||
.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |