summaryrefslogtreecommitdiffstats
path: root/client/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'client/connection.c')
-rw-r--r--client/connection.c292
1 files changed, 292 insertions, 0 deletions
diff --git a/client/connection.c b/client/connection.c
new file mode 100644
index 0000000..fb04e41
--- /dev/null
+++ b/client/connection.c
@@ -0,0 +1,292 @@
+#include <gtk/gtk.h>
+#include <netdb.h>
+#include <time.h>
+#include <linux/ip.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#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), "<span size=\"xx-large\" color=\"white\"><b>%s Connection</b></span>", 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();
+}