Skip to content
Snippets Groups Projects
Commit 335bb742 authored by Kali Kaneko's avatar Kali Kaneko
Browse files

[feat] expose gateway selection in webapi

parent 68f566cf
No related branches found
No related tags found
No related merge requests found
......@@ -30,6 +30,16 @@ func SwitchOff() {
backend.SwitchOff()
}
//export UseGateway
func UseGateway(label string) {
backend.UseGateway(label)
}
//export UseTransport
func UseTransport(transport string) {
backend.UseTransport(transport)
}
//export Quit
func Quit() {
backend.Quit()
......
......@@ -19,3 +19,23 @@ func stopVPN() {
log.Println(err)
}
}
// TODO return bool?
func useGateway(label string) {
err := ctx.bm.UseGateway(label)
if err != nil {
log.Println(err)
}
}
func getGateway() string {
return ctx.bm.GetCurrentGateway()
}
// TODO return bool?
func useTransport(transport string) {
err := ctx.bm.UseTransport(transport)
if err != nil {
log.Println(err)
}
}
......@@ -54,6 +54,16 @@ func SwitchOff() {
go stopVPN()
}
// TODO implement Reconnect?
func UseGateway(label string) {
ctx.bm.UseGateway(label)
}
func UseTransport(label string) {
ctx.bm.UseTransport(label)
}
func Quit() {
if ctx.autostart != nil {
ctx.autostart.Disable()
......
package backend
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"strconv"
"time"
"0xacab.org/leap/bitmask-vpn/pkg/bitmask"
)
......@@ -36,6 +38,52 @@ func webStatus(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, ctx.Status.String())
}
func webGatewayGet(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, ctx.bm.GetCurrentGateway())
}
func webGatewaySet(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "POST":
if err := r.ParseForm(); err != nil {
fmt.Fprintf(w, "ParseForm() err: %v", err)
return
}
gwLabel := r.FormValue("gw")
fmt.Fprintf(w, "selected gateway: %s\n", gwLabel)
// FIXME catch error here, return it (error code)
useGateway(gwLabel)
// TODO make sure we don't tear the fw down on reconnect...
SwitchOff()
// a little sleep is needed, though, because iptables takes some time
time.Sleep(500 * time.Millisecond)
SwitchOn()
default:
fmt.Fprintf(w, "Only POST supported.")
}
}
func webGatewayList(w http.ResponseWriter, r *http.Request) {
gws, err := ctx.bm.ListGateways(ctx.Provider)
if err != nil {
fmt.Fprintf(w, "ListGateways() err: %v", err)
}
gwJson, _ := json.Marshal(gws)
fmt.Fprintf(w, string(gwJson))
}
// TODO
func webTransportGet(w http.ResponseWriter, r *http.Request) {
}
// TODO
func webTransportSet(w http.ResponseWriter, r *http.Request) {
}
// TODO
func webTransportList(w http.ResponseWriter, r *http.Request) {
}
func webQuit(w http.ResponseWriter, r *http.Request) {
log.Println("Web UI: quit")
Quit()
......@@ -48,6 +96,12 @@ func enableWebAPI(port int) {
token := bitmask.ReadAuthToken()
http.Handle("/vpn/start", CheckAuth(http.HandlerFunc(webOn), token))
http.Handle("/vpn/stop", CheckAuth(http.HandlerFunc(webOff), token))
http.Handle("/vpn/gw/get", CheckAuth(http.HandlerFunc(webGatewayGet), token))
http.Handle("/vpn/gw/set", CheckAuth(http.HandlerFunc(webGatewaySet), token))
http.Handle("/vpn/gw/list", CheckAuth(http.HandlerFunc(webGatewayList), token))
//http.Handle("/vpn/transport/get", CheckAuth(http.HandlerFunc(webTransportGet), token))
//http.Handle("/vpn/transport/set", CheckAuth(http.HandlerFunc(webTransportSet), token))
//http.Handle("/vpn/transport/list", CheckAuth(http.HandlerFunc(webTransportList), token))
http.Handle("/vpn/status", CheckAuth(http.HandlerFunc(webStatus), token))
http.Handle("/vpn/quit", CheckAuth(http.HandlerFunc(webQuit), token))
http.ListenAndServe(":"+strconv.Itoa(port), nil)
......
// Copyright (C) 2018 LEAP
// Copyright (C) 2018-2020 LEAP
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
......@@ -28,6 +28,7 @@ type Bitmask interface {
VPNCheck() (helpers bool, priviledge bool, err error)
ListGateways(provider string) ([]string, error)
UseGateway(name string) error
GetCurrentGateway() string
UseTransport(transport string) error
NeedsCredentials() bool
DoLogin(username, password string) (bool, error)
......
......@@ -197,6 +197,8 @@ func (b *Bonafide) maybeInitializeEIP() error {
return nil
}
// GetGateways filters by transport, and will return the maximum number defined
// in bonafide.maxGateways, or the maximum by default (3).
func (b *Bonafide) GetGateways(transport string) ([]Gateway, error) {
err := b.maybeInitializeEIP()
if err != nil {
......@@ -211,6 +213,17 @@ func (b *Bonafide) GetGateways(transport string) ([]Gateway, error) {
return gws, err
}
// GetAllGateways only filters gateways by transport.
// TODO could pass "any" instead?
func (b *Bonafide) GetAllGateways(transport string) ([]Gateway, error) {
err := b.maybeInitializeEIP()
if err != nil {
return nil, err
}
gws, err := b.gateways.getAll(transport, b.tzOffsetHours)
return gws, err
}
func (b *Bonafide) SetManualGateway(label string) {
b.gateways.setUserChoice(label)
}
......@@ -219,6 +232,10 @@ func (b *Bonafide) SetAutomaticGateway() {
b.gateways.setAutomaticChoice()
}
func (b *Bonafide) GetGatewayByIP(ip string) (Gateway, error) {
return b.gateways.getGatewayByIP(ip)
}
/* TODO this still needs to be called periodically */
func (b *Bonafide) fetchGatewayRanking() 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.
......
......@@ -142,6 +142,14 @@ func (p *gatewayPool) getBest(transport string, tz, max int) ([]Gateway, error)
}
}
func (p *gatewayPool) getAll(transport string, tz int) ([]Gateway, error) {
if len(p.ranked) != 0 {
return p.getGatewaysByServiceRank(transport, 999)
} else {
return p.getGatewaysByTimezone(transport, tz, 999)
}
}
func (p *gatewayPool) getGatewaysByServiceRank(transport string, max int) ([]Gateway, error) {
gws := make([]Gateway, 0)
for _, host := range p.ranked {
......
......@@ -29,7 +29,7 @@ import (
// Bitmask holds the bitmask client data
type Bitmask struct {
tempdir string
onGateway string
onGateway bonafide.Gateway
statusCh chan string
managementClient *openvpn.MgmtClient
bonafide *bonafide.Bonafide
......@@ -45,12 +45,12 @@ func Init() (*Bitmask, error) {
if err != nil {
return nil, err
}
bonafide := bonafide.New()
bf := bonafide.New()
launch, err := newLauncher()
if err != nil {
return nil, err
}
b := Bitmask{tempdir, "", statusCh, nil, bonafide, launch, "", nil}
b := Bitmask{tempdir, bonafide.Gateway{}, statusCh, nil, bf, launch, "", nil}
/*
TODO -- we still want to do this, since it resets the fw/vpn if running
......
......@@ -230,22 +230,23 @@ func (b *Bitmask) VPNCheck() (helpers bool, privilege bool, err error) {
return b.launch.check()
}
// ListGateways return the names of the gateways
// ListGateways return the labels of the gateways (only for transport=openvpn, at the moment)
// TODO return other transports too
func (b *Bitmask) ListGateways(provider string) ([]string, error) {
gateways, err := b.bonafide.GetGateways("openvpn")
gateways, err := b.bonafide.GetAllGateways("openvpn")
if err != nil {
return nil, err
}
gatewayNames := make([]string, len(gateways))
for i, gw := range gateways {
gatewayNames[i] = gw.Location
gatewayNames[i] = gw.Label
}
return gatewayNames, nil
}
// UseGateway selects name as the default gateway
func (b *Bitmask) UseGateway(name string) error {
b.bonafide.SetManualGateway(name)
// UseGateway selects a gateway, by label, as the default gateway
func (b *Bitmask) UseGateway(label string) error {
b.bonafide.SetManualGateway(label)
return nil
}
......
......@@ -73,13 +73,23 @@ func (b *Bitmask) eventHandler(eventCh <-chan openvpn.Event) {
b.statusCh <- status
}
if statusName == "CONNECTED" {
b.onGateway = strings.Split(stateEvent.String(), ": ")[1]
log.Println(">>> CONNECTED TO", b.onGateway)
ip := strings.Split(stateEvent.String(), ": ")[1]
gw, err := b.bonafide.GetGatewayByIP(ip)
if err == nil {
b.onGateway = gw
log.Println("Connected to gateway:", b.onGateway.Label)
} else {
log.Println("ERROR: connected to unknown gateway", ip)
}
}
}
b.statusCh <- Off
}
func (b *Bitmask) GetCurrentGateway() string {
return b.onGateway.Label
}
func (b *Bitmask) getOpenvpnState() (string, error) {
if b.managementClient == nil {
return "", fmt.Errorf("No management connected")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment