@@ -56,7 +56,8 @@ func (t *Tui) LoadInterfaces() ([]string, error) {
56
56
}
57
57
58
58
func (t * Tui ) LoadTableData () ([]string , error ) {
59
- err , out , _ := shellout ("ufw status | sed '/^$/d' | awk '{$2=$2};1' | tail -n +4 | sed -r 's/(\\ w)\\ s(\\ (v6\\ ))/\\ 1/;s/([A-Z]{2,})\\ s([A-Z]{2,3})/\\ 1-\\ 2/;s/^(.*)\\ s([A-Z]{2,}(-[A-Z]{2,3})?)\\ s(.*)\\ s(on)\\ s(.*)#?/\\ 1_\\ 5_\\ 6 - \\ 2 \\ 4/;s/^([A-Z][a-z]+\\ /[a-z]{3})\\ s(([A-Z]+).*)/\\ 1 - \\ 2/;s/^([0-9]+)\\ s([A-Z]{2,}(-[A-Z]{2,3})?)/- \\ 1 \\ 2/;s/^(.*)\\ s([0-9]+)\\ /([a-z]{3})/\\ 1\\ /\\ 3 \\ 2/;s/(\\ w+)\\ s(on)\\ s(\\ w+)/\\ 1-\\ 2-\\ 3 -/;s/^([0-9]+)\\ /([a-z]{3})/\\ 2 \\ 1/;s/^(([0-9]{1,3}\\ .){3}[0-9]{1,3})\\ s([A-Z]+)/\\ 1 - \\ 3/;s/^(\\ w+)\\ s([A-Z]+)/\\ 1 - \\ 2/'" )
59
+ //err, out, _ := shellout("ufw status | sed '/^$/d' | awk '{$2=$2};1' | tail -n +4 | sed -r 's/(\\w)\\s(\\(v6\\))/\\1/;s/([A-Z]{2,})\\s([A-Z]{2,3})/\\1-\\2/;s/^(.*)\\s([A-Z]{2,}(-[A-Z]{2,3})?)\\s(.*)\\s(on)\\s(.*)#?/\\1_\\5_\\6 - \\2 \\4/;s/^([A-Z][a-z]+\\/[a-z]{3})\\s(([A-Z]+).*)/\\1 - \\2/;s/^([0-9]+)\\s([A-Z]{2,}(-[A-Z]{2,3})?)/- \\1 \\2/;s/^(.*)\\s([0-9]+)\\/([a-z]{3})/\\1\\/\\3 \\2/;s/(\\w+)\\s(on)\\s(\\w+)/\\1-\\2-\\3 -/;s/^([0-9]+)\\/([a-z]{3})/\\2 \\1/;s/^(([0-9]{1,3}\\.){3}[0-9]{1,3})\\s([A-Z]+)/\\1 - \\3/;s/^(\\w+)\\s([A-Z]+)/\\1 - \\2/'")
60
+ err , out , _ := shellout ("ufw status numbered | sed '/^$/d' | awk '{$2=$2};1' | tail -n +4 | sed -r 's/(\\ [(\\ s)([0-9]+)\\ ])/\\ [\\ 3\\ ] /;s/(\\ [([0-9]+)\\ ])/\\ [\\ 2\\ ] /;s/\\ (out\\ )//;s/(\\ w)\\ s(\\ (v6\\ ))/\\ 1/;s/([A-Z]{2,})\\ s([A-Z]{2,3})/\\ 1-\\ 2/;s/^(.*)\\ s([A-Z]{2,}(-[A-Z]{2,3})?)\\ s(.*)\\ s(on)\\ s(.*)#?/\\ 1_\\ 5_\\ 6- \\ 2 \\ 4/;s/([A-Z][a-z]+\\ /[a-z]{3})\\ s(([A-Z]+).*)/\\ 1 - \\ 2/;s/(\\ ]\\ s+)([0-9]{2,})\\ s([A-Z]{2,}(-[A-Z]{2,3})?)/\\ 1Anywhere \\ 2 \\ 3/;s/(\\ ]\\ s+)(([0-9]{1,3}\\ .){3}[0-9]{1,3}(\\ /[0-9]{1,2})?)\\ s([A-Z]{2,}-[A-Z]{2,3})/\\ 1\\ 2 - \\ 5/;s/([A-Z][a-z]+)\\ s(([A-Z]+).*)/\\ 1 - \\ 2/;s/(\\ ]\\ s+)(.*)\\ s([0-9]+)(\\ /[a-z]{3})/\\ 1\\ 2\\ 4 \\ 3/;s/(\\ ]\\ s+)\\ /([a-z]{3})\\ s/\\ 1\\ 2 /;s/^(.*)\\ s(on)\\ s(.*)\\ s([A-Z]{2,}(-[A-Z]{2,3})?)\\ s(.*)/\\ 1_\\ 2_\\ 3 - \\ 4 \\ 6/'" )
60
61
61
62
if err != nil {
62
63
log .Printf ("error: %v\n " , err )
@@ -73,7 +74,7 @@ func (t *Tui) CreateTable(rows []string) {
73
74
74
75
for c := 0 ; c < len (columns ); c ++ {
75
76
t .table .SetCell (0 , c , tview .NewTableCell (columns [c ]).SetTextColor (tcell .ColorDarkCyan ).SetAlign (tview .AlignCenter ))
76
- if c >= len (columns )- 1 {
77
+ if c >= len (columns ) {
77
78
break
78
79
}
79
80
@@ -82,21 +83,20 @@ func (t *Tui) CreateTable(rows []string) {
82
83
break
83
84
}
84
85
85
- t .table .SetCell (r + 1 , 0 , tview .NewTableCell (fmt .Sprintf ("[%d]" , r + 1 )).SetTextColor (tcell .ColorDarkCyan ).SetAlign (tview .AlignCenter ).SetExpansion (1 ))
86
-
87
86
cols := strings .Fields (row )
88
-
87
+ alignment := tview . AlignCenter
89
88
value := ""
90
89
switch {
91
90
case len (cols ) < len (columns ) && c >= len (cols ):
92
91
value = ""
93
- case c >= 4 :
92
+ case c >= 5 :
94
93
value = strings .ReplaceAll (strings .Join (cols [c :], " " ), "#" , "" )
94
+ alignment = tview .AlignLeft
95
95
default :
96
96
value = strings .ReplaceAll (cols [c ], "_" , " " )
97
97
}
98
98
99
- t .table .SetCell (r + 1 , c + 1 , tview .NewTableCell (value ).SetTextColor (tcell .ColorWhite ).SetAlign (tview . AlignCenter ).SetExpansion (1 ))
99
+ t .table .SetCell (r + 1 , c , tview .NewTableCell (value ).SetTextColor (tcell .ColorWhite ).SetAlign (alignment ).SetExpansion (1 ))
100
100
}
101
101
}
102
102
@@ -144,7 +144,7 @@ func (t *Tui) CreateForm() {
144
144
AddInputField ("Port" , "" , 20 , validatePort , nil ).SetFieldTextColor (tcell .ColorWhite ).
145
145
AddDropDown ("Interface" , interfaces , len (interfaces ), nil ).
146
146
AddDropDown ("Protocol" , []string {"" , "tcp" , "udp" }, 0 , nil ).
147
- AddDropDown ("Action *" , []string {"ALLOW" , "DENY" , "REJECT" , "LIMIT" , "ALLOW OUT" , "DENY OUT" , "REJECT OUT" , "LIMIT OUT" }, 0 , nil ).
147
+ AddDropDown ("Action *" , []string {"ALLOW IN " , "DENY IN " , "REJECT IN " , "LIMIT IN " , "ALLOW OUT" , "DENY OUT" , "REJECT OUT" , "LIMIT OUT" }, 0 , nil ).
148
148
AddInputField ("From" , "" , 20 , nil , nil ).
149
149
AddInputField ("Comment" , "" , 40 , nil , nil ).
150
150
AddButton ("Save" , func () { t .CreateRule () }).
@@ -154,14 +154,67 @@ func (t *Tui) CreateForm() {
154
154
SetFieldBackgroundColor (tcell .ColorDarkCyan ).
155
155
SetLabelColor (tcell .ColorWhite )
156
156
157
- t .secondHelp .SetText ("* Mandatory field\n \n To and From fields match any and Anywhere if left empty" ).SetTextColor (tcell .ColorDarkCyan ).SetBorderPadding (0 , 0 , 1 , 1 )
157
+ t .secondHelp .SetText ("* Mandatory field\n \n Port, To and From fields respectively match any and Anywhere if left empty" ).SetTextColor (tcell .ColorDarkCyan ).SetBorderPadding (0 , 0 , 1 , 1 )
158
158
}
159
159
160
160
func validatePort (text string , ch rune ) bool {
161
161
_ , err := strconv .Atoi (text )
162
162
return err == nil
163
163
}
164
164
165
+ func parseIPAddress (input string ) string {
166
+ r := regexp .MustCompile (`(([0-9]{1,3}\.){3}[0-9]{1,3})(/[0-9]{1,2})?` )
167
+ matches := r .FindStringSubmatch (input )
168
+ value := ""
169
+ if len (matches ) > 0 {
170
+ value = matches [0 ]
171
+ }
172
+ return value
173
+ }
174
+
175
+ func parseProtocol (inputs ... string ) string {
176
+ r := regexp .MustCompile (`/?(tcp|udp)` )
177
+ value := ""
178
+ for _ , input := range inputs {
179
+ matches := r .FindStringSubmatch (input )
180
+ if len (matches ) > 1 {
181
+ return matches [1 ]
182
+ }
183
+ }
184
+
185
+ return value
186
+ }
187
+
188
+ func parsePort (input string ) string {
189
+ r := regexp .MustCompile (`([0-9]*)(/[a-z]{3})?` )
190
+ value := ""
191
+ matches := r .FindStringSubmatch (input )
192
+ if len (matches ) > 0 {
193
+ value = matches [1 ]
194
+ }
195
+
196
+ return value
197
+ }
198
+
199
+ func parseInterfaceIndex (input string , interfaces []string ) int {
200
+ r := regexp .MustCompile (`.* on (.+)` )
201
+ matches := r .FindStringSubmatch (input )
202
+ index := len (interfaces )
203
+
204
+ if len (matches ) == 0 {
205
+ return index
206
+ }
207
+
208
+ for i , interfaceValue := range interfaces {
209
+ if matches [1 ] == interfaceValue {
210
+ fmt .Println (i )
211
+ return i
212
+ }
213
+ }
214
+
215
+ return index
216
+ }
217
+
165
218
func (t * Tui ) EditForm () {
166
219
t .table .SetSelectedFunc (func (row int , column int ) {
167
220
if row == 0 {
@@ -172,28 +225,12 @@ func (t *Tui) EditForm() {
172
225
interfaces , _ := t .LoadInterfaces ()
173
226
174
227
to := t .table .GetCell (row , 1 ).Text
175
- rip := regexp .MustCompile (`(([0-9]{1,3}\.){3}[0-9]{1,3})(/[0-9]{1,2})?` )
176
- rproto := regexp .MustCompile (`/?([a-z]{3})` )
177
- matchIP := rip .FindStringSubmatch (to )
178
- matchProto := rproto .FindStringSubmatch (to )
179
-
180
- toValue := ""
181
- proto := ""
182
- if len (matchIP ) > 0 {
183
- toValue = matchIP [0 ]
184
- }
185
- if len (matchProto ) > 1 {
186
- proto = matchProto [1 ]
187
- }
188
-
189
- portValue := ""
190
- port := t .table .GetCell (row , 2 ).Text
191
- rport := regexp .MustCompile (`([0-9]*)(/[a-z]{3})?` )
192
- matchPort := rport .FindStringSubmatch (port )
193
- portValue = matchPort [1 ]
228
+ from := t .table .GetCell (row , 4 ).Text
194
229
195
- interfaceOptionIndex := len (interfaces )
230
+ toValue := parseIPAddress (to )
231
+ fromValue := parseIPAddress (from )
196
232
233
+ proto := parseProtocol (to , from )
197
234
protocolOptionIndex := 0
198
235
switch proto {
199
236
case "tcp" :
@@ -204,15 +241,19 @@ func (t *Tui) EditForm() {
204
241
protocolOptionIndex = 0
205
242
}
206
243
244
+ portValue := parsePort (t .table .GetCell (row , 2 ).Text )
245
+
246
+ interfaceOptionIndex := parseInterfaceIndex (to , interfaces )
247
+
207
248
actionOptionIndex := 0
208
249
switch t .table .GetCell (row , 3 ).Text {
209
- case "ALLOW" :
250
+ case "ALLOW-IN " :
210
251
actionOptionIndex = 0
211
- case "DENY" :
252
+ case "DENY-IN " :
212
253
actionOptionIndex = 1
213
- case "REJECT" :
254
+ case "REJECT-IN " :
214
255
actionOptionIndex = 2
215
- case "LIMIT" :
256
+ case "LIMIT-IN " :
216
257
actionOptionIndex = 3
217
258
case "ALLOW-OUT" :
218
259
actionOptionIndex = 4
@@ -224,18 +265,13 @@ func (t *Tui) EditForm() {
224
265
actionOptionIndex = 7
225
266
}
226
267
227
- from := t .table .GetCell (row , 4 ).Text
228
- fromValue := from
229
- if t .table .GetCell (row , 4 ).Text == "Anywhere" {
230
- fromValue = ""
231
- }
232
268
comment := strings .ReplaceAll (t .table .GetCell (row , 5 ).Text , "# " , "" )
233
269
234
270
t .form .AddInputField ("To" , toValue , 20 , nil , nil ).SetFieldTextColor (tcell .ColorWhite ).
235
271
AddInputField ("Port" , portValue , 20 , validatePort , nil ).SetFieldTextColor (tcell .ColorWhite ).
236
272
AddDropDown ("Interface" , interfaces , interfaceOptionIndex , nil ).
237
273
AddDropDown ("Protocol" , []string {"" , "tcp" , "udp" }, protocolOptionIndex , nil ).
238
- AddDropDown ("Action *" , []string {"ALLOW" , "DENY" , "REJECT" , "LIMIT" , "ALLOW OUT" , "DENY OUT" , "REJECT OUT" , "LIMIT OUT" }, actionOptionIndex , nil ).
274
+ AddDropDown ("Action *" , []string {"ALLOW IN " , "DENY IN " , "REJECT IN " , "LIMIT IN " , "ALLOW OUT" , "DENY OUT" , "REJECT OUT" , "LIMIT OUT" }, actionOptionIndex , nil ).
239
275
AddInputField ("From" , fromValue , 20 , nil , nil ).
240
276
AddInputField ("Comment" , comment , 40 , nil , nil ).
241
277
AddButton ("Save" , func () {
@@ -251,7 +287,7 @@ func (t *Tui) EditForm() {
251
287
SetFieldBackgroundColor (tcell .ColorDarkCyan ).
252
288
SetLabelColor (tcell .ColorWhite )
253
289
254
- t .secondHelp .SetText ("* Mandatory field\n \n To and From fields match any and Anywhere if left empty" ).
290
+ t .secondHelp .SetText ("* Mandatory field\n \n Port, To and From fields respectively match any and Anywhere if left empty" ).
255
291
SetTextColor (tcell .ColorDarkCyan ).
256
292
SetBorderPadding (0 , 0 , 1 , 1 )
257
293
@@ -279,15 +315,11 @@ func (t *Tui) CreateRule(position ...int) {
279
315
return
280
316
}
281
317
282
- if proto != "" && ( from == "" || to == "" ) {
318
+ if port == "" && proto == "" && ninterface == "" {
283
319
return
284
320
}
285
321
286
- if port != "" && (from == "" || to == "" ) {
287
- return
288
- }
289
-
290
- if (proto == "" || port == "" ) && from == "" && to == "" && ninterface == "" {
322
+ if ninterface != "" && proto != "" {
291
323
return
292
324
}
293
325
@@ -301,9 +333,9 @@ func (t *Tui) CreateRule(position ...int) {
301
333
}
302
334
303
335
cmd := ""
304
- preCmd := fmt .Sprintf ("%s " , strings .ToLower (action ))
336
+ preCmd := fmt .Sprintf ("%s from " , strings .ToLower (action ))
305
337
if ninterface != "" {
306
- preCmd = fmt .Sprintf ("%s on %s " , strings .ToLower (action ), ninterface )
338
+ preCmd = fmt .Sprintf ("%s on %s from " , strings .ToLower (action ), ninterface )
307
339
}
308
340
309
341
if port != "" && proto == "" {
@@ -318,11 +350,12 @@ func (t *Tui) CreateRule(position ...int) {
318
350
if port == "" && proto == "" {
319
351
cmd = fmt .Sprintf ("%s to %s comment '%s'" , fromValue , toValue , comment )
320
352
}
321
- if ninterface != "" && ( to == "" || from == "" ) {
322
- cmd = fmt .Sprintf ("comment '%s'" , comment )
353
+ if ninterface != "" && to == "" {
354
+ cmd = fmt .Sprintf ("%s comment '%s'" , fromValue , comment )
323
355
}
324
356
325
357
// Dry-run
358
+ //fmt.Println(dryCmd + preCmd + cmd) // debugging
326
359
err , _ , _ := shellout (dryCmd + preCmd + cmd )
327
360
if err == nil {
328
361
// Delete first
@@ -337,6 +370,7 @@ func (t *Tui) CreateRule(position ...int) {
337
370
}
338
371
}
339
372
if err != nil {
373
+ log .Print (err )
340
374
return
341
375
}
342
376
t .Reset ()
0 commit comments