summaryrefslogtreecommitdiffstats
path: root/client/rule.c
diff options
context:
space:
mode:
Diffstat (limited to 'client/rule.c')
-rw-r--r--client/rule.c318
1 files changed, 318 insertions, 0 deletions
diff --git a/client/rule.c b/client/rule.c
new file mode 100644
index 0000000..60c7081
--- /dev/null
+++ b/client/rule.c
@@ -0,0 +1,318 @@
+#include <string.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "rule.h"
+#include "format.h"
+
+static int id = 0;
+
+rule_t* rule_new() {
+ rule_t* rule = g_new0(rule_t, 1);
+
+ rule->enabled = TRUE;
+ rule->realized = FALSE;
+ rule->match = 0;
+
+ rule->direction = DIR_OUTGOING;
+ rule->src_netmask_bits = 32;
+ rule->dst_netmask_bits = 32;
+
+ rule->id = id++;
+
+ //g_message("allocated rule %u", rule->id);
+
+ return rule;
+}
+
+void rule_free(rule_t *rule) {
+ //g_message("freed rule %u", rule->id);
+
+ if (rule->being_edited)
+ g_message("WARNING! Rule being currently edited is freed!");
+ g_free(rule);
+}
+
+rule_t* rule_new_from_conn_info(conn_info_t *ci) {
+ rule_t *rule = rule_new();
+ g_assert(ci);
+
+ rule->enabled = TRUE;
+ rule->realized = FALSE;
+ rule->match = MATCH_DIRECTION | MATCH_TYPE;
+
+ strncpy(rule->description, ci->type_string, sizeof(rule->description));
+ strncpy(rule->device_in, ci->device_in, IFNAMSIZ);
+ strncpy(rule->device_out, ci->device_out, IFNAMSIZ);
+
+ rule->protocol = ci->protocol;
+ rule->port = ci->port;
+ rule->icmp_type = ci->icmp_type;
+ rule->direction = ci->direction;
+
+ rule->src_ip_address = ci->src_ip_address;
+ rule->dst_ip_address = ci->dst_ip_address;
+
+ rule->src_netmask_bits = 32;
+ rule->dst_netmask_bits = 32;
+
+ if (ci->broadcast)
+ rule->match |= MATCH_BROADCAST;
+
+ if (ci->direction == DIR_INCOMING)
+ rule->match |= MATCH_SOURCE;
+
+ if (ci->direction == DIR_OUTGOING)
+ rule->match |= MATCH_DESTINATION;
+
+ if (ci->direction == DIR_PASSING)
+ rule->match |= MATCH_DESTINATION|MATCH_SOURCE;
+
+ return rule;
+}
+
+rule_t* rule_new_from_xml(xmlDocPtr doc, xmlNodePtr node) {
+ rule_t *rule = rule_new();
+ xmlChar *text = NULL;
+
+ rule->match = 0;
+ rule->enabled = TRUE;
+ rule->realized = TRUE;
+
+ for (node = node->xmlChildrenNode; node; node = node->next) {
+
+ if (node->type == XML_TEXT_NODE)
+ continue;
+
+ if (node->type != XML_ELEMENT_NODE)
+ goto finish;
+
+ text = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
+
+ if (!xmlStrcmp(node->name, "description"))
+ g_strlcpy(rule->description, text, sizeof(rule->description));
+ else if (!xmlStrcmp(node->name, "direction")) {
+ rule->match |= MATCH_DIRECTION;
+
+ if (!xmlStrcmp(text, "incoming"))
+ rule->direction = DIR_INCOMING;
+ else if (!xmlStrcmp(text, "outgoing"))
+ rule->direction = DIR_OUTGOING;
+ else if (!xmlStrcmp(text, "passing"))
+ rule->direction = DIR_PASSING;
+ else
+ goto finish;
+
+ } else if (!xmlStrcmp(node->name, "protocol")) {
+ rule->match |= MATCH_TYPE;
+
+ if (!xmlStrcmp(text, "udp"))
+ rule->protocol = IPPROTO_UDP;
+ else if (!xmlStrcmp(text, "tcp"))
+ rule->protocol = IPPROTO_TCP;
+ else if (!xmlStrcmp(text, "tcp"))
+ rule->protocol = IPPROTO_ICMP;
+ else
+ goto finish;
+
+ } else if (!xmlStrcmp(node->name, "destination-port")) {
+ rule->match |= MATCH_TYPE;
+ rule->port = atoi(text);
+ } else if (!xmlStrcmp(node->name, "icmp-type")) {
+ rule->match |= MATCH_TYPE;
+ rule->icmp_type = atoi(text);
+ } else if (!xmlStrcmp(node->name, "source")) {
+ rule->match |= MATCH_SOURCE;
+ if (!inet_aton(text, (struct in_addr*) &rule->src_ip_address))
+ goto finish;
+ } else if (!xmlStrcmp(node->name, "destination")) {
+ rule->match |= MATCH_DESTINATION;
+ if (!inet_aton(text, (struct in_addr*) &rule->dst_ip_address))
+ goto finish;
+ } else if (!xmlStrcmp(node->name, "input-device")) {
+ rule->match |= MATCH_INTERFACES;
+ g_strlcpy(rule->device_in, text, sizeof(rule->device_in));
+ } else if (!xmlStrcmp(node->name, "output-device")) {
+ rule->match |= MATCH_INTERFACES;
+ g_strlcpy(rule->device_out, text, sizeof(rule->device_out));
+ } else if (!xmlStrcmp(node->name, "source-netmask-bits")) {
+ rule->src_netmask_bits = atoi(text);
+ } else if (!xmlStrcmp(node->name, "destination-netmask-bits")) {
+ rule->dst_netmask_bits = atoi(text);
+ } else if (!xmlStrcmp(node->name, "broadcast")) {
+ rule->match |= MATCH_BROADCAST;
+ rule->match &= ~MATCH_UNICAST;
+ } else if (!xmlStrcmp(node->name, "unicast")) {
+ rule->match |= MATCH_UNICAST;
+ rule->match &= ~MATCH_BROADCAST;
+ } else if (!xmlStrcmp(node->name, "target")) {
+
+ if (!xmlStrcmp(text, "drop"))
+ rule->verdict = VERDICT_DROP;
+ else if (!xmlStrcmp(text, "reject"))
+ rule->verdict = VERDICT_REJECT;
+ else if (!xmlStrcmp(text, "accept"))
+ rule->verdict = VERDICT_ACCEPT;
+ else if (!xmlStrcmp(text, "query") || !xmlStrcmp(text, "ask"))
+ rule->verdict = VERDICT_QUERY;
+ else
+ goto finish;
+ } else if (!xmlStrcmp(node->name, "disabled")) {
+ rule->enabled = FALSE;
+ } else
+ goto finish;
+
+ if (text)
+ xmlFree(text);
+ text = NULL;
+ }
+
+ return rule;
+
+finish:
+ if (text)
+ xmlFree(text);
+
+ rule_free(rule);
+ return NULL;
+}
+
+
+gchar* rule_match_string(rule_t* rule) {
+ static char txt[256], txt2[256];
+ guint l;
+ g_assert(rule);
+
+ txt[0] = 0;
+
+ if (rule->match & MATCH_DIRECTION) {
+ switch (rule->direction) {
+ case DIR_INCOMING: g_strlcat(txt, "incoming; ", sizeof(txt)); break;
+ case DIR_OUTGOING: g_strlcat(txt, "outgoing; ", sizeof(txt)); break;
+ case DIR_PASSING: g_strlcat(txt, "passing; ", sizeof(txt)); break;
+ }
+
+ if (rule->match & MATCH_INTERFACES) {
+ if (rule->direction == DIR_INCOMING)
+ snprintf(txt2, sizeof(txt2), "device %s; ", rule->device_in);
+ else if (rule->direction == DIR_OUTGOING)
+ snprintf(txt2, sizeof(txt2), "device %s; ", rule->device_out);
+ else
+ snprintf(txt2, sizeof(txt2), "devices %s to %s; ", rule->device_in, rule->device_out);
+
+ g_strlcat(txt, txt2, sizeof(txt));
+ }
+ }
+
+ if (rule->match & MATCH_TYPE) {
+ if (rule->protocol == IPPROTO_ICMP)
+ snprintf(txt2, sizeof(txt2), "protocol ICMP; type %s; ", icmp_type_str(rule->icmp_type));
+ else
+ snprintf(txt2, sizeof(txt2), "protocol %s; port %u; ", rule->protocol == IPPROTO_TCP ? "TCP" : "UDP", rule->port);
+
+ g_strlcat(txt, txt2, sizeof(txt));
+ }
+
+ if (rule->match & MATCH_SOURCE) {
+ if (rule->src_netmask_bits < 32)
+ snprintf(txt2, sizeof(txt2), "from %s/%i; ", format_ip_address(rule->src_ip_address), rule->src_netmask_bits);
+ else
+ snprintf(txt2, sizeof(txt2), "from %s; ", format_ip_address(rule->src_ip_address));
+
+ g_strlcat(txt, txt2, sizeof(txt));
+ }
+
+ if (rule->match & MATCH_DESTINATION) {
+ if (rule->dst_netmask_bits < 32)
+ snprintf(txt2, sizeof(txt2), "to %s/%i; ", format_ip_address(rule->dst_ip_address), rule->dst_netmask_bits);
+ else
+ snprintf(txt2, sizeof(txt2), "to %s; ", format_ip_address(rule->dst_ip_address));
+ g_strlcat(txt, txt2, sizeof(txt));
+ }
+
+ if (rule->match & MATCH_BROADCAST)
+ g_strlcat(txt, "broadcast; ", sizeof(txt));
+
+ if (rule->match & MATCH_UNICAST)
+ g_strlcat(txt, "unicast; ", sizeof(txt));
+
+
+ if ((l = strlen(txt)) > 2) {
+ txt[l-2] = 0;
+ return txt;
+ } else
+ return "all";
+}
+
+int rule_to_xml(rule_t*rule, xmlDocPtr doc, xmlNodePtr parent) {
+ static char txt[256];
+
+ xmlNodePtr node = NULL;
+
+ if (!(node = xmlNewDocNode(doc, NULL, "rule", NULL)))
+ goto finish;
+
+ snprintf(txt, sizeof(txt), "%u", rule->id);
+ xmlNewProp(node, "id", txt);
+
+ xmlNewTextChild(node, NULL, "description", rule->description);
+
+ if (!rule->enabled)
+ xmlNewTextChild(node, NULL, "disabled", NULL);
+
+ xmlNewTextChild(node, NULL, "target", format_verdict(rule->verdict, FORMAT_XML));
+
+ if (rule->match & MATCH_DIRECTION) {
+
+ xmlNewTextChild(node, NULL, "direction", rule->direction == DIR_INCOMING ? "incoming" : (rule->direction == DIR_OUTGOING ? "outgoing" : "passing"));
+
+ if (rule->match & MATCH_INTERFACES) {
+ if ((rule->direction == DIR_INCOMING || rule->direction == DIR_PASSING) && rule->device_in[0])
+ xmlNewTextChild(node, NULL, "input-device", rule->device_in);
+ else if ((rule->direction == DIR_OUTGOING || rule->direction == DIR_PASSING) && rule->device_out[0])
+ xmlNewTextChild(node, NULL, "output-device", rule->device_out);
+ }
+ }
+
+ if (rule->match & MATCH_TYPE) {
+ xmlNewTextChild(node, NULL, "protocol", rule->protocol == IPPROTO_UDP ? "udp" : (rule->protocol == IPPROTO_ICMP ? "icmp" : "tcp"));
+
+ if (rule->protocol == IPPROTO_ICMP) {
+ snprintf(txt, sizeof(txt), "%u", rule->icmp_type);
+ xmlNewTextChild(node, NULL, "icmp-type", txt);
+ } else {
+ snprintf(txt, sizeof(txt), "%u", rule->port);
+ xmlNewTextChild(node, NULL, "destination-port", txt);
+ }
+ }
+
+ if (rule->match & MATCH_SOURCE) {
+ xmlNewTextChild(node, NULL, "source", format_ip_address(rule->src_ip_address));
+ if (rule->src_netmask_bits < 32) {
+ snprintf(txt, sizeof(txt), "%u", rule->src_netmask_bits);
+ xmlNewTextChild(node, NULL, "source-netmask-bits", txt);
+ }
+ }
+
+ if (rule->match & MATCH_DESTINATION) {
+ xmlNewTextChild(node, NULL, "destination", format_ip_address(rule->dst_ip_address));
+ if (rule->dst_netmask_bits < 32) {
+ snprintf(txt, sizeof(txt), "%u", rule->dst_netmask_bits);
+ xmlNewTextChild(node, NULL, "destination-netmask-bits", txt);
+ }
+ } else if (rule->match & MATCH_BROADCAST)
+ xmlNewTextChild(node, NULL, "broadcast", NULL);
+ else if (rule->match & MATCH_UNICAST)
+ xmlNewTextChild(node, NULL, "unicast", NULL);
+
+
+ xmlAddChild(parent, node);
+ return 0;
+
+finish:
+ if (node)
+ xmlFreeNode(node);
+
+ return -1;
+}