feat(vpn): VPN_UP_COMMAND and VPN_DOWN_COMMAND options

This commit is contained in:
Quentin McGaw
2026-03-08 16:06:16 +00:00
parent c0af198155
commit 57c53bc19e
14 changed files with 152 additions and 68 deletions
+25 -1
View File
@@ -3,9 +3,22 @@ package vpn
import (
"context"
"errors"
"strings"
"github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants/vpn"
)
func (l *Loop) cleanup() {
settings := l.GetSettings()
var err error
commandString := strings.ReplaceAll(*settings.DownCommand, "{{VPN_INTERFACE}}", getVPNInterface(settings))
err = l.cmder.RunAndLog(context.Background(), commandString, l.logger)
if err != nil {
l.logger.Error("failed to run VPN down command: " + err.Error())
}
for _, vpnPort := range l.vpnInputPorts {
err := l.fw.RemoveAllowedPort(context.Background(), vpnPort)
if err != nil {
@@ -13,7 +26,7 @@ func (l *Loop) cleanup() {
}
}
err := l.publicip.ClearData()
err = l.publicip.ClearData()
if err != nil {
l.logger.Error("clearing public IP data: " + err.Error())
}
@@ -31,3 +44,14 @@ func (l *Loop) cleanup() {
l.logger.Error("stopping boring poll: " + err.Error())
}
}
func getVPNInterface(settings settings.VPN) string {
switch settings.Type {
case vpn.OpenVPN:
return settings.OpenVPN.Interface
case vpn.Wireguard:
return settings.Wireguard.Interface
default:
panic("invalid VPN type: " + settings.Type)
}
}
+5
View File
@@ -5,6 +5,7 @@ import (
"net/netip"
"os/exec"
"github.com/qdm12/gluetun/internal/command"
"github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/netlink"
@@ -120,3 +121,7 @@ type Service interface {
Start() (runError <-chan error, err error)
Stop() error
}
type Cmder interface {
RunAndLog(ctx context.Context, command string, logger command.Logger) (err error)
}
+1
View File
@@ -17,6 +17,7 @@ type Loop struct {
state *state.State
providers Providers
storage Storage
cmder Cmder
healthSettings settings.Health
healthChecker HealthChecker
healthServer HealthServer
+1
View File
@@ -47,6 +47,7 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
continue
}
tunnelUpData := tunnelUpData{
upCommand: *settings.UpCommand,
pmtud: tunnelUpPMTUDData{
enabled: settings.Type != vpn.Wireguard || *settings.Wireguard.MTU == 0,
vpnType: settings.Type,
+10
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net/netip"
"strings"
"time"
"github.com/qdm12/gluetun/internal/constants"
@@ -16,6 +17,7 @@ import (
)
type tunnelUpData struct {
upCommand string
// Healthcheck
serverIP netip.Addr
pmtud tunnelUpPMTUDData
@@ -107,6 +109,14 @@ func (l *Loop) onTunnelUp(ctx, loopCtx context.Context, data tunnelUpData) {
}
}
if data.upCommand != "" {
commandString := strings.ReplaceAll(data.upCommand, "{{VPN_INTERFACE}}", data.vpnIntf)
err := l.cmder.RunAndLog(context.Background(), commandString, l.logger)
if err != nil {
l.logger.Error("failed to run VPN up command: " + err.Error())
}
}
err = l.startPortForwarding(data)
if err != nil {
l.logger.Error(err.Error())