446 lines
12 KiB
C
446 lines
12 KiB
C
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <pcap.h>
|
|
#include <netinet/if_ether.h>
|
|
#include <netinet/ip.h>
|
|
#include <netinet/udp.h>
|
|
#include <netinet/tcp.h>
|
|
#include <netinet/ip_icmp.h>
|
|
#include <search.h>
|
|
|
|
// Global structures
|
|
struct scanTypes
|
|
{
|
|
u_int connect;
|
|
u_int null;
|
|
u_int halfOpen;
|
|
u_int udp;
|
|
u_int attemptedScans;
|
|
u_int xmas;
|
|
} scansInFile;
|
|
|
|
struct scanTypesBools
|
|
{
|
|
bool connect;
|
|
bool null;
|
|
bool halfOpen;
|
|
bool udp;
|
|
bool attemptedScans;
|
|
bool xmas;
|
|
};
|
|
|
|
struct tcpFlagsSet
|
|
{
|
|
bool ACK;
|
|
bool SYN;
|
|
bool SYN_ACK;
|
|
bool RST_ACK;
|
|
bool FIN;
|
|
bool RST;
|
|
bool PSH;
|
|
bool URG;
|
|
};
|
|
|
|
struct tcpDictionary
|
|
{
|
|
struct tcpFlagsSet tcpFlags;
|
|
int packetNumInGroup;
|
|
struct scanTypesBools scanTypes;
|
|
uint16_t srcPort;
|
|
uint16_t port;
|
|
uint16_t dstPort;
|
|
uint16_t srcIP;
|
|
uint16_t dstIP;
|
|
} currentTCPPacket;
|
|
struct udpPacket
|
|
{
|
|
uint16_t srcPort;
|
|
uint16_t port;
|
|
uint16_t dstPort;
|
|
uint16_t srcIP;
|
|
uint16_t dstIP;
|
|
} currentUDPPacket;
|
|
|
|
// Provided structures
|
|
struct pcap_pkthdr *pcapHeaderStruct;
|
|
struct ether_header *ethNetHeaderStruct;
|
|
struct ip *ipHeaderStruct;
|
|
struct tcphdr *tcpHeaderStruct;
|
|
struct udphdr *udpHeaderStruct;
|
|
struct icmphdr *icmpHeaderStruct;
|
|
|
|
// Functions
|
|
void myHandler(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
|
|
|
|
ENTRY *seachTable(int key);
|
|
|
|
void addToTable(int key, void *data);
|
|
|
|
void printScans();
|
|
|
|
// Global variables and constants
|
|
int *seqNums;
|
|
|
|
int connectScans = 0;
|
|
|
|
const int TCP_DICTIONARY_SIZE = 100000;
|
|
const char *ErrorMSG = "Must provide input file.\n";
|
|
|
|
|
|
uint8_t *shost;
|
|
uint8_t *dhost;
|
|
|
|
ENTRY *search;
|
|
ENTRY entry;
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
if (hcreate(TCP_DICTIONARY_SIZE) == 0)
|
|
{
|
|
printf("error");
|
|
hcreate(50000);
|
|
};
|
|
if (argc < 3)
|
|
{
|
|
printf("%s", ErrorMSG);
|
|
return 0;
|
|
}
|
|
|
|
seqNums = malloc(TCP_DICTIONARY_SIZE * TCP_DICTIONARY_SIZE * sizeof(int));
|
|
|
|
char errbuf[PCAP_ERRBUF_SIZE];
|
|
char *pcapFileName = argv[2];
|
|
|
|
pcap_t *pcapFile = pcap_open_offline(pcapFileName, errbuf);
|
|
|
|
pcap_loop(pcapFile, 0, myHandler, NULL);
|
|
|
|
/* And close the session */
|
|
pcap_close(pcapFile);
|
|
|
|
printScans();
|
|
}
|
|
|
|
void printScans()
|
|
{
|
|
printf("Null: %d\n", scansInFile.null);
|
|
printf("Xmas: %d\n", scansInFile.xmas);
|
|
printf("UDP: %d\n", scansInFile.udp);
|
|
printf("Half-open: %d\n", scansInFile.halfOpen);
|
|
printf("Connect: %d\n", scansInFile.connect);
|
|
printf("Attempted scans: %d\n", scansInFile.attemptedScans);
|
|
}
|
|
|
|
void myHandler(
|
|
u_char *args,
|
|
const struct pcap_pkthdr *header,
|
|
const u_char *packet)
|
|
{
|
|
/* First, lets make sure we have an IP packet */
|
|
struct ether_header *eth_header;
|
|
eth_header = (struct ether_header *)packet;
|
|
if (ntohs(eth_header->ether_type) != ETHERTYPE_IP)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const u_char *ip_header;
|
|
const u_char *tcp_header;
|
|
const u_char *udp_header;
|
|
const u_char *icmp_header;
|
|
const u_char *payload;
|
|
|
|
// Packet lengths
|
|
int ethHeaderLength = 14;
|
|
int ipHeaderLength;
|
|
int tcpHeaderLength;
|
|
int payloadLength;
|
|
|
|
ip_header = packet + ethHeaderLength;
|
|
|
|
ipHeaderLength = ((*ip_header) & 0x0F);
|
|
|
|
ipHeaderLength = ipHeaderLength * 4;
|
|
ipHeaderStruct = (struct iphdr *)ip_header;
|
|
// printf("%d\n", ipHeaderStruct->ip_id);
|
|
|
|
u_char protocol = *(ip_header + 9);
|
|
|
|
|
|
|
|
if ( protocol == IPPROTO_ICMP)
|
|
{
|
|
search = seachTable(currentUDPPacket.port);
|
|
|
|
struct udpPacket *prevUDPPacket;
|
|
if (search != NULL) prevUDPPacket = search->data;
|
|
scansInFile.udp--;
|
|
icmp_header = packet + ethHeaderLength + ipHeaderLength;
|
|
icmpHeaderStruct = (struct icmphdr *)icmp_header;
|
|
if (icmpHeaderStruct->type == ICMP_DEST_UNREACH)
|
|
{
|
|
scansInFile.attemptedScans++;
|
|
}
|
|
}
|
|
|
|
if (protocol == IPPROTO_UDP)
|
|
{
|
|
udp_header = packet + ethHeaderLength + ipHeaderLength;
|
|
udpHeaderStruct = (struct udphdr *)udp_header;
|
|
currentUDPPacket.port= ntohs(udpHeaderStruct->source);
|
|
addToTable(currentUDPPacket.port, ¤tUDPPacket);
|
|
if (udpHeaderStruct->uh_dport == 53)
|
|
{
|
|
return;
|
|
}
|
|
scansInFile.udp++;
|
|
return;
|
|
}
|
|
|
|
if (protocol != IPPROTO_TCP)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tcp_header = packet + ethHeaderLength + ipHeaderLength;
|
|
|
|
tcpHeaderLength = ((*(tcp_header + 12)) & 0xF0) >> 4;
|
|
|
|
tcpHeaderLength = tcpHeaderLength * 4;
|
|
tcpHeaderStruct = (struct tcphdr *)tcp_header;
|
|
|
|
|
|
const bool ACKflag = (tcpHeaderStruct->ack == 1);
|
|
const bool RSTflag = (tcpHeaderStruct->rst == 1);
|
|
const bool SYNflag = (tcpHeaderStruct->syn == 1);
|
|
const bool FINflag = (tcpHeaderStruct->fin == 1);
|
|
const bool PSHflag = (tcpHeaderStruct->fin == 1);
|
|
const bool URGflag = (tcpHeaderStruct->urg == 1);
|
|
const uint32_t tcpSEQ = tcpHeaderStruct->seq;
|
|
const uint32_t tcpACKSeq = tcpHeaderStruct->ack_seq;
|
|
|
|
currentTCPPacket.tcpFlags.ACK = ACKflag;
|
|
currentTCPPacket.tcpFlags.RST = RSTflag;
|
|
currentTCPPacket.tcpFlags.SYN = SYNflag;
|
|
currentTCPPacket.tcpFlags.FIN = FINflag;
|
|
currentTCPPacket.tcpFlags.PSH = PSHflag;
|
|
currentTCPPacket.tcpFlags.URG = URGflag;
|
|
|
|
/*
|
|
TCP SYN flag is set when connection is made and when server sends back SYN/ACK
|
|
|
|
ACK flag set when server sends back SYN/ACK, and when client sends response to SYN/ACK
|
|
|
|
TCP Half-open:
|
|
SYN, SYN/ACK, RST
|
|
Connect scan:
|
|
|
|
Open state:
|
|
SYN is first
|
|
SYN, ACK is second
|
|
RST is last
|
|
*/
|
|
|
|
search = seachTable(currentTCPPacket.port);
|
|
// printf("Packet Num: %d\n", currentTCPPacket.packetNumInGroup);
|
|
/*
|
|
returns a value when
|
|
|
|
|
|
*/
|
|
// first packet
|
|
|
|
const uint16_t srcPort = ntohs(tcpHeaderStruct->th_sport);
|
|
const uint16_t dstPort = ntohs(tcpHeaderStruct->th_dport);
|
|
// struct in_addr_t srcIP = ipHeaderStruct->ip_src.s_addr;
|
|
|
|
struct tcpDictionary *prevPacket;
|
|
if (search!=NULL) prevPacket = search->data;
|
|
|
|
|
|
if (search == NULL || srcPort == prevPacket->port
|
|
|| dstPort == prevPacket->port)
|
|
{
|
|
search = seachTable(currentTCPPacket.srcPort);
|
|
|
|
|
|
currentTCPPacket.packetNumInGroup = 0;
|
|
if (ACKflag || RSTflag)
|
|
{
|
|
return;
|
|
}
|
|
// start of packet for Half-open and Connect
|
|
if (SYNflag && !ACKflag && !RSTflag && !FINflag && !PSHflag && !URGflag)
|
|
{
|
|
currentTCPPacket.port = dstPort;
|
|
currentTCPPacket.packetNumInGroup = 1;
|
|
// hdestroy();
|
|
// hcreate(TCP_DICTIONARY_SIZE);
|
|
addToTable(currentTCPPacket.dstPort, ¤tTCPPacket);
|
|
return;
|
|
}
|
|
// else one of the other scans
|
|
else
|
|
{
|
|
if (FINflag)
|
|
{
|
|
// Xmas pattern
|
|
if (PSHflag && URGflag)
|
|
{
|
|
scansInFile.xmas++;
|
|
currentTCPPacket.port = dstPort;
|
|
currentTCPPacket.packetNumInGroup = 1;
|
|
addToTable(currentTCPPacket.port, ¤tTCPPacket);
|
|
return;
|
|
}
|
|
}
|
|
// NULL pattern
|
|
if (!SYNflag && !ACKflag &&
|
|
!RSTflag && !FINflag &&
|
|
!PSHflag && !URGflag)
|
|
{
|
|
currentTCPPacket.port = dstPort;
|
|
currentTCPPacket.packetNumInGroup = 1;
|
|
addToTable(currentTCPPacket.port, ¤tTCPPacket);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// printf("found\n");
|
|
// found packet
|
|
prevPacket = search->data;
|
|
|
|
currentTCPPacket.packetNumInGroup++;
|
|
// does last packet match X-Mas pattern?
|
|
if (prevPacket->tcpFlags.PSH &&
|
|
prevPacket->tcpFlags.FIN &&
|
|
prevPacket->tcpFlags.URG)
|
|
{
|
|
// printf("Run\n");
|
|
if (FINflag)
|
|
{
|
|
// Xmas pattern
|
|
if (PSHflag && URGflag)
|
|
{
|
|
// scansInFile.xmas++;
|
|
currentTCPPacket.port = dstPort;
|
|
currentTCPPacket.packetNumInGroup = 1;
|
|
addToTable(currentTCPPacket.port, ¤tTCPPacket);
|
|
return;
|
|
}
|
|
}
|
|
scansInFile.xmas++;
|
|
if (ACKflag && RSTflag)
|
|
{
|
|
scansInFile.xmas--;
|
|
scansInFile.attemptedScans++;
|
|
// printf("XMas\n");
|
|
currentTCPPacket.packetNumInGroup = 0;
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
// ACK and SYN current
|
|
else if (SYNflag && ACKflag &&
|
|
!RSTflag && !FINflag &&
|
|
!PSHflag && !URGflag)
|
|
{
|
|
currentTCPPacket.packetNumInGroup++;
|
|
if (prevPacket->tcpFlags.SYN && prevPacket->tcpFlags.ACK)
|
|
{
|
|
addToTable(currentTCPPacket.port, ¤tTCPPacket);
|
|
return;
|
|
}
|
|
addToTable(currentTCPPacket.port, ¤tTCPPacket);
|
|
return;
|
|
}
|
|
// ACK and SYN prev
|
|
// Connect and half-open
|
|
else if (prevPacket->tcpFlags.ACK && prevPacket->tcpFlags.SYN &&
|
|
!prevPacket->tcpFlags.FIN && !prevPacket->tcpFlags.PSH &&
|
|
!prevPacket->tcpFlags.RST && !prevPacket->tcpFlags.URG)
|
|
{
|
|
if (RSTflag){
|
|
scansInFile.halfOpen++;
|
|
addToTable(currentTCPPacket.port, ¤tTCPPacket);
|
|
currentTCPPacket.packetNumInGroup = 0;
|
|
return;
|
|
}
|
|
else if (ACKflag)
|
|
{
|
|
currentTCPPacket.packetNumInGroup++;
|
|
addToTable(currentTCPPacket.port, ¤tTCPPacket);
|
|
return;
|
|
}
|
|
}
|
|
// ACK prev
|
|
// Connect successful?
|
|
else if (prevPacket->tcpFlags.ACK && !prevPacket->tcpFlags.SYN &&
|
|
!prevPacket->tcpFlags.FIN && !prevPacket->tcpFlags.PSH &&
|
|
!prevPacket->tcpFlags.RST && !prevPacket->tcpFlags.URG)
|
|
{
|
|
// yes
|
|
if (RSTflag){
|
|
scansInFile.connect++;
|
|
currentTCPPacket.packetNumInGroup = 0;
|
|
return;
|
|
}
|
|
// no
|
|
else if (ACKflag)
|
|
{
|
|
currentTCPPacket.packetNumInGroup++;
|
|
addToTable(currentTCPPacket.port, ¤tTCPPacket);
|
|
return;
|
|
}
|
|
|
|
}
|
|
// ACK prev, SYN current
|
|
else if (SYNflag && !ACKflag && !RSTflag && !FINflag && !PSHflag && !URGflag && prevPacket->tcpFlags.ACK)
|
|
{
|
|
currentTCPPacket.packetNumInGroup++;
|
|
addToTable(currentTCPPacket.port, ¤tTCPPacket);
|
|
return;
|
|
}
|
|
|
|
// Filtered for
|
|
else if (!SYNflag && !ACKflag &&
|
|
!RSTflag && !FINflag &&
|
|
!PSHflag && !URGflag &&
|
|
prevPacket->tcpFlags.SYN)
|
|
{
|
|
scansInFile.attemptedScans++;
|
|
}
|
|
// scans for
|
|
else if (prevPacket->tcpFlags.SYN &&
|
|
!SYNflag && !ACKflag &&
|
|
RSTflag && !FINflag &&
|
|
!PSHflag && !URGflag)
|
|
{
|
|
return;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void addToTable(int key, void *data)
|
|
{
|
|
ENTRY dictionaryEntry;
|
|
char index[50];
|
|
sprintf(index, "%u", key);
|
|
dictionaryEntry.key = index;
|
|
dictionaryEntry.data = data;
|
|
hsearch(dictionaryEntry, ENTER);
|
|
}
|
|
|
|
ENTRY *seachTable(int key)
|
|
{
|
|
ENTRY dictionaryEntry;
|
|
char index[50];
|
|
sprintf(index, "%u", key);
|
|
dictionaryEntry.key = index;
|
|
ENTRY *search = hsearch(dictionaryEntry, FIND);
|
|
return search;
|
|
} |