2016-07-05 21:15:54 +00:00
|
|
|
// +build linux
|
|
|
|
|
|
|
|
package iptables
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/influxdata/telegraf/testutil"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestIptables_Gather(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
table string
|
|
|
|
chains []string
|
|
|
|
values []string
|
|
|
|
tags []map[string]string
|
|
|
|
fields [][]map[string]interface{}
|
|
|
|
err error
|
|
|
|
}{
|
|
|
|
{ // 1 - no configured table => no results
|
|
|
|
values: []string{
|
|
|
|
`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)
|
|
|
|
pkts bytes target prot opt in out source destination
|
|
|
|
57 4520 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0
|
|
|
|
`},
|
|
|
|
},
|
|
|
|
{ // 2 - no configured chains => no results
|
|
|
|
table: "filter",
|
|
|
|
values: []string{
|
|
|
|
`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)
|
|
|
|
pkts bytes target prot opt in out source destination
|
|
|
|
57 4520 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0
|
|
|
|
`},
|
|
|
|
},
|
|
|
|
{ // 3 - pkts and bytes are gathered as integers
|
|
|
|
table: "filter",
|
|
|
|
chains: []string{"INPUT"},
|
|
|
|
values: []string{
|
|
|
|
`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)
|
|
|
|
pkts bytes target prot opt in out source destination
|
|
|
|
57 4520 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* foobar */
|
|
|
|
`},
|
|
|
|
tags: []map[string]string{map[string]string{"table": "filter", "chain": "INPUT", "ruleid": "foobar"}},
|
|
|
|
fields: [][]map[string]interface{}{
|
|
|
|
{map[string]interface{}{"pkts": uint64(57), "bytes": uint64(4520)}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{ // 4 - missing fields header => no results
|
|
|
|
table: "filter",
|
|
|
|
chains: []string{"INPUT"},
|
|
|
|
values: []string{`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)`},
|
|
|
|
},
|
|
|
|
{ // 5 - invalid chain header => error
|
|
|
|
table: "filter",
|
|
|
|
chains: []string{"INPUT"},
|
|
|
|
values: []string{
|
|
|
|
`INPUT (policy ACCEPT 58 packets, 5096 bytes)
|
|
|
|
pkts bytes target prot opt in out source destination
|
|
|
|
57 4520 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0
|
|
|
|
`},
|
|
|
|
err: errParse,
|
|
|
|
},
|
|
|
|
{ // 6 - invalid fields header => error
|
|
|
|
table: "filter",
|
|
|
|
chains: []string{"INPUT"},
|
|
|
|
values: []string{
|
|
|
|
`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)
|
|
|
|
|
|
|
|
57 4520 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0
|
|
|
|
`},
|
|
|
|
err: errParse,
|
|
|
|
},
|
|
|
|
{ // 7 - invalid integer value => best effort, no error
|
|
|
|
table: "filter",
|
|
|
|
chains: []string{"INPUT"},
|
|
|
|
values: []string{
|
|
|
|
`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)
|
|
|
|
pkts bytes target prot opt in out source destination
|
|
|
|
K 4520 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0
|
|
|
|
`},
|
|
|
|
},
|
|
|
|
{ // 8 - Multiple rows, multipe chains => no error
|
|
|
|
table: "filter",
|
|
|
|
chains: []string{"INPUT", "FORWARD"},
|
|
|
|
values: []string{
|
|
|
|
`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)
|
|
|
|
pkts bytes target prot opt in out source destination
|
|
|
|
100 4520 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0
|
|
|
|
200 4520 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* foo */
|
|
|
|
`,
|
|
|
|
`Chain FORWARD (policy ACCEPT 58 packets, 5096 bytes)
|
|
|
|
pkts bytes target prot opt in out source destination
|
|
|
|
300 4520 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* bar */
|
|
|
|
400 4520 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0
|
|
|
|
500 4520 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* foobar */
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
tags: []map[string]string{
|
|
|
|
map[string]string{"table": "filter", "chain": "INPUT", "ruleid": "foo"},
|
|
|
|
map[string]string{"table": "filter", "chain": "FORWARD", "ruleid": "bar"},
|
|
|
|
map[string]string{"table": "filter", "chain": "FORWARD", "ruleid": "foobar"},
|
|
|
|
},
|
|
|
|
fields: [][]map[string]interface{}{
|
|
|
|
{map[string]interface{}{"pkts": uint64(200), "bytes": uint64(4520)}},
|
|
|
|
{map[string]interface{}{"pkts": uint64(300), "bytes": uint64(4520)}},
|
|
|
|
{map[string]interface{}{"pkts": uint64(500), "bytes": uint64(4520)}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{ // 9 - comments are used as ruleid if any
|
|
|
|
table: "filter",
|
|
|
|
chains: []string{"INPUT"},
|
|
|
|
values: []string{
|
|
|
|
`Chain INPUT (policy ACCEPT 58 packets, 5096 bytes)
|
|
|
|
pkts bytes target prot opt in out source destination
|
|
|
|
57 4520 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 /* foobar */
|
|
|
|
100 4520 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
|
|
|
|
`},
|
|
|
|
tags: []map[string]string{
|
|
|
|
map[string]string{"table": "filter", "chain": "INPUT", "ruleid": "foobar"},
|
|
|
|
},
|
|
|
|
fields: [][]map[string]interface{}{
|
|
|
|
{map[string]interface{}{"pkts": uint64(57), "bytes": uint64(4520)}},
|
|
|
|
},
|
|
|
|
},
|
2017-07-27 22:21:06 +00:00
|
|
|
{ // 10 - allow trailing text
|
|
|
|
table: "mangle",
|
|
|
|
chains: []string{"SHAPER"},
|
|
|
|
values: []string{
|
|
|
|
`Chain SHAPER (policy ACCEPT 58 packets, 5096 bytes)
|
|
|
|
pkts bytes target prot opt in out source destination
|
|
|
|
0 0 ACCEPT all -- * * 1.3.5.7 0.0.0.0/0 /* test */
|
|
|
|
0 0 CLASSIFY all -- * * 1.3.5.7 0.0.0.0/0 /* test2 */ CLASSIFY set 1:4
|
|
|
|
`},
|
|
|
|
tags: []map[string]string{
|
|
|
|
map[string]string{"table": "mangle", "chain": "SHAPER", "ruleid": "test"},
|
|
|
|
map[string]string{"table": "mangle", "chain": "SHAPER", "ruleid": "test2"},
|
|
|
|
},
|
|
|
|
fields: [][]map[string]interface{}{
|
|
|
|
{map[string]interface{}{"pkts": uint64(0), "bytes": uint64(0)}},
|
|
|
|
{map[string]interface{}{"pkts": uint64(0), "bytes": uint64(0)}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{ // 11 - invalid pkts/bytes
|
|
|
|
table: "mangle",
|
|
|
|
chains: []string{"SHAPER"},
|
|
|
|
values: []string{
|
|
|
|
`Chain SHAPER (policy ACCEPT 58 packets, 5096 bytes)
|
|
|
|
pkts bytes target prot opt in out source destination
|
|
|
|
a a ACCEPT all -- * * 1.3.5.7 0.0.0.0/0 /* test */
|
|
|
|
a a CLASSIFY all -- * * 1.3.5.7 0.0.0.0/0 /* test2 */ CLASSIFY set 1:4
|
|
|
|
`},
|
|
|
|
tags: []map[string]string{},
|
|
|
|
fields: [][]map[string]interface{}{},
|
|
|
|
},
|
2017-09-14 21:59:28 +00:00
|
|
|
{ // 11 - all target and ports
|
|
|
|
table: "all_recv",
|
|
|
|
chains: []string{"accountfwd"},
|
|
|
|
values: []string{
|
|
|
|
`Chain accountfwd (1 references)
|
|
|
|
pkts bytes target prot opt in out source destination
|
|
|
|
123 456 all -- eth0 * 0.0.0.0/0 0.0.0.0/0 /* all_recv */
|
|
|
|
`},
|
|
|
|
tags: []map[string]string{
|
|
|
|
map[string]string{"table": "all_recv", "chain": "accountfwd", "ruleid": "all_recv"},
|
|
|
|
},
|
|
|
|
fields: [][]map[string]interface{}{
|
|
|
|
{map[string]interface{}{"pkts": uint64(123), "bytes": uint64(456)}},
|
|
|
|
},
|
|
|
|
},
|
2016-07-05 21:15:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for i, tt := range tests {
|
2017-09-14 21:59:28 +00:00
|
|
|
t.Run(tt.table, func(t *testing.T) {
|
|
|
|
i++
|
|
|
|
ipt := &Iptables{
|
|
|
|
Table: tt.table,
|
|
|
|
Chains: tt.chains,
|
|
|
|
lister: func(table, chain string) (string, error) {
|
|
|
|
if len(tt.values) > 0 {
|
|
|
|
v := tt.values[0]
|
|
|
|
tt.values = tt.values[1:]
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
return "", nil
|
|
|
|
},
|
2016-07-05 21:15:54 +00:00
|
|
|
}
|
2017-09-14 21:59:28 +00:00
|
|
|
acc := new(testutil.Accumulator)
|
|
|
|
err := acc.GatherError(ipt.Gather)
|
|
|
|
if !reflect.DeepEqual(tt.err, err) {
|
|
|
|
t.Errorf("%d: expected error '%#v' got '%#v'", i, tt.err, err)
|
2016-07-05 21:15:54 +00:00
|
|
|
}
|
2017-09-14 21:59:28 +00:00
|
|
|
if tt.table == "" {
|
|
|
|
n := acc.NFields()
|
|
|
|
if n != 0 {
|
|
|
|
t.Errorf("%d: expected 0 fields if empty table got %d", i, n)
|
2016-07-05 21:15:54 +00:00
|
|
|
}
|
2017-09-14 21:59:28 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(tt.chains) == 0 {
|
|
|
|
n := acc.NFields()
|
|
|
|
if n != 0 {
|
|
|
|
t.Errorf("%d: expected 0 fields if empty chains got %d", i, n)
|
2016-07-05 21:15:54 +00:00
|
|
|
}
|
2017-09-14 21:59:28 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(tt.tags) == 0 {
|
|
|
|
n := acc.NFields()
|
|
|
|
if n != 0 {
|
|
|
|
t.Errorf("%d: expected 0 values got %d", i, n)
|
2016-07-05 21:15:54 +00:00
|
|
|
}
|
2017-09-14 21:59:28 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
n := 0
|
|
|
|
for j, tags := range tt.tags {
|
|
|
|
for k, fields := range tt.fields[j] {
|
|
|
|
if len(acc.Metrics) < n+1 {
|
|
|
|
t.Errorf("%d: expected at least %d values got %d", i, n+1, len(acc.Metrics))
|
|
|
|
break
|
|
|
|
}
|
|
|
|
m := acc.Metrics[n]
|
|
|
|
if !reflect.DeepEqual(m.Measurement, measurement) {
|
|
|
|
t.Errorf("%d %d %d: expected measurement '%#v' got '%#v'\n", i, j, k, measurement, m.Measurement)
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(m.Tags, tags) {
|
|
|
|
t.Errorf("%d %d %d: expected tags\n%#v got\n%#v\n", i, j, k, tags, m.Tags)
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(m.Fields, fields) {
|
|
|
|
t.Errorf("%d %d %d: expected fields\n%#v got\n%#v\n", i, j, k, fields, m.Fields)
|
|
|
|
}
|
|
|
|
n++
|
2016-07-05 21:15:54 +00:00
|
|
|
}
|
|
|
|
}
|
2017-09-14 21:59:28 +00:00
|
|
|
})
|
2016-07-05 21:15:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestIptables_Gather_listerError(t *testing.T) {
|
|
|
|
errFoo := errors.New("error foobar")
|
|
|
|
ipt := &Iptables{
|
|
|
|
Table: "nat",
|
|
|
|
Chains: []string{"foo", "bar"},
|
|
|
|
lister: func(table, chain string) (string, error) {
|
|
|
|
return "", errFoo
|
|
|
|
},
|
|
|
|
}
|
|
|
|
acc := new(testutil.Accumulator)
|
2017-04-24 18:13:26 +00:00
|
|
|
err := acc.GatherError(ipt.Gather)
|
2016-07-05 21:15:54 +00:00
|
|
|
if !reflect.DeepEqual(err, errFoo) {
|
|
|
|
t.Errorf("Expected error %#v got\n%#v\n", errFoo, err)
|
|
|
|
}
|
|
|
|
}
|