X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/4271ab433cd55bbd2612292bcf39e4dc3d7274f1..0907aa4037b12b6b88ee24495d4577a064d4f8db:/projects/stargazer/plugins/capture/cap_nf/cap_nf.cpp diff --git a/projects/stargazer/plugins/capture/cap_nf/cap_nf.cpp b/projects/stargazer/plugins/capture/cap_nf/cap_nf.cpp new file mode 100644 index 00000000..817ed715 --- /dev/null +++ b/projects/stargazer/plugins/capture/cap_nf/cap_nf.cpp @@ -0,0 +1,441 @@ +/* + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* +Date: 16.05.2008 +*/ + +/* +* Author : Maxim Mamontov +*/ + +/* +$Revision: 1.11 $ +$Date: 2010/09/10 06:41:06 $ +$Author: faust $ +*/ + +#include "cap_nf.h" + +#include "stg/common.h" +#include "stg/raw_ip_packet.h" +#include "stg/traffcounter.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace +{ + +struct NF_HEADER { + uint16_t version; // Protocol version + uint16_t count; // Flows count + uint32_t uptime; // System uptime + uint32_t timestamp; // UNIX timestamp + uint32_t nsecs; // Residual nanoseconds + uint32_t flowSeq; // Sequence counter + uint8_t eType; // Engine type + uint8_t eID; // Engine ID + uint16_t sInterval; // Sampling mode and interval +}; + +struct NF_DATA { + uint32_t srcAddr; // Flow source address + uint32_t dstAddr; // Flow destination address + uint32_t nextHop; // IP addres on next hop router + uint16_t inSNMP; // SNMP index of input iface + uint16_t outSNMP; // SNMP index of output iface + uint32_t packets; // Packets in flow + uint32_t octets; // Total number of bytes in flow + uint32_t timeStart; // Uptime on first packet in flow + uint32_t timeFinish;// Uptime on last packet in flow + uint16_t srcPort; // Flow source port + uint16_t dstPort; // Flow destination port + uint8_t pad1; // 1-byte padding + uint8_t TCPFlags; // Cumulative OR of TCP flags + uint8_t proto; // IP protocol type (tcp, udp, etc.) + uint8_t tos; // IP Type of Service (ToS) + uint16_t srcAS; // Source BGP autonomous system number + uint16_t dstAS; // Destination BGP autonomus system number + uint8_t srcMask; // Source address mask in "slash" notation + uint8_t dstMask; // Destination address mask in "slash" notation + uint16_t pad2; // 2-byte padding +}; + +#define BUF_SIZE (sizeof(NF_HEADER) + 30 * sizeof(NF_DATA)) + +} + +extern "C" STG::Plugin* GetPlugin() +{ + static NF_CAP plugin; + return &plugin; +} + +NF_CAP::NF_CAP() + : traffCnt(NULL), + runningTCP(false), + runningUDP(false), + stoppedTCP(true), + stoppedUDP(true), + portT(0), + portU(0), + sockTCP(-1), + sockUDP(-1), + logger(STG::PluginLogger::get("cap_nf")) +{ +} + +int NF_CAP::ParseSettings() +{ +std::vector::iterator it; +for (it = settings.moduleParams.begin(); it != settings.moduleParams.end(); ++it) + { + if (it->param == "TCPPort" && !it->value.empty()) + { + if (str2x(it->value[0], portT)) + { + errorStr = "Invalid TCPPort value"; + printfd(__FILE__, "Error: Invalid TCPPort value\n"); + return -1; + } + continue; + } + if (it->param == "UDPPort" && !it->value.empty()) + { + if (str2x(it->value[0], portU)) + { + errorStr = "Invalid UDPPort value"; + printfd(__FILE__, "Error: Invalid UDPPort value\n"); + return -1; + } + continue; + } + printfd(__FILE__, "'%s' is not a valid module param\n", it->param.c_str()); + } +return 0; +} + +int NF_CAP::Start() +{ +if (portU > 0) + { + if (OpenUDP()) + { + return -1; + } + runningUDP = true; + if (pthread_create(&tidUDP, NULL, RunUDP, this)) + { + runningUDP = false; + CloseUDP(); + errorStr = "Cannot create UDP thread"; + logger("Cannot create UDP thread."); + printfd(__FILE__, "Error: Cannot create UDP thread\n"); + return -1; + } + } +if (portT > 0) + { + if (OpenTCP()) + { + return -1; + } + runningTCP = true; + if (pthread_create(&tidTCP, NULL, RunTCP, this)) + { + runningTCP = false; + CloseTCP(); + logger("Cannot create TCP thread."); + errorStr = "Cannot create TCP thread"; + printfd(__FILE__, "Error: Cannot create TCP thread\n"); + return -1; + } + } +return 0; +} + +int NF_CAP::Stop() +{ +runningTCP = runningUDP = false; +if (portU && !stoppedUDP) + { + CloseUDP(); + for (int i = 0; i < 25 && !stoppedUDP; ++i) + { + struct timespec ts = {0, 200000000}; + nanosleep(&ts, NULL); + } + if (stoppedUDP) + { + pthread_join(tidUDP, NULL); + } + else + { + if (pthread_kill(tidUDP, SIGUSR1)) + { + errorStr = "Error sending signal to UDP thread"; + logger("Error sending sugnal to UDP thread."); + printfd(__FILE__, "Error: Error sending signal to UDP thread\n"); + return -1; + } + printfd(__FILE__, "UDP thread NOT stopped\n"); + logger("Cannot stop UDP thread."); + } + } +if (portT && !stoppedTCP) + { + CloseTCP(); + for (int i = 0; i < 25 && !stoppedTCP; ++i) + { + struct timespec ts = {0, 200000000}; + nanosleep(&ts, NULL); + } + if (stoppedTCP) + { + pthread_join(tidTCP, NULL); + } + else + { + if (pthread_kill(tidTCP, SIGUSR1)) + { + errorStr = "Error sending signal to TCP thread"; + logger("Error sending signal to TCP thread."); + printfd(__FILE__, "Error: Error sending signal to TCP thread\n"); + return -1; + } + printfd(__FILE__, "TCP thread NOT stopped\n"); + logger("Cannot stop TCP thread."); + } + } +return 0; +} + +bool NF_CAP::OpenUDP() +{ +struct sockaddr_in sin; +sockUDP = socket(PF_INET, SOCK_DGRAM, 0); +if (sockUDP <= 0) + { + errorStr = "Error opening UDP socket"; + logger("Cannot create UDP socket: %s", strerror(errno)); + printfd(__FILE__, "Error: Error opening UDP socket\n"); + return true; + } +sin.sin_family = AF_INET; +sin.sin_port = htons(portU); +sin.sin_addr.s_addr = inet_addr("0.0.0.0"); +if (bind(sockUDP, (struct sockaddr *)&sin, sizeof(sin))) + { + errorStr = "Error binding UDP socket"; + logger("Cannot bind UDP socket: %s", strerror(errno)); + printfd(__FILE__, "Error: Error binding UDP socket\n"); + return true; + } +return false; +} + +bool NF_CAP::OpenTCP() +{ +struct sockaddr_in sin; +sockTCP = socket(PF_INET, SOCK_STREAM, 0); +if (sockTCP <= 0) + { + errorStr = "Error opening TCP socket"; + logger("Cannot create TCP socket: %s", strerror(errno)); + printfd(__FILE__, "Error: Error opening TCP socket\n"); + return true; + } +sin.sin_family = AF_INET; +sin.sin_port = htons(portT); +sin.sin_addr.s_addr = inet_addr("0.0.0.0"); +if (bind(sockTCP, (struct sockaddr *)&sin, sizeof(sin))) + { + errorStr = "Error binding TCP socket"; + logger("Cannot bind TCP socket: %s", strerror(errno)); + printfd(__FILE__, "Error: Error binding TCP socket\n"); + return true; + } +if (listen(sockTCP, 1)) + { + errorStr = "Error listening on TCP socket"; + logger("Cannot listen on TCP socket: %s", strerror(errno)); + printfd(__FILE__, "Error: Error listening TCP socket\n"); + return true; + } +return false; +} + +void * NF_CAP::RunUDP(void * c) +{ +sigset_t signalSet; +sigfillset(&signalSet); +pthread_sigmask(SIG_BLOCK, &signalSet, NULL); + +NF_CAP * cap = static_cast(c); +cap->stoppedUDP = false; +while (cap->runningUDP) + { + if (!WaitPackets(cap->sockUDP)) + { + continue; + } + + // Data + struct sockaddr_in sin; + socklen_t slen = sizeof(sin); + uint8_t buf[BUF_SIZE]; + ssize_t res = recvfrom(cap->sockUDP, buf, BUF_SIZE, 0, reinterpret_cast(&sin), &slen); + if (!cap->runningUDP) + break; + + if (res < 0) + { + cap->logger("recvfrom error: %s", strerror(errno)); + continue; + } + + if (res == 0) // EOF + { + continue; + } + + if (res < 24) + { + if (errno != EINTR) + { + cap->errorStr = "Invalid data received"; + printfd(__FILE__, "Error: Invalid data received through UDP\n"); + } + continue; + } + + cap->ParseBuffer(buf, res); + } +cap->stoppedUDP = true; +return NULL; +} + +void * NF_CAP::RunTCP(void * c) +{ +sigset_t signalSet; +sigfillset(&signalSet); +pthread_sigmask(SIG_BLOCK, &signalSet, NULL); + +NF_CAP * cap = static_cast(c); +cap->stoppedTCP = false; +while (cap->runningTCP) + { + if (!WaitPackets(cap->sockTCP)) + { + continue; + } + + // Data + struct sockaddr_in sin; + socklen_t slen = sizeof(sin); + int sd = accept(cap->sockTCP, reinterpret_cast(&sin), &slen); + if (!cap->runningTCP) + break; + + if (sd <= 0) + { + if (sd < 0) + cap->logger("accept error: %s", strerror(errno)); + continue; + } + + if (!WaitPackets(sd)) + { + close(sd); + continue; + } + + uint8_t buf[BUF_SIZE]; + ssize_t res = recv(sd, buf, BUF_SIZE, MSG_WAITALL); + + if (res < 0) + cap->logger("recv error: %s", strerror(errno)); + + close(sd); + + if (!cap->runningTCP) + break; + + if (res == 0) // EOF + { + continue; + } + + // Wrong logic! + // Need to check actual data length and wait all data to receive + if (res < 24) + { + continue; + } + + cap->ParseBuffer(buf, res); + } +cap->stoppedTCP = true; +return NULL; +} + +void NF_CAP::ParseBuffer(uint8_t * buf, ssize_t size) +{ +STG::RawPacket ip; +NF_HEADER * hdr = reinterpret_cast(buf); +if (htons(hdr->version) != 5) + { + return; + } + +int packets = htons(hdr->count); + +if (packets < 0 || packets > 30) + { + return; + } + +if (24 + 48 * packets != size) + { + // See 'wrong logic' upper + return; + } + +for (int i = 0; i < packets; ++i) + { + NF_DATA * data = reinterpret_cast(buf + 24 + i * 48); + + ip.rawPacket.header.ipHeader.ip_v = 4; + ip.rawPacket.header.ipHeader.ip_hl = 5; + ip.rawPacket.header.ipHeader.ip_p = data->proto; + ip.dataLen = ntohl(data->octets); + ip.rawPacket.header.ipHeader.ip_src.s_addr = data->srcAddr; + ip.rawPacket.header.ipHeader.ip_dst.s_addr = data->dstAddr; + ip.rawPacket.header.sPort = data->srcPort; + ip.rawPacket.header.dPort = data->dstPort; + + traffCnt->process(ip); + } +}