From 37413f5eb2b8d4719c959db03874cc9bcc362ddc Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Wed, 13 Jun 2018 20:48:27 +0200 Subject: [feat] get openvpn args/gateways from the eip-service.json --- bitmask_go/bonafide.go | 94 ++++++++++++++++++++++++++++++++++++++++++-- bitmask_go/bonafide_test.go | 22 +++++++++-- bitmask_go/launcher_linux.go | 6 ++- bitmask_go/main.go | 6 ++- bitmask_go/vpn.go | 22 ++++++----- 5 files changed, 130 insertions(+), 20 deletions(-) diff --git a/bitmask_go/bonafide.go b/bitmask_go/bonafide.go index 25fa302..cc94b25 100644 --- a/bitmask_go/bonafide.go +++ b/bitmask_go/bonafide.go @@ -18,13 +18,16 @@ package bitmask import ( "crypto/tls" "crypto/x509" + "encoding/json" "fmt" "io/ioutil" + "log" "net/http" ) const ( certAPI = "https://api.black.riseup.net/1/cert" + eipAPI = "https://api.black.riseup.net/1/config/eip-service.json" ) var ( @@ -62,7 +65,33 @@ UN9SaWRlWKSdP4haujnzCoJbM7dU9bjvlGZNyXEekgeT0W2qFeGGp+yyUWw8tNsp -----END CERTIFICATE-----`) ) -func getCertPem() ([]byte, error) { +type bonafide struct { + client *http.Client + eip *eipService +} + +type eipService struct { + Gateways []gateway + Locations map[string]struct { + CountryCode string + Hemisphere string + Name string + Timezone string + } + OpenvpnConfiguration map[string]interface{} `json:"openvpn_configuration"` +} + +type gateway struct { + Capabilities struct { + Ports []string + Protocols []string + } + Host string + IPAddress string `json:"ip_address"` + Location string +} + +func newBonafide() *bonafide { certs := x509.NewCertPool() certs.AppendCertsFromPEM(caCert) client := &http.Client{ @@ -73,15 +102,74 @@ func getCertPem() ([]byte, error) { }, } - resp, err := client.Post(certAPI, "", nil) + return &bonafide{client, nil} +} + +func (b *bonafide) getCertPem() ([]byte, error) { + resp, err := b.client.Post(certAPI, "", nil) if err != nil { return nil, err } defer resp.Body.Close() - if resp.StatusCode != 200 { return nil, fmt.Errorf("get vpn cert has failed with status: %s", resp.Status) } return ioutil.ReadAll(resp.Body) } + +func (b *bonafide) getGateways() ([]gateway, error) { + if b.eip == nil { + err := b.fetchEipJSON() + if err != nil { + return nil, err + } + } + + return b.eip.Gateways, nil +} + +func (b *bonafide) getOpenvpnArgs() ([]string, error) { + if b.eip == nil { + err := b.fetchEipJSON() + if err != nil { + return nil, err + } + } + + args := []string{} + for arg, value := range b.eip.OpenvpnConfiguration { + switch v := value.(type) { + case string: + args = append(args, "--"+arg, v) + case bool: + if v { + args = append(args, "--"+arg) + } + default: + log.Printf("Uknwon openvpn argument type: %s - %v", arg, value) + } + } + return args, nil +} + +func (b *bonafide) fetchEipJSON() error { + resp, err := b.client.Post(eipAPI, "", nil) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return fmt.Errorf("get vpn cert has failed with status: %s", resp.Status) + } + + var eip eipService + decoder := json.NewDecoder(resp.Body) + err = decoder.Decode(&eip) + if err != nil { + return err + } + + b.eip = &eip + return nil +} diff --git a/bitmask_go/bonafide_test.go b/bitmask_go/bonafide_test.go index c40c98d..152b108 100644 --- a/bitmask_go/bonafide_test.go +++ b/bitmask_go/bonafide_test.go @@ -11,16 +11,32 @@ var ( ) func TestGetCert(t *testing.T) { - cert, err := getCertPem() + b := newBonafide() + cert, err := b.getCertPem() if err != nil { - t.Fatal("get_cert returned an error: ", err) + t.Fatal("getCert returned an error: ", err) } if !bytes.Contains(cert, privateKeyHeader) { t.Errorf("No private key present: \n%q", cert) } - if !bytes.Equal(cert, certHeader) { + if !bytes.Contains(cert, certHeader) { t.Errorf("No cert present: \n%q", cert) } } + +func TestGetGateways(t *testing.T) { + b := newBonafide() + gateways, err := b.getGateways() + if err != nil { + t.Fatal("getGateways returned an error: ", err) + } + + for _, gw := range gateways { + if gw.IPAddress == "5.79.86.180" { + return + } + } + t.Errorf("5.79.86.180 not in the list") +} diff --git a/bitmask_go/launcher_linux.go b/bitmask_go/launcher_linux.go index 6a1407c..12bd1cb 100644 --- a/bitmask_go/launcher_linux.go +++ b/bitmask_go/launcher_linux.go @@ -58,10 +58,12 @@ func (l *launcher) openvpnStop() error { return runBitmaskRoot("openvpn", "stop") } -func (l *launcher) firewallStart(gateways []string) error { +func (l *launcher) firewallStart(gateways []gateway) error { log.Println("firewall start") arg := []string{"firewall", "start"} - arg = append(arg, gateways...) + for _, gw := range gateways { + arg = append(arg, gw.IPAddress) + } return runBitmaskRoot(arg...) } diff --git a/bitmask_go/main.go b/bitmask_go/main.go index 6b60d43..fee4a42 100644 --- a/bitmask_go/main.go +++ b/bitmask_go/main.go @@ -28,6 +28,7 @@ type Bitmask struct { tempdir string statusCh chan string managementClient *openvpn.MgmtClient + bonafide *bonafide launch *launcher } @@ -38,15 +39,16 @@ func Init() (*Bitmask, error) { if err != nil { return nil, err } + bonafide := newBonafide() launch := newLauncher() - b := Bitmask{tempdir, statusCh, nil, launch} + b := Bitmask{tempdir, statusCh, nil, bonafide, launch} err = b.StopVPN() if err != nil { return nil, err } - cert, err := getCertPem() + cert, err := b.bonafide.getCertPem() if err != nil { return nil, err } diff --git a/bitmask_go/vpn.go b/bitmask_go/vpn.go index 2e69368..041a8e4 100644 --- a/bitmask_go/vpn.go +++ b/bitmask_go/vpn.go @@ -24,26 +24,28 @@ const ( openvpnManagementPort = "6061" ) -var gateways = []string{ - "5.79.86.180", - "199.58.81.145", - "198.252.153.28", -} - // StartVPN for provider func (b *Bitmask) StartVPN(provider string) error { - // TODO: openvpn args are hardcoded - err := b.launch.firewallStart(gateways) + gateways, err := b.bonafide.getGateways() + if err != nil { + return err + } + err = b.launch.firewallStart(gateways) if err != nil { return err } arg := []string{"--nobind", "--verb", "1"} + bonafideArgs, err := b.bonafide.getOpenvpnArgs() + if err != nil { + return err + } + arg = append(arg, bonafideArgs...) for _, gw := range gateways { - arg = append(arg, "--remote", gw, "443", "tcp4") + arg = append(arg, "--remote", gw.IPAddress, "443", "tcp4") } certPemPath := b.getCertPemPath() - arg = append(arg, "--client", "--tls-client", "--remote-cert-tls", "server", "--tls-cipher", "DHE-RSA-AES128-SHA", "--cipher", "AES-128-CBC", "--tun-ipv6", "--auth", "SHA1", "--keepalive", "10 30", "--management-client", "--management", openvpnManagementAddr+" "+openvpnManagementPort, "--ca", b.getCaCertPath(), "--cert", certPemPath, "--key", certPemPath) + arg = append(arg, "--client", "--tls-client", "--remote-cert-tls", "server", "--management-client", "--management", openvpnManagementAddr+" "+openvpnManagementPort, "--ca", b.getCaCertPath(), "--cert", certPemPath, "--key", certPemPath) return b.launch.openvpnStart(arg...) } -- cgit v1.2.3