Compare commits

...

5 Commits

Author SHA1 Message Date
Philippe Caseiro 972e21754f Adding test data
Cadoles/owrt/master There was a failure building this commit Details
Cadoles/owrt/pipeline/head Something is wrong with the build of this commit Details
2018-11-12 09:17:30 +01:00
Philippe Caseiro da4fa533b4 Adding new UCIFirewall struct
This is to manage all Firewall
2018-11-12 09:16:41 +01:00
Philippe Caseiro b9559bb9f3 Fixing add command 2018-11-09 14:38:58 +01:00
Philippe Caseiro b26fa7f280 Moving UCI Client to structure for Redirects to 2018-11-07 17:17:57 +01:00
Philippe Caseiro 36ba15ab4e Moving UCI client to the structure
avoid pass UCI object to each method
2018-11-07 17:09:51 +01:00
8 changed files with 332 additions and 33 deletions

137
testdata/uci_show_firewall.txt vendored Normal file
View File

@ -0,0 +1,137 @@
firewall.@defaults[0]=defaults
firewall.@defaults[0].syn_flood='1'
firewall.@defaults[0].input='ACCEPT'
firewall.@defaults[0].output='ACCEPT'
firewall.@defaults[0].forward='REJECT'
firewall.@zone[0]=zone
firewall.@zone[0].name='lan'
firewall.@zone[0].input='ACCEPT'
firewall.@zone[0].output='ACCEPT'
firewall.@zone[0].forward='ACCEPT'
firewall.@zone[0].network='lan'
firewall.@zone[1]=zone
firewall.@zone[1].name='wan'
firewall.@zone[1].input='REJECT'
firewall.@zone[1].output='ACCEPT'
firewall.@zone[1].forward='REJECT'
firewall.@zone[1].masq='1'
firewall.@zone[1].mtu_fix='1'
firewall.@zone[1].network='wan wan6'
firewall.@forwarding[0]=forwarding
firewall.@forwarding[0].src='lan'
firewall.@forwarding[0].dest='wan'
firewall.@rule[0]=rule
firewall.@rule[0].name='Allow-Ping'
firewall.@rule[0].src='wan'
firewall.@rule[0].proto='icmp'
firewall.@rule[0].icmp_type='echo-request'
firewall.@rule[0].family='ipv4'
firewall.@rule[0].target='ACCEPT'
firewall.@rule[1]=rule
firewall.@rule[1].name='Allow-IGMP'
firewall.@rule[1].src='wan'
firewall.@rule[1].proto='igmp'
firewall.@rule[1].family='ipv4'
firewall.@rule[1].target='ACCEPT'
firewall.@rule[2]=rule
firewall.@rule[2].name='Allow-DHCPv6'
firewall.@rule[2].src='wan'
firewall.@rule[2].proto='udp'
firewall.@rule[2].src_ip='fe80::/10'
firewall.@rule[2].src_port='547'
firewall.@rule[2].dest_ip='fe80::/10'
firewall.@rule[2].dest_port='546'
firewall.@rule[2].family='ipv6'
firewall.@rule[2].target='ACCEPT'
firewall.@rule[3]=rule
firewall.@rule[3].name='Allow-MLD'
firewall.@rule[3].src='wan'
firewall.@rule[3].proto='icmp'
firewall.@rule[3].src_ip='fe80::/10'
firewall.@rule[3].icmp_type='130/0' '131/0' '132/0' '143/0'
firewall.@rule[3].family='ipv6'
firewall.@rule[3].target='ACCEPT'
firewall.@rule[4]=rule
firewall.@rule[4].name='Allow-ICMPv6-Input'
firewall.@rule[4].src='wan'
firewall.@rule[4].proto='icmp'
firewall.@rule[4].icmp_type='echo-request' 'echo-reply' 'destination-unreachable' 'packet-too-big' 'time-exceeded' 'bad-header' 'unknown-header-type' 'router-solicitation' 'neighbour-solicitation' 'router-advertisement' 'neighbour-advertisement'
firewall.@rule[4].limit='1000/sec'
firewall.@rule[4].family='ipv6'
firewall.@rule[4].target='ACCEPT'
firewall.@rule[5]=rule
firewall.@rule[5].name='Allow-ICMPv6-Forward'
firewall.@rule[5].src='wan'
firewall.@rule[5].dest='*'
firewall.@rule[5].proto='icmp'
firewall.@rule[5].icmp_type='echo-request' 'echo-reply' 'destination-unreachable' 'packet-too-big' 'time-exceeded' 'bad-header' 'unknown-header-type'
firewall.@rule[5].limit='1000/sec'
firewall.@rule[5].family='ipv6'
firewall.@rule[5].target='ACCEPT'
firewall.@include[0]=include
firewall.@include[0].path='/etc/firewall.user'
firewall.@rule[6]=rule
firewall.@rule[6].src='wan'
firewall.@rule[6].dest='lan'
firewall.@rule[6].proto='esp'
firewall.@rule[6].target='ACCEPT'
firewall.@rule[7]=rule
firewall.@rule[7].src='wan'
firewall.@rule[7].dest='lan'
firewall.@rule[7].dest_port='500'
firewall.@rule[7].proto='udp'
firewall.@rule[7].target='ACCEPT'
firewall.@rule[8]=rule
firewall.@rule[8].target='ACCEPT'
firewall.@rule[8].src='wan'
firewall.@rule[8].proto='tcp'
firewall.@rule[8].dest_port='22'
firewall.@rule[8].name='SSH'
firewall.@rule[9]=rule
firewall.@rule[9].target='ACCEPT'
firewall.@rule[9].src='wan'
firewall.@rule[9].proto='tcp'
firewall.@rule[9].dest_port='80'
firewall.@rule[9].name='HTTP'
firewall.@zone[2]=zone
firewall.@zone[2].name='efs'
firewall.@zone[2].forward='REJECT'
firewall.@zone[2].input='REJECT'
firewall.@zone[2].output='REJECT'
firewall.@zone[2].network=' '
firewall.@zone[3]=zone
firewall.@zone[3].name='dds'
firewall.@zone[3].forward='REJECT'
firewall.@zone[3].input='REJECT'
firewall.@zone[3].output='ACCEPT'
firewall.@zone[3].network=' '
firewall.@rule[10]=rule
firewall.@rule[10].target='ACCEPT'
firewall.@rule[10].proto='tcp'
firewall.@rule[10].dest_port='9090'
firewall.@rule[10].name='MyTestRule'
firewall.@rule[10].src='wan'
firewall.@rule[11]=rule
firewall.@rule[11].name='MyTestRule'
firewall.@rule[11].src='wan'
firewall.@rule[11].target='ACCEPT'
firewall.@rule[11].proto='tcp'
firewall.@rule[11].dest_port='9090'
firewall.@rule[12]=rule
firewall.@rule[12].src='wan'
firewall.@rule[12].target='ACCEPT'
firewall.@rule[12].proto='tcp'
firewall.@rule[12].dest_port='9090'
firewall.@rule[12].name='MyTestRule'
firewall.@rule[13]=rule
firewall.@rule[13].name='MyTestRule'
firewall.@rule[13].src='wan'
firewall.@rule[13].target='ACCEPT'
firewall.@rule[13].proto='tcp'
firewall.@rule[13].dest_port='9090'
firewall.@rule[14]=rule
firewall.@rule[14].dest_port='9090'
firewall.@rule[14].name='MyTestRule'
firewall.@rule[14].src='wan'
firewall.@rule[14].target='ACCEPT'
firewall.@rule[14].proto='tcp'

