diff --git a/uci.go b/uci.go index 0934946..c652b7a 100644 --- a/uci.go +++ b/uci.go @@ -16,6 +16,7 @@ type UCI struct { exec Executor CustomFirewallFile string Wireless *UCIWirelessConf + Firewall *UCIFirewall } // NewUCI return an UCI instance to interact with UCI @@ -23,7 +24,8 @@ func NewUCI() *UCI { exec := &localExecutor{} customFWFile := "/etc/" wireless := &UCIWirelessConf{} - return &UCI{exec, customFWFile, wireless} + firewall := &UCIFirewall{} + return &UCI{exec, customFWFile, wireless, firewall} } // NewUCIWithExecutor returns a UCI Instance an gives you the ability to provide @@ -31,7 +33,8 @@ func NewUCI() *UCI { func NewUCIWithExecutor(exec Executor, customFWFile string) *UCI { wireless := &UCIWirelessConf{} - return &UCI{exec, customFWFile, wireless} + firewall := &UCIFirewall{} + return &UCI{exec, customFWFile, wireless, firewall} } // uciRun, private method to run the UCI command @@ -103,6 +106,13 @@ func (u *UCI) LoadWirelessConf() { u.Wireless.Load() } +// LoadFirewallConf scan UCI configration and load saved firewall rules +func (u *UCI) LoadFirewallConf() error { + fmt.Println("DEBUG ICI ICI ICI ICI !!!") + u.Firewall = NewUCIFirewall(u) + return u.Firewall.Load() +} + // GetWifiIface returns the wifi Interface by Index func (u *UCI) GetWifiIface(idx int) *UCIWirelessInterface { ifaces := u.Wireless.Interfaces diff --git a/uci_firewall.go b/uci_firewall.go new file mode 100644 index 0000000..55da50e --- /dev/null +++ b/uci_firewall.go @@ -0,0 +1,119 @@ +package owrt + +import ( + "fmt" + "regexp" + "strconv" + "strings" +) + +// UCIFirewall is the description of the OpenWRT Firewall rules (all types) +type UCIFirewall struct { + UCI *UCI + Rules map[int]*UCIFirewallRule + Redirects map[int]*UCIFirewallRedirect + Customs map[int]*UCIFirewallCustomRule +} + +// NewUCIFirewall builds a new UCIFirewall instance +func NewUCIFirewall(uci *UCI) *UCIFirewall { + return &UCIFirewall{ + UCI: uci, + Rules: map[int]*UCIFirewallRule{}, + Redirects: map[int]*UCIFirewallRedirect{}, + Customs: map[int]*UCIFirewallCustomRule{}, + } +} + +// loadRules loads existing firewall rules +func (f *UCIFirewall) loadRules() error { + var rules = map[int]*UCIFirewallRule{} + var lines []string + + matches := map[string]*regexp.Regexp{ + "Name": regexp.MustCompile(`@rule\[[0-9]*\].name=`), + "Src": regexp.MustCompile(`@rule\[[0-9]*\].src=`), + "Target": regexp.MustCompile(`@rule\[[0-9]*\].target=`), + "Proto": regexp.MustCompile(`@rule\[[0-9]*\].porto=`), + "DestPort": regexp.MustCompile(`@rule\[[0-9]*\].dest_port=`), + } + + if f.UCI == nil { + return fmt.Errorf("No UCI Client present ... this could not append") + } + + firewallRes := f.UCI.uciRun("uci", "show", "firewall") + if firewallRes.ReturnCode == 0 { + lines = grep(firewallRes.Stdout, "firewall.@rule") + // lines = strings.Split(firewallRes.Stdout, "\n") + } else { + return fmt.Errorf("%d - %s %s %s", + firewallRes.ReturnCode, + firewallRes.Command, + firewallRes.Stdout, + firewallRes.Stdout) + } + + for _, li := range lines { + var idx int + var sIdx string + + if li != "" { + sIdx = strings.Split(li, "[")[1] + sIdx = strings.Split(sIdx, "]")[0] + + if s, err := strconv.ParseInt(sIdx, 10, 32); err == nil { + idx = int(s) + } + } + + if _, exists := rules[idx]; !exists { + rules[idx] = NewUCIFirewallRule(f.UCI) + rules[idx].Index = idx + } + + for key, expr := range matches { + if expr.MatchString(li) { + value := strings.Split(li, "=")[1] + value = strings.Trim(value, "'") + if key == "Name" { + fmt.Printf("Setting Name %s for rule #%d\n", value, idx) + rules[idx].Name = value + } + if key == "Src" { + rules[idx].Src = value + } + if key == "Proto" { + rules[idx].Proto = value + } + if key == "DestPort" { + rules[idx].DestPort = value + } + if key == "Target" { + rules[idx].Target = value + } + } + } + } + f.Rules = rules + return nil +} + +func (f *UCIFirewall) loadRedirects() error { + return nil +} + +func (f *UCIFirewall) loadCustoms() error { + return nil +} + +// Load run uci show firewall and creates an nice UCIFirewall Object +func (f *UCIFirewall) Load() error { + if r := f.loadRules(); r != nil { + return r + } + if r := f.loadRedirects(); r != nil { + return r + } + return f.loadCustoms() +} diff --git a/uci_firewall_test.go b/uci_firewall_test.go new file mode 100644 index 0000000..6330b43 --- /dev/null +++ b/uci_firewall_test.go @@ -0,0 +1,23 @@ +package owrt + +import ( + "io/ioutil" + "testing" +) + +func TestUCILoadFirewall(t *testing.T) { + config, err := ioutil.ReadFile("./testdata/uci_show_firewall.txt") + if err != nil { + t.Fatal(err) + } + + exec := createMockExecutor(string(config), "", 0) + uci := NewUCIWithExecutor(exec, "") + if err := uci.LoadFirewallConf(); err != nil { + t.Fatalf("%s", err.Error()) + } + + //if uci.Firewall.Rules[13].Name != "MyTestRule" { + // t.Fatalf("Something is wrong with the last firewall rule") + //} +}