summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKali Kaneko (leap communications) <kali@leap.se>2018-12-17 23:48:38 +0100
committerKali Kaneko (leap communications) <kali@leap.se>2018-12-19 18:18:33 +0100
commitc9163f221d4cc7b167b5f68eb51ce09843939352 (patch)
treeb02783e349d165710fc7274b3c5c585e41226861
parent25364ba279bcac72a363748c5e65964864b94358 (diff)
[feat] use geolocated gateways
we try to use the geoip service, and if the answer has an entry for the sorted gateways, we just use it instead of using the timezone heuristic. - Resolves: #84
-rw-r--r--.gitlab-ci.yml1
-rw-r--r--standalone/bonafide.go81
2 files changed, 68 insertions, 14 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b3f1861..7a39e59 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -38,6 +38,7 @@ win_installer:
- git clone https://github.com/AllenDang/w32
- cd w32
- curl https://downloads.leap.se/thirdparty/w32.patch | patch -p1 -N
+
- cd ${APP_PATH}
- git clone https://0xacab.org/leap/riseup_vpn
diff --git a/standalone/bonafide.go b/standalone/bonafide.go
index e37c332..e28eb08 100644
--- a/standalone/bonafide.go
+++ b/standalone/bonafide.go
@@ -34,6 +34,7 @@ import (
const (
certAPI = "https://api.black.riseup.net/1/cert"
eipAPI = "https://api.black.riseup.net/1/config/eip-service.json"
+ geolocationAPI = "https://api.black.riseup.net/getmyip/json"
secondsPerHour = 60 * 60
)
@@ -78,6 +79,7 @@ type bonafide struct {
eip *eipService
defaultGateway string
}
+
type httpClient interface {
Post(url, contentType string, body io.Reader) (resp *http.Response, err error)
}
@@ -103,6 +105,20 @@ type gateway struct {
Location string
}
+type gatewayDistance struct {
+ gateway gateway
+ distance int
+}
+
+type geoLocation struct {
+ IPAddress string `json:"ip"`
+ Country string `json:"cc"`
+ City string `json:"city"`
+ Latitude float64 `json:"lat"`
+ Longitude float64 `json:"lon"`
+ SortedGateways []string `json:"gateways"`
+}
+
func newBonafide() *bonafide {
certs := x509.NewCertPool()
certs.AppendCertsFromPEM(caCert)
@@ -172,12 +188,34 @@ func (b *bonafide) getOpenvpnArgs() ([]string, error) {
args = append(args, "--"+arg)
}
default:
- log.Printf("Uknwon openvpn argument type: %s - %v", arg, value)
+ log.Printf("Unknown openvpn argument type: %s - %v", arg, value)
}
}
return args, nil
}
+func (b *bonafide) fetchGeolocation() ([]string, error) {
+ resp, err := b.client.Post(geolocationAPI, "", nil)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != 200 {
+ return nil, fmt.Errorf("get geolocation failed with status: %s", resp.Status)
+ }
+
+ geo := &geoLocation{}
+ dataJSON, err := ioutil.ReadAll(resp.Body)
+ err = json.Unmarshal(dataJSON, &geo)
+ if err != nil {
+ _ = fmt.Errorf("get vpn cert has failed with status: %s", resp.Status)
+ return nil, err
+ }
+
+ return geo.SortedGateways, nil
+
+}
+
func (b *bonafide) fetchEipJSON() error {
resp, err := b.client.Post(eipAPI, "", nil)
if err != nil {
@@ -200,13 +238,22 @@ func (b *bonafide) fetchEipJSON() error {
return nil
}
-func (b *bonafide) sortGateways() {
- type gatewayDistance struct {
- gateway gateway
- distance int
+func (b *bonafide) sortGatewaysByGeolocation(geolocatedGateways []string) []gatewayDistance {
+ gws := []gatewayDistance{}
+
+ for i, host := range geolocatedGateways {
+ for _, gw := range b.eip.Gateways {
+ if gw.Host == host {
+ gws = append(gws, gatewayDistance{gw, i})
+ }
+ }
}
+ return gws
+}
+func (b *bonafide) sortGatewaysByTimezone() []gatewayDistance {
gws := []gatewayDistance{}
+
for _, gw := range b.eip.Gateways {
distance := 13
if gw.Location == b.defaultGateway {
@@ -221,23 +268,29 @@ func (b *bonafide) sortGateways() {
}
gws = append(gws, gatewayDistance{gw, distance})
}
-
rand.Seed(time.Now().UnixNano())
cmp := func(i, j int) bool {
if gws[i].distance == gws[j].distance {
- // TODO: a hack to distribute more the load into the new gw.
- // Let's delete it as soon as is more spread the load.
- if gws[i].gateway.Host == "giraffe.riseup.net" {
- return rand.Intn(4) != 0
- } else if gws[j].gateway.Host == "giraffe.riseup.net" {
- return rand.Intn(4) == 0
- }
-
return rand.Intn(2) == 1
}
return gws[i].distance < gws[j].distance
}
sort.Slice(gws, cmp)
+ return gws
+}
+
+func (b *bonafide) sortGateways() {
+ gws := []gatewayDistance{}
+
+ geolocatedGateways, _ := b.fetchGeolocation()
+
+ if len(geolocatedGateways) > 0 {
+ gws = b.sortGatewaysByGeolocation(geolocatedGateways)
+ } else {
+ log.Printf("Falling back to timezone heuristic for gateway selection")
+ gws = b.sortGatewaysByTimezone()
+ }
+
for i, gw := range gws {
b.eip.Gateways[i] = gw.gateway
}