package handlers import ( "log" "alpine-router/config" "alpine-router/firewall" "alpine-router/nat" "alpine-router/network" ) // applyAllRules rebuilds the complete nftables ruleset from the current config: // NAT masquerade + user firewall rules + VLAN isolation + blocked clients. func applyAllRules(cfg *config.AppConfig) error { if !nat.IsInstalled() { return nil } // Collect blocked client IPs. var blockedIPs []string for _, kd := range cfg.KnownDevices { if kd.Blocked { ip := kd.IP if kd.StaticIP != "" { ip = kd.StaticIP } if ip != "" { blockedIPs = append(blockedIPs, ip) } } } // Build the LAN interface set for isolation: // all NAT interfaces + all VLAN interfaces (active + pending). // This ensures native interfaces (eth0) and their VLANs (eth0.100) are all // mutually isolated when VLANIsolation is enabled. seen := map[string]bool{} var lanIfaces []string addLAN := func(name string) { if name != "" && !seen[name] { lanIfaces = append(lanIfaces, name) seen[name] = true } } for _, name := range cfg.NAT.Interfaces { addLAN(name) } names, _ := network.GetInterfaces() for _, name := range names { if network.IsVLAN(name) { addLAN(name) addLAN(network.VLANParent(name)) // include parent (native VLAN) too } } for name := range network.GetAllPending() { if network.IsVLAN(name) { addLAN(name) addLAN(network.VLANParent(name)) } } // Convert config.FirewallRule → firewall.Rule. fwRules := make([]firewall.Rule, len(cfg.Firewall.Rules)) for i, r := range cfg.Firewall.Rules { fwRules[i] = firewall.Rule{ ID: r.ID, Enabled: r.Enabled, Action: r.Action, Protocol: r.Protocol, SrcAddr: r.SrcAddr, SrcPort: r.SrcPort, DstAddr: r.DstAddr, DstPort: r.DstPort, InIface: r.InIface, OutIface: r.OutIface, Comment: r.Comment, } } return firewall.ApplyAll( firewall.NATConfig{Interfaces: cfg.NAT.Interfaces}, firewall.Config{Rules: fwRules, VLANIsolation: cfg.Firewall.VLANIsolation}, blockedIPs, lanIfaces, ) } // applyBlockedFirewall is the async helper called after client updates. func applyBlockedFirewall() { cfg, err := config.Load() if err != nil { log.Printf("Warning: load config for firewall: %v", err) return } if err := applyAllRules(cfg); err != nil { log.Printf("Warning: apply firewall rules: %v", err) } }