/*---[ parse.c ]------------------------------------------------------
 * Copyright (C) 2000 Tomas Junnonen (majix@sci.fi)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * The text file parse functions.
 * TODO: Maybe rewrite using GStrings and properly modular functions.
 *       Perl?
 *--------------------------------------------------------------------*/

#include "firestarter.h"
#include "parse.h"
#include "service.h"

extern gboolean NETFILTER;

/* [ get_text_between ]
 * Give a string and two text markers in the string the function returns the
 * text between the markers.
 */
gchar *
get_text_between (gchar *string, gchar *marker1, gchar *marker2)
{
	gchar *text, *marker3;
	gint i = strlen (marker1);

	text = g_strdup (string);
	text = strstr (text, marker1);
	text += i*(sizeof (gchar));
	marker3 = strstr (text, marker2);
	text = g_strndup (text, marker3-text);

	return (text);

}

/* [ parse_hit_log ]
 * Parses *line. Extracts port, remoteip, service, time and protocol
 */
int
parse_hit_log (char *line)
{
	gchar *buf;
	gchar *data[4] = {"port", "remoteip", "service", "time"};
	gchar *proto;
	gint protoi;
	static gchar *time, *port, *ip;
	static gint datakey = 1;
	int i, width;

	data[3] = g_strndup (line, 15);

	/* Netfilter */
	if (NETFILTER) {

		/* Get remote IP */
		buf = (char *)strstr (line, "SRC=");
		if (buf == NULL)
			return FALSE;
		data[1] = get_text_between (line, "SRC=", " ");

		/* Get protocol */
		buf = (char *)strstr (buf, "PROTO=");
		if (buf == NULL)
			return FALSE;
		buf += 6*(sizeof (gchar));
		proto = g_strndup (buf, 3);

		/* Get port */
		buf = (char *)strstr (buf, "DPT=");
		if (buf == NULL)
			return FALSE;
		data[0] = get_text_between (line, "DPT=", " ");

		/* Get service, based on port and protocol */
		if (strstr (proto, "TCP"))
			protoi = 6;
		else
			protoi = 17;
		data[2] = service (atoi (data[0]), protoi);
	}
	/* IP Chains */
	else {
		if ( (buf = (char *)strstr (line, "DENY")) == NULL )
			if ( (buf = (char *)strstr (line, "REJECT")) == NULL )
				return FALSE;

		/* Get proto */
		buf = strstr (line, "PROTO=");
		if (buf == NULL)
			return FALSE;
		proto = get_text_between (buf, "PROTO=", " ");

		/* Get remote IP */
		data[1] = get_text_between (buf, " ", ":");

		/* Get port */
		buf = strstr (buf, ":");
		buf += sizeof(gchar);
		data[0] = get_text_between (buf, ":", " ");

		/* Get service, based on port and protocol */
		data[2] = service (atoi (data[0]), atol (proto));
	}

	/* Reset datakey if the clist is empty */
	if (!gtk_clist_get_text (GTK_CLIST (hitlogclist), 0, 0, NULL))
	datakey = 1;

	/* Remove identical lines */
	if (gnome_config_get_bool ("/firestarter/Program/removedups=TRUE")) {
		if ((time != NULL) && (!g_strcasecmp (time, data[3]))) {
			if (!g_strcasecmp (port, data[0]))
				if (!g_strcasecmp (ip, data[1]))
					return FALSE;
		}
		time = data[3];
		port = data[0];
		ip = data[1];
	}

	gtk_clist_append (GTK_CLIST (hitlogclist), data);

	/* Optimize the clists column widths */
	for (i = 0; i < 4; i++) {
		width = gtk_clist_optimal_column_width (GTK_CLIST (hitlogclist), i);
		gtk_clist_set_column_width (GTK_CLIST (hitlogclist), i, width);
	}

	/* Scroll the clist to the end */
	while (gtk_clist_get_text (GTK_CLIST (hitlogclist), i, 0, NULL))
		i++;
	gtk_clist_moveto (GTK_CLIST (hitlogclist), i-1, 0, 0.0, 0.0);
	
	gtk_widget_queue_draw (hitlogclist);

	gtk_object_set_data (GTK_OBJECT (hitlogclist),
		g_strdup_printf ("%d", datakey), proto);
	gtk_object_set_data (GTK_OBJECT (hitlogclist),
		"keys", GINT_TO_POINTER (datakey));
	++datakey;

	return TRUE;
}

