diff options
author | kali <kali@win> | 2021-04-05 16:15:29 +0200 |
---|---|---|
committer | kali kaneko (leap communications) <kali@leap.se> | 2022-07-06 01:57:45 +0200 |
commit | d1252ef5b90870e55389188d351aabfe55a932f6 (patch) | |
tree | 7994263d56cbbecfe6ab77eff76346c18732ff6c | |
parent | 048e2914a7e646b7fd8bb6b024c7839259aaecc9 (diff) |
[feat] use named pipe to launch openvpn
- Resolves: #339
-rw-r--r-- | Makefile | 23 | ||||
-rw-r--r-- | branding/templates/qtinstaller/packages/bitmaskvpn/meta/install.js | 20 | ||||
-rw-r--r-- | pkg/helper/windows.go | 3 | ||||
-rw-r--r-- | pkg/vpn/launcher_linux.go | 1 | ||||
-rw-r--r-- | pkg/vpn/launcher_osx.go (renamed from pkg/vpn/launcher.go) | 5 | ||||
-rw-r--r-- | pkg/vpn/launcher_windows.go | 158 | ||||
-rw-r--r-- | pkg/vpn/openvpn.go | 12 |
7 files changed, 186 insertions, 36 deletions
@@ -43,7 +43,7 @@ endif SCRIPTS = branding/scripts TEMPLATES = branding/templates -TAP_WINDOWS = https://build.openvpn.net/downloads/releases/tap-windows-9.24.2-I601-Win10.exe +OPENVPN_WINDOWS_INSTALLER = https://build.openvpn.net/downloads/releases/OpenVPN-2.5.1-I601-amd64.msi HAS_QTIFW != which binarycreator.exe 2>/dev/null || PATH=$(PATH) which binarycreator OPENVPN_BIN != echo -n "$(HOME)/openvpn_build/sbin/$$(grep OPENVPN branding/thirdparty/openvpn/build_openvpn.sh | head -n 1 | cut -d = -f 2 | tr -d '"')" @@ -160,21 +160,11 @@ ifeq (${PLATFORM}, windows) "c:\windows\system32\rcedit.exe" ${QTBUILD}/release/${TARGET}.exe --set-version-string CompanyName "LEAP Encryption Access Project" "c:\windows\system32\rcedit.exe" ${QTBUILD}/release/${TARGET}.exe --set-version-string FileDescription "${APPNAME}" "c:\windows\system32\signtool.exe" sign -debug -f "z:\leap\LEAP.pfx" -p ${WINCERTPASS} ${QTBUILD}/release/${TARGET}.exe - # XXX need to deprecate helper and embrace interactive service - cp build/bin/${PLATFORM}/bitmask-helper build/bin/${PLATFORM}/bitmask-helper.exe - "c:\windows\system32\rcedit.exe" build/bin/${PLATFORM}/bitmask-helper.exe --set-file-version ${VERSION} - "c:\windows\system32\rcedit.exe" build/bin/${PLATFORM}/bitmask-helper.exe --set-product-version ${VERSION} - "c:\windows\system32\rcedit.exe" build/bin/${PLATFORM}/bitmask-helper.exe --set-version-string ProductName "bitmask-helper-v2" - "c:\windows\system32\rcedit.exe" build/bin/${PLATFORM}/bitmask-helper.exe --set-version-string CompanyName "LEAP Encryption Access Project" - "c:\windows\system32\rcedit.exe" build/bin/${PLATFORM}/bitmask-helper.exe --set-version-string FileDescription "Administrative helper for ${APPNAME}" - "c:\windows\system32\signtool.exe" sign -debug -f "z:\leap\LEAP.pfx" -p ${WINCERTPASS} build/bin/${PLATFORM}/bitmask-helper.exe endif checksign: ifeq (${PLATFORM}, windows) @"c:\windows\system32\sigcheck.exe" ${QTBUILD}/release/${TARGET}.exe - @"c:\windows\system32\sigcheck.exe" build/bin/${PLATFORM}/bitmask-helper.exe - @"c:\windows\system32\sigcheck.exe" "/c/Program Files/OpenVPN/bin/openvpn.exe" endif installer: check_qtifw checksign @@ -207,29 +197,24 @@ endif endif ifeq (${PLATFORM}, windows) @VERSION=${VERSION} VENDOR_PATH=${VENDOR_PATH} ${SCRIPTS}/gen-qtinstaller windows ${INSTALLER} - @cp build/bin/${PLATFORM}/bitmask-helper.exe ${INST_DATA}helper.exe ifeq (${VENDOR_PATH}, providers) @cp ${VENDOR_PATH}/${PROVIDER}/assets/icon.ico ${INST_DATA}/icon.ico else @cp ${VENDOR_PATH}/assets/icon.ico ${INST_DATA}/icon.ico endif @cp ${QTBUILD}/release/${TARGET}.exe ${INST_DATA}${TARGET}.exe - @cp "/c/Program Files/OpenVPN/bin/openvpn.exe" ${INST_DATA} - @cp "/c/Program Files/OpenVPN/bin/"*.dll ${INST_DATA} ifeq (${RELEASE}, yes) - #@windeployqt --release --qmldir gui/components ${INST_DATA}${TARGET}.exe - #FIXME -- cannot find platform plugin - @windeployqt --qmldir gui/components ${INST_DATA}${TARGET}.exe + @windeployqt --qmldir gui/qml ${INST_DATA}${TARGET}.exe # FIXME --release flag cannot find platform plugin else @windeployqt --qmldir gui/components ${INST_DATA}${TARGET}.exe endif - # TODO stage it to shave some time - @wget ${TAP_WINDOWS} -O ${INST_DATA}/tap-windows.exe # XXX this is a workaround for missing libs after windeployqt --- @cp /c/Qt/5.15.2/mingw81_64/bin/libgcc_s_seh-1.dll ${INST_DATA} @cp /c/Qt/5.15.2/mingw81_64/bin/libstdc++-6.dll ${INST_DATA} @cp /c/Qt/5.15.2/mingw81_64/bin/libwinpthread-1.dll ${INST_DATA} @cp -r /c/Qt/5.15.2/mingw81_64/qml ${INST_DATA} + # TODO stage it + @wget ${OPENVPN_WINDOWS_INSTALLER} -O ${INST_DATA}openvpn-installer.msi endif ifeq (${PLATFORM}, linux) @VERSION=${VERSION} ${SCRIPTS}/gen-qtinstaller linux ${INSTALLER} diff --git a/branding/templates/qtinstaller/packages/bitmaskvpn/meta/install.js b/branding/templates/qtinstaller/packages/bitmaskvpn/meta/install.js index aa3da1f..fcdb61c 100644 --- a/branding/templates/qtinstaller/packages/bitmaskvpn/meta/install.js +++ b/branding/templates/qtinstaller/packages/bitmaskvpn/meta/install.js @@ -99,24 +99,18 @@ function preInstallWindows() { } function postInstallWindows() { - // TODO - check if we're on Windows10 or older, and use the needed tap-windows installer accordingly. - console.log("Installing OpenVPN tap driver"); - component.addElevatedOperation("Execute", "@TargetDir@/tap-windows.exe", "/S", "/SELECT_UTILITIES=1"); /* TODO uninstall */ - /* remove an existing service, if it is stopped. Remove-Service is only in PS>6, and sc.exe delete leaves some garbage on the registry, so let's use the binary itself */ - console.log("Removing any previously installer helper..."); - component.addElevatedOperation("Execute", "{0,1}", "@TargetDir@/helper.exe", "remove"); - console.log("Now trying to install latest helper"); - component.addElevatedOperation("Execute", "@TargetDir@/helper.exe", "install", "UNDOEXECUTE", "@TargetDir@/helper.exe", "remove"); - component.addElevatedOperation("Execute", "@TargetDir@/helper.exe", "start", "UNDOEXECUTE", "@TargetDir@/helper.exe", "stop"); - console.log("Adding shortcut entries/..."); + // TODO - we probably need to package different flavors of the installer for windows 8, arm, i386 etc, and change the installer we ship too. + console.log("Installing OpenVPN binaries and service"); + component.addElevatedOperation("Execute", "{0}", "msiexec", "/i", "@TargetDir@\\openvpn-installer.msi", "ADDLOCAL=OpenVPN.Service,OpenVPN,Drivers,Drivers.TAPWindows6,Drivers.Wintun", "/passive") + console.log("Adding shortcut entries..."); component.addElevatedOperation("Mkdir", "@StartMenuDir@"); - component.addElevatedOperation("CreateShortcut", "@TargetDir@/$BINNAME.exe", "@StartMenuDir@/$APPNAME.lnk", "workingDirectory=@TargetDir@", "iconPath=@TargetDir@/icon.ico", "description=Start $APPNAME"); + component.addElevatedOperation("CreateShortcut", "@TargetDir@\\$BINNAME.exe", "@StartMenuDir@\\$APPNAME.lnk", "workingDirectory=@TargetDir@", "iconPath=@TargetDir@\\icon.ico", "description=Start $APPNAME"); // TODO I think this one is not being created because the path doesn't exist yet. We might want to do this by hooking on the installation finished signal instead. component.addElevatedOperation( "CreateShortcut", - "@TargetDir@/Uninstall-$APPNAME.exe", - "@StartMenuDir@/Uninstall.lnk" + "@TargetDir@\\Uninstall-$APPNAME.exe", + "@StartMenuDir@\\Uninstall.lnk" ); } diff --git a/pkg/helper/windows.go b/pkg/helper/windows.go index ca1642e..f7e035d 100644 --- a/pkg/helper/windows.go +++ b/pkg/helper/windows.go @@ -42,8 +42,9 @@ var ( func getPlatformOpenvpnFlags() []string { return []string{ - "--script-security", "1", + "--script-security", "0", "--block-outside-dns", + "--redirect-gateway", } } diff --git a/pkg/vpn/launcher_linux.go b/pkg/vpn/launcher_linux.go index 1fbcd6f..4925a17 100644 --- a/pkg/vpn/launcher_linux.go +++ b/pkg/vpn/launcher_linux.go @@ -40,6 +40,7 @@ var bitmaskRootPaths = []string{ type launcher struct { openvpnCh chan []string failed bool + mngPass string } func newLauncher() (*launcher, error) { diff --git a/pkg/vpn/launcher.go b/pkg/vpn/launcher_osx.go index f6e08eb..b676c24 100644 --- a/pkg/vpn/launcher.go +++ b/pkg/vpn/launcher_osx.go @@ -1,5 +1,5 @@ -// +build !linux -// Copyright (C) 2018-2020 LEAP +// +build osx +// Copyright (C) 2018-2021 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 @@ -36,6 +36,7 @@ import ( type launcher struct { helperAddr string failed bool + mngPass string } const initialHelperPort = 7171 diff --git a/pkg/vpn/launcher_windows.go b/pkg/vpn/launcher_windows.go new file mode 100644 index 0000000..be5ef83 --- /dev/null +++ b/pkg/vpn/launcher_windows.go @@ -0,0 +1,158 @@ +// +build windows +// Copyright (C) 2018-2021 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 vpn + +import ( + "errors" + "log" + "os" + "strings" + "bufio" + "fmt" + "unicode/utf16" + "bytes" + "time" + "encoding/binary" + + "github.com/natefinch/npipe" + "0xacab.org/leap/bitmask-vpn/pkg/vpn/bonafide" +) + +const pipeName = `\\.\pipe\openvpn\service` + +type launcher struct { + mngPass string +} + +func newLauncher() (*launcher, error) { + l := launcher{} + return &l, nil +} + +func (l *launcher) close() error { + return nil +} + +func (l *launcher) check() (helpers bool, privilege bool, err error) { + // TODO check if the named pipe exists + return true, true, nil +} + +func (l *launcher) openvpnStart(flags ...string) error { + var b bytes.Buffer + var filtered []string + for _, v := range flags { + if v != "--tun-ipv6" { + filtered = append(filtered, v) + } + } + + cwd, _ := os.Getwd() + opts := `--client --dev tun --block-outside-dns --redirect-gateway --script-security 0 ` + strings.Join(filtered, " ") + log.Println("openvpn start: ", opts) + + timeout := 3 * time.Second + conn, err := npipe.DialTimeout(pipeName, timeout) + if err != nil { + fmt.Println("ERROR opening pipe") + return errors.New("cannot open openvpn pipe") + + } + defer conn.Close() + + writeUTF16Bytes(&b, cwd) + writeUTF16Bytes(&b, opts) + writeUTF16Bytes(&b, `\n`) + encoded := b.Bytes() + + rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + + _, err = rw.Write(encoded) + if err != nil { + fmt.Println("ERROR writing to pipe") + return errors.New("cannot write to openvpn pipe") + } + rw.Flush() + pid, err := getCommandResponse(rw) + if err != nil { + fmt.Println("ERROR getting pid") + } + fmt.Println("OpenVPN PID:", pid) + return nil +} + +func (l *launcher) openvpnStop() error { + return nil +} + +// TODO we will have to bring our helper back to do firewall + +func (l *launcher) firewallStart(gateways []bonafide.Gateway) error { + log.Println("NO firewall in windows") + return nil +} + +func (l *launcher) firewallStop() error { + log.Println("NO firewall in windows") + return nil +} + +func (l *launcher) firewallIsUp() bool { + log.Println("NO firewall in windows") + return true +} + + +func writeUTF16Bytes(b *bytes.Buffer, in string) { + var u16 []uint16 = utf16.Encode([]rune(in + "\x00")) + binary.Write(b, binary.LittleEndian, u16) +} + +func decodeUTF16String(s string) int { + var code int + var dec []byte + for _, v := range []byte(s) { + if byte(v) != byte(0) { + dec = append(dec, v) + } + } + _, err := fmt.Sscanf(string(dec), "%v", &code) + if err != nil { + fmt.Println("ERROR decoding") + } + return code +} + +func getCommandResponse(rw *bufio.ReadWriter) (int, error) { + msg, err := rw.ReadString('\n') + if err != nil { + fmt.Println("ERROR reading") + } + ok := decodeUTF16String(msg) + if ok != 0 { + return -1, errors.New("command failed") + } + msg, err = rw.ReadString('\n') + if err != nil { + fmt.Println("ERROR reading") + } + pid := decodeUTF16String(msg) + if pid == 0 { + return -1, errors.New("command failed") + } + return pid, nil +} diff --git a/pkg/vpn/openvpn.go b/pkg/vpn/openvpn.go index a114980..ee0e2f7 100644 --- a/pkg/vpn/openvpn.go +++ b/pkg/vpn/openvpn.go @@ -265,7 +265,17 @@ func (b *Bitmask) StopVPN() error { b.obfsvpnProxy.Stop() b.obfsvpnProxy = nil } - return b.launch.openvpnStop() + b.stopFromManagement() + b.launch.openvpnStop() + return nil +} + +func (b *Bitmask) stopFromManagement() error { + if b.managementClient == nil { + return fmt.Errorf("No management connected") + } + b.managementClient.SendSignal("SIGTERM") + return nil } // Reconnect to the VPN |