#include #include #include #include #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; }