19
uci.go
View File

@ -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
@ -43,8 +46,9 @@ func (u *UCI) uciRun(param ...string) *Action {
// Add add an entry to UCI configuration, specify the Module and the value
func (u *UCI) Add(module string, name string) *Action {
cmd := "uci add"
commandRes := u.exec.Run(cmd, module, name)
cmd := "/sbin/uci"
opt := "add"
commandRes := u.exec.Run(cmd, opt, module, name)
return &Action{commandRes, fmt.Sprintf("%s %s %s", cmd, module, name)}
}
@ -102,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

119
uci_firewall.go Normal file
View File

@ -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()
}

View File

@ -6,6 +6,7 @@ import (
// UCIFirewallRedirect is the description of an Wireless interface (cf Openwrt doc) on top of an Wireless Device
type UCIFirewallRedirect struct {
UCI *UCI
Name string
Index int
Src string
@ -19,12 +20,13 @@ type UCIFirewallRedirect struct {
}
// NewUCIFirewallRedirect builds a new UCIFirewallRedirect instance
func NewUCIFirewallRedirect() *UCIFirewallRedirect {
return &UCIFirewallRedirect{}
func NewUCIFirewallRedirect(uci *UCI) *UCIFirewallRedirect {
return &UCIFirewallRedirect{UCI: uci}
}
// Create add a new firewall rule in UCI Configuration
func (rd *UCIFirewallRedirect) Create(uci *UCI) *Action {
func (rd *UCIFirewallRedirect) Create() *Action {
uci := rd.UCI
confPrefix := fmt.Sprintf("firewall.@redirect[%d]", rd.Index)
conf := make(map[string][]string)
@ -59,7 +61,8 @@ func (rd *UCIFirewallRedirect) Create(uci *UCI) *Action {
}
// Save commit and relaod configuration (writes it to files !)
func (rd *UCIFirewallRedirect) Save(uci *UCI) *Action {
func (rd *UCIFirewallRedirect) Save() *Action {
uci := rd.UCI
commitRes := uci.Commit()
if commitRes.ReturnCode != 0 {
return commitRes
@ -70,7 +73,8 @@ func (rd *UCIFirewallRedirect) Save(uci *UCI) *Action {
}
// Delete remove wifi interface from UCI Configuration
func (rd *UCIFirewallRedirect) Delete(uci *UCI) *Action {
func (rd *UCIFirewallRedirect) Delete() *Action {
uci := rd.UCI
toDelete := fmt.Sprintf("firewall.@redirect[%d]", rd.Index)
del := uci.Delete(toDelete)
if del.ReturnCode != 0 {
@ -80,9 +84,10 @@ func (rd *UCIFirewallRedirect) Delete(uci *UCI) *Action {
}
// Update add a new entry for wifi interface in UCI Configuration
func (rd *UCIFirewallRedirect) Update(uci *UCI) *Action {
rd.Delete(uci)
create := rd.Create(uci)
func (rd *UCIFirewallRedirect) Update() *Action {
uci := rd.UCI
rd.Delete()
create := rd.Create()
if create.ReturnCode != 0 {
return create
}

View File

@ -20,7 +20,7 @@ func TestFWRedirectCreate(t *testing.T) {
exec := createMockExecutor("", "", 0)
uci := NewUCIWithExecutor(exec, "")
redirect := NewUCIFirewallRedirect()
redirect := NewUCIFirewallRedirect(uci)
redirect.Name = redirectName
redirect.Index = redirectIndex
redirect.Src = redirectSrc
@ -31,7 +31,7 @@ func TestFWRedirectCreate(t *testing.T) {
redirect.DestIP = redirectDestIP
redirect.DestPort = redirectDestPort
if redirect.Create(uci).ReturnCode != 0 {
if redirect.Create().ReturnCode != 0 {
t.Fatalf("UCIFirewallRedirect.Create() failed !")
}
}
@ -40,7 +40,7 @@ func TestFWRedirectUpdate(t *testing.T) {
exec := createMockExecutor("", "", 0)
uci := NewUCIWithExecutor(exec, "")
redirect := NewUCIFirewallRedirect()
redirect := NewUCIFirewallRedirect(uci)
redirect.Name = redirectName
redirect.Index = redirectIndex
redirect.Src = redirectSrc
@ -51,13 +51,13 @@ func TestFWRedirectUpdate(t *testing.T) {
redirect.DestIP = redirectDestIP
redirect.DestPort = redirectDestPort
if redirect.Create(uci).ReturnCode != 0 {
if redirect.Create().ReturnCode != 0 {
t.Fatalf("UCIFirewallRedirect.Create() failed !")
}
redirect.Name = "NewRedirect"
if redirect.Update(uci).ReturnCode != 0 {
if redirect.Update().ReturnCode != 0 {
t.Fatalf("UCIFirewallRedirect.Update() failed !")
}
}
@ -66,7 +66,7 @@ func TestFWRedirectDelete(t *testing.T) {
exec := createMockExecutor("", "", 0)
uci := NewUCIWithExecutor(exec, "")
redirect := NewUCIFirewallRedirect()
redirect := NewUCIFirewallRedirect(uci)
redirect.Name = redirectName
redirect.Index = redirectIndex
redirect.Src = redirectSrc
@ -77,7 +77,7 @@ func TestFWRedirectDelete(t *testing.T) {
redirect.DestIP = redirectDestIP
redirect.DestPort = redirectDestPort
if redirect.Delete(uci).ReturnCode != 0 {
if redirect.Delete().ReturnCode != 0 {
t.Fatalf("UCIWirelessInterface.Delete() failed !")
}
}

View File

@ -6,6 +6,7 @@ import (
// UCIFirewallRule is the description of an Wireless interface (cf Openwrt doc) on top of an Wireless Device
type UCIFirewallRule struct {
UCI *UCI
Name string
Index int
Src string
@ -16,12 +17,13 @@ type UCIFirewallRule struct {
}
// NewUCIFirewallRule builds a new UCIFirewallRule instance
func NewUCIFirewallRule() *UCIFirewallRule {
return &UCIFirewallRule{}
func NewUCIFirewallRule(uci *UCI) *UCIFirewallRule {
return &UCIFirewallRule{UCI: uci}
}
// Create add a new firewall rule in UCI Configuration
func (fw *UCIFirewallRule) Create(uci *UCI) *Action {
func (fw *UCIFirewallRule) Create() *Action {
uci := fw.UCI
confPrefix := fmt.Sprintf("firewall.@rule[%d]", fw.Index)
conf := make(map[string][]string)
@ -63,7 +65,8 @@ func (fw *UCIFirewallRule) Save(uci *UCI) *Action {
}
// Delete remove wifi interface from UCI Configuration
func (fw *UCIFirewallRule) Delete(uci *UCI) *Action {
func (fw *UCIFirewallRule) Delete() *Action {
uci := fw.UCI
toDelete := fmt.Sprintf("firewall.@rule[%d]", fw.Index)
del := uci.Delete(toDelete)
if del.ReturnCode != 0 {
@ -73,9 +76,10 @@ func (fw *UCIFirewallRule) Delete(uci *UCI) *Action {
}
// Update add a new entry for wifi interface in UCI Configuration
func (fw *UCIFirewallRule) Update(uci *UCI) *Action {
fw.Delete(uci)
create := fw.Create(uci)
func (fw *UCIFirewallRule) Update() *Action {
uci := fw.UCI
fw.Delete()
create := fw.Create()
if create.ReturnCode != 0 {
return create
}

View File

@ -18,7 +18,7 @@ func TestFWRuleCreate(t *testing.T) {
exec := createMockExecutor("", "", 0)
uci := NewUCIWithExecutor(exec, "")
rule := NewUCIFirewallRule()
rule := NewUCIFirewallRule(uci)
rule.Name = ruleName
rule.Index = ruleIndex
rule.Src = ruleSrc
@ -27,7 +27,7 @@ func TestFWRuleCreate(t *testing.T) {
rule.DestPort = ruleDestPort
rule.SourcePort = ruleSourcePort
if rule.Create(uci).ReturnCode != 0 {
if rule.Create().ReturnCode != 0 {
t.Fatalf("UCIFirewallRule.Create() failed !")
}
}
@ -36,7 +36,7 @@ func TestFWRuleUpdate(t *testing.T) {
exec := createMockExecutor("", "", 0)
uci := NewUCIWithExecutor(exec, "")
rule := NewUCIFirewallRule()
rule := NewUCIFirewallRule(uci)
rule.Name = ruleName
rule.Index = ruleIndex
rule.Src = ruleSrc
@ -45,13 +45,13 @@ func TestFWRuleUpdate(t *testing.T) {
rule.DestPort = ruleDestPort
rule.SourcePort = ruleSourcePort
if rule.Create(uci).ReturnCode != 0 {
if rule.Create().ReturnCode != 0 {
t.Fatalf("UCIFirewallRule.Create() failed !")
}
rule.Name = "Tutu"
if rule.Update(uci).ReturnCode != 0 {
if rule.Update().ReturnCode != 0 {
t.Fatalf("UCIFirewallRule.Update() failed !")
}
}
@ -60,7 +60,7 @@ func TestFWRuleDelete(t *testing.T) {
exec := createMockExecutor("", "", 0)
uci := NewUCIWithExecutor(exec, "")
rule := NewUCIFirewallRule()
rule := NewUCIFirewallRule(uci)
rule.Name = ruleName
rule.Index = ruleIndex
rule.Src = ruleSrc
@ -69,7 +69,7 @@ func TestFWRuleDelete(t *testing.T) {
rule.DestPort = ruleDestPort
rule.SourcePort = ruleSourcePort
if rule.Delete(uci).ReturnCode != 0 {
if rule.Delete().ReturnCode != 0 {
t.Fatalf("UCIWirelessInterface.Delete() failed !")
}
}

23
uci_firewall_test.go Normal file
View File

@ -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")
//}
}