Skip to content

Commit

Permalink
Merge pull request #3 from Obmondo/fix/handle-duplicate-rules-using-h…
Browse files Browse the repository at this point in the history
…ashmap

[Fix] Handle Duplicate Rules Using Hashmap
  • Loading branch information
ashish1099 authored Oct 30, 2024
2 parents f03bbc0 + f1af1b8 commit b29f327
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 0 deletions.
17 changes: 17 additions & 0 deletions iptables/custom1.iptables-save
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by iptables-save v1.8.5 on Mon Oct 28 12:27:51 2024
*nat
:POSTROUTING ACCEPT [539154:42361851]
:LIBVIRT_PRT - [0:0]
[539154:42361851] -A POSTROUTING -j LIBVIRT_PRT
[2:176] -A LIBVIRT_PRT -s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 -d 255.255.255.255/32 -j RETURN
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 -d 255.255.255.255/32 -j RETURN
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
COMMIT
# Completed on Mon Oct 28 12:27:51 2024
18 changes: 18 additions & 0 deletions iptables/custom2.iptables-save
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by iptables-save v1.8.5 on Mon Oct 28 12:27:51 2024
*nat
:POSTROUTING ACCEPT [539154:42361851]
:LIBVIRT_PRT - [0:0]
[539154:42361851] -A POSTROUTING -j LIBVIRT_PRT
[2:176] -A LIBVIRT_PRT -s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 -d 255.255.255.255/32 -j RETURN
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 -d 255.255.255.255/32 -j RETURN
[123:456] -A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535
[0:0] -A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
COMMIT
# Completed on Mon Oct 28 12:27:51 2024
140 changes: 140 additions & 0 deletions iptables/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,38 @@ func (c parserTestCase) run() ([]string, error) {
return deep.Equal(c.expected, result), nil
}

func (c parserTestCase) customRun() ([]string, error) {
f, err := os.Open(c.name)
if err != nil {
return nil, err
}
defer f.Close()
result, err := ParseIptablesSave(f)
if err != nil {
return nil, err
}
updatedResult := make(Tables, len(result))
for tableName, table := range result {
updatedTable := make(Table, len(table))
for chainName, chain := range table {
reportedRule := make(map[Rule]struct{}, len(chain.Rules))
rules := []Rule{}
for _, rule := range chain.Rules {
if _, exists := reportedRule[rule]; exists {
continue
}
reportedRule[rule] = struct{}{}
rules = append(rules, rule)
}
chain.Rules = rules
updatedTable[chainName] = chain
}
updatedResult[tableName] = updatedTable
}

return deep.Equal(c.expected, updatedResult), nil
}

var parserTestCases = []parserTestCase{
{
name: "server.iptables-save",
Expand Down Expand Up @@ -219,6 +251,102 @@ var parserTestCases = []parserTestCase{
},
}

var customParserTestCases = []parserTestCase{
{
name: "custom1.iptables-save",
expected: Tables{
"nat": {
"POSTROUTING": {
Policy: "ACCEPT",
Packets: 539154,
Bytes: 42361851,
Rules: []Rule{
{
Packets: 539154,
Bytes: 42361851,
Rule: "-j LIBVIRT_PRT",
},
},
},
"LIBVIRT_PRT": {
Policy: "-",
Rules: []Rule{
{
Packets: 2,
Bytes: 176,
Rule: "-s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN",
},
{
Rule: "-s 192.168.122.0/24 -d 255.255.255.255/32 -j RETURN",
},
{
Rule: "-s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535",
},
{
Rule: "-s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535",
},
{
Rule: "-s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE",
},
{
Rule: "-s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN",
},
},
},
},
},
},
{
name: "custom2.iptables-save",
expected: Tables{
"nat": {
"POSTROUTING": {
Policy: "ACCEPT",
Packets: 539154,
Bytes: 42361851,
Rules: []Rule{
{
Packets: 539154,
Bytes: 42361851,
Rule: "-j LIBVIRT_PRT",
},
},
},
"LIBVIRT_PRT": {
Policy: "-",
Rules: []Rule{
{
Packets: 2,
Bytes: 176,
Rule: "-s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN",
},
{
Rule: "-s 192.168.122.0/24 -d 255.255.255.255/32 -j RETURN",
},
{
Rule: "-s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535",
},
{
Rule: "-s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535",
},
{
Rule: "-s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE",
},
{
Rule: "-s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN",
},
{
Packets: 123,
Bytes: 456,
Rule: "-s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535",
},
},
},
},
},
},
}

func TestParseIptablesSave(t *testing.T) {
for _, tc := range parserTestCases {
mismatch, err := tc.run()
Expand All @@ -230,3 +358,15 @@ func TestParseIptablesSave(t *testing.T) {
}
}
}

func TestCustomParseIptablesSave(t *testing.T) {
for _, tc := range customParserTestCases {
mismatch, err := tc.customRun()
if err != nil {
t.Fatalf("%s: %+v", tc.name, err)
}
if mismatch != nil {
t.Fatalf("%s: %+v", tc.name, mismatch)
}
}
}
9 changes: 9 additions & 0 deletions iptables_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,16 @@ func (c *collector) Collect(metricChan chan<- prometheus.Metric) {
chainName,
chain.Policy,
)
// Hash map to ensure only unique rule, per table, per chain is used to create metric.
// If we encounter multiple duplicate rules, we simply going to skip the iteration for that rule.
// Note: We considering rule, packets, and bytes altogether to uniquely identify a rule.
reportedRule := make(map[iptables.Rule]struct{}, len(chain.Rules))
for _, rule := range chain.Rules {
if _, exists := reportedRule[rule]; exists {
continue
}
reportedRule[rule] = struct{}{}

metricChan <- prometheus.MustNewConstMetric(
rulePacketsDesc,
prometheus.CounterValue,
Expand Down

0 comments on commit b29f327

Please sign in to comment.