#include #include #include #include #include #include #include #include #include #include #include #include "connection.h" #include "interface.h" #include "support.h" #include "daemon.h" #include "mainwin.h" #include "log.h" #include "rulewin.h" #include "ruleset.h" #include "format.h" GSList *queued_conn_list = NULL; guint queued_conn_count = 0; conn_info_t *conn_current = NULL; guint total_conn_count = 0; static GtkWidget* get_window(void) { static GtkWidget *cw = NULL; if (!cw) { GdkColor color; cw = create_connection_window(); gdk_color_parse ("black", &color); gtk_widget_modify_bg(lookup_widget(cw, "title_eventbox"), GTK_STATE_NORMAL, &color); } return cw; } void conn_fill_info(conn_info_t *c) { struct protoent *pe = NULL; struct servent *se = NULL; static gchar txt[256]; char *t; c->from_string = g_strdup(format_hostname(c->src_ip_address)); c->to_string = g_strdup(format_hostname(c->dst_ip_address)); c->port_string = NULL; if (c->protocol == IPPROTO_ICMP) snprintf(t = txt, sizeof(txt), "ICMP %s", icmp_type_str(c->icmp_type)); else if (c->protocol == IPPROTO_TCP || c->protocol == IPPROTO_UDP) { gchar *pp = c->protocol == IPPROTO_TCP ? "TCP" : "UDP"; if ((se = getservbyport(htons(c->port), NULL))) snprintf(t = txt, sizeof(txt), "%s Port#%u (%s)", pp, c->port, c->port_string = g_strdup(se->s_name)); else snprintf(t = txt, sizeof(txt), "%s Port#%u", pp, c->port); } else if ((pe = getprotobynumber(c->protocol))) t = pe->p_name; else t = "Unknown"; c->type_string = g_strdup(t); strncpy(txt, ctime(&c->timestamp), sizeof(txt)); if (txt[0]) // remove trailing \n txt[strlen(txt)-1] = 0; c->timestamp_string = g_strdup(txt); } void conn_free(conn_info_t*c) { g_free(c->from_string); g_free(c->to_string); g_free(c->type_string); g_free(c->port_string); g_free(c->timestamp_string); g_free(c); } void conn_set_sticky() { if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(get_main_window(), "sticky_button")))) gtk_window_stick(GTK_WINDOW(get_window())); else gtk_window_unstick(GTK_WINDOW(get_window())); } void conn_show_info(conn_info_t *c) { GtkWidget* window; GtkTooltips *tooltips; static gchar txt[256]; static gchar fn[PATH_MAX]; char *d; GdkPixbuf *pixbuf; window = get_window(); snprintf(txt, sizeof(txt), "%s Connection", c->direction == DIR_INCOMING ? "Incoming" : (c->direction == DIR_OUTGOING ? "Outgoing" : "Passing")); gtk_label_set_label(GTK_LABEL(lookup_widget(window, "title_label")), txt); gtk_image_set_from_stock(GTK_IMAGE(lookup_widget(window, "title_image")), c->direction == DIR_INCOMING ? GTK_STOCK_GO_FORWARD : (c->direction == DIR_OUTGOING ? GTK_STOCK_GO_BACK : GTK_STOCK_NEW), GTK_ICON_SIZE_DND); if (c->direction == DIR_INCOMING) d = c->device_in; else if (c->direction == DIR_OUTGOING) d = c->device_out; else snprintf(d = txt, sizeof(txt), "%s => %s", c->device_in, c->device_out); gtk_label_set_label(GTK_LABEL(lookup_widget(window, "interface_label")), d); gtk_label_set_label(GTK_LABEL(lookup_widget(window, "from_label")), c->from_string); gtk_label_set_label(GTK_LABEL(lookup_widget(window, "to_label")), c->to_string); gtk_label_set_label(GTK_LABEL(lookup_widget(window, "type_label")), c->type_string); tooltips = GTK_TOOLTIPS(lookup_widget(window, "tooltips")); gtk_tooltips_set_tip(tooltips, lookup_widget(window, "from_eventbox"), format_ip_address(c->src_ip_address), NULL); gtk_tooltips_set_tip(tooltips, lookup_widget(window, "to_eventbox"), format_ip_address(c->dst_ip_address), NULL); gtk_tooltips_set_delay(tooltips, 0); snprintf(txt, sizeof(txt), "%lu", c->id); gtk_label_set_label(GTK_LABEL(lookup_widget(window, "id_label")), txt); gtk_label_set_label(GTK_LABEL(lookup_widget(window, "time_label")), c->timestamp_string); gtk_widget_set_sensitive(lookup_widget(window, "reject_button"), !c->broadcast); gtk_label_set_label(GTK_LABEL(lookup_widget(window, "broadcast_label")), c->broadcast ? "Yes" : "No"); gtk_image_set_from_stock(GTK_IMAGE(lookup_widget(window, "type_image")), GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DND); if (c->port_string) { snprintf(fn, sizeof(fn), "%s/pixmaps/%s.png", "..", c->port_string); if ((pixbuf = gdk_pixbuf_new_from_file(fn, NULL))) { gtk_image_set_from_pixbuf(GTK_IMAGE(lookup_widget(window, "type_image")), pixbuf); g_object_unref(pixbuf); } } gtk_widget_show_all(window); conn_set_sticky(); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_present(GTK_WINDOW(window)); } void conn_show_count() { static gchar txt[256]; gchar *p; if (queued_conn_count) snprintf(p = txt, sizeof(txt), "Connection (%i in queue)", queued_conn_count); else p = "Connection"; gtk_window_set_title(GTK_WINDOW(get_window()), p); } void conn_pop() { g_assert(!conn_current && queued_conn_list); conn_current = (conn_info_t*) queued_conn_list->data; queued_conn_list = g_slist_remove(queued_conn_list, conn_current); queued_conn_count--; conn_show_count(); conn_show_info(conn_current); } static conn_info_t* ipq2ci(ipq_packet_msg_t* m) { conn_info_t* ci = g_new0(conn_info_t, 1); struct iphdr *ip = (struct iphdr*) m->payload; ci->id = m->packet_id; ci->direction = (m->indev_name[0] && m->outdev_name[0]) ? DIR_PASSING : (m->indev_name[0] ? DIR_INCOMING : DIR_OUTGOING); strncpy(ci->device_in, m->indev_name, IFNAMSIZ); ci->device_in[IFNAMSIZ] = 0; strncpy(ci->device_out, m->outdev_name, IFNAMSIZ); ci->device_out[IFNAMSIZ] = 0; if (m->data_len < sizeof(struct iphdr)) { g_message("Packet too small for complete IP header"); g_free(ci); return NULL; } ci->src_ip_address = ip->saddr; ci->dst_ip_address = ip->daddr; ci->protocol = ip->protocol; ci->broadcast = is_broadcast(ci->dst_ip_address); ci->port = 0; ci->icmp_type = 0; if (ci->protocol == IPPROTO_TCP || ci->protocol == IPPROTO_UDP) ci->port = ntohs(*((guint16*) (m->payload + sizeof(struct iphdr) + 2))); else if (ci->protocol == IPPROTO_ICMP) ci->icmp_type = *((guint8*) (m->payload + sizeof(struct iphdr))); ci->timestamp = m->timestamp_sec; return ci; } guint verdict2nr(verdict_t v) { switch (v) { case VERDICT_REJECT : return ruleset.icmp_reject_code+2; case VERDICT_QUERY : case VERDICT_DROP : return 0; case VERDICT_ACCEPT : return 1; } return 0; } void conn_new(ipq_packet_msg_t *m) { conn_info_t *ci; if ((ci = ipq2ci(m))) { queued_conn_list = g_slist_append(queued_conn_list, ci); queued_conn_count++; total_conn_count++; conn_fill_info(ci); log_widget_append(ci); conn_show_count(); if (!conn_current) conn_pop(); mainwin_update_status_bar(); } } void conn_verdict(verdict_t v) { if (!conn_current) return; if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(get_window(), "queue_check_button")))) { for (;;) { verdict_t _v; if (v == VERDICT_REJECT && conn_current->broadcast) _v = VERDICT_DROP; else _v = v; daemon_verdict(conn_current->id, verdict2nr(_v)); log_widget_verdict(conn_current, _v); conn_free(conn_current); if (!queued_conn_list) break; conn_current = (conn_info_t*) queued_conn_list->data; queued_conn_list = g_slist_remove(queued_conn_list, conn_current); queued_conn_count--; } conn_current = NULL; g_assert(queued_conn_count == 0); gtk_widget_hide(get_window()); } else { if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(get_window(), "rule_check_button")))) { rule_t *rule; rule = rule_new_from_conn_info(conn_current); rule->verdict = v; rulewin_show(rule); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(get_window(), "rule_check_button")), FALSE); } daemon_verdict(conn_current->id, verdict2nr(v)); log_widget_verdict(conn_current, v); conn_free(conn_current); conn_current = NULL; if (!queued_conn_list) gtk_widget_hide(get_window()); else conn_pop(); } mainwin_update_status_bar(); }