summaryrefslogtreecommitdiff
path: root/standalone/bonafide.go
diff options
context:
space:
mode:
Diffstat (limited to 'standalone/bonafide.go')
-rw-r--r--standalone/bonafide.go81
1 files changed, 67 insertions, 14 deletions
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
}