Skip to content
Snippets Groups Projects
Unverified Commit 6837a8bc authored by meskio's avatar meskio :tent:
Browse files

[feat] move helper into the repo

parent bea32af5
Branches
Tags
1 merge request!50Feat/reorganize code
/bitmask-vpn /bitmask-vpn
cmd/bitmask-vpn/bitmask-vpn cmd/bitmask-vpn/bitmask-vpn
/bitmask-helper
cmd/bitmask-helper/bitmask-helper
locales/*/out.gotext.json locales/*/out.gotext.json
.*.swp .*.swp
*.exe *.exe
......
// 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/>.
package main
import (
"log"
"path"
"0xacab.org/leap/bitmask-systray/pkg/config"
"0xacab.org/leap/bitmask-systray/pkg/helper"
)
const (
bindAddr = "localhost:7171"
logFile = "helper.log"
)
func main() {
logger, err := config.ConfigureLogger(path.Join(helper.LogFolder, logFile))
if err != nil {
log.Println("Can't configure logger: ", err)
} else {
defer logger.Close()
}
helper.ServeHTTP(bindAddr)
}
package helper
import (
"log"
"net"
"os"
"regexp"
"strconv"
)
const (
// TODO: this is the nameserver for tcp, but for udp is 10.42.0.1
// the nameserver pick up should be dependent on the proto being used
nameserver = "10.41.0.1"
)
var (
fixedArgs = []string{
"--nobind",
"--client",
"--dev", "tun",
"--tls-client",
"--remote-cert-tls", "server",
"--dhcp-option", "DNS", nameserver,
"--log", LogFolder + "openvpn.log",
}
allowendArgs = map[string][]string{
"--remote": []string{"IP", "NUMBER", "PROTO"},
"--tls-cipher": []string{"CIPHER"},
"--cipher": []string{"CIPHER"},
"--auth": []string{"CIPHER"},
"--management-client": []string{},
"--management": []string{"IP", "NUMBER"},
"--cert": []string{"FILE"},
"--key": []string{"FILE"},
"--ca": []string{"FILE"},
"--fragment": []string{"NUMBER"},
"--keepalive": []string{"NUMBER", "NUMBER"},
"--verb": []string{"NUMBER"},
"--tun-ipv6": []string{},
}
cipher = regexp.MustCompile("^[A-Z0-9-]+$")
formats = map[string]func(s string) bool{
"NUMBER": isNumber,
"PROTO": isProto,
"IP": isIP,
"CIPHER": cipher.MatchString,
"FILE": isFile,
}
)
func parseOpenvpnArgs(args []string) []string {
newArgs := fixedArgs
newArgs = append(newArgs, platformOpenvpnFlags...)
for i := 0; i < len(args); i++ {
params, ok := allowendArgs[args[i]]
if !ok {
log.Printf("Invalid openvpn arg: %s", args[i])
continue
}
for j, arg := range args[i+1 : i+len(params)+1] {
if !formats[params[j]](arg) {
ok = false
break
}
}
if ok {
newArgs = append(newArgs, args[i:i+len(params)+1]...)
i = i + len(params)
} else {
log.Printf("Invalid openvpn arg params: %v", args[i:i+len(params)+1])
}
}
return newArgs
}
func isNumber(s string) bool {
_, err := strconv.Atoi(s)
return err == nil
}
func isProto(s string) bool {
for _, proto := range []string{"tcp", "udp", "tcp4", "udp4", "tcp6", "udp6"} {
if s == proto {
return true
}
}
return false
}
func isIP(s string) bool {
return net.ParseIP(s) != nil
}
func isFile(s string) bool {
info, err := os.Stat(s)
if err != nil {
return false
}
return !info.IsDir()
}
// +build darwin
// 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/>.
/*
This module holds some specific constants for osx, and it also contains the implementation of the pf firewall.
To inspect the rules in the firewall manually, use the bitmask anchor:
sudo pfctl -s rules -a com.apple/250.BitmaskFirewall
*/
package helper
import (
"bytes"
"errors"
"fmt"
"log"
"os"
"os/exec"
"path"
"strings"
"github.com/sevlyar/go-daemon"
)
const (
appPath = "/Applications/RiseupVPN.app/"
helperPath = appPath + "Contents/helper/"
LogFolder = helperPath
openvpnPath = appPath + "Contents/Resources/openvpn.leap"
rulefilePath = helperPath + "bitmask.pf.conf"
bitmask_anchor = "com.apple/250.BitmaskFirewall"
gateways_table = "bitmask_gateways"
pfctl = "/sbin/pfctl"
)
var (
platformOpenvpnFlags = []string{
"--script-security", "2",
"--up", helperPath + "client.up.sh",
"--down", helperPath + "client.down.sh",
}
)
func daemonize() {
cntxt := &daemon.Context{
PidFileName: "pid",
PidFilePerm: 0644,
LogFileName: "bitmask-helper.log",
LogFilePerm: 0640,
WorkDir: "./",
Umask: 027,
Args: []string{"[bitmask-helper]"},
}
d, err := cntxt.Reborn()
if err != nil {
log.Fatal("Unable to run: ", err)
}
if d != nil {
return
}
defer cntxt.Release()
log.Print("bitmask-helper daemon started")
}
func getOpenvpnPath() string {
return openvpnPath
}
func kill(cmd *exec.Cmd) error {
return cmd.Process.Signal(os.Interrupt)
}
func firewallStart(gateways []string) error {
enablePf()
err := resetGatewaysTable(gateways)
if err != nil {
return err
}
return loadBitmaskAnchor()
}
func firewallStop() error {
return exec.Command(pfctl, "-a", bitmask_anchor, "-F", "all").Run()
}
func firewallIsUp() bool {
out, err := exec.Command(pfctl, "-a", bitmask_anchor, "-sr").Output()
if err != nil {
log.Printf("An error ocurred getting the status of the firewall: %v", err)
return false
}
return bytes.Contains(out, []byte("block out proto udp to any port 53"))
}
func enablePf() {
cmd := exec.Command(pfctl, "-e")
cmd.Run()
}
func resetGatewaysTable(gateways []string) error {
log.Println("Resetting gateways")
cmd := exec.Command(pfctl, "-a", bitmask_anchor, "-t", gateways_table, "-T", "delete")
err := cmd.Run()
if err != nil {
log.Printf("Can't delete table: %v", err)
}
for _, gateway := range gateways {
log.Println("Adding Gateway:", gateway)
cmd = exec.Command(pfctl, "-a", bitmask_anchor, "-t", gateways_table, "-T", "add", gateway)
err = cmd.Run()
if err != nil {
log.Printf("Error adding gateway to table: %v", err)
}
}
cmd = exec.Command(pfctl, "-a", bitmask_anchor, "-t", gateways_table, "-T", "add", nameserver)
return cmd.Run()
}
func getDefaultDevice() string {
out, err := exec.Command("/bin/sh", "-c", "/sbin/route -n get -net default | /usr/bin/grep interface | /usr/bin/awk '{print $2}'").Output()
if err != nil {
log.Printf("Error getting default device")
}
return strings.TrimSpace(bytesToString(out))
}
func loadBitmaskAnchor() error {
dev := getDefaultDevice()
rulePath, err := getRulefilePath()
if err != nil {
return err
}
cmdline := fmt.Sprintf("%s -D default_device=%s -a %s -f %s", pfctl, dev, bitmask_anchor, rulePath)
log.Println("Loading Bitmask Anchor:", cmdline)
_, err = exec.Command("/bin/sh", "-c", cmdline).Output()
return err
}
func getRulefilePath() (string, error) {
if _, err := os.Stat(rulefilePath); !os.IsNotExist(err) {
return rulefilePath, nil
}
gopath := os.Getenv("GOPATH")
if gopath == "" {
gopath = path.Join(os.Getenv("HOME"), "go")
}
rulefile := path.Join(gopath, "0xacab.org", "leap", "riseup_vpn", "osx", "bitmask.pf.conf")
if _, err := os.Stat(rulefile); !os.IsNotExist(err) {
return rulefile, nil
}
return "", errors.New("Can't find rule file for the firewall")
}
func bytesToString(data []byte) string {
return string(data[:])
}
// 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/>.
package helper
import (
"encoding/json"
"log"
"net/http"
"os/exec"
)
type openvpnT struct {
cmd *exec.Cmd
}
func ServeHTTP(bindAddr string) {
daemonize()
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)
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
}
}
// 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.Write([]byte("true"))
w.WriteHeader(http.StatusOK)
} else {
w.Write([]byte("false"))
w.WriteHeader(http.StatusNoContent)
}
}
func getArgs(r *http.Request) ([]string, error) {
args := []string{}
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&args)
return args, err
}
// +build linux
// 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/>.
package helper
import (
"log"
"os"
"os/exec"
)
const (
openvpnUser = "nobody"
openvpnGroup = "nogroup"
LogFolder = "/var/log/"
systemOpenvpnPath = "/usr/sbin/openvpn"
snapOpenvpnPath = "/snap/bin/riseup-vpn.openvpn"
)
var (
platformOpenvpnFlags = []string{
"--script-security", "1",
"--user", openvpnUser,
"--group", openvpnGroup,
}
)
func daemonize() {}
func getOpenvpnPath() string {
if os.Getenv("SNAP") != "" {
return snapOpenvpnPath
}
return systemOpenvpnPath
}
func kill(cmd *exec.Cmd) error {
return cmd.Process.Signal(os.Interrupt)
}
func firewallStart(gateways []string) error {
log.Println("Start firewall: do nothing, not implemented")
return nil
}
func firewallStop() error {
log.Println("Stop firewall: do nothing, not implemented")
return nil
}
func firewallIsUp() bool {
log.Println("IsUp firewall: do nothing, not implemented")
return false
}
// +build windows
// 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/>.
package helper
import (
"log"
"os"
"os/exec"
)
const (
appPath = `C:\Program Files\RiseupVPN\`
LogFolder = appPath
openvpnPath = appPath + `openvpn.exe`
chocoOpenvpnPath = `C:\Program Files\OpenVPN\bin\openvpn.exe`
)
var (
platformOpenvpnFlags = []string{
"--script-security", "1",
}
)
func daemonize() {}
func getOpenvpnPath() string {
if _, err := os.Stat(openvpnPath); !os.IsNotExist(err) {
return openvpnPath
} else if _, err := os.Stat(chocoOpenvpnPath); !os.IsNotExist(err) {
return chocoOpenvpnPath
}
return "openvpn.exe"
}
func kill(cmd *exec.Cmd) error {
return cmd.Process.Kill()
}
func firewallStart(gateways []string) error {
log.Println("Start firewall: do nothing, not implemented")
return nil
}
func firewallStop() error {
log.Println("Stop firewall: do nothing, not implemented")
return nil
}
func firewallIsUp() bool {
log.Println("IsUp firewall: do nothing, not implemented")
return false
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment