diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..f5b8e96 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,17 @@ +--- +name: Test VPN +on: [ push, workflow_dispatch ] + +jobs: + test-vpn: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: ./ + with: + server: ${{ vars.VPN_SERVER }} + psk: ${{ secrets.VPN_PSK }} + username: ${{ vars.VPN_USERNAME }} + password: ${{ secrets.VPN_PASSWORD }} + route: 104.18.0.0/15 + - run: curl --silent https://canhazip.com diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..17d3dbb --- /dev/null +++ b/action.yml @@ -0,0 +1,26 @@ +name: 'Setup VPN connection' +description: 'Connect Github Actions to VPN' +author: 'Arne Jørgensen' +branding: + color: green + icon: globe +inputs: + server: + required: true + description: 'VPN server' + psk: + required: true + description: 'VPN pre-shared key' + username: + required: true + description: 'VPN username' + password: + required: true + description: 'VPN password' + route: + required: true + description: 'VPN route' +runs: + using: 'node20' + main: 'vpn-up.mjs' + post: 'vpn-down.mjs' diff --git a/vpn-down.mjs b/vpn-down.mjs new file mode 100644 index 0000000..76cb5c9 --- /dev/null +++ b/vpn-down.mjs @@ -0,0 +1,6 @@ +// -*- javascript -*- +// Config based on https://github.com/jabas06/l2tp-ipsec-vpn-client + +import { spawn } from "child_process"; + +spawn("sudo", ["./vpn-down.sh"], { stdio: "inherit" }); diff --git a/vpn-down.sh b/vpn-down.sh new file mode 100755 index 0000000..9b9bdad --- /dev/null +++ b/vpn-down.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +bash -c 'echo "d myVPN" > /var/run/xl2tpd/l2tp-control' +ipsec down L2TP-PSK diff --git a/vpn-up.mjs b/vpn-up.mjs new file mode 100644 index 0000000..4ee3899 --- /dev/null +++ b/vpn-up.mjs @@ -0,0 +1,109 @@ +// -*- javascript -*- +// Config based on https://github.com/jabas06/l2tp-ipsec-vpn-client + +import { writeFile } from "fs"; +import { spawn } from "child_process"; + +const server = process.env.INPUT_SERVER || ""; +const username = process.env.INPUT_USERNAME || ""; +const password = process.env.INPUT_PASSWORD || ""; +const psk = process.env.INPUT_PSK || ""; +const route = process.env.INPUT_ROUTE || ""; + +let ipsecConf = "ipsec.conf"; +let ipsecSecrets = "ipsec.secrets"; +let xl2tpdConf = "xl2tpd.conf"; +let optionsL2tpdClient = "options.l2tpd.client"; + +async function vpn() { + const ipsecConfContent = ` +config setup + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev1 + authby=secret + ike=3des-sha1-modp1024 + esp=3des-sha1 + +conn L2TP-PSK + keyexchange=ikev1 + left=%defaultroute + auto=add + authby=secret + type=transport + leftprotoport=17/1701 + rightprotoport=17/1701 + right=${server} +`; + + await writeFile(ipsecConf, ipsecConfContent.trim(), (err) => { + if (err) throw err; + }); + + const ipsecSecretsContent = ` +${server} : PSK "${psk}" +`; + + await writeFile(ipsecSecrets, ipsecSecretsContent.trim(), (err) => { + if (err) throw err; + }); + + const xl2tpdConfigContent = ` +[lac myVPN] +lns = ${server} +ppp debug = yes +pppoptfile = /etc/ppp/options.l2tpd.client +length bit = yes +`; + + await writeFile(xl2tpdConf, xl2tpdConfigContent.trim(), (err) => { + if (err) throw err; + }); + + const optionsL2tpdClientContent = ` +ipcp-accept-local +ipcp-accept-remote +refuse-eap +require-mschap-v2 +noccp +noauth +logfile /var/log/xl2tpd.log +idle 1800 +mtu 1410 +mru 1410 +defaultroute +usepeerdns +debug +connect-delay 5000 +name ${username} +password ${password} +`; + + await writeFile( + optionsL2tpdClient, + optionsL2tpdClientContent.trim(), + (err) => { + if (err) throw err; + }, + ); + + const routeScriptContent = ` +echo A +ip address show dev ppp0 +echo B +echo $(ip address show dev ppp0 | grep -Po '(?<=peer )(\b([0-9]{1,3}\.){3}[0-9]{1,3}\b)') +echo C +echo ip route add ${route} via $(ip address show dev ppp0 | grep -Po '(?<=peer )(\b([0-9]{1,3}\.){3}[0-9]{1,3}\b)') dev ppp0 +`; + await writeFile("route.sh", routeScriptContent.trim(), (err) => { + if (err) throw err; + }); +} + +await vpn(); + +spawn("sudo", ["./vpn-up.sh"], { stdio: "inherit" }); diff --git a/vpn-up.sh b/vpn-up.sh new file mode 100755 index 0000000..fbb0fd8 --- /dev/null +++ b/vpn-up.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +apt-get --quiet --assume-yes update +apt-get --quiet --assume-yes install strongswan xl2tpd + +mkdir -p /var/run/xl2tpd +mkdir -p /etc/xl2tpd +mkdir -p /etc/ppp + +cp ipsec.conf /etc/ipsec.conf +cp ipsec.secrets /etc/ipsec.secrets +cp xl2tpd.conf /etc/xl2tpd/xl2tpd.conf +cp options.l2tpd.client /etc/ppp/options.l2tpd.client + +touch /var/run/xl2tpd/l2tp-control +systemctl restart strongswan-starter xl2tpd ipsec +sleep 8 +ipsec up L2TP-PSK +sleep 8 +bash -c 'echo "c myVPN" > /var/run/xl2tpd/l2tp-control' +sleep 8 +ifconfig + +chmod +x route.sh && ./route.sh