Single connection written to openvpn configuration (#258)
- From now only a single OpenVPN connection is written to the OpenVPN configuration file - If multiple connections are matched given the user parameters (i.e. city, region), it is picked at pseudo random using the current time as the pseudo random seed. - Not relying on Openvpn picking a random remote address, may refer to #229 - Program is aware of which connection is to be used, in order to use its matching CN for port forwarding TLS verification with PIA v4 servers, see #236 - Simplified firewall mechanisms
This commit is contained in:
@@ -85,8 +85,8 @@ func (c *configurator) enable(ctx context.Context) (err error) { //nolint:gocogn
|
||||
if err = c.acceptEstablishedRelatedTraffic(ctx, remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
for _, conn := range c.vpnConnections {
|
||||
if err = c.acceptOutputTrafficToVPN(ctx, c.defaultInterface, conn, remove); err != nil {
|
||||
if c.vpnConnection.IP != nil {
|
||||
if err = c.acceptOutputTrafficToVPN(ctx, c.defaultInterface, c.vpnConnection, remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
type Configurator interface {
|
||||
Version(ctx context.Context) (string, error)
|
||||
SetEnabled(ctx context.Context, enabled bool) (err error)
|
||||
SetVPNConnections(ctx context.Context, connections []models.OpenVPNConnection) (err error)
|
||||
SetVPNConnection(ctx context.Context, connection models.OpenVPNConnection) (err error)
|
||||
SetAllowedSubnets(ctx context.Context, subnets []net.IPNet) (err error)
|
||||
SetAllowedPort(ctx context.Context, port uint16, intf string) (err error)
|
||||
RemoveAllowedPort(ctx context.Context, port uint16) (err error)
|
||||
@@ -39,7 +39,7 @@ type configurator struct { //nolint:maligned
|
||||
|
||||
// State
|
||||
enabled bool
|
||||
vpnConnections []models.OpenVPNConnection
|
||||
vpnConnection models.OpenVPNConnection
|
||||
allowedSubnets []net.IPNet
|
||||
allowedInputPorts map[uint16]string // port to interface mapping
|
||||
stateMutex sync.Mutex
|
||||
|
||||
@@ -7,95 +7,33 @@ import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
func (c *configurator) SetVPNConnections(ctx context.Context, connections []models.OpenVPNConnection) (err error) {
|
||||
func (c *configurator) SetVPNConnection(ctx context.Context, connection models.OpenVPNConnection) (err error) {
|
||||
c.stateMutex.Lock()
|
||||
defer c.stateMutex.Unlock()
|
||||
|
||||
if !c.enabled {
|
||||
c.logger.Info("firewall disabled, only updating VPN connections internal list")
|
||||
c.vpnConnections = make([]models.OpenVPNConnection, len(connections))
|
||||
copy(c.vpnConnections, connections)
|
||||
c.logger.Info("firewall disabled, only updating internal VPN connection")
|
||||
c.vpnConnection = connection
|
||||
return nil
|
||||
}
|
||||
|
||||
c.logger.Info("setting VPN connections through firewall...")
|
||||
c.logger.Info("setting VPN connection through firewall...")
|
||||
|
||||
connectionsToAdd := findConnectionsToAdd(c.vpnConnections, connections)
|
||||
connectionsToRemove := findConnectionsToRemove(c.vpnConnections, connections)
|
||||
if len(connectionsToAdd) == 0 && len(connectionsToRemove) == 0 {
|
||||
if c.vpnConnection.Equal(connection) {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.removeConnections(ctx, connectionsToRemove, c.defaultInterface)
|
||||
if err := c.addConnections(ctx, connectionsToAdd, c.defaultInterface); err != nil {
|
||||
return fmt.Errorf("cannot set VPN connections through firewall: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeConnectionFromConnections(connections []models.OpenVPNConnection, connection models.OpenVPNConnection) []models.OpenVPNConnection {
|
||||
L := len(connections)
|
||||
for i := range connections {
|
||||
if connection.Equal(connections[i]) {
|
||||
connections[i] = connections[L-1]
|
||||
connections = connections[:L-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
return connections
|
||||
}
|
||||
|
||||
func findConnectionsToAdd(oldConnections, newConnections []models.OpenVPNConnection) (connectionsToAdd []models.OpenVPNConnection) {
|
||||
for _, newConnection := range newConnections {
|
||||
found := false
|
||||
for _, oldConnection := range oldConnections {
|
||||
if oldConnection.Equal(newConnection) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
connectionsToAdd = append(connectionsToAdd, newConnection)
|
||||
}
|
||||
}
|
||||
return connectionsToAdd
|
||||
}
|
||||
|
||||
func findConnectionsToRemove(oldConnections, newConnections []models.OpenVPNConnection) (connectionsToRemove []models.OpenVPNConnection) {
|
||||
for _, oldConnection := range oldConnections {
|
||||
found := false
|
||||
for _, newConnection := range newConnections {
|
||||
if oldConnection.Equal(newConnection) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
connectionsToRemove = append(connectionsToRemove, oldConnection)
|
||||
}
|
||||
}
|
||||
return connectionsToRemove
|
||||
}
|
||||
|
||||
func (c *configurator) removeConnections(ctx context.Context, connections []models.OpenVPNConnection, defaultInterface string) {
|
||||
for _, conn := range connections {
|
||||
const remove = true
|
||||
if err := c.acceptOutputTrafficToVPN(ctx, defaultInterface, conn, remove); err != nil {
|
||||
remove := true
|
||||
if c.vpnConnection.IP != nil {
|
||||
if err := c.acceptOutputTrafficToVPN(ctx, c.defaultInterface, c.vpnConnection, remove); err != nil {
|
||||
c.logger.Error("cannot remove outdated VPN connection through firewall: %s", err)
|
||||
continue
|
||||
}
|
||||
c.vpnConnections = removeConnectionFromConnections(c.vpnConnections, conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *configurator) addConnections(ctx context.Context, connections []models.OpenVPNConnection, defaultInterface string) error {
|
||||
const remove = false
|
||||
for _, conn := range connections {
|
||||
if err := c.acceptOutputTrafficToVPN(ctx, defaultInterface, conn, remove); err != nil {
|
||||
return err
|
||||
}
|
||||
c.vpnConnections = append(c.vpnConnections, conn)
|
||||
c.vpnConnection = models.OpenVPNConnection{}
|
||||
remove = false
|
||||
if err := c.acceptOutputTrafficToVPN(ctx, c.defaultInterface, connection, remove); err != nil {
|
||||
return fmt.Errorf("cannot set VPN connection through firewall: %w", err)
|
||||
}
|
||||
c.vpnConnection = connection
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user