Maint: dynamically set allowed VPN input ports

- Feat: allow to change VPN type at runtime
- Feat: allow to change interface name at runtime
- Maint: Add cleanup method to cleanup VPN loop on a vpn shutdown
- Change: allow VPN inputs ports only when tunnel is up
This commit is contained in:
Quentin McGaw (desktop)
2021-09-13 00:50:20 +00:00
parent 19bf62c21f
commit 40342619e7
6 changed files with 49 additions and 30 deletions

View File

@@ -292,14 +292,6 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
} }
} }
for _, vpnPort := range allSettings.Firewall.VPNInputPorts {
vpnIntf := allSettings.VPN.VPNInterface()
err = firewallConf.SetAllowedPort(ctx, vpnPort, vpnIntf)
if err != nil {
return err
}
}
for _, port := range allSettings.Firewall.InputPorts { for _, port := range allSettings.Firewall.InputPorts {
err = firewallConf.SetAllowedPort(ctx, port, defaultInterface) err = firewallConf.SetAllowedPort(ctx, port, defaultInterface)
if err != nil { if err != nil {
@@ -360,7 +352,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
tickersGroupHandler.Add(pubIPTickerHandler) tickersGroupHandler.Add(pubIPTickerHandler)
vpnLogger := logger.NewChild(logging.Settings{Prefix: "vpn: "}) vpnLogger := logger.NewChild(logging.Settings{Prefix: "vpn: "})
vpnLooper := vpn.NewLoop(allSettings.VPN, vpnLooper := vpn.NewLoop(allSettings.VPN, allSettings.Firewall.VPNInputPorts,
allServers, ovpnConf, netLinker, firewallConf, routingConf, portForwardLooper, allServers, ovpnConf, netLinker, firewallConf, routingConf, portForwardLooper,
cmder, publicIPLooper, unboundLooper, vpnLogger, httpClient, cmder, publicIPLooper, unboundLooper, vpnLogger, httpClient,
buildInfo, allSettings.VersionInformation) buildInfo, allSettings.VersionInformation)

27
internal/vpn/cleanup.go Normal file
View File

@@ -0,0 +1,27 @@
package vpn
import (
"context"
"time"
"github.com/qdm12/gluetun/internal/publicip/models"
)
func (l *Loop) cleanup(ctx context.Context, pfEnabled bool) {
for _, vpnPort := range l.vpnInputPorts {
err := l.fw.RemoveAllowedPort(ctx, vpnPort)
if err != nil {
l.logger.Error("cannot remove allowed input port from firewall: " + err.Error())
}
}
l.publicip.SetData(models.IPInfoData{}) // clear public IP address data
if pfEnabled {
const pfTimeout = 100 * time.Millisecond
err := l.stopPortForwarding(ctx, pfTimeout)
if err != nil {
l.logger.Error("cannot stop port forwarding: " + err.Error())
}
}
}

View File

@@ -34,8 +34,9 @@ type Loop struct {
statusManager loopstate.Manager statusManager loopstate.Manager
state state.Manager state state.Manager
// Fixed parameters // Fixed parameters
buildInfo models.BuildInformation buildInfo models.BuildInformation
versionInfo bool versionInfo bool
vpnInputPorts []uint16 // TODO make changeable through stateful firewall
// Configurators // Configurators
openvpnConf openvpn.Interface openvpnConf openvpn.Interface
netLinker netlink.NetLinker netLinker netlink.NetLinker
@@ -67,7 +68,7 @@ const (
defaultBackoffTime = 15 * time.Second defaultBackoffTime = 15 * time.Second
) )
func NewLoop(vpnSettings configuration.VPN, func NewLoop(vpnSettings configuration.VPN, vpnInputPorts []uint16,
allServers models.AllServers, openvpnConf openvpn.Interface, allServers models.AllServers, openvpnConf openvpn.Interface,
netLinker netlink.NetLinker, fw firewallConfigurer, routing routing.VPNGetter, netLinker netlink.NetLinker, fw firewallConfigurer, routing routing.VPNGetter,
portForward portforward.StartStopper, starter command.Starter, portForward portforward.StartStopper, starter command.Starter,
@@ -87,6 +88,7 @@ func NewLoop(vpnSettings configuration.VPN,
state: state, state: state,
buildInfo: buildInfo, buildInfo: buildInfo,
versionInfo: versionInfo, versionInfo: versionInfo,
vpnInputPorts: vpnInputPorts,
openvpnConf: openvpnConf, openvpnConf: openvpnConf,
netLinker: netLinker, netLinker: netLinker,
fw: fw, fw: fw,

View File

@@ -40,20 +40,14 @@ func (l *Loop) startPortForwarding(ctx context.Context, data tunnelUpData) (err
return nil return nil
} }
func (l *Loop) stopPortForwarding(ctx context.Context, enabled bool, func (l *Loop) stopPortForwarding(ctx context.Context,
timeout time.Duration) { timeout time.Duration) (err error) {
if !enabled {
return // nothing to stop
}
if timeout > 0 { if timeout > 0 {
var cancel context.CancelFunc var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, timeout) ctx, cancel = context.WithTimeout(ctx, timeout)
defer cancel() defer cancel()
} }
_, err := l.portForward.Stop(ctx) _, err = l.portForward.Stop(ctx)
if err != nil { return err
l.logger.Error("cannot stop port forwarding: " + err.Error())
}
} }

View File

@@ -6,7 +6,6 @@ import (
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/provider" "github.com/qdm12/gluetun/internal/provider"
"github.com/qdm12/gluetun/internal/publicip/models"
"github.com/qdm12/golibs/logging" "github.com/qdm12/golibs/logging"
) )
@@ -32,6 +31,7 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
providerConf := provider.New(settings.Provider.Name, allServers, time.Now) providerConf := provider.New(settings.Provider.Name, allServers, time.Now)
portForwarding := settings.Provider.PortForwarding.Enabled
var vpnRunner vpnRunner var vpnRunner vpnRunner
var serverName, vpnInterface string var serverName, vpnInterface string
var err error var err error
@@ -49,7 +49,7 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
continue continue
} }
tunnelUpData := tunnelUpData{ tunnelUpData := tunnelUpData{
portForwarding: settings.Provider.PortForwarding.Enabled, portForwarding: portForwarding,
serverName: serverName, serverName: serverName,
portForwarder: providerConf, portForwarder: providerConf,
vpnIntf: vpnInterface, vpnIntf: vpnInterface,
@@ -76,9 +76,7 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
case <-tunnelReady: case <-tunnelReady:
go l.onTunnelUp(openvpnCtx, tunnelUpData) go l.onTunnelUp(openvpnCtx, tunnelUpData)
case <-ctx.Done(): case <-ctx.Done():
const pfTimeout = 100 * time.Millisecond l.cleanup(context.Background(), portForwarding)
l.stopPortForwarding(context.Background(),
settings.Provider.PortForwarding.Enabled, pfTimeout)
openvpnCancel() openvpnCancel()
<-waitError <-waitError
close(waitError) close(waitError)
@@ -86,8 +84,7 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
case <-l.stop: case <-l.stop:
l.userTrigger = true l.userTrigger = true
l.logger.Info("stopping") l.logger.Info("stopping")
l.publicip.SetData(models.IPInfoData{}) // clear public IP address data l.cleanup(context.Background(), portForwarding)
l.stopPortForwarding(ctx, settings.Provider.PortForwarding.Enabled, 0)
openvpnCancel() openvpnCancel()
<-waitError <-waitError
// do not close waitError or the waitError // do not close waitError or the waitError
@@ -102,7 +99,7 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
l.statusManager.Lock() // prevent SetStatus from running in parallel l.statusManager.Lock() // prevent SetStatus from running in parallel
l.stopPortForwarding(ctx, settings.Provider.PortForwarding.Enabled, 0) l.cleanup(context.Background(), portForwarding)
openvpnCancel() openvpnCancel()
l.statusManager.SetStatus(constants.Crashed) l.statusManager.SetStatus(constants.Crashed)
l.logAndWait(ctx, err) l.logAndWait(ctx, err)

View File

@@ -19,6 +19,13 @@ type tunnelUpData struct {
func (l *Loop) onTunnelUp(ctx context.Context, data tunnelUpData) { func (l *Loop) onTunnelUp(ctx context.Context, data tunnelUpData) {
l.client.CloseIdleConnections() l.client.CloseIdleConnections()
for _, vpnPort := range l.vpnInputPorts {
err := l.fw.SetAllowedPort(ctx, vpnPort, data.vpnIntf)
if err != nil {
l.logger.Error("cannot allow input port through firewall: " + err.Error())
}
}
if l.dnsLooper.GetSettings().Enabled { if l.dnsLooper.GetSettings().Enabled {
_, _ = l.dnsLooper.ApplyStatus(ctx, constants.Running) _, _ = l.dnsLooper.ApplyStatus(ctx, constants.Running)
} }