/* [ generic_parse_sender ]
 * Convinience function to parse a generic dynrule file for packet sender info
 */
static void
generic_parse_sender (gchar *path, GtkWidget *clist)
{
	gchar *data[1];
	char buf[512];
	FILE *f;

	if ((f = fopen (path, "r")) == NULL) {
		return;
	}

	gtk_clist_clear (GTK_CLIST (clist));
	while (fgets (buf, 512, f) != NULL) {
		if (strstr (buf, " -A ") == NULL)
			continue;

		data[0] = get_text_between (buf, "-s ", " -d");
		if (data[0] != NULL)
			gtk_clist_append (GTK_CLIST (clist), data);
	}
	fclose (f);
}

/* [ parse_allow_and_deny_all ]
 * Parses the allow-all file, populates allowallclist
  */
void
parse_allow_and_deny_all (void)
{
	generic_parse_sender (FIRESTARTER_RULES_DIR "/firestarter/deny-all",
			      denyallclist);
	generic_parse_sender (FIRESTARTER_RULES_DIR "/firestarter/allow-all",
			      allowallclist);
}

/* [ parse_allow_service_machine ]
 * Parses the allow-service-machine file, populates allowsmclist
 */
void
parse_allow_service_machine (void)
{
	gchar *data[4];
	char buf[512];
	gchar *entry[1];
	FILE *f;

	f = fopen (FIRESTARTER_RULES_DIR "/firestarter/allow-service-machine", "r");
	if (f == NULL) {
		return;
	}

	gtk_clist_clear (GTK_CLIST (allowsmclist));

	while (fgets (buf, 512, f) != NULL) {
		if (strstr (buf, "-j ACCEPT") != NULL) {
			if (strstr (buf, "-s ")== NULL)
				continue;
			data[3] = get_text_between (buf, "-p ", " -s");
			data[2] = get_text_between (buf, "-s ", " -d");
			if (NETFILTER)
				data[1] = get_text_between (buf, "--dport ", " -j");
			else
				data[1] = get_text_between (buf, "$NET ", " -j");
			data[0] = service (atoi (data[1]), atoi (data[3]));

			entry[0] = g_strjoin (NULL, data[0],"/", data[1],
					      "    ", data[2], NULL);
			gtk_clist_append (GTK_CLIST (allowsmclist), entry);
		}
	}
}

/* [ parse_allow_service_all ]
 * Parses the allow-service-all file, populates allowsaclist
 */
void
parse_allow_service_all (void)
{
	gchar *data[3];
	char buf[512];
	gchar *entry[1];
	FILE *f;

	f = fopen (FIRESTARTER_RULES_DIR "/firestarter/allow-service-all", "r");
	if (f == NULL) {
		return;
	}

	gtk_clist_clear (GTK_CLIST (allowsaclist));

	while (fgets (buf, 512, f) != NULL) {
		if (strstr (buf, "-j ACCEPT") != NULL) {
			if (strstr (buf, "$NET ") == NULL)
				continue;
			if (NETFILTER)
				data[1] = get_text_between (buf, "--dport ", " -j");
			else
				data[1] = get_text_between (buf, "$NET ", " -j");
			data[2] = get_text_between (buf, "-p ", " -s");
			data[0] = service (atoi (data[1]), atoi(data[2]));

			entry[0] = g_strjoin (NULL, data[0], "/", data[1], NULL);
			gtk_clist_append (GTK_CLIST (allowsaclist), entry);
		}
	}
}

void
parse_do_not_log_ports (GtkWidget *clist)
{
	gchar buf[512];
	gchar *entry[2];
	static gint lastentry;
	FILE *f;


	f = fopen (FIRESTARTER_RULES_DIR "/firestarter/block-ports", "r");

	if (f == NULL) {
		return;
	}

	gtk_clist_clear (GTK_CLIST (clist));

	while (fgets (buf, 512, f) != NULL) {
		if (strstr (buf, "-j") != NULL) {
			if (strstr (buf, "-s 0/0") == NULL)
				continue;
			if (NETFILTER)
				entry[0] = get_text_between (buf, "--dport ", " -j");
			else
				entry[0] = get_text_between (buf, "-d 0/0 ", " -j");
			entry[1] = service (atoi (entry[0]), 6);

			if (atoi (entry[0]) == lastentry)
				continue;
			gtk_clist_append (GTK_CLIST (clist), entry);
			lastentry = atoi (entry[0]);
		}
	}
}
