summaryrefslogtreecommitdiff
path: root/pkg/vpn/bonafide
diff options
context:
space:
mode:
authorkali kaneko (leap communications) <kali@leap.se>2020-08-26 16:10:32 +0200
committerkali kaneko (leap communications) <kali@leap.se>2021-05-04 14:58:38 +0200
commit16f53bd79a9ffb6f89c4e9c81af110287c85d265 (patch)
treeaf4063f70cbcc50e606e04f20357aeaf7f4f07dc /pkg/vpn/bonafide
parent2124a55d4a3d0ca00f8eab8f86c292ba1e7ccccf (diff)
[refactor] some renaming, preliminar refactor
Diffstat (limited to 'pkg/vpn/bonafide')
-rw-r--r--pkg/vpn/bonafide/bonafide.go35
-rw-r--r--pkg/vpn/bonafide/bonafide_test.go45
-rw-r--r--pkg/vpn/bonafide/eip_service.go88
-rw-r--r--pkg/vpn/bonafide/testdata/eip-service3.json26
-rw-r--r--pkg/vpn/bonafide/testdata/geoloc.json1
5 files changed, 105 insertions, 90 deletions
diff --git a/pkg/vpn/bonafide/bonafide.go b/pkg/vpn/bonafide/bonafide.go
index 28cfe44..4426da6 100644
--- a/pkg/vpn/bonafide/bonafide.go
+++ b/pkg/vpn/bonafide/bonafide.go
@@ -203,22 +203,13 @@ func (b *Bonafide) GetGateways(transport string) ([]Gateway, error) {
return b.eip.getGateways(transport), nil
}
-func (b *Bonafide) SetDefaultGateway(name string) {
- b.eip.setDefaultGateway(name)
- b.sortGateways()
+func (b *Bonafide) SetManualGateway(name string) {
+ /* TODO use gateway-id instead - a location-id is probably more useful than
+ * the gateway hostname */
+ b.eip.setManualGateway(name)
}
-func (b *Bonafide) GetOpenvpnArgs() ([]string, error) {
- if b.eip == nil {
- err := b.fetchEipJSON()
- if err != nil {
- return nil, err
- }
- }
- return b.eip.getOpenvpnArgs(), nil
-}
-
-func (b *Bonafide) fetchGeolocation() ([]string, error) {
+func (b *Bonafide) requestBestGatewaysFromService() ([]string, error) {
/* FIXME in float deployments, geolocation is served on gemyip.domain/json, with a LE certificate, but in riseup is served behind the api certificate.
So this is a workaround until we streamline that behavior */
resp, err := b.client.Post(config.GeolocationAPI, "", nil)
@@ -254,12 +245,22 @@ func (b *Bonafide) fetchGeolocation() ([]string, error) {
}
func (b *Bonafide) sortGateways() {
- geolocatedGateways, _ := b.fetchGeolocation()
+ serviceSelection, _ := b.requestBestGatewaysFromService()
- if len(geolocatedGateways) > 0 {
- b.eip.sortGatewaysByGeolocation(geolocatedGateways)
+ if len(serviceSelection) > 0 {
+ b.eip.autoSortGateways(serviceSelection)
} else {
log.Printf("Falling back to timezone heuristic for gateway selection")
b.eip.sortGatewaysByTimezone(b.tzOffsetHours)
}
}
+
+func (b *Bonafide) GetOpenvpnArgs() ([]string, error) {
+ if b.eip == nil {
+ err := b.fetchEipJSON()
+ if err != nil {
+ return nil, err
+ }
+ }
+ return b.eip.getOpenvpnArgs(), nil
+}
diff --git a/pkg/vpn/bonafide/bonafide_test.go b/pkg/vpn/bonafide/bonafide_test.go
index ee54fdb..481c079 100644
--- a/pkg/vpn/bonafide/bonafide_test.go
+++ b/pkg/vpn/bonafide/bonafide_test.go
@@ -28,21 +28,37 @@ import (
const (
certPath = "testdata/cert"
+ geoPath = "testdata/geoloc.json"
eip1Path = "testdata/eip-service.json"
eipPath = "testdata/eip-service3.json"
eipPathSip = "testdata/eip-service3-sip.json"
)
+type nopCloser struct {
+ io.Reader
+}
+
+func (nopCloser) Close() error { return nil }
+
type client struct {
path string
+ geo string
}
func (c client) Post(url, contentType string, body io.Reader) (resp *http.Response, err error) {
- f, err := os.Open(c.path)
- return &http.Response{
- Body: f,
- StatusCode: 200,
- }, err
+ if strings.Contains(url, "api.black.riseup.net:9001/json") {
+ f, err := os.Open(c.geo)
+ return &http.Response{
+ Body: f,
+ StatusCode: 200,
+ }, err
+ } else {
+ f, err := os.Open(c.path)
+ return &http.Response{
+ Body: f,
+ StatusCode: 200,
+ }, err
+ }
}
func (c client) Do(req *http.Request) (*http.Response, error) {
@@ -54,7 +70,7 @@ func (c client) Do(req *http.Request) (*http.Response, error) {
}
func TestAnonGetCert(t *testing.T) {
- b := Bonafide{client: client{certPath}}
+ b := Bonafide{client: client{certPath, geoPath}}
b.auth = &anonymousAuthentication{}
cert, err := b.GetPemCertificate()
if err != nil {
@@ -93,10 +109,11 @@ func TestGatewayTzLocation(t *testing.T) {
for tzOffset, location := range values {
b := Bonafide{
- client: client{eipPath},
+ client: client{eipPath, geoPath},
tzOffsetHours: tzOffset,
}
gateways, err := b.GetGateways("openvpn")
+
if err != nil {
t.Errorf("getGateways returned an error: %v", err)
continue
@@ -114,7 +131,7 @@ func TestGatewayTzLocation(t *testing.T) {
func TestOpenvpnGateways(t *testing.T) {
b := Bonafide{
- client: client{eipPath},
+ client: client{eipPath, geoPath},
}
gateways, err := b.GetGateways("openvpn")
if err != nil {
@@ -150,7 +167,7 @@ func TestOpenvpnGateways(t *testing.T) {
func TestObfs4Gateways(t *testing.T) {
b := Bonafide{
- client: client{eipPath},
+ client: client{eipPath, geoPath},
}
gateways, err := b.GetGateways("obfs4")
if err != nil {
@@ -192,13 +209,11 @@ func TestObfs4Gateways(t *testing.T) {
}
}
-/* TODO -- failClient instead? */
-
-type fallClient struct {
+type failingClient struct {
path string
}
-func (c fallClient) Post(url, contentType string, body io.Reader) (resp *http.Response, err error) {
+func (c failingClient) Post(url, contentType string, body io.Reader) (resp *http.Response, err error) {
statusCode := 200
if strings.Contains(url, "3/config/eip-service.json") {
statusCode = 404
@@ -210,7 +225,7 @@ func (c fallClient) Post(url, contentType string, body io.Reader) (resp *http.Re
}, err
}
-func (c fallClient) Do(req *http.Request) (*http.Response, error) {
+func (c failingClient) Do(req *http.Request) (*http.Response, error) {
f, err := os.Open(c.path)
return &http.Response{
Body: f,
@@ -220,7 +235,7 @@ func (c fallClient) Do(req *http.Request) (*http.Response, error) {
func TestEipServiceV1Fallback(t *testing.T) {
b := Bonafide{
- client: fallClient{eip1Path},
+ client: failingClient{eip1Path},
}
gateways, err := b.GetGateways("obfs4")
if err != nil {
diff --git a/pkg/vpn/bonafide/eip_service.go b/pkg/vpn/bonafide/eip_service.go
index 21cc8e8..9c8dc66 100644
--- a/pkg/vpn/bonafide/eip_service.go
+++ b/pkg/vpn/bonafide/eip_service.go
@@ -16,14 +16,16 @@ import (
type eipService struct {
Gateways []gatewayV3
+ SelectedGateways []gatewayV3
Locations map[string]location
+ defaultGateway string
OpenvpnConfiguration openvpnConfig `json:"openvpn_configuration"`
auth string
- defaultGateway string
}
type eipServiceV1 struct {
Gateways []gatewayV1
+ SelectedGateways []gatewayV1
Locations map[string]location
OpenvpnConfiguration openvpnConfig `json:"openvpn_configuration"`
}
@@ -161,7 +163,8 @@ func decodeEIP1(body io.Reader) (*eipService, error) {
func (eip eipService) getGateways(transport string) []Gateway {
gws := []Gateway{}
- for _, g := range eip.Gateways {
+ // TODO check that len(selected) != 0
+ for _, g := range eip.SelectedGateways {
for _, t := range g.Capabilities.Transport {
if t.Type != transport {
continue
@@ -178,47 +181,27 @@ func (eip eipService) getGateways(transport string) []Gateway {
gws = append(gws, gateway)
}
}
+ // TODO return only top 3, at least for openvpn
return gws
}
-func (eip *eipService) setDefaultGateway(name string) {
+func (eip *eipService) setManualGateway(name string) {
eip.defaultGateway = name
-}
-func (eip eipService) getOpenvpnArgs() []string {
- args := []string{}
- for arg, value := range eip.OpenvpnConfiguration {
- switch v := value.(type) {
- case string:
- args = append(args, "--"+arg)
- args = append(args, strings.Split(v, " ")...)
- case bool:
- if v {
- args = append(args, "--"+arg)
- }
- default:
- log.Printf("Unknown openvpn argument type: %s - %v", arg, value)
+ gws := make([]gatewayV3, 0)
+ for _, gw := range eip.Gateways {
+ if gw.Location == eip.defaultGateway {
+ gws = append(gws, gw)
+ break
}
}
- return args
+ eip.SelectedGateways = gws
}
-func (eip *eipService) sortGatewaysByGeolocation(geolocatedGateways []string) {
+func (eip *eipService) autoSortGateways(serviceSelection []string) {
gws := make([]gatewayV3, 0)
- /* TODO this probably should be moved out of this method */
- if eip.defaultGateway != "" {
- for _, gw := range eip.Gateways {
- if gw.Location == eip.defaultGateway {
- gws = append(gws, gw)
- break
- }
- }
- // a manually selected gateway means we do want exactly one remote
- return
- }
-
- for _, host := range geolocatedGateways {
+ for _, host := range serviceSelection {
for _, gw := range eip.Gateways {
if gw.Host == host {
gws = append(gws, gw)
@@ -229,22 +212,13 @@ func (eip *eipService) sortGatewaysByGeolocation(geolocatedGateways []string) {
if len(gws) == 0 {
// this can happen if a misconfigured geoip service does not match the
// providers list we got.
- log.Println("ERROR: avoiding to nullify eip.Gateways. Is the geolocation service properly configured?")
+ log.Println("ERROR: did not get any useful selection. Is the geolocation service properly configured?")
+ eip.SelectedGateways = eip.Gateways
} else {
- if len(gws) > 2 {
- eip.Gateways = gws[:3]
- } else {
- eip.Gateways = gws
- }
- log.Println("Picked best gateways for location:", eip.Gateways)
+ eip.SelectedGateways = gws
}
}
-type gatewayDistance struct {
- gateway gatewayV3
- distance int
-}
-
func (eip *eipService) sortGatewaysByTimezone(tzOffsetHours int) {
gws := []gatewayDistance{}
@@ -271,9 +245,33 @@ func (eip *eipService) sortGatewaysByTimezone(tzOffsetHours int) {
}
sort.Slice(gws, cmp)
+ eip.SelectedGateways = make([]gatewayV3, len(eip.Gateways))
for i, gw := range gws {
- eip.Gateways[i] = gw.gateway
+ eip.SelectedGateways[i] = gw.gateway
+ }
+}
+
+func (eip eipService) getOpenvpnArgs() []string {
+ args := []string{}
+ for arg, value := range eip.OpenvpnConfiguration {
+ switch v := value.(type) {
+ case string:
+ args = append(args, "--"+arg)
+ args = append(args, strings.Split(v, " ")...)
+ case bool:
+ if v {
+ args = append(args, "--"+arg)
+ }
+ default:
+ log.Printf("Unknown openvpn argument type: %s - %v", arg, value)
+ }
}
+ return args
+}
+
+type gatewayDistance struct {
+ gateway gatewayV3
+ distance int
}
func tzDistance(offset1, offset2 int) int {
diff --git a/pkg/vpn/bonafide/testdata/eip-service3.json b/pkg/vpn/bonafide/testdata/eip-service3.json
index cefd6c0..31a2a3b 100644
--- a/pkg/vpn/bonafide/testdata/eip-service3.json
+++ b/pkg/vpn/bonafide/testdata/eip-service3.json
@@ -14,7 +14,7 @@
"protocols": [
"tcp"
]
- },
+ },
{
"type": "obfs4",
"ports": [
@@ -23,11 +23,11 @@
"protocols": [
"tcp"
],
- "options": {
+ "options": {
"cert": "obfs-cert",
"iat-mode": "0"
- }
- }
+ }
+ }
],
"user_ips": false
},
@@ -49,7 +49,7 @@
"protocols": [
"tcp"
]
- }
+ }
],
"user_ips": false
},
@@ -71,7 +71,7 @@
"protocols": [
"tcp"
]
- },
+ },
{
"type": "obfs4",
"ports": [
@@ -80,11 +80,11 @@
"protocols": [
"tcp"
],
- "options": {
+ "options": {
"cert": "obfs-cert",
"iat-mode": "0"
- }
- }
+ }
+ }
],
"user_ips": false
},
@@ -106,7 +106,7 @@
"protocols": [
"tcp"
]
- }
+ }
],
"user_ips": false
},
@@ -128,11 +128,11 @@
"protocols": [
"tcp"
],
- "options": {
+ "options": {
"cert": "obfs-cert",
"iat-mode": "0"
- }
- }
+ }
+ }
],
"user_ips": false
},
diff --git a/pkg/vpn/bonafide/testdata/geoloc.json b/pkg/vpn/bonafide/testdata/geoloc.json
new file mode 100644
index 0000000..3f984c6
--- /dev/null
+++ b/pkg/vpn/bonafide/testdata/geoloc.json
@@ -0,0 +1 @@
+{"ip":"1.1.1.1","cc":"UK","city":"London","lat":0,"lon":0,"gateways":[]}