Remove unneeded includes from ui folder
[metze/wireshark/wip.git] / ui / gtk / firewall_dlg.c
1 /* firewall_rules_dlg.c
2  *
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU General Public License
5  * as published by the Free Software Foundation; either version 2
6  * of the License, or (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17
18 /*
19  * Generate firewall ACL rules based on packet addresses and ports.
20  * For directional rules, an outside interface is assumed.
21  *
22  * There may be better ways to present the information, e.g. all rules
23  * in one huge text window, or some sort of tree view.
24  */
25
26 /*
27  * To add a new product, add syntax functions modify the products[] array.
28  *
29  * To add a new syntax function, add its prototype above the products[]
30  * array, and add the function below with all the others.
31  */
32
33 /* Copied from ssl-dlg.c */
34
35 #include "config.h"
36
37 #include <string.h>
38
39 #ifdef HAVE_FCNTL_H
40 #include <fcntl.h>
41 #endif
42
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
46
47 #include <gtk/gtk.h>
48
49 #include <epan/packet.h>
50 #include <epan/addr_resolv.h>
51 #include <epan/epan_dissect.h>
52 #include <wsutil/filesystem.h>
53 #include <epan/dissectors/packet-ipv6.h>
54
55 #include <ui/alert_box.h>
56 #include <ui/last_open_dir.h>
57
58 #include <wsutil/file_util.h>
59
60 #include "ui/gtk/main.h"
61 #include "ui/gtk/dlg_utils.h"
62 #include "ui/gtk/file_dlg.h"
63 #include "ui/gtk/help_dlg.h"
64 #include "ui/gtk/gui_utils.h"
65 #include "ui/gtk/old-gtk-compat.h"
66 #include "ui/gtk/firewall_dlg.h"
67
68 #define MAX_RULE_LEN 200
69
70 /* Rule types */
71 typedef enum {
72     RT_NONE,
73     RT_MAC_SRC,
74     RT_MAC_DST,
75     RT_IPv4_SRC,
76     RT_IPv4_DST,
77     RT_PORT_SRC,
78     RT_PORT_DST,
79     RT_IPv4_PORT_SRC,
80     RT_IPv4_PORT_DST,
81     NUM_RULE_TYPES
82 } rule_type_t;
83
84
85 /* Copied from packet_info struct */
86 typedef struct _rule_info_t {
87     gint product;
88     address dl_src;
89     address dl_dst;
90     address net_src;
91     address net_dst;
92     port_type ptype;
93     guint32 srcport;
94     guint32 destport;
95     GtkWidget *text;
96     GtkWidget *filter_combo_box;
97     GtkWidget *deny_cb;
98     GtkWidget *inbound_cb;
99     gboolean inbound;
100     gboolean deny;
101     rule_type_t rule_type;
102 } rule_info_t;
103
104 /* Syntax function prototypes */
105 typedef void (*syntax_func)(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
106
107 static void sf_dummy(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
108
109 static void sf_ipfw_mac(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
110 static void sf_netfilter_mac(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
111
112 static void sf_ios_std_ipv4(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
113 static void sf_ios_ext_ipv4(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
114 static void sf_ipfilter_ipv4(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
115 static void sf_ipfw_ipv4(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
116 static void sf_netfilter_ipv4(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
117 static void sf_pf_ipv4(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
118 /* XXX - Can you addresses-only filters using WFW/netsh? */
119
120 static void sf_ios_ext_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
121 static void sf_ipfilter_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
122 static void sf_ipfw_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
123 static void sf_netfilter_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
124 static void sf_pf_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
125 static void sf_netsh_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
126
127 static void sf_ios_ext_ipv4_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
128 static void sf_ipfilter_ipv4_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
129 static void sf_ipfw_ipv4_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
130 static void sf_netfilter_ipv4_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
131 static void sf_pf_ipv4_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
132 static void sf_netsh_ipv4_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny);
133
134 typedef struct _fw_product_t {
135     const gchar *name;
136     const gchar *comment_pfx;
137     syntax_func mac_func;
138     syntax_func ipv4_func;
139     syntax_func port_func;
140     syntax_func ipv4_port_func;
141     gboolean does_inbound;
142 } fw_product;
143
144 static fw_product products[] = {
145     { "Cisco IOS (standard)", "!", NULL, sf_ios_std_ipv4, NULL, NULL, FALSE },
146     { "Cisco IOS (extended)", "!",
147         NULL, sf_ios_ext_ipv4, sf_ios_ext_port, sf_ios_ext_ipv4_port, TRUE },
148     { "IP Filter (ipfilter)", "#",
149         NULL, sf_ipfilter_ipv4, sf_ipfilter_port, sf_ipfilter_ipv4_port, TRUE },
150     { "IPFirewall (ipfw)", "#",
151         sf_ipfw_mac, sf_ipfw_ipv4, sf_ipfw_port, sf_ipfw_ipv4_port, TRUE },
152     { "Netfilter (iptables)", "#",
153         sf_netfilter_mac, sf_netfilter_ipv4, sf_netfilter_port,
154         sf_netfilter_ipv4_port, TRUE },
155     { "Packet Filter (pf)", "#",
156         NULL, sf_pf_ipv4, sf_pf_port, sf_pf_ipv4_port, TRUE },
157     { "Windows Firewall (netsh)", "#",
158         NULL, NULL, sf_netsh_port, sf_netsh_ipv4_port, FALSE }
159 };
160 #define NUM_PRODS (sizeof(products) / sizeof(fw_product))
161
162
163 static void select_product(GtkWidget * win, gpointer data);
164 static void select_filter(GtkWidget * win, gpointer data);
165 static void toggle_inbound(GtkToggleButton *t, gpointer data);
166 static void toggle_deny(GtkToggleButton *t, gpointer data);
167 static void set_rule_text(rule_info_t *rule_info);
168 static void firewall_destroy_cb(GtkWidget * win, gpointer data);
169 static void firewall_copy_cmd_cb(GtkWidget * w, gpointer data);
170 static void firewall_save_as_cmd_cb(GtkWidget * w, gpointer data);
171
172 #define WS_RULE_INFO_KEY "rule_info_key"
173
174 #if 0
175 /* List of "rule_info_t" structures for all rule windows. */
176 static GList *rule_infos;
177
178 /* Remove a "rule_info_t" structure from the list. */
179 static void
180 forget_rule_info(rule_info_t *rule_info)
181 {
182   rule_infos = g_list_remove(rule_infos, rule_info);
183 }
184 #endif
185
186 void
187 firewall_rule_cb(GtkWidget *w _U_, gpointer data _U_)
188 {
189     GtkWidget       *rule_w, *vbox, *txt_scrollw, *text;
190     GtkWidget       *label,  *product_combo_box;
191     GtkWidget       *hbox,   *button_hbox, *button;
192     rule_info_t     *rule_info;
193     packet_info     *pinfo = &cfile.edt->pi;
194     guint i;
195
196     rule_info = g_new0(rule_info_t, 1);
197     COPY_ADDRESS(&(rule_info->dl_src), &(pinfo->dl_src));
198     COPY_ADDRESS(&(rule_info->dl_dst), &(pinfo->dl_dst));
199     COPY_ADDRESS(&(rule_info->net_src), &(pinfo->net_src));
200     COPY_ADDRESS(&(rule_info->net_dst), &(pinfo->net_dst));
201     rule_info->ptype = pinfo->ptype;
202     rule_info->srcport = pinfo->srcport;
203     rule_info->destport = pinfo->destport;
204     rule_info->inbound = TRUE;
205     rule_info->deny = TRUE;
206     rule_info->product = 0;
207
208     rule_w = dlg_window_new("Firewall ACL Rules");
209
210     gtk_widget_set_name(rule_w, "Firewall ACL rule window");
211     gtk_container_set_border_width(GTK_CONTAINER(rule_w), 6);
212
213     /* setup the container */
214     vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 6, FALSE);
215     gtk_container_add(GTK_CONTAINER(rule_w), vbox);
216
217     /* rule type selectors hbox */
218     hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1, FALSE);
219     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
220
221     /* product selector */
222     label = gtk_label_new("Product");
223     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
224
225     product_combo_box = gtk_combo_box_text_new();
226     for (i = 0; i < NUM_PRODS; i++) {
227         gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(product_combo_box), products[i].name);
228     }
229     g_object_set_data(G_OBJECT(product_combo_box), WS_RULE_INFO_KEY, rule_info);
230     g_signal_connect(product_combo_box, "changed", G_CALLBACK(select_product), NULL);
231     gtk_box_pack_start(GTK_BOX(hbox), product_combo_box, FALSE, FALSE, 5);
232
233     /* type selector */
234     label = gtk_label_new("Filter");
235     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10);
236
237     rule_info->filter_combo_box = ws_combo_box_new_text_and_pointer();
238     g_object_set_data(G_OBJECT(rule_info->filter_combo_box), WS_RULE_INFO_KEY, rule_info); \
239     g_signal_connect(rule_info->filter_combo_box, "changed", G_CALLBACK(select_filter), NULL);
240     gtk_box_pack_start(GTK_BOX(hbox), rule_info->filter_combo_box, FALSE, FALSE, 5);
241
242     /* inbound selector */
243     rule_info->inbound_cb = gtk_check_button_new_with_label("Inbound");
244     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rule_info->inbound_cb),
245         rule_info->inbound);
246     gtk_box_pack_start(GTK_BOX(hbox), rule_info->inbound_cb, FALSE, FALSE, 10);
247     g_signal_connect(rule_info->inbound_cb, "toggled", G_CALLBACK(toggle_inbound), rule_info);
248
249     /* deny selector */
250     rule_info->deny_cb = gtk_check_button_new_with_label("Deny");
251     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rule_info->deny_cb),
252         rule_info->deny);
253     gtk_box_pack_start(GTK_BOX(hbox), rule_info->deny_cb, FALSE, FALSE, 10);
254     g_signal_connect(rule_info->deny_cb, "toggled", G_CALLBACK(toggle_deny), rule_info);
255
256     /* create a scrolled window for the text */
257     txt_scrollw = scrolled_window_new(NULL, NULL);
258     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scrollw),
259                                         GTK_SHADOW_IN);
260     gtk_box_pack_start(GTK_BOX(vbox), txt_scrollw, TRUE, TRUE, 0);
261
262     /* create a text box */
263     text = gtk_text_view_new();
264     gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
265     gtk_container_add(GTK_CONTAINER(txt_scrollw), text);
266     rule_info->text = text;
267
268     /* Button row */
269     button_hbox = dlg_button_row_new(GTK_STOCK_HELP, GTK_STOCK_COPY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, NULL);
270     gtk_box_pack_start(GTK_BOX(vbox), button_hbox, FALSE, FALSE, 0);
271
272     /* Create Copy Button */
273     button = (GtkWidget *)g_object_get_data(G_OBJECT(button_hbox), GTK_STOCK_COPY);
274     g_signal_connect(button, "clicked", G_CALLBACK(firewall_copy_cmd_cb), rule_info);
275         gtk_widget_set_tooltip_text(button, "Copy rule to clipboard");
276
277     /* Create Save Button */
278     button = (GtkWidget *)g_object_get_data(G_OBJECT(button_hbox), GTK_STOCK_SAVE);
279     g_signal_connect(button, "clicked", G_CALLBACK(firewall_save_as_cmd_cb), rule_info);
280         gtk_widget_set_tooltip_text(button, "Save the rule as currently displayed");
281
282     button = (GtkWidget *)g_object_get_data(G_OBJECT(button_hbox), GTK_STOCK_CANCEL);
283         gtk_widget_set_tooltip_text(button, "Cancel the dialog");
284     window_set_cancel_button(rule_w, button, window_cancel_button_cb);
285
286     button = (GtkWidget *)g_object_get_data(G_OBJECT(button_hbox), GTK_STOCK_HELP);
287     g_signal_connect(button, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_FIREWALL_DIALOG);
288
289     /* Tuck away the rule_info object into the window */
290     g_object_set_data(G_OBJECT(rule_w), WS_RULE_INFO_KEY, rule_info);
291
292     g_signal_connect(rule_w, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
293     g_signal_connect(rule_w, "destroy", G_CALLBACK(firewall_destroy_cb), NULL);
294
295     /* Make sure this widget gets destroyed if we quit the main loop,
296        so that if we exit, we clean up any temporary files we have
297        for "Follow SSL Stream" windows.
298        gtk_quit_add_destroy is deprecated and should not be used in newly-written code. This function is going to be removed in GTK+ 3.0
299
300        gtk_quit_add_destroy(gtk_main_level(), GTK_OBJECT(rule_w));
301
302            */
303
304     gtk_combo_box_set_active(GTK_COMBO_BOX(product_combo_box), 0);  /* invokes select_product callback */
305     gtk_widget_show_all(rule_w);
306     window_present(rule_w);
307 }
308
309 /* Set the current product. */
310 #define ADD_TO_FILTER_MENU(rt) \
311         ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(rule_info->filter_combo_box), name, GUINT_TO_POINTER(rt)); \
312         if (rule_type == RT_NONE) { \
313             rule_type = rt; \
314         }
315
316 #define NAME_TCP_UDP (rule_info->ptype == PT_TCP ? "TCP" : "UDP")
317
318 static void
319 select_product(GtkWidget *w, gpointer data _U_)
320 {
321     guint prod = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
322     rule_info_t *rule_info;
323     gchar name[MAX_RULE_LEN], addr_str[MAX_RULE_LEN];
324     address *addr;
325     rule_type_t rule_type = RT_NONE;
326     gboolean sensitive = FALSE;
327
328     rule_info =(rule_info_t     *)g_object_get_data(G_OBJECT(w), WS_RULE_INFO_KEY);
329
330     if (prod >= NUM_PRODS || !rule_info)
331         return;
332
333     rule_info->product = prod;
334
335     /* Clear the list store (ie: the como_box list items) */
336     ws_combo_box_clear_text_and_pointer(GTK_COMBO_BOX(rule_info->filter_combo_box));
337
338     /* Fill in valid combo_box list items (in the list store).   */
339     if (products[prod].mac_func && rule_info->dl_src.type == AT_ETHER) {
340         addr = &(rule_info->dl_src);
341         address_to_str_buf(addr, name, MAX_RULE_LEN);
342         ADD_TO_FILTER_MENU(RT_MAC_SRC);
343
344         addr = &(rule_info->dl_dst);
345         address_to_str_buf(addr, name, MAX_RULE_LEN);
346         ADD_TO_FILTER_MENU(RT_MAC_DST);
347     }
348
349     if (products[prod].ipv4_func && rule_info->net_src.type == AT_IPv4) {
350         addr = &(rule_info->net_src);
351         address_to_str_buf(addr, name, MAX_RULE_LEN);
352         ADD_TO_FILTER_MENU(RT_IPv4_SRC);
353
354         addr = &(rule_info->net_dst);
355         address_to_str_buf(addr, name, MAX_RULE_LEN);
356         ADD_TO_FILTER_MENU(RT_IPv4_DST);
357     }
358
359     if (products[prod].port_func && (rule_info->ptype == PT_TCP || rule_info->ptype == PT_UDP)) {
360         g_snprintf(name, MAX_RULE_LEN, "%s port %u", NAME_TCP_UDP,
361             rule_info->srcport);
362         ADD_TO_FILTER_MENU(RT_PORT_SRC);
363         if (rule_info->srcport != rule_info->destport) {
364             g_snprintf(name, MAX_RULE_LEN, "%s port %u", NAME_TCP_UDP,
365                 rule_info->destport);
366             ADD_TO_FILTER_MENU(RT_PORT_DST);
367         }
368     }
369
370     if (products[prod].ipv4_port_func && rule_info->net_src.type == AT_IPv4 &&
371             (rule_info->ptype == PT_TCP || rule_info->ptype == PT_UDP)) {
372         addr = &(rule_info->net_src);
373         address_to_str_buf(addr, addr_str, MAX_RULE_LEN);
374         g_snprintf(name, MAX_RULE_LEN, "%s + %s port %u", addr_str,
375             NAME_TCP_UDP, rule_info->srcport);
376         ADD_TO_FILTER_MENU(RT_IPv4_PORT_SRC);
377
378         addr = &(rule_info->net_dst);
379         address_to_str_buf(addr, addr_str, MAX_RULE_LEN);
380         g_snprintf(name, MAX_RULE_LEN, "%s + %s port %u", addr_str,
381             NAME_TCP_UDP, rule_info->destport);
382         ADD_TO_FILTER_MENU(RT_IPv4_PORT_DST);
383     }
384
385     if (rule_type != RT_NONE) {
386         gtk_combo_box_set_active(GTK_COMBO_BOX(rule_info->filter_combo_box), 0); /* invokes select_filter callback */
387         sensitive = TRUE;
388     } else {
389         select_filter(rule_info->filter_combo_box, NULL);  /* Call if RT_NONE [with nothing selected]  */
390     }
391
392     gtk_widget_set_sensitive(rule_info->filter_combo_box, sensitive);
393     gtk_widget_set_sensitive(rule_info->inbound_cb, products[prod].does_inbound && sensitive);
394     gtk_widget_set_sensitive(rule_info->deny_cb, sensitive);
395 }
396
397 /* Set the rule text based upon the current product and current filter. */
398 static void
399 select_filter(GtkWidget *w, gpointer data _U_)
400 {
401     rule_type_t cur_type;
402     rule_info_t *rule_info;
403     gpointer ptr;
404
405     rule_info = (rule_info_t *)g_object_get_data(G_OBJECT(w), WS_RULE_INFO_KEY);
406     if (!rule_info)
407         return;
408
409
410     if (ws_combo_box_get_active_pointer(GTK_COMBO_BOX(w), &ptr))
411         cur_type = (rule_type_t)GPOINTER_TO_UINT(ptr);
412     else
413         cur_type = RT_NONE; /* If nothing selected (eg: nothing in filter list) */
414
415     if (cur_type >= NUM_RULE_TYPES)
416         return;
417
418     rule_info->rule_type = cur_type;
419
420     set_rule_text(rule_info);
421 }
422
423 /* Set inbound/outbound */
424 static void
425 toggle_inbound(GtkToggleButton *t, gpointer data)
426 {
427     rule_info_t *rule_info = (rule_info_t *) data;
428
429     rule_info->inbound = gtk_toggle_button_get_active(t);
430
431     set_rule_text(rule_info);
432 }
433
434 /* Set deny/allow. */
435 static void
436 toggle_deny(GtkToggleButton *t, gpointer data)
437 {
438     rule_info_t *rule_info = (rule_info_t *) data;
439
440     rule_info->deny = gtk_toggle_button_get_active(t);
441
442     set_rule_text(rule_info);
443 }
444
445 /* Set the rule text */
446 #define DL_ADDR (rt == RT_MAC_SRC ? &(rule_info->dl_src) : &(rule_info->dl_dst))
447 #define NET_ADDR (rt == RT_IPv4_SRC ? &(rule_info->net_src) : &(rule_info->net_dst))
448 #define NET_PORT (rt == RT_PORT_SRC ? rule_info->srcport : rule_info->destport)
449 static void
450 set_rule_text(rule_info_t *rule_info) {
451     GString *rtxt = g_string_new("");
452     gchar addr_str[MAX_RULE_LEN];
453     rule_type_t rt = rule_info->rule_type;
454     guint prod = rule_info->product;
455     address *addr = NULL;
456     guint32 port = 0;
457     syntax_func rt_func = NULL;
458
459     GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(rule_info->text));
460
461     if (prod < NUM_PRODS) {
462         g_string_printf(rtxt, "%s %s\n", products[prod].comment_pfx, products[prod].name);
463         switch(rt) {
464             case RT_NONE:
465                 g_string_append_printf(rtxt, "%s Not supported", products[prod].comment_pfx);
466                 rt_func = sf_dummy;
467                 break;
468             case RT_MAC_SRC:
469             case RT_MAC_DST:
470                 addr = DL_ADDR;
471                 address_to_str_buf(addr, addr_str, MAX_RULE_LEN);
472                 rt_func = products[prod].mac_func;
473                 break;
474             case RT_IPv4_SRC:
475             case RT_IPv4_DST:
476                 addr = NET_ADDR;
477                 address_to_str_buf(addr, addr_str, MAX_RULE_LEN);
478                 rt_func = products[prod].ipv4_func;
479                 break;
480             case RT_PORT_SRC:
481             case RT_PORT_DST:
482                 port = NET_PORT;
483                 rt_func = products[prod].port_func;
484                 break;
485             case RT_IPv4_PORT_SRC:
486             case RT_IPv4_PORT_DST:
487                 addr = NET_ADDR;
488                 address_to_str_buf(addr, addr_str, MAX_RULE_LEN);
489                 port = NET_PORT;
490                 rt_func = products[prod].ipv4_port_func;
491                 break;
492             default:
493                 break;
494         }
495     }
496
497     if (rt_func) {
498         rt_func(rtxt, addr_str, port, rule_info->ptype, rule_info->inbound, rule_info->deny);
499     } else {
500         g_string_append_printf(rtxt, "ERROR: Unable to create rule");
501     }
502
503     gtk_text_buffer_set_text(buf, rtxt->str, (gint) rtxt->len);
504
505     g_string_free(rtxt, TRUE);
506 }
507
508
509 /* Rule text functions */
510 /* Dummy */
511 static void sf_dummy(GString *rtxt _U_, gchar *addr _U_, guint32 port _U_, port_type ptype _U_, gboolean inbound _U_, gboolean deny _U_) {
512 }
513
514 /* MAC */
515 #define IPFW_DENY (deny ? "deny" : "allow")
516 #define IPFW_IN (inbound ? "in" : "out")
517 static void sf_ipfw_mac(GString *rtxt, gchar *addr, guint32 port _U_, port_type ptype _U_, gboolean inbound, gboolean deny) {
518     g_string_append_printf(rtxt, "add %s MAC %s any %s",
519         IPFW_DENY, addr, IPFW_IN);
520 }
521
522 #define NF_DROP (deny ? "DROP" : "ACCEPT")
523 #define NF_INPUT (inbound ? "INPUT" : "OUTPUT")
524 static void sf_netfilter_mac(GString *rtxt, gchar *addr, guint32 port _U_, port_type ptype _U_, gboolean inbound, gboolean deny) {
525     g_string_append_printf(rtxt, "iptables -A %s --mac-source %s -j %s",
526         NF_INPUT, addr, NF_DROP);
527 }
528
529 /* IPv4 */
530 #define IOS_DENY (deny ? "deny" : "permit")
531 static void sf_ios_std_ipv4(GString *rtxt, gchar *addr, guint32 port _U_, port_type ptype _U_, gboolean inbound _U_, gboolean deny) {
532     g_string_append_printf(rtxt, "access-list NUMBER %s host %s", IOS_DENY, addr);
533 }
534
535 static void sf_ios_ext_ipv4(GString *rtxt, gchar *addr, guint32 port _U_, port_type ptype _U_, gboolean inbound, gboolean deny) {
536     if (inbound)
537         g_string_append_printf(rtxt, "access-list NUMBER %s ip host %s any", IOS_DENY, addr);
538     else
539         g_string_append_printf(rtxt, "access-list NUMBER %s ip any host %s", IOS_DENY, addr);
540 }
541
542 #define IPFILTER_DENY (deny ? "block" : "pass")
543 #define IPFILTER_IN (inbound ? "in" : "out")
544 static void sf_ipfilter_ipv4(GString *rtxt, gchar *addr, guint32 port _U_, port_type ptype _U_, gboolean inbound, gboolean deny) {
545     g_string_append_printf(rtxt, "%s %s on le0 from %s to any",
546         IPFILTER_DENY, IPFILTER_IN, addr);
547 }
548
549 static void sf_ipfw_ipv4(GString *rtxt, gchar *addr, guint32 port _U_, port_type ptype _U_, gboolean inbound, gboolean deny) {
550     g_string_append_printf(rtxt, "add %s ip from %s to any %s",
551         IPFW_DENY, addr, IPFW_IN);
552 }
553
554 static void sf_netfilter_ipv4(GString *rtxt, gchar *addr, guint32 port _U_, port_type ptype _U_, gboolean inbound, gboolean deny) {
555     g_string_append_printf(rtxt, "iptables -A %s -i eth0 -d %s/32 -j %s",
556         NF_INPUT, addr, NF_DROP);
557 }
558
559 #define PF_DENY (deny ? "block" : "pass")
560 #define PF_IN (inbound ? "in" : "out")
561 static void sf_pf_ipv4(GString *rtxt, gchar *addr, guint32 port _U_, port_type ptype _U_, gboolean inbound, gboolean deny) {
562     g_string_append_printf(rtxt, "%s %s quick on $ext_if from %s to any",
563         PF_DENY, PF_IN, addr);
564 }
565
566 /* Port */
567 #define RT_TCP_UDP (ptype == PT_TCP ? "tcp" : "udp")
568 static void sf_ios_ext_port(GString *rtxt, gchar *addr _U_, guint32 port, port_type ptype, gboolean inbound _U_, gboolean deny) {
569     g_string_append_printf(rtxt, "access-list NUMBER %s %s any any eq %u",
570         IOS_DENY, RT_TCP_UDP, port);
571 }
572
573 static void sf_ipfilter_port(GString *rtxt, gchar *addr _U_, guint32 port, port_type ptype _U_, gboolean inbound, gboolean deny) {
574     g_string_append_printf(rtxt, "%s %s on le0 proto %s from any to any port = %u",
575         IPFILTER_DENY, IPFILTER_IN, RT_TCP_UDP, port);
576 }
577
578 static void sf_ipfw_port(GString *rtxt, gchar *addr _U_, guint32 port, port_type ptype, gboolean inbound, gboolean deny) {
579     g_string_append_printf(rtxt, "add %s %s from any to any %u %s",
580         IPFW_DENY, RT_TCP_UDP, port, IPFW_IN);
581 }
582
583 static void sf_netfilter_port(GString *rtxt, gchar *addr _U_, guint32 port, port_type ptype, gboolean inbound, gboolean deny) {
584     g_string_append_printf(rtxt, "iptables -A %s -p %s --destination-port %u -j %s",
585             NF_INPUT, RT_TCP_UDP, port, NF_DROP);
586 }
587
588 static void sf_pf_port(GString *rtxt, gchar *addr _U_, guint32 port, port_type ptype, gboolean inbound, gboolean deny) {
589     g_string_append_printf(rtxt, "%s %s quick on $ext_if proto %s from any to any port %u",
590         PF_DENY, PF_IN, RT_TCP_UDP, port);
591 }
592
593 #define NETSH_DENY (deny ? "DISABLE" : "ENABLE")
594 static void sf_netsh_port(GString *rtxt, gchar *addr _U_, guint32 port, port_type ptype, gboolean inbound _U_, gboolean deny) {
595     g_string_append_printf(rtxt, "add portopening %s %u Wireshark %s",
596         RT_TCP_UDP, port, NETSH_DENY);
597 }
598
599 /* IPv4 + port */
600 static void sf_ios_ext_ipv4_port(GString *rtxt, gchar *addr, guint32 port _U_, port_type ptype _U_, gboolean inbound, gboolean deny) {
601     if (inbound)
602         g_string_append_printf(rtxt, "access-list NUMBER %s %s host %s any eq %u", IOS_DENY, RT_TCP_UDP, addr, port);
603     else
604         g_string_append_printf(rtxt, "access-list NUMBER %s %s any host %s eq %u", IOS_DENY, RT_TCP_UDP, addr, port);
605 }
606
607 static void sf_ipfilter_ipv4_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny) {
608     if (inbound)
609         g_string_append_printf(rtxt, "%s %s on le0 proto %s from %s to any port = %u",
610             IPFILTER_DENY, IPFILTER_IN, RT_TCP_UDP, addr, port);
611     else
612         g_string_append_printf(rtxt, "%s %s on le0 proto %s from any to %s port = %u",
613             IPFILTER_DENY, IPFILTER_IN, RT_TCP_UDP, addr, port);
614 }
615
616 static void sf_ipfw_ipv4_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny) {
617     g_string_append_printf(rtxt, "add %s %s from %s to any %u %s",
618         IPFW_DENY, RT_TCP_UDP, addr, port, IPFW_IN);
619 }
620
621 static void sf_pf_ipv4_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny) {
622     g_string_append_printf(rtxt, "%s %s quick on $ext_if proto %s from %s to any port %u",
623         PF_DENY, PF_IN, RT_TCP_UDP, addr, port);
624 }
625
626 static void sf_netfilter_ipv4_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound, gboolean deny) {
627     g_string_append_printf(rtxt, "iptables -A %s -p %s -d %s/32 --destination-port %u -j %s",
628         NF_INPUT, RT_TCP_UDP, addr, port, NF_DROP);
629 }
630
631 static void sf_netsh_ipv4_port(GString *rtxt, gchar *addr, guint32 port, port_type ptype, gboolean inbound _U_, gboolean deny) {
632     g_string_append_printf(rtxt, "add portopening %s %u Wireshark %s %s",
633         RT_TCP_UDP, port, NETSH_DENY, addr);
634 }
635
636 /* The destroy call back has the responsibility of
637  * unlinking the temporary file
638  * and freeing the filter_out_filter */
639 static void
640 firewall_destroy_cb(GtkWidget *w, gpointer data _U_)
641 {
642     rule_info_t *rule_info;
643
644     rule_info = (rule_info_t *)g_object_get_data(G_OBJECT(w), WS_RULE_INFO_KEY);
645 #if 0
646     forget_rule_info(rule_info);
647 #endif
648     g_free(rule_info);
649     gtk_widget_destroy(w);
650 }
651
652 static void
653 firewall_copy_cmd_cb(GtkWidget *w _U_, gpointer data)
654 {
655     rule_info_t *rule_info = (rule_info_t *)data;
656
657     GtkTextIter start, end;
658     GtkTextBuffer *buf;
659
660     buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(rule_info->text));
661     gtk_text_buffer_get_start_iter(buf, &start);
662     gtk_text_buffer_get_end_iter(buf, &end);
663     gtk_text_buffer_select_range(buf, &start, &end);
664     gtk_text_buffer_copy_clipboard(buf, gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
665 }
666
667 static gboolean
668 firewall_save_as_ok_cb(char *to_name, rule_info_t *rule_info)
669 {
670     FILE        *fh;
671     gchar       *rule;
672
673     GtkTextIter start, end;
674     GtkTextBuffer *buf;
675
676     fh = ws_fopen(to_name, "w");
677     if (fh == NULL) {
678         open_failure_alert_box(to_name, errno, TRUE);
679         g_free(to_name);
680         return FALSE;
681     }
682
683     buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(rule_info->text));
684     gtk_text_buffer_get_start_iter(buf, &start);
685     gtk_text_buffer_get_end_iter(buf, &end);
686     rule = gtk_text_buffer_get_text(buf, &start, &end, FALSE);
687
688     fputs(rule, fh);
689     fclose(fh);
690
691     return TRUE;
692 }
693
694 static char *
695 gtk_firewall_save_as_file(GtkWidget *caller)
696 {
697     GtkWidget   *new_win;
698     char        *pathname;
699
700     new_win = file_selection_new("Wireshark: Save Firewall ACL Rule",
701                                  GTK_WINDOW(caller),
702                                  FILE_SELECTION_SAVE);
703
704     pathname = file_selection_run(new_win);
705     if (pathname == NULL) {
706         /* User cancelled or closed the dialog. */
707         return NULL;
708     }
709
710     /* We've crosed the Rubicon; get rid of the dialog box. */
711     window_destroy(new_win);
712
713     return pathname;
714 }
715
716 static void
717 firewall_save_as_cmd_cb(GtkWidget *w, gpointer data)
718 {
719     GtkWidget   *caller = gtk_widget_get_toplevel(w);
720     rule_info_t *rule_info = (rule_info_t *)data;
721     char        *pathname;
722
723     /*
724      * Loop until the user either selects a file or gives up.
725      */
726     for (;;) {
727         pathname = gtk_firewall_save_as_file(caller);
728         if (pathname == NULL) {
729             /* User gave up. */
730             break;
731         }
732         if (firewall_save_as_ok_cb(pathname, rule_info)) {
733             /* We succeeded. */
734             g_free(pathname);
735             break;
736         }
737         /* Dump failed; let the user select another file or give up. */
738         g_free(pathname);
739     }
740 }