1
16
17
18
19
20 package ebtables
21
22 import (
23 "fmt"
24 "regexp"
25 "strings"
26
27 utilexec "k8s.io/utils/exec"
28 )
29
30 const (
31 cmdebtables = "ebtables"
32
33
34 fullMac = "--Lmac2"
35 )
36
37
38 type RulePosition string
39
40
41 const (
42 Prepend RulePosition = "-I"
43 Append RulePosition = "-A"
44 )
45
46
47 type Table string
48
49
50 const (
51 TableNAT Table = "nat"
52 TableFilter Table = "filter"
53 TableBroute Table = "broute"
54 )
55
56
57 type Chain string
58
59
60 const (
61 ChainPostrouting Chain = "POSTROUTING"
62 ChainPrerouting Chain = "PREROUTING"
63 ChainOutput Chain = "OUTPUT"
64 ChainInput Chain = "INPUT"
65 ChainBrouting Chain = "BROUTING"
66 )
67
68 type operation string
69
70 const (
71 opCreateChain operation = "-N"
72 opFlushChain operation = "-F"
73 opDeleteChain operation = "-X"
74 opListChain operation = "-L"
75 opAppendRule operation = "-A"
76 opPrependRule operation = "-I"
77 opDeleteRule operation = "-D"
78 )
79
80
81 type Interface interface {
82
83 GetVersion() (string, error)
84
85
86
87
88 EnsureRule(position RulePosition, table Table, chain Chain, args ...string) (bool, error)
89
90 DeleteRule(table Table, chain Chain, args ...string) error
91
92 EnsureChain(table Table, chain Chain) (bool, error)
93
94 DeleteChain(table Table, chain Chain) error
95
96 FlushChain(table Table, chain Chain) error
97 }
98
99
100 type runner struct {
101 exec utilexec.Interface
102 }
103
104
105 func New(exec utilexec.Interface) Interface {
106 runner := &runner{
107 exec: exec,
108 }
109 return runner
110 }
111
112 func makeFullArgs(table Table, op operation, chain Chain, args ...string) []string {
113 return append([]string{"-t", string(table), string(op), string(chain)}, args...)
114 }
115
116
117
118 func getEbtablesVersionString(exec utilexec.Interface) (string, error) {
119
120 bytes, err := exec.Command(cmdebtables, "--version").CombinedOutput()
121 if err != nil {
122 return "", err
123 }
124 return parseVersion(string(bytes))
125 }
126
127 func parseVersion(version string) (string, error) {
128
129
130
131 versionMatcher := regexp.MustCompile(`v?([0-9]+\.[0-9]+\.[0-9]+)`)
132 match := versionMatcher.FindStringSubmatch(version)
133 if match == nil {
134 return "", fmt.Errorf("no ebtables version found in string: %s", version)
135 }
136 return match[1], nil
137 }
138
139 func (runner *runner) GetVersion() (string, error) {
140 return getEbtablesVersionString(runner.exec)
141 }
142
143 func (runner *runner) EnsureRule(position RulePosition, table Table, chain Chain, args ...string) (bool, error) {
144 var exist bool
145 fullArgs := makeFullArgs(table, opListChain, chain, fullMac)
146 out, err := runner.exec.Command(cmdebtables, fullArgs...).CombinedOutput()
147 if err != nil {
148 exist = false
149 } else {
150 exist = checkIfRuleExists(string(out), args...)
151 }
152 if !exist {
153 fullArgs = makeFullArgs(table, operation(position), chain, args...)
154 out, err := runner.exec.Command(cmdebtables, fullArgs...).CombinedOutput()
155 if err != nil {
156 return exist, fmt.Errorf("Failed to ensure rule: %v, output: %v", err, string(out))
157 }
158 }
159 return exist, nil
160 }
161
162 func (runner *runner) DeleteRule(table Table, chain Chain, args ...string) error {
163 var exist bool
164 fullArgs := makeFullArgs(table, opListChain, chain, fullMac)
165 out, err := runner.exec.Command(cmdebtables, fullArgs...).CombinedOutput()
166 if err != nil {
167 exist = false
168 } else {
169 exist = checkIfRuleExists(string(out), args...)
170 }
171
172 if !exist {
173 return nil
174 }
175 fullArgs = makeFullArgs(table, opDeleteRule, chain, args...)
176 out, err = runner.exec.Command(cmdebtables, fullArgs...).CombinedOutput()
177 if err != nil {
178 return fmt.Errorf("Failed to delete rule: %v, output: %s", err, out)
179 }
180 return nil
181 }
182
183 func (runner *runner) EnsureChain(table Table, chain Chain) (bool, error) {
184 exist := true
185
186 args := makeFullArgs(table, opListChain, chain)
187 _, err := runner.exec.Command(cmdebtables, args...).CombinedOutput()
188 if err != nil {
189 exist = false
190 }
191 if !exist {
192 args = makeFullArgs(table, opCreateChain, chain)
193 out, err := runner.exec.Command(cmdebtables, args...).CombinedOutput()
194 if err != nil {
195 return exist, fmt.Errorf("Failed to ensure %v chain: %v, output: %v", chain, err, string(out))
196 }
197 }
198 return exist, nil
199 }
200
201
202
203 func checkIfRuleExists(listChainOutput string, args ...string) bool {
204 rule := strings.Join(args, " ")
205 for _, line := range strings.Split(listChainOutput, "\n") {
206 if strings.TrimSpace(line) == rule {
207 return true
208 }
209 }
210 return false
211 }
212
213 func (runner *runner) DeleteChain(table Table, chain Chain) error {
214 fullArgs := makeFullArgs(table, opDeleteChain, chain)
215 out, err := runner.exec.Command(cmdebtables, fullArgs...).CombinedOutput()
216 if err != nil {
217 return fmt.Errorf("Failed to delete %v chain %v: %v, output: %v", string(table), string(chain), err, string(out))
218 }
219 return nil
220 }
221
222 func (runner *runner) FlushChain(table Table, chain Chain) error {
223 fullArgs := makeFullArgs(table, opFlushChain, chain)
224 out, err := runner.exec.Command(cmdebtables, fullArgs...).CombinedOutput()
225 if err != nil {
226 return fmt.Errorf("Failed to flush %v chain %v: %v, output: %v", string(table), string(chain), err, string(out))
227 }
228 return nil
229 }
230
View as plain text