/* * * Copyright (c) 2011-2016 The University of Waikato, Hamilton, New Zealand. * All rights reserved. * * This file is part of libprotoident. * * This code has been developed by the University of Waikato WAND * research group. For further information please see http://www.wand.net.nz/ * * libprotoident is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * libprotoident is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * */ #define __STDC_FORMAT_MACROS #define __STDC_LIMIT_MACROS #include #include //#include #include #include #include #include #include #include "libprotoident.h" #include "proto_manager.h" bool init_called = false; LPIModuleMap TCP_protocols; LPIModuleMap UDP_protocols; lpi_module_t *lpi_icmp = NULL; lpi_module_t *lpi_unsupported = NULL; lpi_module_t *lpi_unknown_tcp = NULL; lpi_module_t *lpi_unknown_udp = NULL; static LPINameMap lpi_names; static LPIProtocolMap lpi_protocols; static LPICategoryMap lpi_categories; static LPICategoryProtocolMap lpi_category_protocols; int lpi_init_library(int level) { if (init_called) { fprintf(stderr, "WARNING: lpi_init_library has already been called\n"); return 0; } if (register_tcp_protocols(&TCP_protocols) == -1) return -1; if (register_udp_protocols(&UDP_protocols) == -1) return -1; init_other_protocols(&lpi_names, &lpi_protocols, &lpi_category_protocols); register_names(&TCP_protocols, &lpi_names, &lpi_protocols, &lpi_category_protocols); register_names(&UDP_protocols, &lpi_names, &lpi_protocols, &lpi_category_protocols); register_category_names(&lpi_categories); init_called = true; if (TCP_protocols.empty() && UDP_protocols.empty()) { fprintf(stderr, "WARNING: No protocol modules loaded\n"); return -1; } return 0; } void lpi_free_library() { free_protocols(&TCP_protocols); free_protocols(&UDP_protocols); if (lpi_icmp != NULL) { delete lpi_icmp; lpi_icmp = NULL; } if (lpi_unsupported != NULL) { delete lpi_unsupported; lpi_unsupported = NULL; } if (lpi_unknown_tcp != NULL) { delete lpi_unknown_tcp; lpi_unknown_tcp = NULL; } if (lpi_unknown_udp != NULL) { delete lpi_unknown_udp; lpi_unknown_udp = NULL; } init_called = false; } void lpi_init_data(lpi_data_t *data) { data->payload[0] = 0; data->payload[1] = 0; data->seen_syn[0] = false; data->seen_syn[1] = false; data->seqno[0] = 0; data->seqno[1] = 0; data->observed[0] = 0; data->observed[1] = 0; data->server_port = 0; data->client_port = 0; data->trans_proto = 0; data->payload_len[0] = 0; data->payload_len[1] = 0; data->ips[0] = 0; data->ips[1] = 0; } typedef enum { TRACE_IPPROTO_IP = 0, /**< IP pseudo protocol number */ TRACE_IPPROTO_ICMP = 1, /**< Internet Control Message protocol */ TRACE_IPPROTO_IGMP = 2, /**< Internet Group Management Protocol */ TRACE_IPPROTO_IPIP = 4, /**< IP encapsulated in IP */ TRACE_IPPROTO_TCP = 6, /**< Transmission Control Protocol */ TRACE_IPPROTO_UDP = 17, /**< User Datagram Protocol */ TRACE_IPPROTO_IPV6 = 41, /**< IPv6 over IPv4 */ TRACE_IPPROTO_ROUTING = 43, /**< IPv6 Routing header */ TRACE_IPPROTO_FRAGMENT = 44, /**< IPv6 Fragmentation header */ TRACE_IPPROTO_RSVP = 46, /**< Resource Reservation Protocol */ TRACE_IPPROTO_GRE = 47, /**< General Routing Encapsulation */ TRACE_IPPROTO_ESP = 50, /**< Encapsulated Security Payload [RFC2406] */ TRACE_IPPROTO_AH = 51, /**< Authentication Header [RFC2402] */ TRACE_IPPROTO_ICMPV6 = 58, /**< ICMPv6 */ TRACE_IPPROTO_NONE = 59, /**< IPv6 no next header */ TRACE_IPPROTO_DSTOPTS = 60, /**< IPv6 destination options */ TRACE_IPPROTO_OSPF = 89, /**< Open Shortest Path First routing protocol */ TRACE_IPPROTO_PIM = 103, /**< Protocol Independant Multicast */ TRACE_IPPROTO_SCTP = 132 /**< Stream Control Transmission Protocol */ } libtrace_ipproto_t; static lpi_module_t *test_protocol_list(LPIModuleList *ml, lpi_data_t *data) { LPIModuleList::iterator l_it; /* Turns out naively looping through the modules is quicker * than trying to do intelligent stuff with threads. Most * callbacks complete very quickly so threading overhead is a * major problem */ for (l_it = ml->begin(); l_it != ml->end(); ++ l_it) { lpi_module_t *module = *l_it; /* To save time, I'm going to break on the first successful * match. A threaded version would wait for all the modules * to run, storing all successful results in a list of some * sort and selecting an appropriate result from there. */ if (module->lpi_callback(data, module)) return module; } return NULL; } static lpi_module_t *guess_protocol(LPIModuleMap *modmap, lpi_data_t *data) { lpi_module_t *proto = NULL; LPIModuleMap::iterator m_it; /* Deal with each priority in turn - want to match higher priority * rules first. */ for (m_it = modmap->begin(); m_it != modmap->end(); ++ m_it) { LPIModuleList *ml = m_it->second; proto = test_protocol_list(ml, data); if (proto != NULL) break; } return proto; } lpi_module_t *lpi_guess_protocol(lpi_data_t *data) { lpi_module_t *p = NULL; if (!init_called) { fprintf(stderr, "lpi_init_library was never called - cannot guess the protocol\n"); return NULL; } switch(data->trans_proto) { case TRACE_IPPROTO_ICMP: return lpi_icmp; case TRACE_IPPROTO_TCP: p = guess_protocol(&TCP_protocols, data); if (p == NULL) p = lpi_unknown_tcp; return p; case TRACE_IPPROTO_UDP: p = guess_protocol(&UDP_protocols, data); if (p == NULL) p = lpi_unknown_udp; return p; default: return lpi_unsupported; } return p; } lpi_category_t lpi_categorise(lpi_module_t *module) { if (module == NULL) return LPI_CATEGORY_NO_CATEGORY; return module->category; } const char *lpi_print_category(lpi_category_t category) { switch(category) { case LPI_CATEGORY_WEB: return "Web"; case LPI_CATEGORY_MAIL: return "Mail"; case LPI_CATEGORY_CHAT: return "Chat"; case LPI_CATEGORY_P2P: return "P2P"; case LPI_CATEGORY_P2P_STRUCTURE: return "P2P_Structure"; case LPI_CATEGORY_KEY_EXCHANGE: return "Key_Exchange"; case LPI_CATEGORY_ECOMMERCE: return "ECommerce"; case LPI_CATEGORY_GAMING: return "Gaming"; case LPI_CATEGORY_ENCRYPT: return "Encryption"; case LPI_CATEGORY_MONITORING: return "Measurement"; case LPI_CATEGORY_NEWS: return "News"; case LPI_CATEGORY_MALWARE: return "Malware"; case LPI_CATEGORY_SECURITY: return "Security"; case LPI_CATEGORY_ANTISPAM: return "Antispam"; case LPI_CATEGORY_VOIP: return "VOIP"; case LPI_CATEGORY_TUNNELLING: return "Tunnelling"; case LPI_CATEGORY_NAT: return "NAT_Traversal"; case LPI_CATEGORY_STREAMING: return "Streaming"; case LPI_CATEGORY_SERVICES: return "Services"; case LPI_CATEGORY_DATABASES: return "Databases"; case LPI_CATEGORY_FILES: return "File_Transfer"; case LPI_CATEGORY_REMOTE: return "Remote_Access"; case LPI_CATEGORY_TELCO: return "Telco_Services"; case LPI_CATEGORY_P2PTV: return "P2PTV"; case LPI_CATEGORY_RCS: return "Revision_Control"; case LPI_CATEGORY_LOGGING: return "Logging"; case LPI_CATEGORY_PRINTING: return "Printing"; case LPI_CATEGORY_TRANSLATION: return "Translation"; case LPI_CATEGORY_CDN: return "CDN"; case LPI_CATEGORY_CLOUD: return "Cloud"; case LPI_CATEGORY_NOTIFICATION: return "Notification"; case LPI_CATEGORY_SERIALISATION: return "Serialisation"; case LPI_CATEGORY_BROADCAST: return "Broadcast"; case LPI_CATEGORY_LOCATION: return "Location"; case LPI_CATEGORY_CACHING: return "Caching"; case LPI_CATEGORY_ICS: return "ICS"; case LPI_CATEGORY_MOBILE_APP: return "Mobile App"; case LPI_CATEGORY_IPCAMERAS: return "IP Cameras"; case LPI_CATEGORY_EDUCATIONAL: return "Educational"; case LPI_CATEGORY_MESSAGE_QUEUE: return "Message_Queuing"; case LPI_CATEGORY_ICMP: return "ICMP"; case LPI_CATEGORY_MIXED: return "Mixed"; case LPI_CATEGORY_NOPAYLOAD: return "No_Payload"; case LPI_CATEGORY_UNKNOWN: return "Unknown"; case LPI_CATEGORY_UNSUPPORTED: return "Unsupported"; case LPI_CATEGORY_NO_CATEGORY: return "Uncategorised"; case LPI_CATEGORY_LAST: return "Invalid_Category"; } return "Invalid_Category"; } const char *lpi_print(lpi_protocol_t proto) { LPINameMap::iterator it; it = lpi_names.find(proto); if (it == lpi_names.end()) { return "NULL"; } return (it->second); } lpi_protocol_t lpi_get_protocol_by_name(char *name) { LPIProtocolMap::iterator it; it = lpi_protocols.find(name); if (it == lpi_protocols.end()) { return LPI_PROTO_UNKNOWN; } return (it->second); } lpi_category_t lpi_get_category_by_name(char *name) { LPICategoryMap::iterator it; it = lpi_categories.find(name); if (it == lpi_categories.end()) { return LPI_CATEGORY_UNKNOWN; } return (it->second); } lpi_category_t lpi_get_category_by_protocol(lpi_protocol_t protocol) { LPICategoryProtocolMap::iterator it; it = lpi_category_protocols.find(protocol); if (it == lpi_category_protocols.end()) { return LPI_CATEGORY_UNKNOWN; } return (it->second); } bool lpi_is_protocol_inactive(lpi_protocol_t proto) { LPINameMap::iterator it; it = lpi_names.find(proto); if (it == lpi_names.end()) { return true; } return false; }