Skip to content

Commit

Permalink
Process all lists completely before writing them to dnsmasq. Fixes #2
Browse files Browse the repository at this point in the history
  • Loading branch information
maksimkurb committed Feb 1, 2025
1 parent 8b24781 commit 4dafa24
Show file tree
Hide file tree
Showing 15 changed files with 520 additions and 160 deletions.
12 changes: 7 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
module github.com/maksimkurb/keenetic-pbr

go 1.21
go 1.23.4

require github.com/BurntSushi/toml v1.4.0

require github.com/vishvananda/netlink v1.3.0
require (
github.com/coreos/go-iptables v0.8.0
github.com/valyala/fasttemplate v1.2.2
github.com/vishvananda/netlink v1.3.0
golang.org/x/sys v0.10.0
)

require (
github.com/coreos/go-iptables v0.8.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
golang.org/x/sys v0.10.0 // indirect
)
24 changes: 12 additions & 12 deletions lib/commands/self_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ func (g *SelfCheckCommand) Run() error {

log.Infof("----------------- Configuration END ------------------")

for _, ipset := range g.cfg.Ipset {
for _, ipset := range g.cfg.IPSets {
if err := checkIpset(g.cfg, ipset); err != nil {
log.Errorf("Failed to check ipset routing configuration [%s]: %v", ipset.IpsetName, err)
log.Errorf("Failed to check ipset routing configuration [%s]: %v", ipset.IPSetName, err)
return err
}
}
Expand All @@ -71,8 +71,8 @@ func (g *SelfCheckCommand) Run() error {
return nil
}

func checkIpset(cfg *config.Config, ipset *config.IpsetConfig) error {
log.Infof("----------------- IPSet [%s] ------------------", ipset.IpsetName)
func checkIpset(cfg *config.Config, ipset *config.IPSetConfig) error {
log.Infof("----------------- IPSet [%s] ------------------", ipset.IPSetName)

if ipset.Routing.KillSwitch {
log.Infof("Usage of kill-switch is enabled")
Expand All @@ -81,13 +81,13 @@ func checkIpset(cfg *config.Config, ipset *config.IpsetConfig) error {
}

if exists, err := networking.CheckIpsetExists(ipset); err != nil {
log.Errorf("Failed to check ipset presense [%s]: %v", ipset.IpsetName, err)
log.Errorf("Failed to check ipset presense [%s]: %v", ipset.IPSetName, err)
return err
} else {
if exists {
log.Infof("ipset [%s] is exists", ipset.IpsetName)
log.Infof("ipset [%s] is exists", ipset.IPSetName)
} else {
log.Errorf("ipset [%s] is NOT exists", ipset.IpsetName)
log.Errorf("ipset [%s] is NOT exists", ipset.IPSetName)
}
}

Expand Down Expand Up @@ -137,11 +137,11 @@ func checkIpset(cfg *config.Config, ipset *config.IpsetConfig) error {
}
}

log.Infof("----------------- IPSet [%s] END ------------------", ipset.IpsetName)
log.Infof("----------------- IPSet [%s] END ------------------", ipset.IPSetName)
return nil
}

func checkIpTables(ipset *config.IpsetConfig) error {
func checkIpTables(ipset *config.IPSetConfig) error {
ipTableRules, err := networking.BuildIPTablesForIpset(ipset)
if err != nil {
log.Errorf("Failed to build iptable rules: %v", err)
Expand All @@ -165,7 +165,7 @@ func checkIpTables(ipset *config.IpsetConfig) error {
return nil
}

func checkIpRoutes(ipset *config.IpsetConfig, chosenIface *networking.Interface) error {
func checkIpRoutes(ipset *config.IPSetConfig, chosenIface *networking.Interface) error {
if routes, err := networking.ListRoutesInTable(ipset.Routing.IpRouteTable); err != nil {
log.Errorf("Failed to list IP routes in table %d: %v", ipset.Routing.IpRouteTable, err)
return err
Expand Down Expand Up @@ -194,7 +194,7 @@ func checkIpRoutes(ipset *config.IpsetConfig, chosenIface *networking.Interface)
}

if chosenIface != nil {
defaultIpRoute := networking.BuildDefaultRoute(ipset.IpVersion, *chosenIface, ipset.Routing.IpRouteTable)
defaultIpRoute := networking.BuildDefaultRoute(ipset.IPVersion, *chosenIface, ipset.Routing.IpRouteTable)
if exists, err := defaultIpRoute.IsExists(); err != nil {
log.Errorf("Failed to check default IP route [%v]: %v", defaultIpRoute, err)
return err
Expand All @@ -209,7 +209,7 @@ func checkIpRoutes(ipset *config.IpsetConfig, chosenIface *networking.Interface)
log.Infof("Default IP route check SKIPPED because no interface is connected")
}

blackholeIpRoute := networking.BuildBlackholeRoute(ipset.IpVersion, ipset.Routing.IpRouteTable)
blackholeIpRoute := networking.BuildBlackholeRoute(ipset.IPVersion, ipset.Routing.IpRouteTable)
if exists, err := blackholeIpRoute.IsExists(); err != nil {
log.Errorf("Failed to check blackhole IP route [%v]: %v", blackholeIpRoute, err)
return err
Expand Down
10 changes: 5 additions & 5 deletions lib/commands/undo.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ func (g *UndoCommand) Init(args []string, ctx *AppContext) error {
func (g *UndoCommand) Run() error {
log.Infof("Removing all iptables rules, ip rules and ip routes...")

for _, ipset := range g.cfg.Ipset {
for _, ipset := range g.cfg.IPSets {
if err := undoIpset(ipset); err != nil {
log.Errorf("Failed to undo routing configuration for ipset [%s]: %v", ipset.IpsetName, err)
log.Errorf("Failed to undo routing configuration for ipset [%s]: %v", ipset.IPSetName, err)
return err
}
}
Expand All @@ -54,8 +54,8 @@ func (g *UndoCommand) Run() error {
return nil
}

func undoIpset(ipset *config.IpsetConfig) error {
log.Infof("----------------- IPSet [%s] ------------------", ipset.IpsetName)
func undoIpset(ipset *config.IPSetConfig) error {
log.Infof("----------------- IPSet [%s] ------------------", ipset.IPSetName)

log.Infof("Deleting IP route table %d", ipset.Routing.IpRouteTable)
if err := networking.DelIpRouteTable(ipset.Routing.IpRouteTable); err != nil {
Expand Down Expand Up @@ -88,6 +88,6 @@ func undoIpset(ipset *config.IpsetConfig) error {
}
}

log.Infof("----------------- IPSet [%s] END ------------------", ipset.IpsetName)
log.Infof("----------------- IPSet [%s] END ------------------", ipset.IPSetName)
return nil
}
63 changes: 32 additions & 31 deletions lib/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ var (
type IpFamily uint8

const (
Ipv4 IpFamily = 4
Ipv6 IpFamily = 6
Ipv4 IpFamily = 4
Ipv6 IpFamily = 6
IpAll IpFamily = 46
)

const (
Expand All @@ -31,7 +32,7 @@ const (

type Config struct {
General *GeneralConfig `toml:"general"`
Ipset []*IpsetConfig `toml:"ipset"`
IPSets []*IPSetConfig `toml:"ipset"`
_configFilePath string
}

Expand All @@ -41,13 +42,13 @@ type GeneralConfig struct {
UseKeeneticAPI *bool `toml:"use_keenetic_api"`
}

type IpsetConfig struct {
IpsetName string `toml:"ipset_name"`
IpVersion IpFamily `toml:"ip_version"`
type IPSetConfig struct {
IPSetName string `toml:"ipset_name"`
IPVersion IpFamily `toml:"ip_version"`
FlushBeforeApplying bool `toml:"flush_before_applying"`
Routing *RoutingConfig `toml:"routing"`
IPTablesRule []*IPTablesRule `toml:"iptables_rule"`
List []*ListSource `toml:"list"`
IPTablesRules []*IPTablesRule `toml:"iptables_rule"`
Lists []*ListSource `toml:"list"`
}

type IPTablesRule struct {
Expand Down Expand Up @@ -131,7 +132,7 @@ func (c *Config) ValidateConfig() error {
c.General.UseKeeneticAPI = &def
}

if c.Ipset == nil {
if c.IPSets == nil {
return fmt.Errorf("configuration should contain \"ipset\" field, check your configuration")
}

Expand All @@ -140,28 +141,28 @@ func (c *Config) ValidateConfig() error {
tables := make(map[int]bool)
priorities := make(map[int]bool)

for _, ipset := range c.Ipset {
for _, ipset := range c.IPSets {
if ipset.Routing == nil {
return fmt.Errorf("ipset %s should contain \"ipset.routing\" field, check your configuration", ipset.IpsetName)
return fmt.Errorf("ipset %s should contain \"ipset.routing\" field, check your configuration", ipset.IPSetName)
}

if ipset.List == nil {
return fmt.Errorf("ipset %s should contain \"ipset.list\" field, check your configuration", ipset.IpsetName)
if ipset.Lists == nil {
return fmt.Errorf("ipset %s should contain \"ipset.list\" field, check your configuration", ipset.IPSetName)
}

// Validate ipset name
if err := validateIpsetName(ipset.IpsetName); err != nil {
if err := validateIpsetName(ipset.IPSetName); err != nil {
return err
}
if err := checkDuplicates(ipset.IpsetName, names, "ipset name"); err != nil {
if err := checkDuplicates(ipset.IPSetName, names, "ipset name"); err != nil {
return err
}

// Validate IP version
if newVersion, err := validateIpVersion(ipset.IpVersion); err != nil {
if newVersion, err := validateIpVersion(ipset.IPVersion); err != nil {
return err
} else {
ipset.IpVersion = newVersion
ipset.IPVersion = newVersion
}

// Validate iptables rules
Expand All @@ -171,21 +172,21 @@ func (c *Config) ValidateConfig() error {

// Validate interfaces
if ipset.Routing.Interface == "" && len(ipset.Routing.Interfaces) == 0 {
return fmt.Errorf("ipset %s routing configuration should contain \"interfaces\" field, check your configuration", ipset.IpsetName)
return fmt.Errorf("ipset %s routing configuration should contain \"interfaces\" field, check your configuration", ipset.IPSetName)
}
if ipset.Routing.Interface != "" && len(ipset.Routing.Interfaces) > 0 {
return fmt.Errorf("ipset %s contains both \"interface\" and \"interfaces\" fields, please use only one field to configure routing", ipset.IpsetName)
return fmt.Errorf("ipset %s contains both \"interface\" and \"interfaces\" fields, please use only one field to configure routing", ipset.IPSetName)
}
if ipset.Routing.Interface != "" {
log.Warnf("ipset %s contains deprecated \"interface\" field, please use \"interfaces\" instead", ipset.IpsetName)
log.Warnf("ipset %s contains deprecated \"interface\" field, please use \"interfaces\" instead", ipset.IPSetName)
ipset.Routing.Interfaces = []string{ipset.Routing.Interface}
ipset.Routing.Interface = ""
}
// check duplicate interfaces
ifNames := make(map[string]bool)
for _, ifName := range ipset.Routing.Interfaces {
if ifNames[ifName] {
return fmt.Errorf("ipset %s contains duplicate interface \"%s\", check your configuration", ipset.IpsetName, ifName)
return fmt.Errorf("ipset %s contains duplicate interface \"%s\", check your configuration", ipset.IPSetName, ifName)
}
ifNames[ifName] = true
}
Expand All @@ -203,18 +204,18 @@ func (c *Config) ValidateConfig() error {

// Validate lists
listNames := make(map[string]bool)
for _, list := range ipset.List {
if err := validateList(c, list, listNames, ipset.IpsetName); err != nil {
for _, list := range ipset.Lists {
if err := validateList(c, list, listNames, ipset.IPSetName); err != nil {
return err
}
}
}
return nil
}

func validateIPTablesRules(ipset *IpsetConfig) error {
if ipset.IPTablesRule == nil {
ipset.IPTablesRule = []*IPTablesRule{
func validateIPTablesRules(ipset *IPSetConfig) error {
if ipset.IPTablesRules == nil {
ipset.IPTablesRules = []*IPTablesRule{
{
Chain: "PREROUTING",
Table: "mangle",
Expand All @@ -228,16 +229,16 @@ func validateIPTablesRules(ipset *IpsetConfig) error {
return nil
}

if len(ipset.IPTablesRule) > 0 {
for _, rule := range ipset.IPTablesRule {
if len(ipset.IPTablesRules) > 0 {
for _, rule := range ipset.IPTablesRules {
if rule.Chain == "" {
return fmt.Errorf("ipset %s iptables rule should contain non-empty \"chain\" field, check your configuration", ipset.IpsetName)
return fmt.Errorf("ipset %s iptables rule should contain non-empty \"chain\" field, check your configuration", ipset.IPSetName)
}
if rule.Table == "" {
return fmt.Errorf("ipset %s iptables rule should contain non-empty \"table\" field, check your configuration", ipset.IpsetName)
return fmt.Errorf("ipset %s iptables rule should contain non-empty \"table\" field, check your configuration", ipset.IPSetName)
}
if len(rule.Rule) == 0 {
return fmt.Errorf("ipset %s iptables rule should contain non-empty \"rule\" field, check your configuration", ipset.IpsetName)
return fmt.Errorf("ipset %s iptables rule should contain non-empty \"rule\" field, check your configuration", ipset.IPSetName)
}
}
}
Expand Down
Loading

0 comments on commit 4dafa24

Please sign in to comment.