feat: add web proxy target allowlist support via NEXAVPN_ALWAYS_ALLOW_WEB_PROXY_IPS environment variable
Add alwaysAllowWebProxyTargets function to parse comma-separated IPs from NEXAVPN_ALWAYS_ALLOW_WEB_PROXY_IPS environment variable with deduplication. Update mergeProfileAllowedIPs to accept webProxyTargets parameter and merge them into profile allowed IPs using /32 routes. Add WebProxyTargets field to wireguard.Peer struct and populate it in BuildSyncBundle and device enrollment/policy application
This commit is contained in:
@@ -2,6 +2,7 @@ package device
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
@@ -62,7 +63,7 @@ func (s *Service) Enroll(ctx context.Context, userID uuid.UUID, input EnrollRequ
|
||||
if len(destinations) == 0 {
|
||||
destinations = []string{"172.16.10.0/24"}
|
||||
}
|
||||
profileAllowedIPs := mergeProfileAllowedIPs(destinations, selectedGateway.DNSServers)
|
||||
profileAllowedIPs := mergeProfileAllowedIPs(destinations, selectedGateway.DNSServers, alwaysAllowWebProxyTargets())
|
||||
|
||||
enrollment.Peer = PeerView{
|
||||
AssignedIP: assignedIP,
|
||||
@@ -184,13 +185,13 @@ func (s *Service) applyCurrentPolicy(ctx context.Context, enrollment EnrollmentR
|
||||
Label: destination,
|
||||
})
|
||||
}
|
||||
enrollment.Peer.AllowedIPs = mergeProfileAllowedIPs(destinations, enrollment.Peer.DNSServers)
|
||||
enrollment.Peer.AllowedIPs = mergeProfileAllowedIPs(destinations, enrollment.Peer.DNSServers, alwaysAllowWebProxyTargets())
|
||||
return withDebugProfile(enrollment), nil
|
||||
}
|
||||
|
||||
func mergeProfileAllowedIPs(destinations []string, dnsServers []string) []string {
|
||||
seen := make(map[string]struct{}, len(destinations)+len(dnsServers))
|
||||
merged := make([]string, 0, len(destinations)+len(dnsServers))
|
||||
func mergeProfileAllowedIPs(destinations []string, dnsServers []string, webProxyTargets []string) []string {
|
||||
seen := make(map[string]struct{}, len(destinations)+len(dnsServers)+len(webProxyTargets))
|
||||
merged := make([]string, 0, len(destinations)+len(dnsServers)+len(webProxyTargets))
|
||||
|
||||
for _, destination := range destinations {
|
||||
destination = strings.TrimSpace(destination)
|
||||
@@ -216,6 +217,18 @@ func mergeProfileAllowedIPs(destinations []string, dnsServers []string) []string
|
||||
merged = append(merged, route)
|
||||
}
|
||||
|
||||
for _, target := range webProxyTargets {
|
||||
route := dnsServerRoute(target)
|
||||
if route == "" {
|
||||
continue
|
||||
}
|
||||
if _, exists := seen[route]; exists {
|
||||
continue
|
||||
}
|
||||
seen[route] = struct{}{}
|
||||
merged = append(merged, route)
|
||||
}
|
||||
|
||||
return merged
|
||||
}
|
||||
|
||||
@@ -229,3 +242,25 @@ func dnsServerRoute(value string) string {
|
||||
}
|
||||
return value + "/32"
|
||||
}
|
||||
|
||||
func alwaysAllowWebProxyTargets() []string {
|
||||
raw := os.Getenv("NEXAVPN_ALWAYS_ALLOW_WEB_PROXY_IPS")
|
||||
if strings.TrimSpace(raw) == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
seen := make(map[string]struct{})
|
||||
targets := make([]string, 0)
|
||||
for _, part := range strings.Split(raw, ",") {
|
||||
value := strings.TrimSpace(part)
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[value]; ok {
|
||||
continue
|
||||
}
|
||||
seen[value] = struct{}{}
|
||||
targets = append(targets, value)
|
||||
}
|
||||
return targets
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
@@ -118,12 +120,35 @@ func (r *PGRepository) BuildSyncBundle(ctx context.Context, gatewayID uuid.UUID)
|
||||
return wireguard.GatewayBundle{}, err
|
||||
}
|
||||
peer.DeviceID = deviceID.String()
|
||||
peer.WebProxyTargets = alwaysAllowWebProxyTargets()
|
||||
bundle.Peers = append(bundle.Peers, peer)
|
||||
}
|
||||
|
||||
return bundle, rows.Err()
|
||||
}
|
||||
|
||||
func alwaysAllowWebProxyTargets() []string {
|
||||
raw := os.Getenv("NEXAVPN_ALWAYS_ALLOW_WEB_PROXY_IPS")
|
||||
if strings.TrimSpace(raw) == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
seen := make(map[string]struct{})
|
||||
targets := make([]string, 0)
|
||||
for _, part := range strings.Split(raw, ",") {
|
||||
value := strings.TrimSpace(part)
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[value]; ok {
|
||||
continue
|
||||
}
|
||||
seen[value] = struct{}{}
|
||||
targets = append(targets, value)
|
||||
}
|
||||
return targets
|
||||
}
|
||||
|
||||
func (r *PGRepository) Update(ctx context.Context, gatewayID uuid.UUID, input UpdateRequest) (Gateway, error) {
|
||||
row := r.db.QueryRow(ctx, `
|
||||
update gateways
|
||||
|
||||
@@ -6,6 +6,7 @@ type Peer struct {
|
||||
AssignedIP string `json:"assigned_ip"`
|
||||
AllowedDestinations []string `json:"allowed_destinations"`
|
||||
DNSServers []string `json:"dns_servers"`
|
||||
WebProxyTargets []string `json:"web_proxy_targets"`
|
||||
}
|
||||
|
||||
type GatewayBundle struct {
|
||||
|
||||
Reference in New Issue
Block a user