Hello! We are running our annual fundraising. Please consider making a donation if you value this freely available service or want to support people around the world working towards liberatory social change. https://riseup.net/donate.

helper.go 4.66 KB
Newer Older
meskio's avatar
meskio committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Copyright (C) 2018 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

Kali Kaneko's avatar
Kali Kaneko committed
16
17
18
19
20
21
// This helper is intended to be long-lived, and run with administrator privileges.
// It will launch a http server and expose a REST API to control OpenVPN and the firewall.
// At the moment, it is only used in Darwin and Windows - although it could also be used in GNU/Linux systems (but we use the one-shot bitmask-root wrapper in GNU/Linux instead).
// In Windows, this helper will run on the first available port after the standard one (7171).
// In other systems, the 7171 port is hardcoded.

meskio's avatar
meskio committed
22
23
24
25
26
27
28
29
30
package helper

import (
	"encoding/json"
	"log"
	"net/http"
	"os/exec"
)

kali's avatar
kali committed
31
var (
32
	AppName    = "DemoLibVPN"
kali's avatar
kali committed
33
	BinaryName = "bitmask"
34
	Version    = "git"
kali's avatar
kali committed
35
36
)

meskio's avatar
meskio committed
37
38
39
40
type openvpnT struct {
	cmd *exec.Cmd
}

41
42
43
44
45
46
47
48
49
50
51
52
53
// startHelper is the main entrypoint. It can react to cli args (used to install or manage the service in windows), and
// eventually will start the http server.
func StartHelper(port int) {
	initializeService(port)
	parseCliArgs()
	daemonize()
	runServer(port)
}

// serveHTTP will start the HTTP server that exposes the firewall and openvpn api.
// this can be called at different times by the different implementations of the helper.
func serveHTTP(bindAddr string) {
	log.Println("Starting HTTP server at", bindAddr)
meskio's avatar
meskio committed
54
55
56
57
58
59
	openvpn := openvpnT{nil}
	http.HandleFunc("/openvpn/start", openvpn.start)
	http.HandleFunc("/openvpn/stop", openvpn.stop)
	http.HandleFunc("/firewall/start", firewallStartHandler)
	http.HandleFunc("/firewall/stop", firewallStopHandler)
	http.HandleFunc("/firewall/isup", firewallIsUpHandler)
Kali Kaneko's avatar
Kali Kaneko committed
60
	http.HandleFunc("/version", versionHandler)
meskio's avatar
meskio committed
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

	log.Fatal(http.ListenAndServe(bindAddr, nil))
}

func (openvpn *openvpnT) start(w http.ResponseWriter, r *http.Request) {
	args, err := getArgs(r)
	if err != nil {
		log.Printf("An error has occurred processing flags: %v", err)
		w.Write([]byte(err.Error()))
		return
	}

	args = parseOpenvpnArgs(args)
	log.Printf("start openvpn: %v", args)
	err = openvpn.run(args)
	if err != nil {
		log.Printf("Error starting openvpn: %v", err)
		w.Write([]byte(err.Error()))
	}
}

func (openvpn *openvpnT) run(args []string) error {
	if openvpn.cmd != nil {
		log.Printf("openvpn was running, stop it first")
		err := openvpn.kill()
		if err != nil {
			return err
		}
	}
kali's avatar
kali committed
90
	log.Println("OPENVPN PATH:", getOpenvpnPath())
meskio's avatar
meskio committed
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

	// TODO: if it dies we should restart it
	openvpn.cmd = exec.Command(getOpenvpnPath(), args...)
	return openvpn.cmd.Start()
}

func (openvpn *openvpnT) stop(w http.ResponseWriter, r *http.Request) {
	log.Println("stop openvpn")
	if openvpn.cmd == nil || openvpn.cmd.ProcessState != nil {
		openvpn.cmd = nil
		return
	}

	err := openvpn.kill()
	if err != nil {
		log.Printf("Error stoping openvpn: %v", err)
		w.Write([]byte(err.Error()))
	}
}

func (openvpn *openvpnT) kill() error {
	err := kill(openvpn.cmd)
	if err == nil {
		openvpn.cmd.Wait()
	} else {
		log.Printf("Error killing the process: %v", err)
	}

	openvpn.cmd = nil
	return nil
}

func firewallStartHandler(w http.ResponseWriter, r *http.Request) {
	gateways, err := getArgs(r)
	if err != nil {
		log.Printf("An error has occurred processing gateways: %v", err)
		w.Write([]byte(err.Error()))
		return
	}

	err = firewallStart(gateways)
	if err != nil {
		log.Printf("Error starting firewall: %v", err)
		w.Write([]byte(err.Error()))
		return
	}
	log.Println("Start firewall: firewall started")
}

func firewallStopHandler(w http.ResponseWriter, r *http.Request) {
	err := firewallStop()
	if err != nil {
		log.Printf("Error stoping firewall: %v", err)
		w.Write([]byte(err.Error()))
	}
	log.Println("Stop firewall: firewall stopped")
}

func firewallIsUpHandler(w http.ResponseWriter, r *http.Request) {
	if firewallIsUp() {
		w.WriteHeader(http.StatusOK)
152
		w.Write([]byte("true"))
meskio's avatar
meskio committed
153
154
	} else {
		w.WriteHeader(http.StatusNoContent)
155
		w.Write([]byte("false"))
meskio's avatar
meskio committed
156
157
158
	}
}

Kali Kaneko's avatar
Kali Kaneko committed
159
160
func versionHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
161
	w.Write([]byte(AppName + "/" + Version + "\n"))
Kali Kaneko's avatar
Kali Kaneko committed
162
163
}

meskio's avatar
meskio committed
164
165
166
167
168
169
func getArgs(r *http.Request) ([]string, error) {
	args := []string{}
	decoder := json.NewDecoder(r.Body)
	err := decoder.Decode(&args)
	return args, err
}