@@ -47,8 +47,16 @@ func (t *Tui) Init() {
47
47
t .pages = tview .NewPages ()
48
48
}
49
49
50
+ func (t * Tui ) LoadInterfaces () ([]string , error ) {
51
+ err , out , _ := shellout ("ip link show | awk -F: '{ print $2 }' | sed -r 's/^[0-9]+//' | sed '/^$/d' | awk '{$2=$2};1'" )
52
+ if err != nil {
53
+ log .Printf ("error: %v\n " , err )
54
+ }
55
+ return strings .Split (out , "\n " ), nil
56
+ }
57
+
50
58
func (t * Tui ) LoadTableData () ([]string , error ) {
51
- err , out , _ := shellout ("ufw status | sed '/^$/d' | awk '{$2=$2};1' | tail -n +4 | sed -r 's/^(([0-9]{1,3} \\ .){3}[0-9]{1 ,3})\\ s(.*)(\\ /[a-z]{3})/\\ 1\\ 4 \\ 3 /;s/^(([ 0-9]* )\\ /([a-z]{3}))/\\ 3 \\ 2 /;s/(\\ w)\\ s(\\ (v6 \\ ))$ /\\ 1\\ 2/;s/\\ (v6 \\ )/ /'" )
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(.*)(\\ /[a-z]{3})/\\ 1\\ 5 \\ 2 \\ 3 \\ 4 /;s/^(.*) \\ s([A-Z]{2,}(-[A-Z]{2,3})?) \\ s(.*) \\ s(on) \\ s(.*)#?/ \\ 1_ \\ 5_ \\ 6 - \\ 2 \\ 4/;s/^(.*) \\ s(([ 0-9]+ )\\ /([a-z]{3}))/\\ 1 \\ / \\ 4 \\ 3/;s/(^[0-9]+) \\ /([a-z]{3})/ \\ 2 \\ 1 /;s/(\\ w+ )\\ s(on) \\ s( \\ w+) /\\ 1- \\ 2- \\ 3 - /;s/^([A-Z][a-z]+ \\ /[a-z]{3}) \\ s(([A-Z]+).*)/ \\ 1 - \\ 2 /'" )
52
60
53
61
if err != nil {
54
62
log .Printf ("error: %v\n " , err )
@@ -80,10 +88,12 @@ func (t *Tui) CreateTable(rows []string) {
80
88
81
89
value := ""
82
90
switch {
91
+ case len (cols ) < len (columns ) && c >= len (cols ):
92
+ value = ""
83
93
case c >= 4 :
84
- value = strings .Join (cols [c :], " " )
94
+ value = strings .ReplaceAll ( strings . Join (cols [c :], " " ), "#" , " " )
85
95
default :
86
- value = cols [c ]
96
+ value = strings . ReplaceAll ( cols [c ], "-" , " " )
87
97
}
88
98
89
99
t .table .SetCell (r + 1 , c + 1 , tview .NewTableCell (value ).SetTextColor (tcell .ColorWhite ).SetAlign (tview .AlignCenter ).SetExpansion (1 ))
@@ -126,69 +136,30 @@ func (t *Tui) CreateModal(text string, confirm func(), cancel func(), finally fu
126
136
}), true , true )
127
137
}
128
138
129
- func (t * Tui ) CreateRule (position ... int ) {
130
- to := t .form .GetFormItem (0 ).(* tview.InputField ).GetText ()
131
- port := t .form .GetFormItem (1 ).(* tview.InputField ).GetText ()
132
- _ , proto := t .form .GetFormItem (2 ).(* tview.DropDown ).GetCurrentOption ()
133
- _ , action := t .form .GetFormItem (3 ).(* tview.DropDown ).GetCurrentOption ()
134
- from := t .form .GetFormItem (4 ).(* tview.InputField ).GetText ()
135
- comment := t .form .GetFormItem (5 ).(* tview.InputField ).GetText ()
136
-
137
- baseCmd := "ufw "
138
- if len (position ) > 0 && position [0 ] < t .table .GetRowCount ()- 1 {
139
- baseCmd = fmt .Sprintf ("ufw insert %d " , position [0 ])
140
- }
141
-
142
- if port == "" {
143
- return
144
- }
145
-
146
- cmd := ""
147
- if from == "" && to == "" {
148
- cmd = fmt .Sprintf ("%s proto %s to any port %s comment '%s'" , strings .ToLower (action ), proto , port , comment )
149
- }
150
-
151
- if from == "" && to != "" {
152
- cmd = fmt .Sprintf ("%s proto %s to %s port %s comment '%s'" , strings .ToLower (action ), proto , to , port , comment )
153
- }
154
-
155
- if to == "" && from != "" {
156
- cmd = fmt .Sprintf ("%s from %s proto %s to any port %s comment '%s'" , strings .ToLower (action ), from , proto , port , comment )
157
- }
139
+ func (t * Tui ) CreateForm () {
140
+ t .help .SetText ("Use <Tab> and <Enter> keys to navigate through the form" ).SetBorderPadding (1 , 0 , 1 , 1 )
141
+ interfaces , _ := t .LoadInterfaces ()
158
142
159
- if to != "" && from != "" {
160
- cmd = fmt .Sprintf ("%s from %s proto %s to %s port %s comment '%s'" , strings .ToLower (action ), from , proto , to , port , comment )
161
- }
143
+ t .form .AddInputField ("To" , "" , 20 , nil , nil ).SetFieldTextColor (tcell .ColorWhite ).
144
+ AddInputField ("Port" , "" , 20 , validatePort , nil ).SetFieldTextColor (tcell .ColorWhite ).
145
+ AddDropDown ("Interface" , interfaces , len (interfaces ), nil ).
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 ).
148
+ AddInputField ("From" , "" , 20 , nil , nil ).
149
+ AddInputField ("Comment" , "" , 40 , nil , nil ).
150
+ AddButton ("Save" , func () { t .CreateRule () }).
151
+ AddButton ("Cancel" , t .Reset ).
152
+ SetButtonTextColor (tcell .ColorWhite ).
153
+ SetButtonBackgroundColor (tcell .ColorDarkCyan ).
154
+ SetFieldBackgroundColor (tcell .ColorDarkCyan ).
155
+ SetLabelColor (tcell .ColorWhite )
162
156
163
- err , _ , _ := shellout (baseCmd + cmd )
164
- if err != nil {
165
- log .Print (err )
166
- }
167
- t .Reset ()
168
- t .ReloadTable ()
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 )
169
158
}
170
159
171
- func (t * Tui ) RemoveRule () {
172
- t .table .SetSelectedFunc (func (row int , column int ) {
173
- t .table .SetSelectable (false , false )
174
- if row == 0 {
175
- t .app .SetFocus (t .table )
176
- return
177
- }
178
- t .CreateModal ("Are you sure you want to remove this rule?" ,
179
- func () {
180
- shellout (fmt .Sprintf ("ufw --force delete %d" , row ))
181
- },
182
- func () {
183
- t .pages .HidePage ("modal" )
184
- t .app .SetFocus (t .table )
185
- },
186
- func () {
187
- t .pages .HidePage ("modal" )
188
- t .app .SetFocus (t .table )
189
- },
190
- )
191
- })
160
+ func validatePort (text string , ch rune ) bool {
161
+ _ , err := strconv .Atoi (text )
162
+ return err == nil
192
163
}
193
164
194
165
func (t * Tui ) EditForm () {
@@ -198,6 +169,7 @@ func (t *Tui) EditForm() {
198
169
return
199
170
}
200
171
t .help .SetText ("Use <Tab> and <Enter> keys to navigate through the form" ).SetBorderPadding (1 , 0 , 1 , 1 )
172
+ interfaces , _ := t .LoadInterfaces ()
201
173
202
174
to := t .table .GetCell (row , 1 ).Text
203
175
rip := regexp .MustCompile (`(([0-9]{1,3}\.){3}[0-9]{1,3})(/[0-9]{1,2})?` )
@@ -220,8 +192,15 @@ func (t *Tui) EditForm() {
220
192
matchPort := rport .FindStringSubmatch (port )
221
193
portValue = matchPort [1 ]
222
194
223
- protocolOptionIndex := 1
224
- if proto == "tcp" {
195
+ interfaceOptionIndex := len (interfaces )
196
+
197
+ protocolOptionIndex := 0
198
+ switch proto {
199
+ case "tcp" :
200
+ protocolOptionIndex = 1
201
+ case "udp" :
202
+ protocolOptionIndex = 2
203
+ default :
225
204
protocolOptionIndex = 0
226
205
}
227
206
@@ -235,6 +214,14 @@ func (t *Tui) EditForm() {
235
214
actionOptionIndex = 2
236
215
case "LIMIT" :
237
216
actionOptionIndex = 3
217
+ case "ALLOW-OUT" :
218
+ actionOptionIndex = 4
219
+ case "DENY-OUT" :
220
+ actionOptionIndex = 5
221
+ case "REJECT-OUT" :
222
+ actionOptionIndex = 6
223
+ case "LIMIT-OUT" :
224
+ actionOptionIndex = 7
238
225
}
239
226
240
227
from := t .table .GetCell (row , 4 ).Text
@@ -245,20 +232,25 @@ func (t *Tui) EditForm() {
245
232
comment := strings .ReplaceAll (t .table .GetCell (row , 5 ).Text , "# " , "" )
246
233
247
234
t .form .AddInputField ("To" , toValue , 20 , nil , nil ).SetFieldTextColor (tcell .ColorWhite ).
248
- AddInputField ("Port *" , portValue , 20 , validatePort , nil ).SetFieldTextColor (tcell .ColorWhite ).
249
- AddDropDown ("Protocol *" , []string {"tcp" , "udp" }, protocolOptionIndex , nil ).
250
- AddDropDown ("Action *" , []string {"ALLOW" , "DENY" , "REJECT" , "LIMIT" }, actionOptionIndex , nil ).
235
+ AddInputField ("Port" , portValue , 20 , validatePort , nil ).SetFieldTextColor (tcell .ColorWhite ).
236
+ AddDropDown ("Interface" , interfaces , interfaceOptionIndex , nil ).
237
+ 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 ).
251
239
AddInputField ("From" , fromValue , 20 , nil , nil ).
252
240
AddInputField ("Comment" , comment , 40 , nil , nil ).
253
- AddButton ("Save" , func () { t .CreateRule (row ); t .table .SetSelectable (false , false ) }).
254
- AddButton ("Cancel" , func () { t .CreateRule (row ); t .Reset (); t .table .SetSelectable (false , false ) }).
241
+ AddButton ("Save" , func () {
242
+ t .CreateRule (row )
243
+ t .table .SetSelectable (false , false )
244
+ }).
245
+ AddButton ("Cancel" , func () {
246
+ t .Reset ()
247
+ t .table .SetSelectable (false , false )
248
+ }).
255
249
SetButtonTextColor (tcell .ColorWhite ).
256
250
SetButtonBackgroundColor (tcell .ColorDarkCyan ).
257
251
SetFieldBackgroundColor (tcell .ColorDarkCyan ).
258
252
SetLabelColor (tcell .ColorWhite )
259
253
260
- shellout (fmt .Sprintf ("ufw --force delete %d" , row ))
261
-
262
254
t .secondHelp .SetText ("* Mandatory field\n \n To and From fields match any and Anywhere if left empty" ).
263
255
SetTextColor (tcell .ColorDarkCyan ).
264
256
SetBorderPadding (0 , 0 , 1 , 1 )
@@ -267,6 +259,113 @@ func (t *Tui) EditForm() {
267
259
})
268
260
}
269
261
262
+ func (t * Tui ) CreateRule (position ... int ) {
263
+ to := t .form .GetFormItem (0 ).(* tview.InputField ).GetText ()
264
+ port := t .form .GetFormItem (1 ).(* tview.InputField ).GetText ()
265
+ _ , ninterface := t .form .GetFormItem (2 ).(* tview.DropDown ).GetCurrentOption ()
266
+ _ , proto := t .form .GetFormItem (3 ).(* tview.DropDown ).GetCurrentOption ()
267
+ _ , action := t .form .GetFormItem (4 ).(* tview.DropDown ).GetCurrentOption ()
268
+ from := t .form .GetFormItem (5 ).(* tview.InputField ).GetText ()
269
+ comment := t .form .GetFormItem (6 ).(* tview.InputField ).GetText ()
270
+
271
+ dryCmd := "ufw --dry-run "
272
+ baseCmd := "ufw "
273
+ if len (position ) > 0 && position [0 ] < t .table .GetRowCount ()- 1 {
274
+ dryCmd = fmt .Sprintf ("ufw --dry-run insert %d " , position [0 ])
275
+ baseCmd = fmt .Sprintf ("ufw insert %d " , position [0 ])
276
+ }
277
+
278
+ if port != "" && ninterface != "" {
279
+ return
280
+ }
281
+
282
+ if proto != "" && (from == "" || to == "" ) {
283
+ return
284
+ }
285
+
286
+ if port != "" && (from == "" || to == "" ) {
287
+ return
288
+ }
289
+
290
+ if (proto == "" || port == "" ) && from == "" && to == "" && ninterface == "" {
291
+ return
292
+ }
293
+
294
+ toValue := to
295
+ if to == "" {
296
+ toValue = "any"
297
+ }
298
+ fromValue := from
299
+ if from == "" {
300
+ fromValue = "any"
301
+ }
302
+
303
+ cmd := ""
304
+ preCmd := fmt .Sprintf ("%s " , strings .ToLower (action ))
305
+ if ninterface != "" {
306
+ preCmd = fmt .Sprintf ("%s on %s " , strings .ToLower (action ), ninterface )
307
+ }
308
+
309
+ if port != "" && proto == "" {
310
+ cmd = fmt .Sprintf ("%s to %s port %s comment '%s'" , fromValue , toValue , port , comment )
311
+ }
312
+ if port == "" && proto != "" {
313
+ cmd = fmt .Sprintf ("%s proto %s to %s comment '%s'" , fromValue , proto , toValue , comment )
314
+ }
315
+ if port != "" && proto != "" {
316
+ cmd = fmt .Sprintf ("%s proto %s to %s port %s comment '%s'" , fromValue , proto , toValue , port , comment )
317
+ }
318
+ if port == "" && proto == "" {
319
+ cmd = fmt .Sprintf ("%s to %s comment '%s'" , fromValue , toValue , comment )
320
+ }
321
+ if ninterface != "" && (to == "" || from == "" ) {
322
+ cmd = fmt .Sprintf ("comment '%s'" , comment )
323
+ }
324
+
325
+ // Dry-run
326
+ err , _ , _ := shellout (dryCmd + preCmd + cmd )
327
+ if err == nil {
328
+ // Delete first
329
+ if len (position ) > 0 {
330
+ shellout (fmt .Sprintf ("ufw --force delete %d" , position [0 ]))
331
+ }
332
+
333
+ // Then create
334
+ err , _ , _ = shellout (baseCmd + preCmd + cmd )
335
+ if err != nil {
336
+ log .Print (err )
337
+ }
338
+ }
339
+ if err != nil {
340
+ return
341
+ }
342
+ t .Reset ()
343
+ t .ReloadTable ()
344
+ }
345
+
346
+ func (t * Tui ) RemoveRule () {
347
+ t .table .SetSelectedFunc (func (row int , column int ) {
348
+ t .table .SetSelectable (false , false )
349
+ if row == 0 {
350
+ t .app .SetFocus (t .table )
351
+ return
352
+ }
353
+ t .CreateModal ("Are you sure you want to remove this rule?" ,
354
+ func () {
355
+ shellout (fmt .Sprintf ("ufw --force delete %d" , row ))
356
+ },
357
+ func () {
358
+ t .pages .HidePage ("modal" )
359
+ t .app .SetFocus (t .table )
360
+ },
361
+ func () {
362
+ t .pages .HidePage ("modal" )
363
+ t .app .SetFocus (t .table )
364
+ },
365
+ )
366
+ })
367
+ }
368
+
270
369
func (t * Tui ) CreateMenu () {
271
370
menuList := tview .NewList ()
272
371
menuList .
@@ -319,30 +418,6 @@ func (t *Tui) CreateMenu() {
319
418
t .menu .SetBorder (true ).SetTitle (" Menu " )
320
419
}
321
420
322
- func (t * Tui ) CreateForm () {
323
- t .help .SetText ("Use <Tab> and <Enter> keys to navigate through the form" ).SetBorderPadding (1 , 0 , 1 , 1 )
324
-
325
- t .form .AddInputField ("To" , "" , 20 , nil , nil ).SetFieldTextColor (tcell .ColorWhite ).
326
- AddInputField ("Port *" , "" , 20 , validatePort , nil ).SetFieldTextColor (tcell .ColorWhite ).
327
- AddDropDown ("Protocol *" , []string {"tcp" , "udp" }, 0 , nil ).
328
- AddDropDown ("Action *" , []string {"ALLOW" , "DENY" , "REJECT" , "LIMIT" }, 0 , nil ).
329
- AddInputField ("From" , "" , 20 , nil , nil ).
330
- AddInputField ("Comment" , "" , 40 , nil , nil ).
331
- AddButton ("Save" , func () { t .CreateRule () }).
332
- AddButton ("Cancel" , t .Reset ).
333
- SetButtonTextColor (tcell .ColorWhite ).
334
- SetButtonBackgroundColor (tcell .ColorDarkCyan ).
335
- SetFieldBackgroundColor (tcell .ColorDarkCyan ).
336
- SetLabelColor (tcell .ColorWhite )
337
-
338
- 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 )
339
- }
340
-
341
- func validatePort (text string , ch rune ) bool {
342
- _ , err := strconv .Atoi (text )
343
- return err == nil
344
- }
345
-
346
421
func (t * Tui ) Reset () {
347
422
t .pages .HidePage ("form" )
348
423
t .form .Clear (true )
0 commit comments