File: iptables.go

package info (click to toggle)
golang-github-containernetworking-plugins 1.1.1%2Bds1-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 1,672 kB
  • sloc: sh: 132; makefile: 11
file content (139 lines) | stat: -rw-r--r-- 4,011 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2017 CNI 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 utils

import (
	"errors"
	"fmt"

	"github.com/coreos/go-iptables/iptables"
)

const statusChainExists = 1

// EnsureChain idempotently creates the iptables chain. It does not
// return an error if the chain already exists.
func EnsureChain(ipt *iptables.IPTables, table, chain string) error {
	if ipt == nil {
		return errors.New("failed to ensure iptable chain: IPTables was nil")
	}
	exists, err := ChainExists(ipt, table, chain)
	if err != nil {
		return fmt.Errorf("failed to list iptables chains: %v", err)
	}
	if !exists {
		err = ipt.NewChain(table, chain)
		if err != nil {
			eerr, eok := err.(*iptables.Error)
			if eok && eerr.ExitStatus() != statusChainExists {
				return err
			}
		}
	}
	return nil
}

// ChainExists checks whether an iptables chain exists.
func ChainExists(ipt *iptables.IPTables, table, chain string) (bool, error) {
	if ipt == nil {
		return false, errors.New("failed to check iptable chain: IPTables was nil")
	}
	chains, err := ipt.ListChains(table)
	if err != nil {
		return false, err
	}

	for _, ch := range chains {
		if ch == chain {
			return true, nil
		}
	}
	return false, nil
}

// DeleteRule idempotently delete the iptables rule in the specified table/chain.
// It does not return an error if the referring chain doesn't exist
func DeleteRule(ipt *iptables.IPTables, table, chain string, rulespec ...string) error {
	if ipt == nil {
		return errors.New("failed to ensure iptable chain: IPTables was nil")
	}
	if err := ipt.Delete(table, chain, rulespec...); err != nil {
		eerr, eok := err.(*iptables.Error)
		switch {
		case eok && eerr.IsNotExist():
			// swallow here, the chain was already deleted
			return nil
		case eok && eerr.ExitStatus() == 2:
			// swallow here, invalid command line parameter because the referring rule is missing
			return nil
		default:
			return fmt.Errorf("Failed to delete referring rule %s %s: %v", table, chain, err)
		}
	}
	return nil
}

// DeleteChain idempotently deletes the specified table/chain.
// It does not return an errors if the chain does not exist
func DeleteChain(ipt *iptables.IPTables, table, chain string) error {
	if ipt == nil {
		return errors.New("failed to ensure iptable chain: IPTables was nil")
	}

	err := ipt.DeleteChain(table, chain)
	eerr, eok := err.(*iptables.Error)
	switch {
	case eok && eerr.IsNotExist():
		// swallow here, the chain was already deleted
		return nil
	default:
		return err
	}
}

// ClearChain idempotently clear the iptables rules in the specified table/chain.
// If the chain does not exist, a new one will be created
func ClearChain(ipt *iptables.IPTables, table, chain string) error {
	if ipt == nil {
		return errors.New("failed to ensure iptable chain: IPTables was nil")
	}
	err := ipt.ClearChain(table, chain)
	eerr, eok := err.(*iptables.Error)
	switch {
	case eok && eerr.IsNotExist():
		// swallow here, the chain was already deleted
		return EnsureChain(ipt, table, chain)
	default:
		return err
	}
}

// InsertUnique will add a rule to a chain if it does not already exist.
// By default the rule is appended, unless prepend is true.
func InsertUnique(ipt *iptables.IPTables, table, chain string, prepend bool, rule []string) error {
	exists, err := ipt.Exists(table, chain, rule...)
	if err != nil {
		return err
	}
	if exists {
		return nil
	}

	if prepend {
		return ipt.Insert(table, chain, 1, rule...)
	} else {
		return ipt.Append(table, chain, rule...)
	}
}