2023-12-18 20:12:51 -05:00
//go:build linux
2022-04-08 16:28:59 -04:00
/ *
Copyright 2022 The Kubernetes Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package testing
import (
2022-04-07 11:29:00 -04:00
"fmt"
2022-04-08 16:28:59 -04:00
"reflect"
"strings"
"testing"
2022-04-07 11:29:00 -04:00
"github.com/lithammer/dedent"
2022-04-08 16:28:59 -04:00
"k8s.io/kubernetes/pkg/util/iptables"
2024-04-15 05:16:31 -04:00
"k8s.io/utils/ptr"
2022-04-08 16:28:59 -04:00
)
func TestParseRule ( t * testing . T ) {
testCases := [ ] struct {
name string
rule string
parsed * Rule
nonStrict bool
err string
} {
{
name : "basic rule" ,
rule : ` -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT ` ,
parsed : & Rule {
Raw : ` -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT ` ,
Chain : iptables . Chain ( "KUBE-NODEPORTS" ) ,
Comment : & IPTablesValue { Value : "ns2/svc2:p80 health check node port" } ,
Protocol : & IPTablesValue { Value : "tcp" } ,
DestinationPort : & IPTablesValue { Value : "30000" } ,
Jump : & IPTablesValue { Value : "ACCEPT" } ,
} ,
} ,
{
name : "addRuleToChainRegex requires an actual rule, not just a chain name" ,
rule : ` -A KUBE-NODEPORTS ` ,
err : ` (no match rules) ` ,
} ,
{
name : "ParseRule only parses adds" ,
rule : ` -D KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT ` ,
err : ` (does not start with "-A CHAIN") ` ,
} ,
{
name : "unquoted comment" ,
rule : ` -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment ns1/svc1:p80 -j KUBE-SEP-SXIVWICOYRO3J4NJ ` ,
parsed : & Rule {
Raw : ` -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment ns1/svc1:p80 -j KUBE-SEP-SXIVWICOYRO3J4NJ ` ,
Chain : iptables . Chain ( "KUBE-SVC-XPGD46QRK7WJZT7O" ) ,
Comment : & IPTablesValue { Value : "ns1/svc1:p80" } ,
Jump : & IPTablesValue { Value : "KUBE-SEP-SXIVWICOYRO3J4NJ" } ,
} ,
} ,
{
name : "local source" ,
rule : ` -A KUBE-XLB-GNZBNJ2PO5MGZ6GT -m comment --comment "masquerade LOCAL traffic for ns2/svc2:p80 LB IP" -m addrtype --src-type LOCAL -j KUBE-MARK-MASQ ` ,
parsed : & Rule {
Raw : ` -A KUBE-XLB-GNZBNJ2PO5MGZ6GT -m comment --comment "masquerade LOCAL traffic for ns2/svc2:p80 LB IP" -m addrtype --src-type LOCAL -j KUBE-MARK-MASQ ` ,
Chain : iptables . Chain ( "KUBE-XLB-GNZBNJ2PO5MGZ6GT" ) ,
Comment : & IPTablesValue { Value : "masquerade LOCAL traffic for ns2/svc2:p80 LB IP" } ,
SourceType : & IPTablesValue { Value : "LOCAL" } ,
Jump : & IPTablesValue { Value : "KUBE-MARK-MASQ" } ,
} ,
} ,
{
name : "not local destination" ,
rule : ` -A RULE-TYPE-NOT-CURRENTLY-USED-BY-KUBE-PROXY -m addrtype ! --dst-type LOCAL -j KUBE-MARK-MASQ ` ,
parsed : & Rule {
Raw : ` -A RULE-TYPE-NOT-CURRENTLY-USED-BY-KUBE-PROXY -m addrtype ! --dst-type LOCAL -j KUBE-MARK-MASQ ` ,
Chain : iptables . Chain ( "RULE-TYPE-NOT-CURRENTLY-USED-BY-KUBE-PROXY" ) ,
DestinationType : & IPTablesValue { Negated : true , Value : "LOCAL" } ,
Jump : & IPTablesValue { Value : "KUBE-MARK-MASQ" } ,
} ,
} ,
{
name : "destination IP/port" ,
rule : ` -A KUBE-SERVICES -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 172.30.0.41 --dport 80 -j KUBE-SVC-XPGD46QRK7WJZT7O ` ,
parsed : & Rule {
Raw : ` -A KUBE-SERVICES -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 172.30.0.41 --dport 80 -j KUBE-SVC-XPGD46QRK7WJZT7O ` ,
Chain : iptables . Chain ( "KUBE-SERVICES" ) ,
Comment : & IPTablesValue { Value : "ns1/svc1:p80 cluster IP" } ,
Protocol : & IPTablesValue { Value : "tcp" } ,
DestinationAddress : & IPTablesValue { Value : "172.30.0.41" } ,
DestinationPort : & IPTablesValue { Value : "80" } ,
Jump : & IPTablesValue { Value : "KUBE-SVC-XPGD46QRK7WJZT7O" } ,
} ,
} ,
{
name : "source IP" ,
rule : ` -A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -s 10.180.0.1 -j KUBE-MARK-MASQ ` ,
parsed : & Rule {
Raw : ` -A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -s 10.180.0.1 -j KUBE-MARK-MASQ ` ,
Chain : iptables . Chain ( "KUBE-SEP-SXIVWICOYRO3J4NJ" ) ,
Comment : & IPTablesValue { Value : "ns1/svc1:p80" } ,
SourceAddress : & IPTablesValue { Value : "10.180.0.1" } ,
Jump : & IPTablesValue { Value : "KUBE-MARK-MASQ" } ,
} ,
} ,
{
name : "not source IP" ,
rule : ` -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 172.30.0.41 --dport 80 ! -s 10.0.0.0/8 -j KUBE-MARK-MASQ ` ,
parsed : & Rule {
Raw : ` -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 172.30.0.41 --dport 80 ! -s 10.0.0.0/8 -j KUBE-MARK-MASQ ` ,
Chain : iptables . Chain ( "KUBE-SVC-XPGD46QRK7WJZT7O" ) ,
Comment : & IPTablesValue { Value : "ns1/svc1:p80 cluster IP" } ,
Protocol : & IPTablesValue { Value : "tcp" } ,
DestinationAddress : & IPTablesValue { Value : "172.30.0.41" } ,
DestinationPort : & IPTablesValue { Value : "80" } ,
SourceAddress : & IPTablesValue { Negated : true , Value : "10.0.0.0/8" } ,
Jump : & IPTablesValue { Value : "KUBE-MARK-MASQ" } ,
} ,
} ,
{
name : "affinity" ,
rule : ` -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment ns1/svc1:p80 -m recent --name KUBE-SEP-SXIVWICOYRO3J4NJ --rcheck --seconds 10800 --reap -j KUBE-SEP-SXIVWICOYRO3J4NJ ` ,
parsed : & Rule {
Raw : ` -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment ns1/svc1:p80 -m recent --name KUBE-SEP-SXIVWICOYRO3J4NJ --rcheck --seconds 10800 --reap -j KUBE-SEP-SXIVWICOYRO3J4NJ ` ,
Chain : iptables . Chain ( "KUBE-SVC-XPGD46QRK7WJZT7O" ) ,
Comment : & IPTablesValue { Value : "ns1/svc1:p80" } ,
AffinityName : & IPTablesValue { Value : "KUBE-SEP-SXIVWICOYRO3J4NJ" } ,
AffinitySeconds : & IPTablesValue { Value : "10800" } ,
2024-04-15 05:16:31 -04:00
AffinityCheck : ptr . To ( true ) ,
AffinityReap : ptr . To ( true ) ,
2022-04-08 16:28:59 -04:00
Jump : & IPTablesValue { Value : "KUBE-SEP-SXIVWICOYRO3J4NJ" } ,
} ,
} ,
{
name : "jump to DNAT" ,
rule : ` -A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -m tcp -p tcp -j DNAT --to-destination 10.180.0.1:80 ` ,
parsed : & Rule {
Raw : ` -A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -m tcp -p tcp -j DNAT --to-destination 10.180.0.1:80 ` ,
Chain : iptables . Chain ( "KUBE-SEP-SXIVWICOYRO3J4NJ" ) ,
Comment : & IPTablesValue { Value : "ns1/svc1:p80" } ,
Protocol : & IPTablesValue { Value : "tcp" } ,
Jump : & IPTablesValue { Value : "DNAT" } ,
DNATDestination : & IPTablesValue { Value : "10.180.0.1:80" } ,
} ,
} ,
{
name : "jump to endpoint" ,
rule : ` -A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 -m statistic --mode random --probability 0.5000000000 -j KUBE-SEP-UKSFD7AGPMPPLUHC ` ,
parsed : & Rule {
Raw : ` -A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 -m statistic --mode random --probability 0.5000000000 -j KUBE-SEP-UKSFD7AGPMPPLUHC ` ,
Chain : iptables . Chain ( "KUBE-SVC-4SW47YFZTEDKD3PK" ) ,
Comment : & IPTablesValue { Value : "ns4/svc4:p80" } ,
Probability : & IPTablesValue { Value : "0.5000000000" } ,
StatisticMode : & IPTablesValue { Value : "random" } ,
Jump : & IPTablesValue { Value : "KUBE-SEP-UKSFD7AGPMPPLUHC" } ,
} ,
} ,
{
name : "unrecognized arguments" ,
rule : ` -A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 -i eth0 -j KUBE-SEP-UKSFD7AGPMPPLUHC ` ,
err : ` unrecognized parameter "-i" ` ,
} ,
{
name : "unrecognized arguments with strict=false" ,
rule : ` -A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 -i eth0 -j KUBE-SEP-UKSFD7AGPMPPLUHC ` ,
nonStrict : true ,
parsed : & Rule {
Raw : ` -A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 -i eth0 -j KUBE-SEP-UKSFD7AGPMPPLUHC ` ,
Chain : iptables . Chain ( "KUBE-SVC-4SW47YFZTEDKD3PK" ) ,
Comment : & IPTablesValue { Value : "ns4/svc4:p80" } ,
Jump : & IPTablesValue { Value : "KUBE-SEP-UKSFD7AGPMPPLUHC" } ,
} ,
} ,
{
name : "bad use of !" ,
rule : ` -A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 ! -j KUBE-SEP-UKSFD7AGPMPPLUHC ` ,
err : ` cannot negate parameter "-j" ` ,
} ,
{
name : "missing argument" ,
rule : ` -A KUBE-SVC-4SW47YFZTEDKD3PK -m comment --comment ns4/svc4:p80 -j ` ,
err : ` parameter "-j" requires an argument ` ,
} ,
{
name : "negated bool arg" ,
rule : ` -A TEST -m recent ! --rcheck -j KUBE-SEP-SXIVWICOYRO3J4NJ ` ,
parsed : & Rule {
Raw : ` -A TEST -m recent ! --rcheck -j KUBE-SEP-SXIVWICOYRO3J4NJ ` ,
Chain : iptables . Chain ( "TEST" ) ,
2024-04-15 05:16:31 -04:00
AffinityCheck : ptr . To ( false ) ,
2022-04-08 16:28:59 -04:00
Jump : & IPTablesValue { Value : "KUBE-SEP-SXIVWICOYRO3J4NJ" } ,
} ,
} ,
}
for _ , testCase := range testCases {
t . Run ( testCase . name , func ( t * testing . T ) {
rule , err := ParseRule ( testCase . rule , ! testCase . nonStrict )
if err != nil {
if testCase . err == "" {
t . Errorf ( "expected %+v, got error %q" , testCase . parsed , err )
} else if ! strings . Contains ( err . Error ( ) , testCase . err ) {
t . Errorf ( "wrong error, expected %q got %q" , testCase . err , err )
}
} else {
if testCase . err != "" {
t . Errorf ( "expected error %q, got %+v" , testCase . err , rule )
} else if ! reflect . DeepEqual ( rule , testCase . parsed ) {
t . Errorf ( "bad match: expected\n%+v\ngot\n%+v" , testCase . parsed , rule )
}
}
} )
}
}
2022-04-07 11:29:00 -04:00
// Helper for TestParseIPTablesDump. Obviously it should not be used in TestParseRule...
func mustParseRule ( rule string ) * Rule {
parsed , err := ParseRule ( rule , false )
if err != nil {
panic ( fmt . Sprintf ( "failed to parse test case rule %q: %v" , rule , err ) )
}
return parsed
}
func TestParseIPTablesDump ( t * testing . T ) {
for _ , tc := range [ ] struct {
name string
input string
output * IPTablesDump
error string
} {
{
name : "basic test" ,
input : dedent . Dedent ( `
* filter
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - EXTERNAL - SERVICES - [ 0 : 0 ]
: KUBE - FORWARD - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
- A KUBE - NODEPORTS - m comment -- comment "ns2/svc2:p80 health check node port" - m tcp - p tcp -- dport 30000 - j ACCEPT
- A KUBE - FORWARD - m conntrack -- ctstate INVALID - j DROP
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding rules" - m mark -- mark 0x4000 / 0x4000 - j ACCEPT
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding conntrack rule" - m conntrack -- ctstate RELATED , ESTABLISHED - j ACCEPT
COMMIT
* nat
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
: KUBE - POSTROUTING - [ 0 : 0 ]
: KUBE - MARK - MASQ - [ 0 : 0 ]
: KUBE - SVC - XPGD46QRK7WJZT7O - [ 0 : 0 ]
: KUBE - SEP - SXIVWICOYRO3J4NJ - [ 0 : 0 ]
- A KUBE - POSTROUTING - m mark ! -- mark 0x4000 / 0x4000 - j RETURN
- A KUBE - POSTROUTING - j MARK -- xor - mark 0x4000
- A KUBE - POSTROUTING - m comment -- comment "kubernetes service traffic requiring SNAT" - j MASQUERADE
- A KUBE - MARK - MASQ - j MARK -- or - mark 0x4000
- A KUBE - SERVICES - m comment -- comment "ns1/svc1:p80 cluster IP" - m tcp - p tcp - d 10.20 .30 .41 -- dport 80 - j KUBE - SVC - XPGD46QRK7WJZT7O
- A KUBE - SVC - XPGD46QRK7WJZT7O - m comment -- comment "ns1/svc1:p80 cluster IP" - m tcp - p tcp - d 10.20 .30 .41 -- dport 80 ! - s 10.0 .0 .0 / 24 - j KUBE - MARK - MASQ
- A KUBE - SVC - XPGD46QRK7WJZT7O - m comment -- comment ns1 / svc1 : p80 - j KUBE - SEP - SXIVWICOYRO3J4NJ
- A KUBE - SEP - SXIVWICOYRO3J4NJ - m comment -- comment ns1 / svc1 : p80 - s 10.180 .0 .1 - j KUBE - MARK - MASQ
- A KUBE - SEP - SXIVWICOYRO3J4NJ - m comment -- comment ns1 / svc1 : p80 - m tcp - p tcp - j DNAT -- to - destination 10.180 .0 .1 : 80
- A KUBE - SERVICES - m comment -- comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" - m addrtype -- dst - type LOCAL - j KUBE - NODEPORTS
COMMIT
` ) ,
output : & IPTablesDump {
Tables : [ ] Table { {
Name : iptables . TableFilter ,
Chains : [ ] Chain { {
Name : iptables . Chain ( "KUBE-SERVICES" ) ,
} , {
Name : iptables . Chain ( "KUBE-EXTERNAL-SERVICES" ) ,
} , {
Name : iptables . Chain ( "KUBE-FORWARD" ) ,
Rules : [ ] * Rule {
mustParseRule ( ` -A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP ` ) ,
mustParseRule ( ` -A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT ` ) ,
mustParseRule ( ` -A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT ` ) ,
} ,
} , {
Name : iptables . Chain ( "KUBE-NODEPORTS" ) ,
Rules : [ ] * Rule {
mustParseRule ( ` -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT ` ) ,
} ,
} } ,
} , {
Name : iptables . TableNAT ,
Chains : [ ] Chain { {
Name : iptables . Chain ( "KUBE-SERVICES" ) ,
Rules : [ ] * Rule {
mustParseRule ( ` -A KUBE-SERVICES -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 10.20.30.41 --dport 80 -j KUBE-SVC-XPGD46QRK7WJZT7O ` ) ,
mustParseRule ( ` -A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS ` ) ,
} ,
} , {
Name : iptables . Chain ( "KUBE-NODEPORTS" ) ,
} , {
Name : iptables . Chain ( "KUBE-POSTROUTING" ) ,
Rules : [ ] * Rule {
mustParseRule ( ` -A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN ` ) ,
mustParseRule ( ` -A KUBE-POSTROUTING -j MARK --xor-mark 0x4000 ` ) ,
mustParseRule ( ` -A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE ` ) ,
} ,
} , {
Name : iptables . Chain ( "KUBE-MARK-MASQ" ) ,
Rules : [ ] * Rule {
mustParseRule ( ` -A KUBE-MARK-MASQ -j MARK --or-mark 0x4000 ` ) ,
} ,
} , {
Name : iptables . Chain ( "KUBE-SVC-XPGD46QRK7WJZT7O" ) ,
Rules : [ ] * Rule {
mustParseRule ( ` -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment "ns1/svc1:p80 cluster IP" -m tcp -p tcp -d 10.20.30.41 --dport 80 ! -s 10.0.0.0/24 -j KUBE-MARK-MASQ ` ) ,
mustParseRule ( ` -A KUBE-SVC-XPGD46QRK7WJZT7O -m comment --comment ns1/svc1:p80 -j KUBE-SEP-SXIVWICOYRO3J4NJ ` ) ,
} ,
} , {
Name : iptables . Chain ( "KUBE-SEP-SXIVWICOYRO3J4NJ" ) ,
Rules : [ ] * Rule {
mustParseRule ( ` -A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -s 10.180.0.1 -j KUBE-MARK-MASQ ` ) ,
mustParseRule ( ` -A KUBE-SEP-SXIVWICOYRO3J4NJ -m comment --comment ns1/svc1:p80 -m tcp -p tcp -j DNAT --to-destination 10.180.0.1:80 ` ) ,
} ,
} } ,
} } ,
} ,
} ,
{
name : "deletion" ,
input : dedent . Dedent ( `
* nat
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - SVC - XPGD46QRK7WJZT7O - [ 0 : 0 ]
: KUBE - SEP - SXIVWICOYRO3J4NJ - [ 0 : 0 ]
- X KUBE - SVC - XPGD46QRK7WJZT7O
- X KUBE - SEP - SXIVWICOYRO3J4NJ
- A KUBE - SERVICES - m comment -- comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" - m addrtype -- dst - type LOCAL - j KUBE - NODEPORTS
COMMIT
` ) ,
output : & IPTablesDump {
Tables : [ ] Table { {
Name : iptables . TableNAT ,
Chains : [ ] Chain { {
Name : iptables . Chain ( "KUBE-SERVICES" ) ,
Rules : [ ] * Rule {
mustParseRule ( ` -A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS ` ) ,
} ,
} , {
Name : iptables . Chain ( "KUBE-SVC-XPGD46QRK7WJZT7O" ) ,
Deleted : true ,
} , {
Name : iptables . Chain ( "KUBE-SEP-SXIVWICOYRO3J4NJ" ) ,
Deleted : true ,
} } ,
} } ,
} ,
} ,
{
name : "whitespace and comments" ,
input : dedent . Dedent ( `
# Generated by iptables - save v1 .8 .7 on Mon May 9 11 : 22 : 21 2022
# ( not really ... )
* filter
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - EXTERNAL - SERVICES - [ 0 : 0 ]
: KUBE - FORWARD - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
- A KUBE - NODEPORTS - m comment -- comment "ns2/svc2:p80 health check node port" - m tcp - p tcp -- dport 30000 - j ACCEPT
- A KUBE - FORWARD - m conntrack -- ctstate INVALID - j DROP
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding rules" - m mark -- mark 0x4000 / 0x4000 - j ACCEPT
# This rule does a thing
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding conntrack rule" - m conntrack -- ctstate RELATED , ESTABLISHED - j ACCEPT
COMMIT
# Completed on Mon May 9 11 : 22 : 21 2022
` ) ,
output : & IPTablesDump {
Tables : [ ] Table { {
Name : iptables . TableFilter ,
Chains : [ ] Chain { {
Name : iptables . Chain ( "KUBE-SERVICES" ) ,
} , {
Name : iptables . Chain ( "KUBE-EXTERNAL-SERVICES" ) ,
} , {
Name : iptables . Chain ( "KUBE-FORWARD" ) ,
Rules : [ ] * Rule {
mustParseRule ( ` -A KUBE-FORWARD -m conntrack --ctstate INVALID -j DROP ` ) ,
mustParseRule ( ` -A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT ` ) ,
mustParseRule ( ` -A KUBE-FORWARD -m comment --comment "kubernetes forwarding conntrack rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT ` ) ,
} ,
} , {
Name : iptables . Chain ( "KUBE-NODEPORTS" ) ,
Rules : [ ] * Rule {
mustParseRule ( ` -A KUBE-NODEPORTS -m comment --comment "ns2/svc2:p80 health check node port" -m tcp -p tcp --dport 30000 -j ACCEPT ` ) ,
} ,
} } ,
} } ,
} ,
} ,
{
name : "no COMMIT line" ,
input : dedent . Dedent ( `
* filter
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - EXTERNAL - SERVICES - [ 0 : 0 ]
: KUBE - FORWARD - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
- A KUBE - NODEPORTS - m comment -- comment "ns2/svc2:p80 health check node port" - m tcp - p tcp -- dport 30000 - j ACCEPT
- A KUBE - FORWARD - m conntrack -- ctstate INVALID - j DROP
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding rules" - m mark -- mark 0x4000 / 0x4000 - j ACCEPT
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding conntrack rule" - m conntrack -- ctstate RELATED , ESTABLISHED - j ACCEPT
` ) ,
error : "no COMMIT line?" ,
} ,
{
name : "two tables, no second COMMIT line" ,
input : dedent . Dedent ( `
* filter
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - EXTERNAL - SERVICES - [ 0 : 0 ]
: KUBE - FORWARD - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
- A KUBE - NODEPORTS - m comment -- comment "ns2/svc2:p80 health check node port" - m tcp - p tcp -- dport 30000 - j ACCEPT
- A KUBE - FORWARD - m conntrack -- ctstate INVALID - j DROP
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding rules" - m mark -- mark 0x4000 / 0x4000 - j ACCEPT
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding conntrack rule" - m conntrack -- ctstate RELATED , ESTABLISHED - j ACCEPT
COMMIT
* nat
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
: KUBE - POSTROUTING - [ 0 : 0 ]
: KUBE - MARK - MASQ - [ 0 : 0 ]
: KUBE - SVC - XPGD46QRK7WJZT7O - [ 0 : 0 ]
: KUBE - SEP - SXIVWICOYRO3J4NJ - [ 0 : 0 ]
- A KUBE - POSTROUTING - m mark ! -- mark 0x4000 / 0x4000 - j RETURN
- A KUBE - POSTROUTING - j MARK -- xor - mark 0x4000
- A KUBE - POSTROUTING - m comment -- comment "kubernetes service traffic requiring SNAT" - j MASQUERADE
- A KUBE - MARK - MASQ - j MARK -- or - mark 0x4000
- A KUBE - SERVICES - m comment -- comment "ns1/svc1:p80 cluster IP" - m tcp - p tcp - d 10.20 .30 .41 -- dport 80 - j KUBE - SVC - XPGD46QRK7WJZT7O
- A KUBE - SVC - XPGD46QRK7WJZT7O - m comment -- comment "ns1/svc1:p80 cluster IP" - m tcp - p tcp - d 10.20 .30 .41 -- dport 80 ! - s 10.0 .0 .0 / 24 - j KUBE - MARK - MASQ
- A KUBE - SVC - XPGD46QRK7WJZT7O - m comment -- comment ns1 / svc1 : p80 - j KUBE - SEP - SXIVWICOYRO3J4NJ
- A KUBE - SEP - SXIVWICOYRO3J4NJ - m comment -- comment ns1 / svc1 : p80 - s 10.180 .0 .1 - j KUBE - MARK - MASQ
- A KUBE - SEP - SXIVWICOYRO3J4NJ - m comment -- comment ns1 / svc1 : p80 - m tcp - p tcp - j DNAT -- to - destination 10.180 .0 .1 : 80
- A KUBE - SERVICES - m comment -- comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" - m addrtype -- dst - type LOCAL - j KUBE - NODEPORTS
` ) ,
error : "no COMMIT line?" ,
} ,
{
name : "two tables, no second header line" ,
input : dedent . Dedent ( `
* filter
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - EXTERNAL - SERVICES - [ 0 : 0 ]
: KUBE - FORWARD - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
- A KUBE - NODEPORTS - m comment -- comment "ns2/svc2:p80 health check node port" - m tcp - p tcp -- dport 30000 - j ACCEPT
- A KUBE - FORWARD - m conntrack -- ctstate INVALID - j DROP
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding rules" - m mark -- mark 0x4000 / 0x4000 - j ACCEPT
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding conntrack rule" - m conntrack -- ctstate RELATED , ESTABLISHED - j ACCEPT
COMMIT
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
: KUBE - POSTROUTING - [ 0 : 0 ]
: KUBE - MARK - MASQ - [ 0 : 0 ]
: KUBE - SVC - XPGD46QRK7WJZT7O - [ 0 : 0 ]
: KUBE - SEP - SXIVWICOYRO3J4NJ - [ 0 : 0 ]
- A KUBE - POSTROUTING - m mark ! -- mark 0x4000 / 0x4000 - j RETURN
- A KUBE - POSTROUTING - j MARK -- xor - mark 0x4000
- A KUBE - POSTROUTING - m comment -- comment "kubernetes service traffic requiring SNAT" - j MASQUERADE
- A KUBE - MARK - MASQ - j MARK -- or - mark 0x4000
- A KUBE - SERVICES - m comment -- comment "ns1/svc1:p80 cluster IP" - m tcp - p tcp - d 10.20 .30 .41 -- dport 80 - j KUBE - SVC - XPGD46QRK7WJZT7O
- A KUBE - SVC - XPGD46QRK7WJZT7O - m comment -- comment "ns1/svc1:p80 cluster IP" - m tcp - p tcp - d 10.20 .30 .41 -- dport 80 ! - s 10.0 .0 .0 / 24 - j KUBE - MARK - MASQ
- A KUBE - SVC - XPGD46QRK7WJZT7O - m comment -- comment ns1 / svc1 : p80 - j KUBE - SEP - SXIVWICOYRO3J4NJ
- A KUBE - SEP - SXIVWICOYRO3J4NJ - m comment -- comment ns1 / svc1 : p80 - s 10.180 .0 .1 - j KUBE - MARK - MASQ
- A KUBE - SEP - SXIVWICOYRO3J4NJ - m comment -- comment ns1 / svc1 : p80 - m tcp - p tcp - j DNAT -- to - destination 10.180 .0 .1 : 80
- A KUBE - SERVICES - m comment -- comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" - m addrtype -- dst - type LOCAL - j KUBE - NODEPORTS
COMMIT
` ) ,
error : "not a table name" ,
} ,
{
name : "trailing junk" ,
input : dedent . Dedent ( `
* filter
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - EXTERNAL - SERVICES - [ 0 : 0 ]
: KUBE - FORWARD - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
- A KUBE - NODEPORTS - m comment -- comment "ns2/svc2:p80 health check node port" - m tcp - p tcp -- dport 30000 - j ACCEPT
- A KUBE - FORWARD - m conntrack -- ctstate INVALID - j DROP
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding rules" - m mark -- mark 0x4000 / 0x4000 - j ACCEPT
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding conntrack rule" - m conntrack -- ctstate RELATED , ESTABLISHED - j ACCEPT
COMMIT
* nat
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - EXTERNAL - SERVICES - [ 0 : 0 ]
: KUBE - FORWARD - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
- A KUBE - NODEPORTS - m comment -- comment "ns2/svc2:p80 health check node port" - m tcp - p tcp -- dport 30000 - j ACCEPT
- A KUBE - FORWARD - m conntrack -- ctstate INVALID - j DROP
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding rules" - m mark -- mark 0x4000 / 0x4000 - j ACCEPT
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding conntrack rule" - m conntrack -- ctstate RELATED , ESTABLISHED - j ACCEPT
COMMIT
junk
` ) ,
error : ` table 3 starts with "junk" ` ,
} ,
{
name : "add to missing chain" ,
input : dedent . Dedent ( `
* filter
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - EXTERNAL - SERVICES - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
- A KUBE - NODEPORTS - m comment -- comment "ns2/svc2:p80 health check node port" - m tcp - p tcp -- dport 30000 - j ACCEPT
- A KUBE - FORWARD - m conntrack -- ctstate INVALID - j DROP
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding rules" - m mark -- mark 0x4000 / 0x4000 - j ACCEPT
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding conntrack rule" - m conntrack -- ctstate RELATED , ESTABLISHED - j ACCEPT
COMMIT
` ) ,
error : ` no such chain "KUBE-FORWARD" ` ,
} ,
{
name : "add to deleted chain" ,
input : dedent . Dedent ( `
* filter
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - EXTERNAL - SERVICES - [ 0 : 0 ]
: KUBE - FORWARD - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
- A KUBE - NODEPORTS - m comment -- comment "ns2/svc2:p80 health check node port" - m tcp - p tcp -- dport 30000 - j ACCEPT
- X KUBE - FORWARD
- A KUBE - FORWARD - m conntrack -- ctstate INVALID - j DROP
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding rules" - m mark -- mark 0x4000 / 0x4000 - j ACCEPT
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding conntrack rule" - m conntrack -- ctstate RELATED , ESTABLISHED - j ACCEPT
COMMIT
` ) ,
error : ` cannot add rules to deleted chain ` ,
} ,
{
name : "deleted non-empty chain" ,
input : dedent . Dedent ( `
* filter
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - EXTERNAL - SERVICES - [ 0 : 0 ]
: KUBE - FORWARD - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
- A KUBE - NODEPORTS - m comment -- comment "ns2/svc2:p80 health check node port" - m tcp - p tcp -- dport 30000 - j ACCEPT
- A KUBE - FORWARD - m conntrack -- ctstate INVALID - j DROP
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding rules" - m mark -- mark 0x4000 / 0x4000 - j ACCEPT
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding conntrack rule" - m conntrack -- ctstate RELATED , ESTABLISHED - j ACCEPT
- X KUBE - FORWARD
COMMIT
` ) ,
error : ` cannot delete chain "KUBE-FORWARD" after adding rules ` ,
} ,
{
name : "junk rule" ,
input : dedent . Dedent ( `
* filter
: KUBE - SERVICES - [ 0 : 0 ]
: KUBE - EXTERNAL - SERVICES - [ 0 : 0 ]
: KUBE - FORWARD - [ 0 : 0 ]
: KUBE - NODEPORTS - [ 0 : 0 ]
- A KUBE - NODEPORTS - m comment -- comment "ns2/svc2:p80 health check node port" - m tcp - p tcp -- dport 30000 - j ACCEPT
- Q KUBE - FORWARD - m conntrack -- ctstate INVALID - j DROP
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding rules" - m mark -- mark 0x4000 / 0x4000 - j ACCEPT
- A KUBE - FORWARD - m comment -- comment "kubernetes forwarding conntrack rule" - m conntrack -- ctstate RELATED , ESTABLISHED - j ACCEPT
COMMIT
` ) ,
error : ` "-Q KUBE-FORWARD ` ,
} ,
} {
t . Run ( tc . name , func ( t * testing . T ) {
dump , err := ParseIPTablesDump ( tc . input )
if err == nil {
if tc . error != "" {
t . Errorf ( "unexpectedly did not get error" )
} else if ! reflect . DeepEqual ( tc . output , dump ) {
t . Errorf ( "bad output: expected %#v got %#v" , tc . output , dump )
}
} else {
if tc . error == "" {
t . Errorf ( "got unexpected error: %v" , err )
} else if ! strings . Contains ( err . Error ( ) , tc . error ) {
t . Errorf ( "got wrong error: %v (expected %q)" , err , tc . error )
}
}
} )
}
}