├── multi-platform ├── 420OS_mapping.txt ├── observations.txt ├── LiveFingerprinter.h ├── structures.h ├── HershelPlusOptimized.cpp ├── HershelPlus.cpp └── LiveFingerprinter.cpp ├── VSProject ├── x64 │ ├── Debug │ │ ├── HershelPlus.exe │ │ ├── HershelPlus.ilk │ │ └── HershelPlus.pdb │ └── Release │ │ ├── HershelPlus.exe │ │ ├── HershelPlus.iobj │ │ ├── HershelPlus.ipdb │ │ └── HershelPlus.pdb ├── HershelPlus │ ├── 420OS_mapping.txt │ ├── HershelPlus.vcxproj.filters │ ├── defines.h │ ├── HershelPlus.vcxproj │ ├── Main.cpp │ ├── HershelPlus.cpp │ ├── SimpleRNG.h │ ├── HershelPlusOptimized.cpp │ └── test_observations.txt └── HershelPlus.sln ├── LICENSE.md └── README.md /multi-platform/420OS_mapping.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk7/hershelplus/HEAD/multi-platform/420OS_mapping.txt -------------------------------------------------------------------------------- /VSProject/x64/Debug/HershelPlus.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk7/hershelplus/HEAD/VSProject/x64/Debug/HershelPlus.exe -------------------------------------------------------------------------------- /VSProject/x64/Debug/HershelPlus.ilk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk7/hershelplus/HEAD/VSProject/x64/Debug/HershelPlus.ilk -------------------------------------------------------------------------------- /VSProject/x64/Debug/HershelPlus.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk7/hershelplus/HEAD/VSProject/x64/Debug/HershelPlus.pdb -------------------------------------------------------------------------------- /VSProject/x64/Release/HershelPlus.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk7/hershelplus/HEAD/VSProject/x64/Release/HershelPlus.exe -------------------------------------------------------------------------------- /VSProject/x64/Release/HershelPlus.iobj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk7/hershelplus/HEAD/VSProject/x64/Release/HershelPlus.iobj -------------------------------------------------------------------------------- /VSProject/x64/Release/HershelPlus.ipdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk7/hershelplus/HEAD/VSProject/x64/Release/HershelPlus.ipdb -------------------------------------------------------------------------------- /VSProject/x64/Release/HershelPlus.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk7/hershelplus/HEAD/VSProject/x64/Release/HershelPlus.pdb -------------------------------------------------------------------------------- /VSProject/HershelPlus/420OS_mapping.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk7/hershelplus/HEAD/VSProject/HershelPlus/420OS_mapping.txt -------------------------------------------------------------------------------- /multi-platform/observations.txt: -------------------------------------------------------------------------------- 1 | 1,8192,128,1,MNWST,7331,1460,0,0,0,0,0.117824,3.123757,9.120044 2 | 2,5808,64,1,MNNSNW,60722,1412,0,0,0,0,0.260635,3.661139 3 | 3,5792,64,1,MSTNW,6386,1402,0,0,0,0,0.144287,3.542840,9.943425,22.742704,46.743477,94.746970 -------------------------------------------------------------------------------- /VSProject/HershelPlus.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HershelPlus", "HershelPlus\HershelPlus.vcxproj", "{2024AA81-9EB3-49F9-8D29-E676829465A5}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {2024AA81-9EB3-49F9-8D29-E676829465A5}.Debug|x64.ActiveCfg = Debug|x64 17 | {2024AA81-9EB3-49F9-8D29-E676829465A5}.Debug|x64.Build.0 = Debug|x64 18 | {2024AA81-9EB3-49F9-8D29-E676829465A5}.Debug|x86.ActiveCfg = Debug|Win32 19 | {2024AA81-9EB3-49F9-8D29-E676829465A5}.Debug|x86.Build.0 = Debug|Win32 20 | {2024AA81-9EB3-49F9-8D29-E676829465A5}.Release|x64.ActiveCfg = Release|x64 21 | {2024AA81-9EB3-49F9-8D29-E676829465A5}.Release|x64.Build.0 = Release|x64 22 | {2024AA81-9EB3-49F9-8D29-E676829465A5}.Release|x86.ActiveCfg = Release|Win32 23 | {2024AA81-9EB3-49F9-8D29-E676829465A5}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | LICENSE 2 | 3 | Copyright © 2017 IRL at Texas A&M University (http://irl.cse.tamu.edu) All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 9 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 11 | Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 14 | -------------------------------------------------------------------------------- /VSProject/HershelPlus/HershelPlus.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | 29 | 30 | Header Files 31 | 32 | 33 | Header Files 34 | 35 | 36 | -------------------------------------------------------------------------------- /VSProject/HershelPlus/defines.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CLASSES_H 3 | #define CLASSES_H 4 | 5 | #define OPT_MSS 1 // max segment size 6 | #define OPT_WIN 2 // window scaling 7 | #define OPT_TS 3 // timestamps 8 | #define OPT_SACK 4 // SACK allowed 9 | #define OPT_EOL 5 // end of list (another type of padding?) 10 | #define OPT_NOP 6 // padding 11 | 12 | #define REAL_DATA true 13 | 14 | #ifdef _DEBUG 15 | #define NUM_THREADS 1 16 | #else 17 | #define NUM_THREADS GetActiveProcessorCount(ALL_PROCESSOR_GROUPS) 18 | #endif 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #pragma comment(lib, "Ws2_32.lib") 30 | 31 | using namespace std; 32 | 33 | extern vector features_enabled; //booleans describing which features are enabled (RTO, WIN, TTL, DF, OPT, MSS, RST) 34 | extern map id_to_label_map; 35 | 36 | class Signature{ 37 | public: 38 | u_int id_classified; 39 | u_int id_int; 40 | int win; 41 | int ttl; 42 | int df; 43 | int rst; 44 | int rst_ack; 45 | int rst_win; 46 | int rst_seq; 47 | int rst_nonzero; 48 | int mss; 49 | char options_str[25]; 50 | unsigned long long options_int; 51 | vector packet_arrival_time; 52 | vector rto; 53 | double secondprob_norm; 54 | double maxprob_norm; 55 | //double T; 56 | //vector owd; 57 | 58 | Signature(){ 59 | win = 0; 60 | ttl = 0; 61 | df = 0; 62 | mss = 0; 63 | rst = 0; 64 | rst_ack = 0; 65 | rst_win = 0; 66 | rst_seq = 0; 67 | rst_nonzero = 0; 68 | options_int = 0; 69 | } 70 | }; 71 | 72 | 73 | static int factorial(int n){ 74 | return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n; 75 | } 76 | 77 | 78 | void HershelPlusOptimized_ST(map > database_sigs, vector observations); 79 | void HershelPlusOptimized_MT(map > database_sigs, vector observations); 80 | void HershelPlus_ST(map > database_sigs, vector observations); 81 | void HershelPlus_MT(map> database_sigs, vector observations); 82 | double MatchConstantFeatures(Signature& target, Signature& dbsig); 83 | 84 | #endif /* CLASSES_H */ -------------------------------------------------------------------------------- /multi-platform/LiveFingerprinter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Class definition for LiveFingerprinter 3 | * 4 | */ 5 | 6 | #define __STDC_WANT_LIB_EXT1__ 7 | #define _CRT_SECURE_NO_DEPRECATE 8 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 9 | 10 | 11 | 12 | using namespace std; 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "structures.h" 24 | #ifdef _WIN32 25 | #include 26 | #include 27 | 28 | #pragma comment(lib,"ws2_32.lib") //For winsock 29 | #pragma comment(lib,"iphlpapi.lib") //For iphlpapi 30 | #pragma comment(lib,"wpcap.lib") //For pcap 31 | 32 | 33 | //Define gettimeofday - Windows version 34 | //from https://gist.github.com/ugovaretto/5875385 35 | static int gettimeofday(struct timeval *tv, struct timezone *tz) 36 | { 37 | // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) 38 | // until 00:00:00 January 1, 1970 39 | static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); 40 | 41 | SYSTEMTIME system_time; 42 | FILETIME file_time; 43 | uint64_t time; 44 | 45 | GetSystemTime(&system_time); 46 | SystemTimeToFileTime(&system_time, &file_time); 47 | time = ((uint64_t)file_time.dwLowDateTime); 48 | time += ((uint64_t)file_time.dwHighDateTime) << 32; 49 | 50 | tv->tv_sec = (long)((time - EPOCH) / 10000000L); 51 | tv->tv_usec = (long)(system_time.wMilliseconds * 1000); 52 | return 0; 53 | } 54 | 55 | #else 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | 69 | struct route_info { 70 | u_int dstAddr; 71 | u_int srcAddr; 72 | u_int gateway; 73 | char ifName[IF_NAMESIZE]; 74 | }; 75 | 76 | #endif 77 | 78 | #include 79 | 80 | 81 | 82 | class LiveFingerprinter{ 83 | 84 | public: 85 | int setupPcapAdapter(); 86 | int getFingerprint(char* target, unsigned short port, Signature& sig); 87 | ~LiveFingerprinter(); 88 | 89 | private: 90 | unsigned short in_checksum(unsigned short *ptr,int nbytes); 91 | int createPacket(char *target, int target_port, int* srcPort, unsigned char *packet); 92 | int timeval_subtract(timeval *result, timeval *x, timeval *y); 93 | 94 | pcap_t* adapterHandle; 95 | char* adapterName; 96 | }; 97 | -------------------------------------------------------------------------------- /multi-platform/structures.h: -------------------------------------------------------------------------------- 1 | /* 2 | structures.h 3 | - Contains the structures for the IP TCP UDP version 4 headers for raw sockets 4 | can be used with IP_HDRINCL option with setsockopt 5 | */ 6 | 7 | class Signature{ 8 | public: 9 | unsigned int id_classified; 10 | unsigned int id; 11 | int win; 12 | int ttl; 13 | int df; 14 | int rst; 15 | int rst_ack; 16 | int rst_win; 17 | int rst_seq; 18 | int rst_nonzero; 19 | int mss; 20 | char options_str[25]; 21 | unsigned long long options_int; 22 | vector packet_arrival_time; 23 | 24 | Signature(){ 25 | id = 0; win = 0; ttl = 0; df = 0; rst = 0; rst_ack = 0; rst_win = 0; rst_seq = 0; rst_nonzero = 0; mss = 0; options_int = 0; 26 | } 27 | }; 28 | 29 | // Set the packing to a 1 byte boundary 30 | // #include "pshpack1.h" 31 | 32 | //Ethernet Header 33 | typedef struct ethernet_header 34 | { 35 | unsigned char dest[6]; 36 | unsigned char source[6]; 37 | unsigned short type; 38 | } ETHER_HDR, ETHERHeader; 39 | 40 | /* 41 | Define the IPv4 header. Make the version and length field one 42 | character since we can't declare two 4 bit fields without 43 | the compiler aligning them on at least a 1 byte boundary. 44 | */ 45 | 46 | typedef struct ip_hdr 47 | { 48 | unsigned char ip_header_len:4; // 4-bit header length (in 32-bit words) normally=5 (Means 20 Bytes may be 24 also) 49 | unsigned char ip_version :4; // 4-bit IPv4 version 50 | unsigned char ip_tos; // IP type of service 51 | unsigned short ip_total_length; // Total length 52 | unsigned short ip_id; // Unique identifier 53 | 54 | unsigned char ip_frag_offset :5; // Fragment offset field 55 | 56 | unsigned char ip_more_fragment :1; 57 | unsigned char ip_dont_fragment :1; 58 | unsigned char ip_reserved_zero :1; 59 | 60 | unsigned char ip_frag_offset1; //fragment offset 61 | 62 | unsigned char ip_ttl; // Time to live 63 | unsigned char ip_protocol; // Protocol(TCP,UDP etc) 64 | unsigned short ip_checksum; // IP checksum 65 | unsigned int ip_srcaddr; // Source address 66 | unsigned int ip_destaddr; // Source address 67 | } IP_HDR, IP_HEADER, IPHeader; 68 | 69 | 70 | //UDP header 71 | typedef struct udp_hdr 72 | { 73 | unsigned short source_port; // Source port no. 74 | unsigned short dest_port; // Dest. port no. 75 | unsigned short udp_length; // Udp packet length 76 | unsigned short udp_checksum; // Udp checksum (optional) 77 | } UDP_HDR, UDP_HEADER, UDPHeader; 78 | 79 | 80 | // TCP header 81 | typedef struct tcp_header 82 | { 83 | unsigned short source_port; // source port 84 | unsigned short dest_port; // destination port 85 | unsigned int sequence; // sequence number - 32 bits 86 | unsigned int acknowledge; // acknowledgement number - 32 bits 87 | 88 | unsigned char ns : 1; //Nonce Sum Flag Added in RFC 3540. 89 | unsigned char reserved_part1 : 3; //according to rfc 90 | unsigned char data_offset : 4; /*The number of 32-bit words in the TCP header. 91 | This indicates where the data begins. 92 | The length of the TCP header is always a multiple 93 | of 32 bits.*/ 94 | 95 | unsigned char fin : 1; //Finish Flag 96 | unsigned char syn : 1; //Synchronise Flag 97 | unsigned char rst : 1; //Reset Flag 98 | unsigned char psh : 1; //Push Flag 99 | unsigned char ack : 1; //Acknowledgement Flag 100 | unsigned char urg : 1; //Urgent Flag 101 | 102 | unsigned char ecn : 1; //ECN-Echo Flag 103 | unsigned char cwr : 1; //Congestion Window Reduced Flag 104 | 105 | //////////////////////////////// 106 | 107 | unsigned short window; // window 108 | unsigned short checksum; // checksum 109 | unsigned short urgent_pointer; // urgent pointer 110 | 111 | //Options 112 | unsigned int opt1; 113 | unsigned int opt2; 114 | unsigned int opt3; 115 | unsigned int opt4; 116 | unsigned int opt5; 117 | } TCP_HDR, TCP_HEADER, TCPHeader; 118 | 119 | typedef struct pseudo_header //needed for checksum calculation 120 | { 121 | unsigned int source_address; 122 | unsigned int dest_address; 123 | unsigned char placeholder; 124 | unsigned char protocol; 125 | unsigned short tcp_length; 126 | //char tcp[28]; 127 | TCP_HDR tcp; 128 | } PSEUDO_HDR , PSEUDO_HEADER, PseudoHeader; 129 | 130 | // Restore the byte boundary back to the previous value 131 | // #include 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hershel+ 2 | 3 | Hershel+ is an improved version of [Hershel](https://github.com/zk7/hershel), which is an OS fingerprinting algorithm that determines the OS of a remote host using a single outbound TCP SYN packet. To accomplish OS classification, Hershel+ uses several features from the IP/TCP headers as well as TCP retransmission timeouts (RTOs). The improvements of Hershel+ mainly revolve around the handling of the RTO feature, and experiments in our paper show it has superior accuracy to Hershel by up to 10% in just RTO classification. Similar to Hershel, this algorithm also allows standard header fields (e.g., TCP Window size, IP TTL, IP DF etc.) to exhibit volatility, i.e., a probability that a user changes these features. 4 | 5 | # Project files 6 | 7 | Hershel+ is written in C++. 8 | 9 | This repository includes two versions of Hershel+. The multi-platform version contains the main Hershel+ algorithm and should work on most systems. This version can be run in "live mode" or "offline mode". 10 | + Live Mode: Sends a TCP SYN packet to the target host/port, gathers a signature, and attempts to classify it. 11 | + Offline Mode: Reads an existing observations file and classifies all signatures using Hershel+. 12 | 13 | Compiling: 14 | - On Linux, Hershel+ was compiled on Ubuntu 17.04 using: 15 | 16 | `g++ HershelPlus.cpp LiveFingerprinter.cpp -lpcap -pthread` 17 | 18 | - On Windows, Hershel+ was compiled using VS2015. 19 | 20 | libpcap/Winpcap is required. The HershelPlusOptimized.cpp can be substituted for HershelPlus.cpp to run the optimized algorithm, but should not matter for a single observation in live mode or a small observation set in offline mode. 21 | 22 | Running: 23 | - Live Mode: `HershelPlus.exe database_file mapping_file IP port` 24 | **NOTE:** Running in Live mode requires your machine to allow half-open TCP connections. This means kernel generated RSTs need to be suppressed. 25 | - On Windows, the Windows firewall should do this by default. If not, create a custom rule to drop unsolicited SYN/ACKs 26 | - On Linux, inserting the following iptables rules should take care of this: 27 | `sudo iptables -t filter -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT` 28 | `sudo iptables -t filter -A INPUT -p icmp -j ACCEPT` 29 | `sudo iptables -t filter -A INPUT -i lo -j ACCEPT` 30 | `sudo iptables -t filter -A INPUT -j DROP` 31 | This accepts anything from established connections, icmp pings, and all traffic on the loopback interface. Everything else is dropped. 32 | - Offline Mode: `HershelPlus.exe database_file mapping_file observations_file` 33 | 34 | The Visual Studio project files use the Windows library for multi-threading and hence compile in Win32/64. It also includes the Hershel+ database and example signatures. This is likely the version you want to run if you have a large dataset. 35 | 36 | ### File structure 37 | 38 | The data files containing the OS and Internet signatures have mostly the same text format. For the files in the multi-platform folder, this is format: 39 | 40 | int id 41 | int tcp_window 42 | int ip_ttl 43 | int ip_df 44 | string tcp_options 45 | longlong tcp_options_encoded 46 | int mss 47 | int rst_present 48 | int rst_ack flag 49 | int rst_window 50 | int rst_nonzero 51 | double RTT (0 value for database) 52 | double RTO1_timestamp 53 | double RTO2_timestamp 54 | double RTO3_timestamp 55 | ... 56 | 57 | 420OS_db.txt contains the database signatures, 420OS_mapping.txt maps plain text labels to signature data in the database, and observations.txt contains sample observed signatures that are to be classified using the Hershel+ algorithm. 58 | 59 | 60 | # Publication 61 | ### Conference 62 | Z. Shamsi and D. Loguinov, "Unsupervised Clustering Under Temporal Feature Volatility in Network Stack Fingerprinting,", ACM SIGMETRICS, June 2016. 63 | 64 | @inproceedings{shamsi2016, 65 | title={Unsupervised Clustering Under Temporal Feature Volatility in Network Stack Fingerprinting}, 66 | author={Zain Shamsi and Dmitri Loguinov}, 67 | booktitle={ACM SIGMETRICS}, 68 | year={2016}, 69 | organization={ACM} 70 | location = {Antibes Juan-les-Pins, France}, 71 | pages = {127--138}, 72 | doi = {10.1145/2896377.2901449}, 73 | keywords = {internet measurement, os classification, device fingerprinting}, 74 | } 75 | 76 | [ACM Portal](http://dl.acm.org/citation.cfm?id=2901449) 77 | 78 | [Direct Paper Link](http://irl.cs.tamu.edu/people/zain/papers/sigmetrics2016.pdf) 79 | 80 | ### Journal 81 | Z. Shamsi and D. Loguinov, "Unsupervised Clustering Under Temporal Feature Volatility in Network Stack Fingerprinting," IEEE/ACM Transactions on Networking, vol. 25, no. 4, August 2017. 82 | 83 | @ARTICLE{shamsi2016, 84 | author={Zain Shamsi and Dmitri Loguinov}, 85 | journal={IEEE/ACM Transactions on Networking}, 86 | title={Unsupervised Clustering Under Temporal Feature Volatility in Network Stack Fingerprinting}, 87 | year={2017}, 88 | month={Aug}, 89 | volume={25}, 90 | number={4}, 91 | pages={2430-2443}, 92 | doi={10.1109/TNET.2017.2690641}, 93 | ISSN={1063-6692}, 94 | } 95 | 96 | [IEEE Xplore](http://ieeexplore.ieee.org/document/7902193/) 97 | 98 | [Direct Paper Link](http://irl.cs.tamu.edu/people/zain/papers/ton2017.pdf) 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /VSProject/HershelPlus/HershelPlus.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {2024AA81-9EB3-49F9-8D29-E676829465A5} 23 | Win32Proj 24 | HershelPlus 25 | 8.1 26 | 27 | 28 | 29 | Application 30 | true 31 | v140 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v140 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v140 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v140 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | 87 | 88 | Level3 89 | Disabled 90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 91 | true 92 | 93 | 94 | Console 95 | true 96 | 97 | 98 | 99 | 100 | 101 | 102 | Level3 103 | Disabled 104 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 105 | true 106 | 107 | 108 | Console 109 | true 110 | 111 | 112 | 113 | 114 | Level3 115 | 116 | 117 | MaxSpeed 118 | true 119 | true 120 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | 123 | 124 | Console 125 | true 126 | true 127 | true 128 | 129 | 130 | 131 | 132 | Level3 133 | 134 | 135 | MaxSpeed 136 | true 137 | true 138 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 139 | true 140 | 141 | 142 | Console 143 | true 144 | true 145 | true 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /VSProject/HershelPlus/Main.cpp: -------------------------------------------------------------------------------- 1 | //Hershel+ Parallel 2 | //Written by Zain Shamsi 3 | 4 | #include "defines.h" 5 | #include "SimpleRNG.h" 6 | 7 | 8 | //simulation parameters for sample generation 9 | #if _DEBUG 10 | #define TOTAL_NUM_DISTORTIONS (1 << 5) 11 | #else 12 | #define TOTAL_NUM_DISTORTIONS (1 << 18) 13 | #endif 14 | 15 | vector features_enabled = { 1, 1, 1, 1, 1, 1, 1 }; //booleans describing which features are enabled (RTO, WIN, TTL, DF, OPT, MSS, RST) 16 | map id_to_label_map; 17 | 18 | vector getRTOs(vector absolutes){ 19 | 20 | if (absolutes.size() > 1){ 21 | vector return_vector; 22 | double rto = 0; 23 | return_vector.push_back(absolutes[0]); //push back first packet right away 24 | for (int i = 1; i < absolutes.size(); i++){ 25 | rto = absolutes[i] - absolutes[i - 1]; //now calculate diff between this and last 26 | return_vector.push_back(rto); 27 | } 28 | return return_vector; 29 | } 30 | else return absolutes; 31 | } 32 | 33 | void printSignature(FILE* fout, Signature s){ 34 | fprintf(fout, "%u,%d,%d,%d,%llu,%d,%d,%d,%d,%d", s.id_int, 35 | s.win, s.ttl, s.df, s.options_int, s.mss, 36 | s.rst, s.rst_ack, s.rst_win, s.rst_nonzero); 37 | for (int m = 0; m < s.packet_arrival_time.size(); m++){ 38 | fprintf(fout, ",%f", s.packet_arrival_time[m]); 39 | } 40 | fprintf(fout, "\n"); 41 | } 42 | 43 | vector createDisturbedUniform(map >& database_sigs){ 44 | //creates samples uniformly distributed across OS and subOS 45 | map>::iterator it; 46 | vector disturbed_vectors; 47 | SimpleRNG srng; 48 | srng.SetState(time(NULL) % 7427, time(NULL)); 49 | 50 | for (int i = 0; i < TOTAL_NUM_DISTORTIONS; i++){ 51 | 52 | //pick subOS based on distribution 53 | int chosenOS = rand() % database_sigs.size(); 54 | 55 | it = database_sigs.begin(); 56 | advance(it, chosenOS); 57 | Signature randsubOS = it->second[rand() % it->second.size()]; 58 | 59 | Signature dos; 60 | dos.id_int = it->first; 61 | 62 | double qi = srng.GetUniform(); 63 | double T = srng.GetUniform(); 64 | 65 | dos.packet_arrival_time.push_back(T + qi); //RTT 66 | 67 | //create distortions of this sig's rto and add to array, start at 1 to skip first (0) 68 | for (int t = 1; t < randsubOS.packet_arrival_time.size(); t++){ 69 | qi = srng.GetExponential(0.5); 70 | 71 | double tau = max(T + randsubOS.packet_arrival_time[t] + qi, dos.packet_arrival_time.back()); //new arrival time = max(T + RTO-C + Q, last arrival) 72 | dos.packet_arrival_time.push_back(tau); 73 | 74 | } 75 | disturbed_vectors.push_back(dos); 76 | } 77 | 78 | 79 | printf("Created %d disturbed vectors\n", disturbed_vectors.size()); 80 | return disturbed_vectors; 81 | } 82 | 83 | vector createDisturbedZipf(map>& database_sigs, double T_mean, double owd_mean, double loss_prob){ 84 | //build sample observation data by disturbing database signatures. Only disturbs RTO 85 | //first build Zipf pmf 86 | vector ratios; 87 | double sum = 0; 88 | for (int j = 0; j < database_sigs.size(); j++){ 89 | ratios.push_back(1.0 / pow((j + 1), 1.2)); 90 | sum += ratios[j]; 91 | } 92 | 93 | //normalize ratio 94 | for (int i = 0; i < database_sigs.size(); i++){ 95 | ratios[i] /= sum; 96 | } 97 | 98 | vector ret_list; 99 | int loss_counter = 0; 100 | SimpleRNG srng; 101 | srng.SetState(time(NULL) % 7427, time(NULL)); 102 | //srng.SetState(5, 5); //seed set to same for testing 103 | 104 | //start backwards and generate samples 105 | map>::iterator it = database_sigs.begin(); 106 | for (int j = 0; it != database_sigs.end(); ++it, ++j){ 107 | 108 | int totalsamplesj = TOTAL_NUM_DISTORTIONS * ratios[j]; 109 | 110 | //cycle through subOSes until reached totalsamples 111 | for (int s = 0, i = 0; i < totalsamplesj; s = ((s + 1) % it->second.size()), i++){ 112 | 113 | bool loss_happened = false; 114 | Signature sig(it->second[s]); 115 | sig.packet_arrival_time.clear(); 116 | sig.maxprob_norm = 0; 117 | sig.id_classified = 0; 118 | 119 | //double T = srng.GetUniform(0.0, T_mean * 2); 120 | double T = srng.GetExponential(T_mean); 121 | //double T = srng.GetPareto(3, T_mean); 122 | 123 | //sig.T = T; 124 | 125 | for (int m = 0; m < it->second[s].packet_arrival_time.size(); m++){ 126 | double loss = srng.GetUniform(); 127 | double qi; 128 | qi = srng.GetExponential(owd_mean); //from http://tcp-reassembly-project.googlecode.com/files/jitter_model.pdf 129 | //qi = srng.GetPareto(3, owd_mean); 130 | //qi = srng.GetUniform(0.0, owd_mean * 2); 131 | 132 | 133 | if (loss >= loss_prob){ 134 | 135 | double departure = T + it->second[s].packet_arrival_time[m]; //departure of packet from server 136 | double arrival = departure + qi; //arrival of packet at client with OWD 137 | 138 | if (sig.packet_arrival_time.empty()){ 139 | //if no packets till now, push this one back as first packet 140 | sig.packet_arrival_time.push_back(arrival); 141 | } 142 | else { //check for FIFO ordering 143 | double last_arrival = sig.packet_arrival_time.back(); 144 | //if new packet arrived after arrival of last packet, add like normal 145 | //else, new packet arrived at same time or before arrival of last one, make arrival equal to last_arrival to preserve order 146 | //this effectively pushes 0 as the RTO 147 | if (arrival > last_arrival) sig.packet_arrival_time.push_back(arrival); 148 | else sig.packet_arrival_time.push_back(last_arrival); 149 | } 150 | } 151 | else { 152 | loss_happened = true; 153 | } 154 | } 155 | if (loss_happened) loss_counter++; 156 | 157 | //add signature if we have packets, if all were lost then dont add 158 | if (!sig.packet_arrival_time.empty()) 159 | ret_list.push_back(sig); 160 | else i--; 161 | } 162 | } 163 | 164 | printf("%d signatures created, %d with loss\n", ret_list.size(), loss_counter); 165 | 166 | return ret_list; 167 | } 168 | 169 | map> readDatabaseSigs(char *filename){ 170 | map> retmap; 171 | int sig_count = 0; 172 | int BUFFER_SIZE = (1 << 27); //128MB 173 | 174 | FILE* fin; 175 | 176 | int ret = fopen_s(&fin, filename, "r"); 177 | if (ret != 0){ 178 | printf("Error opening file %s!\n", filename); 179 | return retmap; 180 | } 181 | char* buffer = new char[BUFFER_SIZE]; 182 | int count, count_discard = 0; 183 | double ts = 0; 184 | u_int old_ip = 0; 185 | vector rtos; 186 | 187 | while (!feof(fin)){ 188 | Signature sig; 189 | 190 | //read next line 191 | fgets(buffer, BUFFER_SIZE, fin); 192 | char* bufferptr = buffer; 193 | 194 | sscanf_s(bufferptr, "%u,%d,%d,%d,%[^,],%llu,%d,%d,%d,%d,%d,%d%n", 195 | &sig.id_int, &sig.win, &sig.ttl, &sig.df, sig.options_str, _countof(sig.options_str), &sig.options_int, &sig.mss, &sig.rst, &sig.rst_ack, &sig.rst_win, &sig.rst_seq, &sig.rst_nonzero, &count); 196 | 197 | 198 | bufferptr += count; 199 | 200 | while (strcmp(bufferptr, "\n") != 0 && strlen(bufferptr) > 0){ 201 | sscanf_s(bufferptr, ",%lf%n", &ts, &count); 202 | sig.packet_arrival_time.push_back(ts); 203 | 204 | if (sig.packet_arrival_time.size() == 20) break; //limit to 20 packets 205 | 206 | bufferptr += count; 207 | } 208 | 209 | retmap[sig.id_int].push_back(sig); 210 | sig_count++; 211 | 212 | if (sig_count % 10000 == 0) printf("Read %d signatures...\r", sig_count); 213 | } 214 | 215 | fclose(fin); 216 | printf("\nStored %d database signatures\n", retmap.size()); 217 | return retmap; 218 | } 219 | 220 | map readLabels(char* filename){ 221 | map retmap; 222 | FILE* fin; 223 | int ret = fopen_s(&fin, filename, "r"); 224 | if (ret != 0){ 225 | printf("Error opening file %s!\n", filename); 226 | return retmap; 227 | } 228 | char* buffer = new char[1500]; 229 | 230 | while (!feof(fin)){ 231 | int id; 232 | char label[1500]; 233 | 234 | //read next line 235 | fgets(buffer, 1500, fin); 236 | sscanf_s(buffer, "%d,%[^\n]", &id, label, _countof(label)); 237 | 238 | retmap[id] = label; 239 | } 240 | 241 | printf("Stored %d ip->banner mappings\n", retmap.size()); 242 | return retmap; 243 | } 244 | 245 | vector readTestData(char* filename){ 246 | vector return_vector; 247 | int sig_count = 0; 248 | int BUFFER_SIZE = (1 << 27); //128MB 249 | 250 | FILE* fin; 251 | 252 | int ret = fopen_s(&fin, filename, "r"); 253 | if (ret != 0){ 254 | printf("Error opening file %s!\n", filename); 255 | return return_vector; 256 | } 257 | char* buffer = new char[BUFFER_SIZE]; 258 | int count, count_discard = 0; 259 | double ts = 0; 260 | u_int old_ip = 0; 261 | vector rtos; 262 | 263 | while (!feof(fin)){ 264 | Signature sig; 265 | 266 | //read next line 267 | fgets(buffer, BUFFER_SIZE, fin); 268 | char* bufferptr = buffer; 269 | 270 | //sscanf_s(bufferptr, "%[^,]", sig.options, _countof(sig.options) 271 | sscanf_s(bufferptr, "%u,%d,%d,%d,%[^,],%llu,%d,%d,%d,%d,%d%n", 272 | &sig.id_int, &sig.win, &sig.ttl, &sig.df, sig.options_str, _countof(sig.options_str), &sig.options_int, &sig.mss, &sig.rst, &sig.rst_ack, &sig.rst_win, &sig.rst_nonzero, &count); 273 | 274 | 275 | bufferptr += count; 276 | 277 | while (strcmp(bufferptr, "\n") != 0 && strlen(bufferptr) > 0){ 278 | sscanf_s(bufferptr, ",%lf%n", &ts, &count); 279 | sig.packet_arrival_time.push_back(ts); 280 | 281 | if (sig.packet_arrival_time.size() == 20) break; //limit to 20 packets 282 | 283 | bufferptr += count; 284 | } 285 | 286 | return_vector.push_back(sig); 287 | sig_count++; 288 | 289 | if (sig_count % 10000 == 0) printf("Read %d signatures...\r", sig_count); 290 | } 291 | 292 | fclose(fin); 293 | printf("\nStored %d observations stored\n", return_vector.size()); 294 | return return_vector; 295 | } 296 | 297 | int main(int argc, char* argv[]){ 298 | 299 | DWORD start_time = clock(); 300 | 301 | printf("REAL_DATA variable is set to %d.\n", REAL_DATA); 302 | printf("Features Enabled: \n"); 303 | vector features = { "RTO", "WIN", "TTL", "DF", "OPT", "MSS", "RST" }; 304 | for (int i = 0; i < features_enabled.size(); i++){ 305 | if (features_enabled[i] == 1) printf("%s ", features[i].c_str()); 306 | } 307 | printf("\n"); 308 | //getchar(); 309 | 310 | /**********Load database signatures*********************************/ 311 | 312 | char* database_filename; 313 | if (argc > 1) database_filename = argv[1]; 314 | else { 315 | database_filename = "420OS_db.txt"; 316 | } 317 | map> sigmap = readDatabaseSigs(database_filename); 318 | 319 | /**********Load observations********************************************/ 320 | 321 | char* test_filename; 322 | if (argc > 2) test_filename = argv[2]; 323 | else { 324 | test_filename = "test_observations.txt"; 325 | } 326 | 327 | vector observations; 328 | if (REAL_DATA){ 329 | //read observations and load database labels 330 | observations = readTestData(test_filename); 331 | id_to_label_map = readLabels("420OS_mapping.txt"); 332 | } 333 | else{ 334 | //generate simulated observations 335 | observations = createDisturbedZipf(sigmap, 0.5, 0.5, 0); 336 | } 337 | 338 | if (sigmap.empty()) { 339 | printf("No signatures loaded!\n"); 340 | exit(0); 341 | } 342 | if (observations.empty()) { 343 | printf("No observations to classify!\n"); 344 | exit(0); 345 | } 346 | 347 | /*******************CHOOSE H+ VERSION**********************/ 348 | 349 | HershelPlusOptimized_MT(sigmap, observations); 350 | //HershelPlus_MT(sigmap, observations); 351 | 352 | 353 | /**********************************************************/ 354 | 355 | printf("__Took %lf minutes___\n", ((double)(clock() - start_time) / CLOCKS_PER_SEC) / 60); 356 | } -------------------------------------------------------------------------------- /VSProject/HershelPlus/HershelPlus.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "defines.h" 3 | 4 | //parameters for Hershel Plus matching 5 | #define HP_JITTER_LOSS_THRESHOLD 4 //how many seconds of jitter we can tolerate when figuring out loss combinations 6 | 7 | #define HP_JITTER_MEAN 0.5 8 | #define HP_JITTER_LAMBDA (1 / HP_JITTER_MEAN) 9 | #define HP_GAMMA_SHAPE 2.0 10 | #define HP_GAMMA_MEAN 0.5 11 | #define HP_GAMMA_SCALE (1 / (HP_GAMMA_SHAPE / HP_GAMMA_MEAN)) 12 | #define HP_GAMMA_NU (HP_GAMMA_SHAPE / HP_GAMMA_MEAN) 13 | #define HP_LOSS_PROB 0.038 14 | #define HP_FEATURE_PROB_PI_RST_OPT 0.01 15 | #define HP_FEATURE_PROB_PI 0.1 16 | 17 | #define T_GUESS_LIMIT_IN_SECS 4.0 18 | #define T_NUM_BINS 100 19 | #define Q_GUESS_LIMIT_IN_SECS 4.0 20 | #define Q_NUM_BINS 100 21 | 22 | struct HPThreadVar{ 23 | HANDLE mutex; 24 | int correct; 25 | int wrong; 26 | int thread_id; 27 | map> training_data; 28 | vector observations; 29 | vector t_prob_array; 30 | vector owd_prob_array; 31 | map classcounts; 32 | }; 33 | 34 | class Estimator{ 35 | public: 36 | int y_nPkts; 37 | int x_nPkts; 38 | double subOS_prob; 39 | double t_step_size = T_GUESS_LIMIT_IN_SECS / T_NUM_BINS; 40 | double owd_step_size = Q_GUESS_LIMIT_IN_SECS / Q_NUM_BINS; 41 | vector& x_timestamps; 42 | vector& y_timestamps; 43 | vector& t_prob_array; 44 | vector& owd_prob_array; 45 | vector accumulator; 46 | 47 | Estimator(vector& sample, vector& signature, vector& rttarray, vector& owdarray) 48 | :subOS_prob(0), x_timestamps(sample), y_timestamps(signature), t_prob_array(rttarray), owd_prob_array(owdarray) 49 | { 50 | y_nPkts = signature.size(); 51 | x_nPkts = sample.size(); 52 | accumulator.resize(x_nPkts); 53 | } 54 | 55 | void ExamineCombination(vector& gamma){ 56 | double gamma_prob = 0; 57 | double t_limit = T_GUESS_LIMIT_IN_SECS; 58 | 59 | //but T has to be less than the smallest distance between any x and y 60 | for (int t = 0; t < x_nPkts; t++){ 61 | double d = x_timestamps[t] - y_timestamps[gamma[t]]; 62 | if (d < t_limit) t_limit = d; 63 | } 64 | 65 | 66 | for (double t_guess = 0; t_guess <= t_limit; t_guess += t_step_size){ 67 | double probQ = 1; 68 | 69 | int t_index = t_guess / t_step_size; 70 | double probT = t_prob_array[t_index]; 71 | 72 | //for each received packet, determine the OWD (Q) and calculate \prod p(Q) 73 | for (int t = 0; t < x_nPkts; t++){ 74 | double Q = (x_timestamps[t] - y_timestamps[gamma[t]] - t_guess); 75 | if (Q < 0){ 76 | probQ = 0; 77 | break; 78 | } 79 | else { 80 | int owd_index = Q / owd_step_size; 81 | if (owd_index > owd_prob_array.size() - 1) owd_index = owd_prob_array.size() - 1; 82 | double p = owd_prob_array[owd_index]; 83 | probQ *= p; 84 | } 85 | } 86 | 87 | //the prob of this gamma with this T is p(T) * \prod p(Q) 88 | gamma_prob += probQ * probT; 89 | } 90 | 91 | subOS_prob += gamma_prob; 92 | } 93 | 94 | void ProduceLossPatterns(int remaining, int start, int accumulatorSize){ 95 | if (remaining > 0){ 96 | for (int i = start; i < y_nPkts - remaining + 1; i++){ 97 | bool possible = false; 98 | double diff = x_timestamps[accumulatorSize] - y_timestamps[i]; 99 | if (diff >= 0){ // must arrive after the signature's timestamp 100 | if (accumulatorSize == 0) // first packet being matched: allow it since the RTT can be anything 101 | possible = true; 102 | else {// non-first packet: do a test on jitter 103 | double jitt = x_timestamps[accumulatorSize] - x_timestamps[accumulatorSize - 1] - 104 | (y_timestamps[i] - y_timestamps[accumulator[accumulatorSize - 1]]); 105 | // TODO: automatically determine the value of jitter for this cutoff 106 | // need the jitter PMF and some threshold: CDF sum above the threshold should be less than some small number 107 | if (abs(jitt) < HP_JITTER_LOSS_THRESHOLD) // only if less than "JITTER_THRESHOLD" OWD 108 | possible = true; 109 | } 110 | } 111 | if (possible){ 112 | accumulator[accumulatorSize] = i; 113 | ProduceLossPatterns(remaining - 1, i + 1, accumulatorSize + 1); 114 | } 115 | } 116 | } 117 | else { 118 | //if (produced == 0) // emulates always taking the first x[i].nPkts packets of the signature 119 | ExamineCombination(accumulator); 120 | //produced ++; 121 | } 122 | } 123 | }; 124 | 125 | //Thread function for Hershel+ MT 126 | void HershelPlus_Thread(LPVOID thread_variables){ 127 | HPThreadVar* hpt = (HPThreadVar*)thread_variables; 128 | 129 | WaitForSingleObject(hpt->mutex, INFINITE); //LOCK Mutex to give self an id 130 | 131 | int thread_id = hpt->thread_id; 132 | hpt->thread_id++; 133 | 134 | ReleaseMutex(hpt->mutex); // RELEASE Mutex 135 | 136 | map>::iterator it; 137 | for (int i = thread_id; i < hpt->observations.size(); i += NUM_THREADS){ 138 | Signature obs = hpt->observations[i]; 139 | int chosenOS = 0; 140 | double probsum = 0; 141 | double maxprob = 0; //keep track of max prob 142 | double secondprob = 0; //keep track of second highest prob 143 | 144 | for (it = hpt->training_data.begin(); it != hpt->training_data.end(); it++){ 145 | double osprob = 0; 146 | 147 | if (features_enabled[0]) { //if RTO enabled 148 | //training data RTO vector must be >= size of sample, due to loss 149 | int lost_packets = it->second[0].packet_arrival_time.size() - obs.packet_arrival_time.size(); 150 | if (lost_packets >= 0) { 151 | 152 | double totalsum = 0; 153 | 154 | for (int s = 0; s < it->second.size(); s++) { 155 | Estimator e(obs.packet_arrival_time, it->second[s].packet_arrival_time, hpt->t_prob_array, hpt->owd_prob_array); 156 | //Estimator e(target.rto_cumulative, candidates[j].rep_rto); //this is when using the 50-subOS average only 157 | e.ProduceLossPatterns(obs.packet_arrival_time.size(), 0, 0); 158 | totalsum += e.subOS_prob; 159 | } 160 | 161 | osprob = totalsum / it->second.size(); //average sum over all subOS 162 | 163 | //multiply by loss probability 164 | osprob *= pow(HP_LOSS_PROB, lost_packets) * pow(1 - HP_LOSS_PROB, obs.packet_arrival_time.size()); 165 | } 166 | } 167 | osprob *= MatchConstantFeatures(hpt->observations[i], it->second[0]); 168 | 169 | if (osprob > maxprob) { 170 | secondprob = maxprob; 171 | maxprob = osprob; 172 | chosenOS = it->first; 173 | } 174 | else { 175 | if (osprob > secondprob) secondprob = osprob; 176 | } 177 | 178 | probsum += osprob; 179 | } 180 | 181 | //track the normalized probability matched for the best and second-best match 182 | hpt->observations[i].maxprob_norm = maxprob / probsum; 183 | hpt->observations[i].secondprob_norm = secondprob / probsum; 184 | 185 | WaitForSingleObject(hpt->mutex, INFINITE); //LOCK Mutex to write correct or wrong 186 | 187 | if (!REAL_DATA) { 188 | if (chosenOS == hpt->observations[i].id_int) hpt->correct++; 189 | else { 190 | hpt->wrong++; 191 | } 192 | } 193 | else { 194 | hpt->classcounts[chosenOS]++; 195 | hpt->observations[i].id_classified = chosenOS; 196 | hpt->correct++; 197 | } 198 | 199 | ReleaseMutex(hpt->mutex); // RELEASE Mutex 200 | } 201 | } 202 | 203 | //Hershel+ multi threaded version 204 | void HershelPlus_MT(map > database_sigs, vector observations){ 205 | 206 | //declare vars for numerical integration using rectangles 207 | //double w = T_GUESS_LIMIT_IN_SECS / T_NUM_BINS; //width of the rect 208 | //thus area of each rectangle is width(w) * height(f(i*w)), where f is the distribution function 209 | 210 | //build array of probabilities 211 | 212 | vector parray; 213 | double sum = 0; 214 | 215 | double meanT = 0.5; 216 | // now the T model: erlang(k); mean = k / lambda 217 | int erlang_k = 2; 218 | double erlang_lambda = (double) erlang_k / meanT; 219 | double common = pow (erlang_lambda, erlang_k) / factorial(erlang_k - 1); 220 | for (DWORD s = 0; s < T_NUM_BINS; s++) { 221 | double x = (s + 1) * T_GUESS_LIMIT_IN_SECS / T_NUM_BINS; 222 | double prob = common * pow(x, erlang_k - 1) * exp(-erlang_lambda * x); 223 | parray.push_back(prob); 224 | sum += prob; 225 | } 226 | //normalize array 227 | for (int i = 0; i < parray.size(); i++){ 228 | parray[i] = parray[i] / sum; 229 | } 230 | /***********************************************/ 231 | 232 | HPThreadVar hpt; 233 | hpt.mutex = CreateMutex(NULL, 0, NULL); 234 | hpt.correct = 0; 235 | hpt.wrong = 0; 236 | hpt.thread_id = 0; 237 | hpt.observations = observations; 238 | hpt.t_prob_array = parray; 239 | hpt.owd_prob_array = parray; 240 | hpt.training_data = database_sigs; 241 | 242 | HANDLE *handles = new HANDLE[NUM_THREADS]; 243 | //Split Threads 244 | for (int i = 0; i < NUM_THREADS; i++){ 245 | handles[i] = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)HershelPlus_Thread, &hpt, 0, NULL); 246 | SetThreadPriority(handles[i], THREAD_PRIORITY_LOWEST); 247 | } 248 | 249 | //Print info every 5 secs until no more active threads 250 | printf("Started %d threads...\n\n", NUM_THREADS); 251 | 252 | int sleep_interval = 5000; 253 | int remaining, done_count, old_done_count = 0, step = 0; 254 | double avg_rate = 0, sum_rate = 0; 255 | while (true){ 256 | //calculate done and remaining 257 | done_count = hpt.correct + hpt.wrong; 258 | remaining = hpt.observations.size() - done_count; 259 | 260 | double rate = (done_count - old_done_count) / (double)(sleep_interval / 1000); 261 | 262 | sum_rate += rate; 263 | step++; 264 | avg_rate = sum_rate / step; 265 | double time_remaining = (remaining / avg_rate) / 60; 266 | 267 | if (!REAL_DATA) printf("IPs left: %d, Correct: %.2lf, Done: %d at %f per sec. %f min to go\r", remaining, (double)hpt.correct / done_count, done_count, rate, time_remaining); 268 | else printf("IPs left: %d, Done: %d at %f per sec. %f min to go\r", remaining, done_count, rate, time_remaining); 269 | 270 | old_done_count = done_count; 271 | if (remaining <= 0) break; 272 | Sleep(sleep_interval); 273 | } 274 | 275 | //Wait for threads to return 276 | printf("\n--->Quit Condition Reached!<---\nWaiting for all threads to end..\n"); 277 | WaitForMultipleObjects(NUM_THREADS, handles, TRUE, INFINITE); 278 | 279 | // Close handles 280 | for (int i = 0; i < NUM_THREADS; i++) CloseHandle(handles[i]); 281 | CloseHandle(hpt.mutex); 282 | 283 | if (!REAL_DATA) printf("--------->Correct: %d, Accuracy: %f\n", hpt.correct, (double)hpt.correct / hpt.observations.size()); 284 | else { 285 | //print out the results 286 | FILE* fout; 287 | fopen_s(&fout, "internet_classcounts.txt", "w"); 288 | for (auto cc : hpt.classcounts) fprintf(fout, "%s, %d\n", id_to_label_map[cc.first].c_str(), cc.second); 289 | fclose(fout); 290 | 291 | fopen_s(&fout, "internet_results.txt", "w"); 292 | fprintf(fout, "Internet ID, Classified ID, Label, MaxProb, SecondMaxProb\n"); 293 | for (int i = 0; i < hpt.observations.size(); i++) { 294 | fprintf(fout, "%u, %u, %s, %lf, %lf\n", hpt.observations[i].id_int, hpt.observations[i].id_classified, id_to_label_map[hpt.observations[i].id_classified].c_str(), hpt.observations[i].maxprob_norm, hpt.observations[i].secondprob_norm); 295 | } 296 | fclose(fout); 297 | 298 | printf("Result files written.\n"); 299 | } 300 | 301 | 302 | } 303 | 304 | //Hershel+ single threaded version. Likely outdated 305 | void HershelPlus_ST(map > database_sigs, vector observations){ 306 | 307 | FILE* file; 308 | fopen_s(&file, "err.txt", "w"); 309 | map>::iterator it; 310 | 311 | 312 | //declare vars for numerical integration using rectangles 313 | double w = T_GUESS_LIMIT_IN_SECS / T_NUM_BINS; //number of rectangles 314 | //thus area of each rectangle is width(h) * height(f(i*h)), where f is the distribution function 315 | 316 | //build array of probabilities 317 | double max = DBL_MIN; 318 | vector parray; 319 | double sum = 0; 320 | 321 | double meanT = 0.5; 322 | // now the T model: erlang(k); mean = k / lambda 323 | int erlang_k = 2; 324 | double erlang_lambda = (double)erlang_k / meanT; 325 | double common = pow(erlang_lambda, erlang_k) / factorial(erlang_k - 1); 326 | for (DWORD s = 0; s < T_NUM_BINS; s++) { 327 | double x = (s + 1) * T_GUESS_LIMIT_IN_SECS / T_NUM_BINS; 328 | double prob = common * pow(x, erlang_k - 1) * exp(-erlang_lambda * x); 329 | parray.push_back(prob); 330 | sum += prob; 331 | } 332 | //normalize array 333 | for (int i = 0; i < parray.size(); i++) { 334 | parray[i] = parray[i] / sum; 335 | } 336 | 337 | //match each disturbedOS 338 | int correct = 0, wrong = 0; 339 | vector finalprobs; 340 | 341 | for (Signature dos : observations){ 342 | int chosenOS; 343 | double maxprob = -1; 344 | finalprobs.clear(); 345 | for (it = database_sigs.begin(); it != database_sigs.end(); it++){ 346 | 347 | //check if RTO vector size is the same 348 | if (it->second[0].packet_arrival_time.size() == dos.packet_arrival_time.size()){ 349 | 350 | double totalsum = 0; 351 | 352 | for (int s = 0; s < it->second.size(); s++){ 353 | //match DOS to host_i 354 | double subOS_sum = 0; 355 | 356 | //for each rtt guess 357 | for (int i = 0; i < parray.size(); i++){ 358 | double rtt_guess = (i + 1) * w; 359 | double subos_prob = 1; 360 | 361 | //for each tau 362 | for (int t = 1; t < dos.packet_arrival_time.size(); t++){ //skip (0) 363 | double Q = (dos.packet_arrival_time[t] - it->second[s].packet_arrival_time[t] - rtt_guess); 364 | if (Q < 0) subos_prob = 0; 365 | else { 366 | double p = exp(-HP_JITTER_LAMBDA * Q); 367 | double q = parray[i]; 368 | subos_prob *= (p * q); 369 | } 370 | } 371 | subOS_sum += subos_prob; 372 | } 373 | 374 | totalsum += subOS_sum; 375 | //printf("sum: %lf\n", sum); 376 | 377 | } 378 | 379 | double osprob = totalsum / it->second.size(); //average sum over all subOS 380 | //printf("Average sum: %lf\n", osprob); 381 | finalprobs.push_back(totalsum); 382 | 383 | if (osprob > maxprob){ 384 | maxprob = osprob; 385 | chosenOS = it->first; 386 | } 387 | } 388 | else{ 389 | //printf("SIZE MISMATCH!"); 390 | finalprobs.push_back(0); 391 | } 392 | } 393 | 394 | if (chosenOS == dos.id_int) correct++; 395 | else{ 396 | /*fprintf(file, "Correct: %d, Picked: %d", dos.correct_class, chosenOS); 397 | for (double r : dos.rto){ 398 | fprintf(file, ",%lf", r); 399 | } 400 | fprintf(file, "\t"); 401 | for (double p : finalprobs){ 402 | fprintf(file, "%lf ", p); 403 | } 404 | fprintf(file, "\n");*/ 405 | wrong++; 406 | } 407 | 408 | 409 | printf("Working on: %d, Correct: %d, Wrong: %d, %.0f%% done.\r", dos.id_int, correct, wrong, ((double)(correct + wrong) / observations.size()) * 100); 410 | } 411 | 412 | printf("Correct: %d, Accuracy: %f\n", correct, (double)correct / observations.size()); 413 | 414 | _fcloseall(); 415 | } 416 | -------------------------------------------------------------------------------- /multi-platform/HershelPlusOptimized.cpp: -------------------------------------------------------------------------------- 1 | // Copyright © 2014 IRL at Texas A&M University (http://irl.cse.tamu.edu) 2 | // 3 | // This file is part of Hershel+. 4 | // 5 | // Hershel+ is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU Lesser General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // Hershel+ is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details 14 | // http://www.gnu.org/licenses/lgpl.txt. 15 | // 16 | // Contact: 17 | // Dmitri Loguinov (dmitri@cse.tamu.edu) 18 | // 19 | // Data and signatures: 20 | // http://irl.cse.tamu.edu/projects/osf 21 | // 22 | // Publication: 23 | // Z. Shamsi, D. Loguinov, "Unsupervised Clustering Under Temporal Feature 24 | // Volatility in Network Stack Fingerprinting, " ACM SIGMETRICS, June 2016. 25 | // 26 | // Since Hershel+ requires the TCP handshake to remain half open, kernel RSTs need to be suppressed. 27 | // On Windows, the Windows firewall should do this by default 28 | // On Linux, inserting the following iptables rules will take care of this: 29 | // sudo iptables -t filter -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 30 | // sudo iptables -t filter -A INPUT -p icmp -j ACCEPT 31 | // sudo iptables -t filter -A INPUT -i lo -j ACCEPT 32 | // sudo iptables -t filter -A INPUT -j DROP 33 | // This accepts anything from established connections, icmp pings, and anything on the loopback interface and drops the rest. 34 | 35 | #ifdef _MSC_VER 36 | #define _CRT_SECURE_NO_WARNINGS 37 | #endif 38 | 39 | #include "LiveFingerprinter.h" 40 | 41 | #define OPT_MSS 1 // max segment size 42 | #define OPT_WIN 2 // window scaling 43 | #define OPT_TS 3 // timestamps 44 | #define OPT_SACK 4 // SACK allowed 45 | #define OPT_EOL 5 // end of list (another type of padding?) 46 | #define OPT_NOP 6 // padding 47 | 48 | //parameters for Hershel Plus matching 49 | #define HP_JITTER_LOSS_THRESHOLD 4 //how many seconds of jitter we can tolerate when figuring out loss combinations 50 | 51 | #define HP_JITTER_MEAN 0.5 52 | #define HP_JITTER_LAMBDA (1 / HP_JITTER_MEAN) 53 | #define HP_GAMMA_SHAPE 2.0 54 | #define HP_GAMMA_MEAN 0.5 55 | #define HP_GAMMA_SCALE (1 / (HP_GAMMA_SHAPE / HP_GAMMA_MEAN)) 56 | #define HP_GAMMA_NU (HP_GAMMA_SHAPE / HP_GAMMA_MEAN) 57 | #define HP_LOSS_PROB 0.038 58 | #define HP_FEATURE_PROB_PI_RST_OPT 0.01 59 | #define HP_FEATURE_PROB_PI 0.1 60 | 61 | #define Q_GUESS_LIMIT_IN_SECS 4.0 62 | #define Q_NUM_BINS 100 63 | 64 | using namespace std; 65 | 66 | //Hershel RTO Estimator 67 | class HershelPlusEstimator{ 68 | public: 69 | public: 70 | int y_nPkts; 71 | int x_nPkts; 72 | double subOS_prob; 73 | double owd_step_size = Q_GUESS_LIMIT_IN_SECS / Q_NUM_BINS; 74 | vector& x_timestamps; 75 | vector& y_timestamps; 76 | vector& owd_prob_array; 77 | vector accumulator; 78 | 79 | HershelPlusEstimator(vector& sample, vector& signature, vector& owdarray) 80 | :subOS_prob(0), x_timestamps(sample), y_timestamps(signature), owd_prob_array(owdarray) 81 | { 82 | y_nPkts = signature.size(); 83 | x_nPkts = sample.size(); 84 | accumulator.resize(x_nPkts); 85 | } 86 | 87 | void ExamineCombination(vector& gamma) { 88 | double gamma_prob = 1; 89 | double s = DBL_MAX; //keep track of the min e_m seen 90 | 91 | //for each received packet, determine the OWD (Q) and calculate \prod p(Q) 92 | for (int m = 0; m < x_nPkts; m++) { 93 | double em = x_timestamps[m] - y_timestamps[gamma[m]]; 94 | if (em < 0) { 95 | gamma_prob = 0; 96 | } 97 | else { 98 | int owd_index = em / (Q_GUESS_LIMIT_IN_SECS / Q_NUM_BINS); 99 | if (owd_index > owd_prob_array.size() - 1) owd_index = owd_prob_array.size() - 1; 100 | 101 | gamma_prob *= owd_prob_array[owd_index]; 102 | //gamma_prob *= exp(-HP_JITTER_LAMBDA * em); 103 | 104 | if (em < s) s = em; 105 | } 106 | } 107 | 108 | if (gamma_prob > 0) { 109 | //have case for denom = 0 110 | if (x_nPkts == HP_GAMMA_NU / HP_JITTER_LAMBDA) gamma_prob *= (s * s) / 2; 111 | //else gamma_prob *= (exp(-HP_GAMMA_NU * s) * (exp(HP_JITTER_LAMBDA * s * x_nPkts) * (HP_JITTER_LAMBDA * s * x_nPkts - HP_GAMMA_NU * s - 1) + exp(HP_GAMMA_NU * s))) / pow((HP_GAMMA_NU - HP_JITTER_LAMBDA * x_nPkts), 2); //result from Wolfram 112 | else gamma_prob *= (1 - exp(s * (-HP_GAMMA_NU * HP_JITTER_LAMBDA * x_nPkts)) * (1 + s * (HP_GAMMA_NU - HP_JITTER_LAMBDA * x_nPkts))) / pow((HP_GAMMA_NU - HP_JITTER_LAMBDA * x_nPkts), 2); // to match paper (16) 113 | 114 | //multiply by the constant for completeness 115 | //gamma_prob *= HP_JITTER_LAMBDA * pow(HP_GAMMA_NU, 2); 116 | gamma_prob *= pow(HP_JITTER_LAMBDA, x_nPkts) * pow(HP_GAMMA_NU, 2); //to match paper (16) 117 | 118 | } 119 | 120 | subOS_prob += gamma_prob; 121 | } 122 | 123 | void ProduceLossPatterns(int remaining, int start, int accumulatorSize) { 124 | if (remaining > 0) { 125 | for (int i = start; i < y_nPkts - remaining + 1; i++) { 126 | bool possible = false; 127 | double diff = x_timestamps[accumulatorSize] - y_timestamps[i]; 128 | if (diff >= 0) { // must arrive after the signature's timestamp 129 | if (accumulatorSize == 0) // first packet being matched: allow it since the RTT can be anything 130 | possible = true; 131 | else {// non-first packet: do a test on jitter 132 | double jitt = x_timestamps[accumulatorSize] - x_timestamps[accumulatorSize - 1] - 133 | (y_timestamps[i] - y_timestamps[accumulator[accumulatorSize - 1]]); 134 | // TODO: automatically determine the value of jitter for this cutoff 135 | // need the jitter PMF and some threshold: CDF sum above the threshold should be less than some small number 136 | if (abs(jitt) < HP_JITTER_LOSS_THRESHOLD) // only if less than "JITTER_THRESHOLD" OWD 137 | possible = true; 138 | } 139 | } 140 | if (possible) { 141 | accumulator[accumulatorSize] = i; 142 | ProduceLossPatterns(remaining - 1, i + 1, accumulatorSize + 1); 143 | } 144 | } 145 | } 146 | else { 147 | //if (produced == 0) // emulates always taking the first x[i].nPkts packets of the signature 148 | ExamineCombination(accumulator); 149 | //produced ++; 150 | } 151 | } 152 | }; 153 | 154 | /*********************CONSTANT FEATURE MATCHING***********************/ 155 | 156 | //match int64 options, intersection of both tar and sig should be ordered the same 157 | int options_match_int64(unsigned long long tar_opts, unsigned long long sig_opts) { 158 | if (tar_opts == sig_opts) return 2; 159 | 160 | int count = 0; 161 | 162 | //keep track of where we found our last option in sig list 163 | int last_found_position = -1; 164 | unsigned long long sig_it; 165 | 166 | while (tar_opts > 0) { 167 | int opt = -1; 168 | while (opt != OPT_MSS && opt != OPT_WIN && opt != OPT_SACK && opt != OPT_TS) { //skip unimportant bits 169 | if (tar_opts == 0) return 1; //we've matched so far and reached 0 without another option 170 | //get last 3 bits from target 171 | opt = tar_opts & 0x7; //AND by 3 bits to get value 172 | //move to next option 173 | tar_opts = tar_opts >> 3; 174 | } 175 | 176 | sig_it = sig_opts; //reset iterator to beginning 177 | int position = 0; 178 | bool found = false; 179 | while (sig_it > 0) { //go through sig_opt list 180 | int sopt = sig_it & 0x7; 181 | if (sopt == opt) { //if found 182 | if (position < last_found_position) return 0; //found it before the last one, doesnt match ordering 183 | else last_found_position = position; 184 | found = true; 185 | break; 186 | } 187 | sig_it = sig_it >> 3; 188 | position++; 189 | } 190 | if (!found) { 191 | //not found in list, was probably enabled by user - do nothing here 192 | } 193 | } 194 | 195 | //all there 196 | return 1; 197 | } 198 | 199 | //calculate likeliest class by adding FEATURE_CHANGE_PROBABILITY onto candidates 200 | double MatchConstantFeatures(Signature& target, Signature& dbsig) { 201 | double prob = 1; 202 | 203 | if (target.win == dbsig.win) prob *= (1 - HP_FEATURE_PROB_PI); 204 | else prob *= HP_FEATURE_PROB_PI; 205 | 206 | if (target.ttl == dbsig.ttl) prob *= (1 - HP_FEATURE_PROB_PI); 207 | else prob *= HP_FEATURE_PROB_PI; 208 | 209 | if (target.df == dbsig.df) prob *= (1 - HP_FEATURE_PROB_PI); 210 | else prob *= HP_FEATURE_PROB_PI; 211 | 212 | int oval = options_match_int64(target.options_int, dbsig.options_int); 213 | if (oval < 1) prob *= HP_FEATURE_PROB_PI_RST_OPT; 214 | else if (oval == 1) prob *= HP_FEATURE_PROB_PI; 215 | else if (oval > 1) prob *= (1 - HP_FEATURE_PROB_PI); 216 | 217 | if (target.mss == dbsig.mss) prob *= (1 - HP_FEATURE_PROB_PI); 218 | else prob *= HP_FEATURE_PROB_PI; 219 | 220 | if (target.rst) { 221 | if (target.rst == dbsig.rst && target.rst_ack == dbsig.rst_ack && target.rst_win == dbsig.rst_win && target.rst_nonzero == dbsig.rst_nonzero) prob *= (1 - HP_FEATURE_PROB_PI_RST_OPT); 222 | else prob *= HP_FEATURE_PROB_PI_RST_OPT; 223 | } 224 | return prob; 225 | } 226 | 227 | /***********************************************************************/ 228 | 229 | void HershelPlus(unordered_map>& database, vector& observations){ 230 | printf("\n---Starting Hershel+ Classification on %zd observation(s)---\n", observations.size()); 231 | 232 | //set up OWD probabilities as exponential 233 | vector owd_prob_array; 234 | double sum = 0; 235 | for (int s = 0; s < Q_NUM_BINS; s++) { 236 | double x = (s + 1) * Q_GUESS_LIMIT_IN_SECS / Q_NUM_BINS; 237 | double prob = exp(-HP_JITTER_LAMBDA * x); 238 | owd_prob_array.push_back(prob); 239 | sum += prob; 240 | } 241 | //normalize array 242 | for (int i = 0; i < owd_prob_array.size(); i++){ 243 | owd_prob_array[i] = owd_prob_array[i] / sum; 244 | } 245 | 246 | int unclassified = 0; 247 | int correct = 0; 248 | int fail = 0; 249 | 250 | //run through all observations and classify 251 | for (int i = 0; i < observations.size(); i++){ 252 | //get next host 253 | Signature target = observations[i]; 254 | double highest_prob = 0; 255 | unsigned int highest_id = 0; 256 | 257 | for (auto it = database.begin(); it != database.end(); it++){ 258 | double os_prob = 0; 259 | 260 | //get difference in lengths 261 | int lost_packets = it->second[0].packet_arrival_time.size() - target.packet_arrival_time.size(); 262 | 263 | //apply loss filter, cant receive more packets than signature 264 | if (lost_packets >= 0){ 265 | 266 | //for each subOS 267 | for (int r = 0; r < it->second.size(); r++){ 268 | 269 | //get the probability of this subOS rto vs. target using estimator 270 | HershelPlusEstimator e(target.packet_arrival_time, it->second[r].packet_arrival_time, owd_prob_array); 271 | e.ProduceLossPatterns(target.packet_arrival_time.size(), 0, 0); 272 | 273 | os_prob += e.subOS_prob; //for all subOS prob 274 | } 275 | 276 | //multiply by lost packet prob 277 | os_prob *= pow(HP_LOSS_PROB, lost_packets) * pow(1 - HP_LOSS_PROB, target.packet_arrival_time.size()); 278 | 279 | //match constants 280 | os_prob *= MatchConstantFeatures(target, it->second[0]); 281 | } 282 | 283 | //track highest prob 284 | if (os_prob > highest_prob){ 285 | highest_prob = os_prob; 286 | highest_id = it->first; 287 | } 288 | } 289 | 290 | if (highest_id == 0) unclassified++; 291 | observations[i].id_classified = highest_id; 292 | 293 | } 294 | 295 | } 296 | 297 | vector readSigList(char *filename){ 298 | //read signatures into vector 299 | vector retvec; 300 | int sig_count = 0; 301 | int BUFFER_SIZE = (1 << 12); //4MB 302 | 303 | FILE* fin = fopen(filename, "r"); 304 | if (fin == NULL){ 305 | printf("Error opening file %s!\n", filename); 306 | exit(-1); 307 | } 308 | else printf("\nReading from %s...\n", filename); 309 | char* buffer = new char[BUFFER_SIZE]; 310 | int count, count_discard = 0; 311 | double timestamp = 0; 312 | unsigned int old_ip = 0; 313 | vector rtos; 314 | 315 | while (!feof(fin)){ 316 | Signature sig; 317 | 318 | //read next line 319 | fgets(buffer, BUFFER_SIZE, fin); 320 | char* bufferptr = buffer; 321 | 322 | sscanf(bufferptr, "%u,%d,%d,%d,%[^,],%lld,%d,%d,%d,%d,%d%n", 323 | &sig.id, &sig.win, &sig.ttl, &sig.df, sig.options_str, &sig.options_int, &sig.mss, &sig.rst, &sig.rst_ack, &sig.rst_win, &sig.rst_nonzero, &count); 324 | 325 | bufferptr += count; 326 | 327 | while (strcmp(bufferptr, "\n") != 0 && strlen(bufferptr) > 0){ 328 | sscanf(bufferptr, ",%lf%n", ×tamp, &count); 329 | sig.packet_arrival_time.push_back(timestamp); 330 | 331 | bufferptr += count; 332 | } 333 | 334 | retvec.push_back(sig); 335 | sig_count++; 336 | if (sig_count % 10000 == 0) printf("Read %d signatures...\r", sig_count); 337 | } 338 | 339 | fclose(fin); 340 | printf("Stored %lu signatures in map\n", retvec.size()); 341 | return retvec; 342 | } 343 | 344 | int main(int argc, char* argv[]){ 345 | if (argc < 4){ 346 | printf("%s can be run in two modes: Live and Offline.\n", argv[0]); 347 | printf("To run in live mode: %s \n", argv[0]); 348 | printf("To run in offline mode: %s \n", argv[0]); 349 | return 0; 350 | } 351 | 352 | //read database signatures 353 | vector database_sigs = readSigList(argv[1]); 354 | //combine them into a hashmap for easier organization 355 | unordered_map> database; 356 | for (Signature s : database_sigs) database[s.id].push_back(s); 357 | 358 | //read class to OS label mapping 359 | FILE *fin = fopen(argv[2], "r"); 360 | if (fin == NULL){ 361 | printf("Error opening file %s!\n", argv[3]); 362 | exit(-1); 363 | } 364 | unordered_map os_mapping; 365 | char buffer[512]; 366 | while (!feof(fin)){ 367 | int id; 368 | char osname[512]; 369 | 370 | fgets(buffer, 512, fin); 371 | sscanf(buffer, "%d,%[^\n]", &id, osname); 372 | os_mapping[id] = string(osname); 373 | } 374 | 375 | //determine if next argument is an IP 376 | unsigned int ip; 377 | unsigned short port; 378 | vector observations; 379 | int result = inet_pton(AF_INET, argv[3], &ip); 380 | if (result == 1){ 381 | //it was an ip 382 | if (argc < 5) { 383 | printf("Port argument missing\n"); 384 | exit(-1); 385 | } 386 | port = atoi(argv[4]); 387 | 388 | //set up for live fingerprinting 389 | printf("Starting Live fingerprinting of %s:%d...\n", argv[3], port); 390 | LiveFingerprinter lf; 391 | if (lf.setupPcapAdapter() < 0){ 392 | printf("Error setting up pcap!\n"); 393 | exit(-1); 394 | } 395 | 396 | Signature s; 397 | if (lf.getFingerprint(argv[3], port, s) < 0){ 398 | printf("Error getting fingerprint\n"); 399 | exit(-1); 400 | } 401 | 402 | observations.push_back(s); 403 | } 404 | else { 405 | //it was not an IP, read observations 406 | observations = readSigList(argv[3]); 407 | } 408 | 409 | //run Hershel on observations 410 | HershelPlus(database, observations); 411 | 412 | //print out observation results 413 | for (Signature o : observations){ 414 | printf("Observed signature: %d,%d,%d,%s,%d,%d,%d,%d,%d,%d", o.win, o.ttl, o.df, o.options_str, o.mss, o.rst, o.rst_ack, o.rst_win, o.rst_seq, o.rst_nonzero); 415 | for (u_int r = 0; r < o.packet_arrival_time.size(); r++) printf(",%lf", o.packet_arrival_time[r]); 416 | printf("\n"); 417 | printf("Matching signature: "); 418 | printf("%d,%d,%d,%s,%d,%d,%d,%d,%d,%d", database[o.id_classified][0].win, database[o.id_classified][0].ttl, database[o.id_classified][0].df, database[o.id_classified][0].options_str, database[o.id_classified][0].mss, database[o.id_classified][0].rst, database[o.id_classified][0].rst_ack, database[o.id_classified][0].rst_win, database[o.id_classified][0].rst_seq, database[o.id_classified][0].rst_nonzero); 419 | for (u_int r = 0; r < database[o.id_classified][0].packet_arrival_time.size(); r++) printf(",%lf", database[o.id_classified][0].packet_arrival_time[r]); 420 | printf("\n"); 421 | 422 | printf("\tObservation %u classified as %s \n\n", o.id, os_mapping[o.id_classified].c_str()); 423 | } 424 | } 425 | -------------------------------------------------------------------------------- /VSProject/HershelPlus/SimpleRNG.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define PI 3.1415926535897932384626433832795 7 | 8 | class SimpleRNG{ 9 | public: 10 | SimpleRNG() 11 | { 12 | // These values are not magical, just the default values Marsaglia used. 13 | // Any unit should work. 14 | m_u = 521288629; 15 | m_v = 362436069; 16 | } 17 | 18 | void SetState(unsigned int u, unsigned int v) 19 | { 20 | m_u = u; 21 | m_v = v; 22 | } 23 | 24 | void GetState(unsigned int& u, unsigned int& v) 25 | { 26 | u = m_u; 27 | v = m_v; 28 | } 29 | 30 | double GetUniform(unsigned int& u, unsigned int& v) 31 | { 32 | // 0 <= u <= 2^32 33 | unsigned int z = GetUint(u, v); 34 | // The magic number is 1/(2^32 + 1) and so result is positive and less than 1. 35 | return z*2.328306435996595e-10; 36 | } 37 | 38 | unsigned int GetUint(unsigned int& u, unsigned int& v) 39 | { 40 | v = 36969 * (v & 65535) + (v >> 16); 41 | u = 18000 * (u & 65535) + (u >> 16); 42 | return (v << 16) + u; 43 | } 44 | 45 | double GetUniform() 46 | { 47 | return GetUniform(m_u, m_v); 48 | } 49 | 50 | double GetUniform(double a, double b){ 51 | double u = GetUniform(); 52 | return a + (b - a)*u; 53 | } 54 | 55 | unsigned int GetUint() 56 | { 57 | return GetUint(m_u, m_v); 58 | } 59 | 60 | // Get normal (Gaussian) random sample with specified mean and standard deviation 61 | double GetNormal(double mean = 0.0, double standardDeviation = 1.0) 62 | { 63 | if (standardDeviation <= 0.0) 64 | { 65 | std::stringstream os; 66 | os << "Standard deviation must be positive." << "\n" 67 | << "Received standard deviation " << standardDeviation; 68 | throw std::invalid_argument(os.str()); 69 | } 70 | // Use Box-Muller algorithm 71 | double u1 = GetUniform(); 72 | double u2 = GetUniform(); 73 | double r = sqrt(-2.0*log(u1)); 74 | double theta = 2.0*PI*u2; 75 | return mean + standardDeviation*r*sin(theta); 76 | } 77 | 78 | // Get exponential random sample with specified mean 79 | double GetExponential(double mean = 1.0) 80 | { 81 | if (mean <= 0.0) 82 | { 83 | std::stringstream os; 84 | os << "Exponential mean must be positive." << "\n" 85 | << "Received standard deviation " << mean; 86 | throw std::invalid_argument(os.str()); 87 | } 88 | return -mean*log(GetUniform()); 89 | } 90 | 91 | double GetPareto(double alpha, double mean){ 92 | double u = GetUniform(); 93 | double beta = (alpha - 1) * mean; 94 | 95 | //apply inverse cdf of pareto to uniform 96 | //beta is scale, alpha is shape 97 | //return beta / pow((1 - u), 1 / alpha); 98 | return ((pow(1 - u, -1.0 / alpha)) - 1) * beta; 99 | } 100 | 101 | double GetGamma(double shape, double scale) 102 | { 103 | // Implementation based on "A Simple Method for Generating Gamma Variables" 104 | // by George Marsaglia and Wai Wan Tsang. ACM Transactions on Mathematical Software 105 | // Vol 26, No 3, September 2000, pages 363-372. 106 | 107 | double d, c, x, xsquared, v, u; 108 | 109 | if (shape >= 1.0) 110 | { 111 | d = shape - 1.0 / 3.0; 112 | c = 1.0 / sqrt(9.0*d); 113 | for (;;) 114 | { 115 | do 116 | { 117 | x = GetNormal(); 118 | v = 1.0 + c*x; 119 | } while (v <= 0.0); 120 | v = v*v*v; 121 | u = GetUniform(); 122 | xsquared = x*x; 123 | if (u < 1.0 - .0331*xsquared*xsquared || log(u) < 0.5*xsquared + d*(1.0 - v + log(v))) 124 | return scale*d*v; 125 | } 126 | } 127 | else if (shape <= 0.0) 128 | { 129 | std::stringstream os; 130 | os << "Shape parameter must be positive." << "\n" 131 | << "Received shape parameter " << shape; 132 | throw std::invalid_argument(os.str()); 133 | } 134 | else 135 | { 136 | double g = GetGamma(shape + 1.0, 1.0); 137 | double w = GetUniform(); 138 | return scale*g*pow(w, 1.0 / shape); 139 | } 140 | } 141 | 142 | double GetChiSquare(double degreesOfFreedom) 143 | { 144 | // A chi squared distribution with n degrees of freedom 145 | // is a gamma distribution with shape n/2 and scale 2. 146 | return GetGamma(0.5 * degreesOfFreedom, 2.0); 147 | } 148 | 149 | double GetInverseGamma(double shape, double scale) 150 | { 151 | // If X is gamma(shape, scale) then 152 | // 1/Y is inverse gamma(shape, 1/scale) 153 | return 1.0 / GetGamma(shape, 1.0 / scale); 154 | } 155 | 156 | double GetWeibull(double shape, double scale) 157 | { 158 | if (shape <= 0.0 || scale <= 0.0) 159 | { 160 | std::stringstream os; 161 | os << "Shape and scale parameters must be positive." << "\n" 162 | << "Received shape " << shape << " and scale " << scale; 163 | throw std::invalid_argument(os.str()); 164 | } 165 | return scale * pow(-log(GetUniform()), 1.0 / shape); 166 | } 167 | 168 | double GetCauchy(double median, double scale) 169 | { 170 | if (scale <= 0) 171 | { 172 | std::stringstream os; 173 | os << "Shape parameter must be positive." << "\n" 174 | << "Received shape parameter " << scale; 175 | throw std::invalid_argument(os.str()); 176 | } 177 | 178 | double p = GetUniform(); 179 | 180 | // Apply inverse of the Cauchy distribution function to a uniform 181 | return median + scale*tan(PI*(p - 0.5)); 182 | } 183 | 184 | double GetStudentT(double degreesOfFreedom) 185 | { 186 | if (degreesOfFreedom <= 0) 187 | { 188 | std::stringstream os; 189 | os << "Degrees of freedom must be positive." << "\n" 190 | << "Received shape parameter " << degreesOfFreedom; 191 | throw std::invalid_argument(os.str()); 192 | } 193 | 194 | // See Seminumerical Algorithms by Knuth 195 | double y1 = GetNormal(); 196 | double y2 = GetChiSquare(degreesOfFreedom); 197 | return y1 / sqrt(y2 / degreesOfFreedom); 198 | } 199 | 200 | // The Laplace distribution is also known as the double exponential distribution. 201 | double GetLaplace(double mean, double scale) 202 | { 203 | double u = GetUniform(); 204 | return (u < 0.5) ? 205 | mean + scale*log(2.0*u) : 206 | mean - scale*log(2 * (1 - u)); 207 | } 208 | 209 | double GetLogNormal(double mu, double sigma) 210 | { 211 | return exp(GetNormal(mu, sigma)); 212 | } 213 | 214 | double GetBeta(double a, double b) 215 | { 216 | if (a <= 0.0 || b <= 0.0) 217 | { 218 | std::stringstream os; 219 | os << "Beta parameters must be positive." << "\n" 220 | << "Received parameters " << a << " and " << b; 221 | throw std::invalid_argument(os.str()); 222 | } 223 | 224 | // There are more efficient methods for generating beta samples. 225 | // However such methods are a little more efficient and much more complicated. 226 | // For an explanation of why the following method works, see 227 | // http://www.johndcook.com/distribution_chart.html#gamma_beta 228 | 229 | double u = GetGamma(a, 1.0); 230 | double v = GetGamma(b, 1.0); 231 | return u / (u + v); 232 | } 233 | 234 | int GetPoisson(double lambda) 235 | { 236 | return (lambda < 30.0) ? PoissonSmall(lambda) : PoissonLarge(lambda); 237 | } 238 | 239 | private: 240 | unsigned int m_u, m_v; 241 | 242 | int PoissonSmall(double lambda) 243 | { 244 | // Algorithm due to Donald Knuth, 1969. 245 | double p = 1.0, L = exp(-lambda); 246 | int k = 0; 247 | do 248 | { 249 | k++; 250 | p *= GetUniform(); 251 | } while (p > L); 252 | return k - 1; 253 | } 254 | 255 | int PoissonLarge(double lambda) 256 | { 257 | // "Rejection method PA" from "The Computer Generation of Poisson Random Variables" by A. C. Atkinson 258 | // Journal of the Royal Statistical Society Series C (Applied Statistics) Vol. 28, No. 1. (1979) 259 | // The article is on pages 29-35. The algorithm given here is on page 32. 260 | 261 | double c = 0.767 - 3.36 / lambda; 262 | double beta = PI / sqrt(3.0*lambda); 263 | double alpha = beta*lambda; 264 | double k = log(c) - lambda - log(beta); 265 | 266 | for (;;) 267 | { 268 | double u = GetUniform(); 269 | double x = (alpha - log((1.0 - u) / u)) / beta; 270 | int n = (int)floor(x + 0.5); 271 | if (n < 0) 272 | continue; 273 | double v = GetUniform(); 274 | double y = alpha - beta*x; 275 | double temp = 1.0 + exp(y); 276 | double lhs = y + log(v / (temp*temp)); 277 | double rhs = k + n*log(lambda) - LogFactorial(n); 278 | if (lhs <= rhs) 279 | return n; 280 | } 281 | } 282 | 283 | double LogFactorial(int n) 284 | { 285 | 286 | if (n < 0) 287 | { 288 | std::stringstream os; 289 | os << "Invalid input argument (" << n 290 | << "); may not be negative"; 291 | throw std::invalid_argument(os.str()); 292 | 293 | } 294 | else if (n > 254) 295 | { 296 | double x = n + 1; 297 | return (x - 0.5)*log(x) - x + 0.5*log(2 * PI) + 1.0 / (12.0*x); 298 | } 299 | else 300 | { 301 | double lf[] = 302 | { 303 | 0.000000000000000, 304 | 0.000000000000000, 305 | 0.693147180559945, 306 | 1.791759469228055, 307 | 3.178053830347946, 308 | 4.787491742782046, 309 | 6.579251212010101, 310 | 8.525161361065415, 311 | 10.604602902745251, 312 | 12.801827480081469, 313 | 15.104412573075516, 314 | 17.502307845873887, 315 | 19.987214495661885, 316 | 22.552163853123421, 317 | 25.191221182738683, 318 | 27.899271383840894, 319 | 30.671860106080675, 320 | 33.505073450136891, 321 | 36.395445208033053, 322 | 39.339884187199495, 323 | 42.335616460753485, 324 | 45.380138898476908, 325 | 48.471181351835227, 326 | 51.606675567764377, 327 | 54.784729398112319, 328 | 58.003605222980518, 329 | 61.261701761002001, 330 | 64.557538627006323, 331 | 67.889743137181526, 332 | 71.257038967168000, 333 | 74.658236348830158, 334 | 78.092223553315307, 335 | 81.557959456115029, 336 | 85.054467017581516, 337 | 88.580827542197682, 338 | 92.136175603687079, 339 | 95.719694542143202, 340 | 99.330612454787428, 341 | 102.968198614513810, 342 | 106.631760260643450, 343 | 110.320639714757390, 344 | 114.034211781461690, 345 | 117.771881399745060, 346 | 121.533081515438640, 347 | 125.317271149356880, 348 | 129.123933639127240, 349 | 132.952575035616290, 350 | 136.802722637326350, 351 | 140.673923648234250, 352 | 144.565743946344900, 353 | 148.477766951773020, 354 | 152.409592584497350, 355 | 156.360836303078800, 356 | 160.331128216630930, 357 | 164.320112263195170, 358 | 168.327445448427650, 359 | 172.352797139162820, 360 | 176.395848406997370, 361 | 180.456291417543780, 362 | 184.533828861449510, 363 | 188.628173423671600, 364 | 192.739047287844900, 365 | 196.866181672889980, 366 | 201.009316399281570, 367 | 205.168199482641200, 368 | 209.342586752536820, 369 | 213.532241494563270, 370 | 217.736934113954250, 371 | 221.956441819130360, 372 | 226.190548323727570, 373 | 230.439043565776930, 374 | 234.701723442818260, 375 | 238.978389561834350, 376 | 243.268849002982730, 377 | 247.572914096186910, 378 | 251.890402209723190, 379 | 256.221135550009480, 380 | 260.564940971863220, 381 | 264.921649798552780, 382 | 269.291097651019810, 383 | 273.673124285693690, 384 | 278.067573440366120, 385 | 282.474292687630400, 386 | 286.893133295426990, 387 | 291.323950094270290, 388 | 295.766601350760600, 389 | 300.220948647014100, 390 | 304.686856765668720, 391 | 309.164193580146900, 392 | 313.652829949878990, 393 | 318.152639620209300, 394 | 322.663499126726210, 395 | 327.185287703775200, 396 | 331.717887196928470, 397 | 336.261181979198450, 398 | 340.815058870798960, 399 | 345.379407062266860, 400 | 349.954118040770250, 401 | 354.539085519440790, 402 | 359.134205369575340, 403 | 363.739375555563470, 404 | 368.354496072404690, 405 | 372.979468885689020, 406 | 377.614197873918670, 407 | 382.258588773060010, 408 | 386.912549123217560, 409 | 391.575988217329610, 410 | 396.248817051791490, 411 | 400.930948278915760, 412 | 405.622296161144900, 413 | 410.322776526937280, 414 | 415.032306728249580, 415 | 419.750805599544780, 416 | 424.478193418257090, 417 | 429.214391866651570, 418 | 433.959323995014870, 419 | 438.712914186121170, 420 | 443.475088120918940, 421 | 448.245772745384610, 422 | 453.024896238496130, 423 | 457.812387981278110, 424 | 462.608178526874890, 425 | 467.412199571608080, 426 | 472.224383926980520, 427 | 477.044665492585580, 428 | 481.872979229887900, 429 | 486.709261136839360, 430 | 491.553448223298010, 431 | 496.405478487217580, 432 | 501.265290891579240, 433 | 506.132825342034830, 434 | 511.008022665236070, 435 | 515.890824587822520, 436 | 520.781173716044240, 437 | 525.679013515995050, 438 | 530.584288294433580, 439 | 535.496943180169520, 440 | 540.416924105997740, 441 | 545.344177791154950, 442 | 550.278651724285620, 443 | 555.220294146894960, 444 | 560.169054037273100, 445 | 565.124881094874350, 446 | 570.087725725134190, 447 | 575.057539024710200, 448 | 580.034272767130800, 449 | 585.017879388839220, 450 | 590.008311975617860, 451 | 595.005524249382010, 452 | 600.009470555327430, 453 | 605.020105849423770, 454 | 610.037385686238740, 455 | 615.061266207084940, 456 | 620.091704128477430, 457 | 625.128656730891070, 458 | 630.172081847810200, 459 | 635.221937855059760, 460 | 640.278183660408100, 461 | 645.340778693435030, 462 | 650.409682895655240, 463 | 655.484856710889060, 464 | 660.566261075873510, 465 | 665.653857411105950, 466 | 670.747607611912710, 467 | 675.847474039736880, 468 | 680.953419513637530, 469 | 686.065407301994010, 470 | 691.183401114410800, 471 | 696.307365093814040, 472 | 701.437263808737160, 473 | 706.573062245787470, 474 | 711.714725802289990, 475 | 716.862220279103440, 476 | 722.015511873601330, 477 | 727.174567172815840, 478 | 732.339353146739310, 479 | 737.509837141777440, 480 | 742.685986874351220, 481 | 747.867770424643370, 482 | 753.055156230484160, 483 | 758.248113081374300, 484 | 763.446610112640200, 485 | 768.650616799717000, 486 | 773.860102952558460, 487 | 779.075038710167410, 488 | 784.295394535245690, 489 | 789.521141208958970, 490 | 794.752249825813460, 491 | 799.988691788643450, 492 | 805.230438803703120, 493 | 810.477462875863580, 494 | 815.729736303910160, 495 | 820.987231675937890, 496 | 826.249921864842800, 497 | 831.517780023906310, 498 | 836.790779582469900, 499 | 842.068894241700490, 500 | 847.352097970438420, 501 | 852.640365001133090, 502 | 857.933669825857460, 503 | 863.231987192405430, 504 | 868.535292100464630, 505 | 873.843559797865740, 506 | 879.156765776907600, 507 | 884.474885770751830, 508 | 889.797895749890240, 509 | 895.125771918679900, 510 | 900.458490711945270, 511 | 905.796028791646340, 512 | 911.138363043611210, 513 | 916.485470574328820, 514 | 921.837328707804890, 515 | 927.193914982476710, 516 | 932.555207148186240, 517 | 937.921183163208070, 518 | 943.291821191335660, 519 | 948.667099599019820, 520 | 954.046996952560450, 521 | 959.431492015349480, 522 | 964.820563745165940, 523 | 970.214191291518320, 524 | 975.612353993036210, 525 | 981.015031374908400, 526 | 986.422203146368590, 527 | 991.833849198223450, 528 | 997.249949600427840, 529 | 1002.670484599700300, 530 | 1008.095434617181700, 531 | 1013.524780246136200, 532 | 1018.958502249690200, 533 | 1024.396581558613400, 534 | 1029.838999269135500, 535 | 1035.285736640801600, 536 | 1040.736775094367400, 537 | 1046.192096209724900, 538 | 1051.651681723869200, 539 | 1057.115513528895000, 540 | 1062.583573670030100, 541 | 1068.055844343701400, 542 | 1073.532307895632800, 543 | 1079.012946818975000, 544 | 1084.497743752465600, 545 | 1089.986681478622400, 546 | 1095.479742921962700, 547 | 1100.976911147256000, 548 | 1106.478169357800900, 549 | 1111.983500893733000, 550 | 1117.492889230361000, 551 | 1123.006317976526100, 552 | 1128.523770872990800, 553 | 1134.045231790853000, 554 | 1139.570684729984800, 555 | 1145.100113817496100, 556 | 1150.633503306223700, 557 | 1156.170837573242400, 558 | }; 559 | return lf[n]; 560 | } 561 | } 562 | }; 563 | -------------------------------------------------------------------------------- /multi-platform/HershelPlus.cpp: -------------------------------------------------------------------------------- 1 | // Copyright © 2014 IRL at Texas A&M University (http://irl.cse.tamu.edu) 2 | // 3 | // This file is part of Hershel+. 4 | // 5 | // Hershel+ is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU Lesser General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // Hershel+ is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details 14 | // http://www.gnu.org/licenses/lgpl.txt. 15 | // 16 | // Contact: 17 | // Dmitri Loguinov (dmitri@cse.tamu.edu) 18 | // 19 | // Data and signatures: 20 | // http://irl.cse.tamu.edu/projects/osf 21 | // 22 | // Publication: 23 | // Z. Shamsi, D. Loguinov, "Unsupervised Clustering Under Temporal Feature 24 | // Volatility in Network Stack Fingerprinting, " ACM SIGMETRICS, June 2016. 25 | // 26 | // 27 | // Since Hershel+ requires the TCP handshake to remain half open, kernel RSTs need to be suppressed. 28 | // On Windows, the Windows firewall should do this by default 29 | // On Linux, inserting the following iptables rules will take care of this: 30 | // sudo iptables -t filter -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 31 | // sudo iptables -t filter -A INPUT -p icmp -j ACCEPT 32 | // sudo iptables -t filter -A INPUT -i lo -j ACCEPT 33 | // sudo iptables -t filter -A INPUT -j DROP 34 | // This accepts anything from established connections, icmp pings, and anything on the loopback interface and drops the rest. 35 | 36 | 37 | #ifdef _MSC_VER 38 | #define _CRT_SECURE_NO_WARNINGS 39 | #endif 40 | 41 | #include "LiveFingerprinter.h" 42 | 43 | 44 | #define OPT_MSS 1 // max segment size 45 | #define OPT_WIN 2 // window scaling 46 | #define OPT_TS 3 // timestamps 47 | #define OPT_SACK 4 // SACK allowed 48 | #define OPT_EOL 5 // end of list (another type of padding?) 49 | #define OPT_NOP 6 // padding 50 | 51 | //parameters for Hershel Plus matching 52 | #define HP_JITTER_LOSS_THRESHOLD 4 //how many seconds of jitter we can tolerate when figuring out loss combinations 53 | 54 | #define HP_JITTER_MEAN 0.5 55 | #define HP_JITTER_LAMBDA (1 / HP_JITTER_MEAN) 56 | #define HP_GAMMA_SHAPE 2.0 57 | #define HP_GAMMA_MEAN 0.5 58 | #define HP_GAMMA_SCALE (1 / (HP_GAMMA_SHAPE / HP_GAMMA_MEAN)) 59 | #define HP_GAMMA_NU (HP_GAMMA_SHAPE / HP_GAMMA_MEAN) 60 | #define HP_LOSS_PROB 0.038 61 | #define HP_FEATURE_PROB_PI_RST_OPT 0.01 62 | #define HP_FEATURE_PROB_PI 0.1 63 | 64 | #define T_GUESS_LIMIT_IN_SECS 4.0 65 | #define T_NUM_BINS 100 66 | #define Q_GUESS_LIMIT_IN_SECS 4.0 67 | #define Q_NUM_BINS 100 68 | 69 | using namespace std; 70 | 71 | int factorial(int n) { 72 | return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n; 73 | } 74 | 75 | //Hershel RTO Estimator 76 | class HershelPlusEstimator{ 77 | public: 78 | public: 79 | int y_nPkts; 80 | int x_nPkts; 81 | double subOS_prob; 82 | double t_step_size = T_GUESS_LIMIT_IN_SECS / T_NUM_BINS; 83 | double owd_step_size = Q_GUESS_LIMIT_IN_SECS / Q_NUM_BINS; 84 | vector& x_timestamps; 85 | vector& y_timestamps; 86 | vector& t_prob_array; 87 | vector& owd_prob_array; 88 | vector accumulator; 89 | 90 | HershelPlusEstimator(vector& sample, vector& signature, vector& tarray, vector& owdarray) 91 | :subOS_prob(0), x_timestamps(sample), y_timestamps(signature), t_prob_array(tarray), owd_prob_array(owdarray) 92 | { 93 | y_nPkts = signature.size(); 94 | x_nPkts = sample.size(); 95 | accumulator.resize(x_nPkts); 96 | } 97 | 98 | void ExamineCombination(vector& gamma) { 99 | double gamma_prob = 0; 100 | double t_limit = T_GUESS_LIMIT_IN_SECS; 101 | 102 | //but T has to be less than the smallest distance between any x and y 103 | for (int t = 0; t < x_nPkts; t++) { 104 | double d = x_timestamps[t] - y_timestamps[gamma[t]]; 105 | if (d < t_limit) t_limit = d; 106 | } 107 | 108 | 109 | for (double t_guess = 0; t_guess <= t_limit; t_guess += t_step_size) { 110 | double probQ = 1; 111 | 112 | int t_index = t_guess / t_step_size; 113 | double probT = t_prob_array[t_index]; 114 | 115 | //for each received packet, determine the OWD (Q) and calculate \prod p(Q) 116 | for (int t = 0; t < x_nPkts; t++) { 117 | double Q = (x_timestamps[t] - y_timestamps[gamma[t]] - t_guess); 118 | if (Q < 0) { 119 | probQ = 0; 120 | break; 121 | } 122 | else { 123 | int owd_index = Q / owd_step_size; 124 | if (owd_index > owd_prob_array.size() - 1) owd_index = owd_prob_array.size() - 1; 125 | double p = owd_prob_array[owd_index]; 126 | probQ *= p; 127 | } 128 | } 129 | 130 | //the prob of this gamma with this T is p(T) * \prod p(Q) 131 | gamma_prob += probQ * probT; 132 | } 133 | 134 | subOS_prob += gamma_prob; 135 | } 136 | 137 | void ProduceLossPatterns(int remaining, int start, int accumulatorSize) { 138 | if (remaining > 0) { 139 | for (int i = start; i < y_nPkts - remaining + 1; i++) { 140 | bool possible = false; 141 | double diff = x_timestamps[accumulatorSize] - y_timestamps[i]; 142 | if (diff >= 0) { // must arrive after the signature's timestamp 143 | if (accumulatorSize == 0) // first packet being matched: allow it since the RTT can be anything 144 | possible = true; 145 | else {// non-first packet: do a test on jitter 146 | double jitt = x_timestamps[accumulatorSize] - x_timestamps[accumulatorSize - 1] - 147 | (y_timestamps[i] - y_timestamps[accumulator[accumulatorSize - 1]]); 148 | // TODO: automatically determine the value of jitter for this cutoff 149 | // need the jitter PMF and some threshold: CDF sum above the threshold should be less than some small number 150 | if (abs(jitt) < HP_JITTER_LOSS_THRESHOLD) // only if less than "JITTER_THRESHOLD" OWD 151 | possible = true; 152 | } 153 | } 154 | if (possible) { 155 | accumulator[accumulatorSize] = i; 156 | ProduceLossPatterns(remaining - 1, i + 1, accumulatorSize + 1); 157 | } 158 | } 159 | } 160 | else { 161 | //if (produced == 0) // emulates always taking the first x[i].nPkts packets of the signature 162 | ExamineCombination(accumulator); 163 | //produced ++; 164 | } 165 | } 166 | }; 167 | 168 | /*********************CONSTANT FEATURE MATCHING***********************/ 169 | 170 | //match int64 options, intersection of both tar and sig should be ordered the same 171 | int options_match_int64(unsigned long long tar_opts, unsigned long long sig_opts) { 172 | if (tar_opts == sig_opts) return 2; 173 | 174 | //keep track of where we found our last option in sig list 175 | int last_found_position = -1; 176 | unsigned long long sig_it; 177 | 178 | while (tar_opts > 0) { 179 | int opt = -1; 180 | while (opt != OPT_MSS && opt != OPT_WIN && opt != OPT_SACK && opt != OPT_TS) { //skip unimportant bits 181 | if (tar_opts == 0) return 1; //we've matched so far and reached 0 without another option 182 | //get last 3 bits from target 183 | opt = tar_opts & 0x7; //AND by 3 bits to get value 184 | //move to next option 185 | tar_opts = tar_opts >> 3; 186 | } 187 | 188 | sig_it = sig_opts; //reset iterator to beginning 189 | int position = 0; 190 | bool found = false; 191 | while (sig_it > 0) { //go through sig_opt list 192 | int sopt = sig_it & 0x7; 193 | if (sopt == opt) { //if found 194 | if (position < last_found_position) return 0; //found it before the last one, doesnt match ordering 195 | else last_found_position = position; 196 | found = true; 197 | break; 198 | } 199 | sig_it = sig_it >> 3; 200 | position++; 201 | } 202 | if (!found) { 203 | //not found in list, was probably enabled by user - do nothing here 204 | } 205 | } 206 | 207 | //all there 208 | return 1; 209 | } 210 | 211 | //calculate likeliest class by adding FEATURE_CHANGE_PROBABILITY onto candidates 212 | double MatchConstantFeatures(Signature& target, Signature& dbsig) { 213 | double prob = 1; 214 | 215 | if (target.win == dbsig.win) prob *= (1 - HP_FEATURE_PROB_PI); 216 | else prob *= HP_FEATURE_PROB_PI; 217 | 218 | if (target.ttl == dbsig.ttl) prob *= (1 - HP_FEATURE_PROB_PI); 219 | else prob *= HP_FEATURE_PROB_PI; 220 | 221 | if (target.df == dbsig.df) prob *= (1 - HP_FEATURE_PROB_PI); 222 | else prob *= HP_FEATURE_PROB_PI; 223 | 224 | int oval = options_match_int64(target.options_int, dbsig.options_int); 225 | if (oval < 1) prob *= HP_FEATURE_PROB_PI_RST_OPT; 226 | else if (oval == 1) prob *= HP_FEATURE_PROB_PI; 227 | else if (oval > 1) prob *= (1 - HP_FEATURE_PROB_PI); 228 | 229 | if (target.mss == dbsig.mss) prob *= (1 - HP_FEATURE_PROB_PI); 230 | else prob *= HP_FEATURE_PROB_PI; 231 | 232 | if (target.rst) { 233 | //rst_seq not used as it does not provide any new information. nonzero is a better feature in all regards 234 | if (target.rst == dbsig.rst && target.rst_ack == dbsig.rst_ack && target.rst_win == dbsig.rst_win && target.rst_nonzero == dbsig.rst_nonzero) prob *= (1 - HP_FEATURE_PROB_PI_RST_OPT); 235 | else prob *= HP_FEATURE_PROB_PI_RST_OPT; 236 | } 237 | return prob; 238 | } 239 | 240 | /***********************************************************************/ 241 | 242 | void HershelPlus(unordered_map>& database, vector& observations){ 243 | printf("\n---Starting Hershel+ Classification on %zd observation(s)---\n", observations.size()); 244 | 245 | //set up T probabilities as Erlang2 246 | vector t_prob_array; 247 | double sum = 0; 248 | double common = pow(HP_GAMMA_NU, HP_GAMMA_SHAPE) / factorial(HP_GAMMA_SHAPE - 1); 249 | for (int s = 0; s < T_NUM_BINS; s++) { 250 | double x = (s + 1) * T_GUESS_LIMIT_IN_SECS / T_NUM_BINS; 251 | double prob = common * pow(x, HP_GAMMA_SHAPE - 1) * exp(-HP_GAMMA_NU * x); 252 | t_prob_array.push_back(prob); 253 | sum += prob; 254 | } 255 | //normalize array 256 | for (int i = 0; i < t_prob_array.size(); i++) { 257 | t_prob_array[i] = t_prob_array[i] / sum; 258 | } 259 | 260 | //set up OWD probabilities as exponential 261 | vector owd_prob_array; 262 | sum = 0; 263 | for (int s = 0; s < Q_NUM_BINS; s++) { 264 | double x = (s + 1) * Q_GUESS_LIMIT_IN_SECS / Q_NUM_BINS; 265 | double prob = exp(-HP_JITTER_LAMBDA * x); 266 | owd_prob_array.push_back(prob); 267 | sum += prob; 268 | } 269 | //normalize array 270 | for (int i = 0; i < owd_prob_array.size(); i++){ 271 | owd_prob_array[i] = owd_prob_array[i] / sum; 272 | } 273 | 274 | int unclassified = 0; 275 | 276 | //run through all observations and classify 277 | for (int i = 0; i < observations.size(); i++){ 278 | //get next host 279 | Signature target = observations[i]; 280 | double highest_prob = 0; 281 | unsigned int highest_id = 0; 282 | 283 | for (auto it = database.begin(); it != database.end(); it++){ 284 | double os_prob = 0; 285 | 286 | //get difference in lengths 287 | int lost_packets = it->second[0].packet_arrival_time.size() - target.packet_arrival_time.size(); 288 | 289 | //apply loss filter, cant receive more packets than signature 290 | if (lost_packets >= 0){ 291 | 292 | //for each subOS 293 | for (int r = 0; r < it->second.size(); r++){ 294 | 295 | //get the probability of this subOS rto vs. target using estimator 296 | HershelPlusEstimator e(target.packet_arrival_time, it->second[r].packet_arrival_time, t_prob_array, owd_prob_array); 297 | e.ProduceLossPatterns(target.packet_arrival_time.size(), 0, 0); 298 | 299 | os_prob += e.subOS_prob; //for all subOS prob 300 | } 301 | 302 | //multiply by lost packet prob 303 | os_prob *= pow(HP_LOSS_PROB, lost_packets) * pow(1 - HP_LOSS_PROB, target.packet_arrival_time.size()); 304 | 305 | //match constants 306 | os_prob *= MatchConstantFeatures(target, it->second[0]); 307 | } 308 | 309 | //track highest prob 310 | if (os_prob > highest_prob){ 311 | highest_prob = os_prob; 312 | highest_id = it->first; 313 | } 314 | } 315 | 316 | if (highest_id == 0) unclassified++; 317 | observations[i].id_classified = highest_id; 318 | 319 | } 320 | 321 | } 322 | 323 | vector readSigList(char *filename){ 324 | //read signatures into vector 325 | vector retvec; 326 | int sig_count = 0; 327 | int BUFFER_SIZE = (1 << 12); //4MB 328 | 329 | FILE* fin = fopen(filename, "r"); 330 | if (fin == NULL){ 331 | printf("Error opening file %s!\n", filename); 332 | exit(-1); 333 | } 334 | else printf("\nReading from %s...\n", filename); 335 | char* buffer = new char[BUFFER_SIZE]; 336 | int count; 337 | double timestamp = 0; 338 | vector rtos; 339 | 340 | while (!feof(fin)){ 341 | Signature sig; 342 | 343 | //read next line 344 | fgets(buffer, BUFFER_SIZE, fin); 345 | char* bufferptr = buffer; 346 | 347 | sscanf(bufferptr, "%u,%d,%d,%d,%[^,],%lld,%d,%d,%d,%d,%d%n", 348 | &sig.id, &sig.win, &sig.ttl, &sig.df, sig.options_str, &sig.options_int, &sig.mss, &sig.rst, &sig.rst_ack, &sig.rst_win, &sig.rst_nonzero, &count); 349 | 350 | bufferptr += count; 351 | 352 | while (strcmp(bufferptr, "\n") != 0 && strlen(bufferptr) > 0){ 353 | sscanf(bufferptr, ",%lf%n", ×tamp, &count); 354 | sig.packet_arrival_time.push_back(timestamp); 355 | 356 | bufferptr += count; 357 | } 358 | 359 | retvec.push_back(sig); 360 | sig_count++; 361 | if (sig_count % 10000 == 0) printf("Read %d signatures...\r", sig_count); 362 | } 363 | 364 | fclose(fin); 365 | printf("Stored %zu signatures in map\n", retvec.size()); 366 | return retvec; 367 | } 368 | 369 | int main(int argc, char* argv[]){ 370 | if (argc < 4){ 371 | printf("%s can be run in two modes: Live and Offline.\n", argv[0]); 372 | printf("To run in live mode: %s \n", argv[0]); 373 | printf("To run in offline mode: %s \n", argv[0]); 374 | return 0; 375 | } 376 | 377 | //read database signatures 378 | vector database_sigs = readSigList(argv[1]); 379 | //combine them into a hashmap for easier organization 380 | unordered_map> database; 381 | for (Signature s : database_sigs) database[s.id].push_back(s); 382 | 383 | //read class to OS label mapping 384 | FILE *fin = fopen(argv[2], "r"); 385 | if (fin == NULL){ 386 | printf("Error opening file %s!\n", argv[3]); 387 | exit(-1); 388 | } 389 | unordered_map os_mapping; 390 | char buffer[512]; 391 | while (!feof(fin)){ 392 | int id; 393 | char osname[512]; 394 | 395 | fgets(buffer, 512, fin); 396 | sscanf(buffer, "%d,%[^\n]", &id, osname); 397 | os_mapping[id] = string(osname); 398 | } 399 | 400 | //determine if next argument is an IP 401 | unsigned short port; 402 | vector observations; 403 | unsigned int ip = inet_addr(argv[3]); 404 | if (ip != INADDR_NONE){ 405 | //it was an ip 406 | if (argc < 5) { 407 | printf("Port argument missing\n"); 408 | exit(-1); 409 | } 410 | port = atoi(argv[4]); 411 | 412 | //set up for live fingerprinting 413 | printf("Starting Live fingerprinting of %s:%d...\n", argv[3], port); 414 | LiveFingerprinter lf; 415 | if (lf.setupPcapAdapter() < 0){ 416 | printf("Error setting up pcap!\n"); 417 | exit(-1); 418 | } 419 | 420 | Signature s; 421 | if (lf.getFingerprint(argv[3], port, s) < 0){ 422 | printf("Error getting fingerprint\n"); 423 | exit(-1); 424 | } 425 | 426 | observations.push_back(s); 427 | } 428 | else { 429 | //it was not an IP, read observations 430 | observations = readSigList(argv[3]); 431 | } 432 | 433 | //run Hershel on observations 434 | HershelPlus(database, observations); 435 | 436 | //print out observation results 437 | for (Signature o : observations){ 438 | printf("Observed signature: %d,%d,%d,%s,%d,%d,%d,%d,%d,%d", o.win, o.ttl, o.df, o.options_str, o.mss, o.rst, o.rst_ack, o.rst_win, o.rst_seq, o.rst_nonzero); 439 | for (u_int r = 0; r < o.packet_arrival_time.size(); r++) printf(",%lf", o.packet_arrival_time[r]); 440 | printf("\n"); 441 | printf("Matching signature: "); 442 | printf("%d,%d,%d,%s,%d,%d,%d,%d,%d,%d", database[o.id_classified][0].win, database[o.id_classified][0].ttl, database[o.id_classified][0].df, database[o.id_classified][0].options_str, database[o.id_classified][0].mss, database[o.id_classified][0].rst, database[o.id_classified][0].rst_ack, database[o.id_classified][0].rst_win, database[o.id_classified][0].rst_seq, database[o.id_classified][0].rst_nonzero); 443 | for (u_int r = 0; r < database[o.id_classified][0].packet_arrival_time.size(); r++) printf(",%lf", database[o.id_classified][0].packet_arrival_time[r]); 444 | printf("\n"); 445 | 446 | printf("\tObservation %u classified as %s \n\n", o.id, os_mapping[o.id_classified].c_str()); 447 | } 448 | } 449 | -------------------------------------------------------------------------------- /VSProject/HershelPlus/HershelPlusOptimized.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Hershel Plus "Optimized" uses closed form of Hershel Plus equation, as opposed to calculating the integral numerically 3 | 4 | */ 5 | 6 | #include "defines.h" 7 | 8 | //parameters for Hershel Plus matching 9 | #define HP_JITTER_LOSS_THRESHOLD 4 //how many seconds of jitter we can tolerate when figuring out loss combinations 10 | 11 | #define HP_JITTER_MEAN 0.5 12 | #define HP_JITTER_LAMBDA (1 / HP_JITTER_MEAN) 13 | #define HP_GAMMA_SHAPE 2.0 14 | #define HP_GAMMA_MEAN 0.5 15 | #define HP_GAMMA_SCALE (1 / (HP_GAMMA_SHAPE / HP_GAMMA_MEAN)) 16 | #define HP_GAMMA_NU (HP_GAMMA_SHAPE / HP_GAMMA_MEAN) 17 | #define HP_LOSS_PROB 0.038 18 | #define HP_FEATURE_PROB_PI_RST_OPT 0.01 19 | #define HP_FEATURE_PROB_PI 0.1 20 | 21 | #define T_GUESS_LIMIT_IN_SECS 4.0 22 | #define T_NUM_BINS 100 23 | #define Q_GUESS_LIMIT_IN_SECS 4.0 24 | #define Q_NUM_BINS 100 25 | 26 | vector owd_prob_array; 27 | 28 | class HPlusOptimizedEstimator{ 29 | public: 30 | int y_nPkts; 31 | int x_nPkts; 32 | double subOS_prob; 33 | vector& x_timestamps; 34 | vector& y_timestamps; 35 | vector accumulator; 36 | 37 | HPlusOptimizedEstimator(vector& sample, vector& signature) 38 | :subOS_prob(0), x_timestamps(sample), y_timestamps(signature) 39 | { 40 | y_nPkts = signature.size(); 41 | x_nPkts = sample.size(); 42 | accumulator.resize(x_nPkts); 43 | } 44 | 45 | void ExamineCombination(vector& gamma){ 46 | double gamma_prob = 1; 47 | double s = DBL_MAX; //keep track of the min e_m seen 48 | 49 | //for each received packet, determine the OWD (Q) and calculate \prod p(Q) 50 | for (int m = 0; m < x_nPkts; m++){ 51 | double em = x_timestamps[m] - y_timestamps[gamma[m]]; 52 | if (em < 0){ 53 | gamma_prob = 0; 54 | } 55 | else { 56 | int owd_index = em / (Q_GUESS_LIMIT_IN_SECS / Q_NUM_BINS); 57 | if (owd_index > owd_prob_array.size() - 1) owd_index = owd_prob_array.size() - 1; 58 | gamma_prob *= owd_prob_array[owd_index]; 59 | 60 | //gamma_prob *= exp(-HP_JITTER_LAMBDA * em); 61 | 62 | if (em < s) s = em; 63 | } 64 | } 65 | 66 | if (gamma_prob > 0){ 67 | //have case for denom = 0 68 | if (x_nPkts == HP_GAMMA_NU / HP_JITTER_LAMBDA) gamma_prob *= (s * s) / 2; 69 | //else gamma_prob *= (exp(-HP_GAMMA_NU * s) * (exp(HP_JITTER_LAMBDA * s * x_nPkts) * (HP_JITTER_LAMBDA * s * x_nPkts - HP_GAMMA_NU * s - 1) + exp(HP_GAMMA_NU * s))) / pow((HP_GAMMA_NU - HP_JITTER_LAMBDA * x_nPkts), 2); //result from Wolfram 70 | else gamma_prob *= (1 - exp(s * (-HP_GAMMA_NU * HP_JITTER_LAMBDA * x_nPkts)) * (1 + s * (HP_GAMMA_NU - HP_JITTER_LAMBDA * x_nPkts))) / pow((HP_GAMMA_NU - HP_JITTER_LAMBDA * x_nPkts), 2); // to match paper (16) 71 | 72 | //multiply by the constant for completeness 73 | //gamma_prob *= HP_JITTER_LAMBDA * pow(HP_GAMMA_NU, 2); 74 | gamma_prob *= pow(HP_JITTER_LAMBDA, x_nPkts) * pow(HP_GAMMA_NU, 2); //to match paper (16) 75 | 76 | } 77 | 78 | subOS_prob += gamma_prob; 79 | } 80 | 81 | void ProduceLossPatterns(int remaining, int start, int accumulatorSize){ 82 | if (remaining > 0){ 83 | for (int i = start; i < y_nPkts - remaining + 1; i++){ 84 | bool possible = false; 85 | double diff = x_timestamps[accumulatorSize] - y_timestamps[i]; 86 | if (diff >= 0){ // must arrive after the signature's timestamp 87 | if (accumulatorSize == 0) // first packet being matched: allow it since the RTT can be anything 88 | possible = true; 89 | else {// non-first packet: do a test on jitter 90 | double jitt = x_timestamps[accumulatorSize] - x_timestamps[accumulatorSize - 1] - 91 | (y_timestamps[i] - y_timestamps[accumulator[accumulatorSize - 1]]); 92 | // TODO: automatically determine the value of jitter for this cutoff 93 | // need the jitter PMF and some threshold: CDF sum above the threshold should be less than some small number 94 | if (abs(jitt) < HP_JITTER_LOSS_THRESHOLD) // only if less than "JITTER_THRESHOLD" OWD 95 | possible = true; 96 | } 97 | } 98 | if (possible){ 99 | accumulator[accumulatorSize] = i; 100 | ProduceLossPatterns(remaining - 1, i + 1, accumulatorSize + 1); 101 | } 102 | } 103 | } 104 | else { 105 | //if (produced == 0) // emulates always taking the first x[i].nPkts packets of the signature 106 | ExamineCombination(accumulator); 107 | //produced ++; 108 | } 109 | } 110 | }; 111 | 112 | struct HPOThreadVars{ 113 | HANDLE mutex; 114 | int correct; 115 | int wrong; 116 | int thread_id; 117 | map> training_data; 118 | vector observations; 119 | map classcounts; 120 | }; 121 | 122 | /*********************CONSTANT FEATURE MATCHING***********************/ 123 | 124 | //match int64 options, intersection of both tar and sig should be ordered the same 125 | int options_match_int64(unsigned long long tar_opts, unsigned long long sig_opts){ 126 | if (tar_opts == sig_opts) return 2; 127 | 128 | int count = 0; 129 | 130 | //keep track of where we found our last option in sig list 131 | int last_found_position = -1; 132 | unsigned long long sig_it; 133 | 134 | while (tar_opts > 0){ 135 | int opt = -1; 136 | while (opt != OPT_MSS && opt != OPT_WIN && opt != OPT_SACK && opt != OPT_TS){ //skip unimportant bits 137 | if (tar_opts == 0) return 1; //we've matched so far and reached 0 without another option 138 | //get last 3 bits from target 139 | opt = tar_opts & 0x7; //AND by 3 bits to get value 140 | //move to next option 141 | tar_opts = tar_opts >> 3; 142 | } 143 | 144 | sig_it = sig_opts; //reset iterator to beginning 145 | int position = 0; 146 | bool found = false; 147 | while (sig_it > 0){ //go through sig_opt list 148 | int sopt = sig_it & 0x7; 149 | if (sopt == opt){ //if found 150 | if (position < last_found_position) return 0; //found it before the last one, doesnt match ordering 151 | else last_found_position = position; 152 | found = true; 153 | break; 154 | } 155 | sig_it = sig_it >> 3; 156 | position++; 157 | } 158 | if (!found){ 159 | //not found in list, was probably enabled by user - do nothing here 160 | } 161 | } 162 | 163 | //all there 164 | return 1; 165 | } 166 | 167 | //calculate likeliest class by adding FEATURE_CHANGE_PROBABILITY onto candidates 168 | double MatchConstantFeatures(Signature& target, Signature& dbsig){ 169 | double total_prob; 170 | 171 | if (!features_enabled[0]){ 172 | total_prob = 0; 173 | //if not using RTO, do a constant score match for simplicity and to avoid probability rounding errors 174 | if (features_enabled[1]){ 175 | if (target.win == dbsig.win) total_prob++; 176 | } 177 | if (features_enabled[2]){ 178 | if (target.ttl == dbsig.ttl) total_prob++; 179 | } 180 | if (features_enabled[3]){ 181 | if (target.df == dbsig.df) total_prob++; 182 | } 183 | if (features_enabled[4]){ 184 | int oval = options_match_int64(target.options_int, dbsig.options_int); 185 | if (oval >= 1) total_prob++; 186 | } 187 | if (features_enabled[5]){ 188 | if (target.mss == dbsig.mss) total_prob++; 189 | } 190 | if (target.rst){ 191 | if (features_enabled[6]){ 192 | if (target.rst == dbsig.rst && target.rst_ack == dbsig.rst_ack && target.rst_win == dbsig.rst_win && target.rst_nonzero == dbsig.rst_nonzero) total_prob++; 193 | } 194 | } 195 | 196 | } 197 | else{ 198 | //start with total prob = 1 199 | total_prob = 1; 200 | 201 | if (features_enabled[1]){ 202 | if (target.win == dbsig.win) total_prob *= (1 - HP_FEATURE_PROB_PI); 203 | else total_prob *= HP_FEATURE_PROB_PI; 204 | } 205 | if (features_enabled[2]){ 206 | if (target.ttl == dbsig.ttl) total_prob *= (1 - HP_FEATURE_PROB_PI); 207 | else total_prob *= HP_FEATURE_PROB_PI; 208 | } 209 | if (features_enabled[3]){ 210 | if (target.df == dbsig.df) total_prob *= (1 - HP_FEATURE_PROB_PI); 211 | else total_prob *= HP_FEATURE_PROB_PI; 212 | } 213 | if (features_enabled[4]){ 214 | int oval = options_match_int64(target.options_int, dbsig.options_int); 215 | if (oval <= 1) total_prob *= HP_FEATURE_PROB_PI_RST_OPT; 216 | else if (oval > 1) total_prob *= (1 - HP_FEATURE_PROB_PI_RST_OPT); 217 | } 218 | if (features_enabled[5]){ 219 | if (target.mss == dbsig.mss) total_prob *= (1 - HP_FEATURE_PROB_PI); 220 | else total_prob *= HP_FEATURE_PROB_PI; 221 | } 222 | if (features_enabled[6]){ 223 | if (target.rst == dbsig.rst && target.rst_ack == dbsig.rst_ack && target.rst_win == dbsig.rst_win && target.rst_nonzero == dbsig.rst_nonzero) total_prob *= (1 - HP_FEATURE_PROB_PI_RST_OPT); 224 | else total_prob *= HP_FEATURE_PROB_PI_RST_OPT; 225 | 226 | //treat rst win differently 227 | //if (target.rst_win == candidates[i].rst_win) candidates[i].prob *= (1 - FEATURE_PROB_PI); 228 | //else candidates[i].prob *= FEATURE_PROB_PI; 229 | } 230 | } 231 | 232 | return total_prob; 233 | } 234 | 235 | /***********************************************************************/ 236 | 237 | //Thread function for Hershel+ Optimized MT 238 | void HershelPlusOptimized_Thread(LPVOID thread_variables){ 239 | HPOThreadVars* hpt = (HPOThreadVars*)thread_variables; 240 | 241 | WaitForSingleObject(hpt->mutex, INFINITE); //LOCK Mutex to give self an id 242 | 243 | int thread_id = hpt->thread_id; 244 | hpt->thread_id++; 245 | 246 | ReleaseMutex(hpt->mutex); // RELEASE Mutex 247 | 248 | map>::iterator it; 249 | for (int i = thread_id; i < hpt->observations.size(); i += NUM_THREADS){ 250 | u_int chosenOS = 0; 251 | double probsum = 0; 252 | double maxprob = 0; //keep track of max prob 253 | double secondprob = 0; //keep track of second highest prob 254 | 255 | for (it = hpt->training_data.begin(); it != hpt->training_data.end(); it++){ 256 | double osprob = 0; 257 | 258 | if (features_enabled[0]) { 259 | //training data RTO vector must be >= size of sample, due to loss 260 | int lost_packets = it->second[0].packet_arrival_time.size() - hpt->observations[i].packet_arrival_time.size(); 261 | if (lost_packets >= 0) { 262 | 263 | double totalsum = 0; 264 | //for each subOS tj of dbsig 265 | for (int tj = 0; tj < it->second.size(); tj++) { 266 | 267 | //calculate jitter probability using Estimator 268 | HPlusOptimizedEstimator e(hpt->observations[i].packet_arrival_time, it->second[tj].packet_arrival_time); 269 | e.ProduceLossPatterns(hpt->observations[i].packet_arrival_time.size(), 0, 0); 270 | totalsum += e.subOS_prob; 271 | 272 | } 273 | 274 | //get average over all subOS 275 | osprob = totalsum / it->second.size(); 276 | 277 | //add loss probability 278 | osprob *= pow(HP_LOSS_PROB, lost_packets) * pow(1 - HP_LOSS_PROB, hpt->observations[i].packet_arrival_time.size()); 279 | } 280 | } 281 | osprob *= MatchConstantFeatures(hpt->observations[i], it->second[0]); 282 | 283 | if (osprob > maxprob){ 284 | secondprob = maxprob; 285 | maxprob = osprob; 286 | chosenOS = it->first; 287 | } 288 | else { 289 | if (osprob > secondprob) secondprob = osprob; 290 | } 291 | 292 | probsum += osprob; 293 | } 294 | 295 | //track the normalized probability matched for the best and second-best match 296 | hpt->observations[i].maxprob_norm = maxprob / probsum; 297 | hpt->observations[i].secondprob_norm = secondprob / probsum; 298 | 299 | WaitForSingleObject(hpt->mutex, INFINITE); //LOCK Mutex to write correct or wrong 300 | 301 | if (!REAL_DATA){ 302 | if (chosenOS == hpt->observations[i].id_int) hpt->correct++; 303 | else { 304 | hpt->wrong++; 305 | } 306 | } 307 | else { 308 | hpt->classcounts[chosenOS]++; 309 | hpt->observations[i].id_classified = chosenOS; 310 | hpt->correct++; 311 | } 312 | 313 | ReleaseMutex(hpt->mutex); // RELEASE Mutex 314 | } 315 | } 316 | 317 | //Multi threaded Hershel+ Optimized 318 | void HershelPlusOptimized_MT(map > database_sigs, vector observations){ 319 | printf("\n---Starting H+ Classification (Using closed form)--\n"); 320 | 321 | //set up OWD probabilities 322 | double sum = 0; 323 | 324 | for (DWORD s = 0; s < Q_NUM_BINS; s++) { 325 | double x = (s + 1) * Q_GUESS_LIMIT_IN_SECS / Q_NUM_BINS; 326 | double prob = exp(-HP_JITTER_LAMBDA * x); 327 | owd_prob_array.push_back(prob); 328 | sum += prob; 329 | } 330 | //normalize array 331 | for (int i = 0; i < owd_prob_array.size(); i++){ 332 | owd_prob_array[i] = owd_prob_array[i] / sum; 333 | } 334 | 335 | HPOThreadVars hpt; 336 | hpt.mutex = CreateMutex(NULL, 0, NULL); 337 | hpt.correct = 0; 338 | hpt.wrong = 0; 339 | hpt.thread_id = 0; 340 | hpt.observations = observations; 341 | hpt.training_data = database_sigs; 342 | 343 | HANDLE *handles = new HANDLE[NUM_THREADS]; 344 | //Split Threads 345 | for (int i = 0; i < NUM_THREADS; i++){ 346 | handles[i] = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)HershelPlusOptimized_Thread, &hpt, 0, NULL); 347 | SetThreadPriority(handles[i], THREAD_PRIORITY_LOWEST); 348 | } 349 | 350 | //Print info every 5 secs until no more active threads 351 | printf("Started %d threads...\n\n", NUM_THREADS); 352 | 353 | int sleep_interval = 5000; 354 | int remaining, done_count, old_done_count = 0, step = 0; 355 | double avg_rate = 0, sum_rate = 0; 356 | while (true){ 357 | //calculate done and remaining 358 | done_count = hpt.correct + hpt.wrong; 359 | remaining = hpt.observations.size() - done_count; 360 | 361 | double rate = (done_count - old_done_count) / (double)(sleep_interval / 1000); 362 | 363 | sum_rate += rate; 364 | step++; 365 | avg_rate = sum_rate / step; 366 | double time_remaining = (remaining / avg_rate) / 60; 367 | 368 | if (!REAL_DATA) printf("IPs left: %d, Correct: %.2lf, Done: %d at %f per sec. %f min to go\r", remaining, (double)hpt.correct / done_count, done_count, rate, time_remaining); 369 | else printf("IPs left: %d, Done: %d at %f per sec. %f min to go\r", remaining, done_count, rate, time_remaining); 370 | 371 | old_done_count = done_count; 372 | if (remaining <= 0) break; 373 | Sleep(sleep_interval); 374 | } 375 | 376 | //Wait for threads to return 377 | printf("\n--->Quit Condition Reached!<---\nWaiting for all threads to end..\n"); 378 | WaitForMultipleObjects(NUM_THREADS, handles, TRUE, INFINITE); 379 | 380 | // Close handles 381 | for (int i = 0; i < NUM_THREADS; i++) CloseHandle(handles[i]); 382 | CloseHandle(hpt.mutex); 383 | 384 | if (!REAL_DATA) printf("--------->Correct: %d, Accuracy: %f\n", hpt.correct, (double)hpt.correct / hpt.observations.size()); 385 | else { 386 | //print out the results 387 | FILE* fout; 388 | fopen_s(&fout, "internet_classcounts.txt", "w"); 389 | for (auto cc : hpt.classcounts) fprintf(fout, "%s, %d\n", id_to_label_map[cc.first].c_str(), cc.second); 390 | fclose(fout); 391 | 392 | fopen_s(&fout, "internet_results.txt", "w"); 393 | fprintf(fout, "Internet ID, Classified ID, Label, MaxProb, SecondMaxProb\n"); 394 | for (int i = 0; i < hpt.observations.size(); i++){ 395 | fprintf(fout, "%u, %u, %s, %lf, %lf\n", hpt.observations[i].id_int, hpt.observations[i].id_classified, id_to_label_map[hpt.observations[i].id_classified].c_str(), hpt.observations[i].maxprob_norm, hpt.observations[i].secondprob_norm); 396 | } 397 | fclose(fout); 398 | 399 | printf("Result files written.\n"); 400 | } 401 | 402 | } 403 | 404 | //Single threaded Hershel+ Optimized 405 | void HershelPlusOptimized_ST(map > database_sigs, vector observations){ 406 | //use the closed form equation to get probability 407 | 408 | int correct = 0, wrong = 0; 409 | int total = 0; 410 | 411 | //classify each observed vector (tau) 412 | for (int t = 0; t < observations.size(); t++){ 413 | 414 | double highest_prob = 0; 415 | u_int highest_matching_ip = UINT_MAX; 416 | 417 | //for each database sig 418 | for (auto dbsig : database_sigs){ 419 | 420 | int lost_packets = dbsig.second[0].packet_arrival_time.size() - observations[t].packet_arrival_time.size(); 421 | 422 | double total_prob = 0; 423 | 424 | if (lost_packets >= 0){ 425 | 426 | //for each subOS tj of dbsig 427 | for (int tj = 0; tj < dbsig.second.size(); tj++){ 428 | 429 | //calculate jitter probability using Estimator 430 | HPlusOptimizedEstimator e(observations[t].packet_arrival_time, dbsig.second[tj].packet_arrival_time); 431 | e.ProduceLossPatterns(observations[t].packet_arrival_time.size(), 0, 0); 432 | total_prob += e.subOS_prob; 433 | 434 | } 435 | 436 | //get average over all subOS 437 | total_prob /= dbsig.second.size(); 438 | 439 | //add loss probability 440 | total_prob *= pow(HP_LOSS_PROB, lost_packets) * pow(1 - HP_LOSS_PROB, observations[t].packet_arrival_time.size()); 441 | } 442 | 443 | if (total_prob > highest_prob){ 444 | highest_prob = total_prob; 445 | highest_matching_ip = dbsig.first; 446 | } 447 | } 448 | 449 | //mark correct or incorrect 450 | if (highest_matching_ip == observations[t].id_int) correct++; 451 | else wrong++; 452 | 453 | total++; 454 | 455 | if (total % 100 == 0) printf("Finished: %d, Correct: %lf\r", total, (double)correct / total); 456 | 457 | } 458 | 459 | printf("\nCorrect: %lf\n", (double)correct / total); 460 | 461 | } -------------------------------------------------------------------------------- /VSProject/HershelPlus/test_observations.txt: -------------------------------------------------------------------------------- 1 | 1,5840,64,1,M,1,1460,0,0,0,0,0.04665,4.353445,10.353628,22.553252,46.555998,94.759729 2 | 2,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.052526,3.855364,9.855588 3 | 3,4380,255,1,M,1,1460,0,0,0,0,0.063122 4 | 4,65535,64,1,MNWST,7331,1460,0,0,0,0,0.161099,3.161195,9.1614,21.161788 5 | 5,5792,64,1,MSTNW,6386,1380,0,0,0,0,0.054402,4.253774,10.255904 6 | 6,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.215531,1.237063,3.237127,7.237246,15.237513,31.43727 7 | 7,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.095402,6.081933,18.084229,30.082712,42.081139 8 | 8,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.181098,1.313926,3.513226,7.513356,15.513612,31.514129 9 | 9,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.048772,1.248034,3.24809,7.250162,15.252377,31.254842 10 | 10,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.122712,1.525101,3.525151,7.525295,15.523629,31.725307 11 | 11,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.125789,1.2977,3.297766,7.297902,15.298169,31.298684 12 | 12,29200,64,1,MNNSNW,60722,1460,0,0,0,0,0.007645,1.607328 13 | 13,8192,128,1,MNWST,7331,1460,1,0,0,1,0.047552,3.051567,9.057616,21.071666 14 | 14,16384,128,0,MNWNNTNNS,30107572,1460,0,0,0,0,0.048454,2.464557,9.02727 15 | 15,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.064852,1.439909,3.439963,7.440092,15.440352,31.440883 16 | 16,4380,255,1,M,1,1460,0,0,0,0,0.131759 17 | 17,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.090556,3.49105,9.891639,22.690922,46.691716,94.695218 18 | 18,5760,64,1,MSTNW,6386,1412,0,0,0,0,0.187119,3.984109,10.38277,23.183961,47.18671,95.186316 19 | 19,5760,64,1,MSTNW,6386,1412,0,0,0,0,0.054306,3.853253,10.253831,23.053122,47.053899,95.055461 20 | 20,8192,128,1,MNWST,7331,1440,1,0,0,1,0.061362,3.061454,9.063606,21.069853 21 | 21,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.115114,1.138572,3.124981,7.115333,15.131232,31.116103 22 | 22,5792,64,1,MSTNW,6386,1402,0,0,0,0,0.144287,3.54284,9.943425,22.742704,46.743477,94.74697 23 | 23,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.157073,4.557598,10.557804 24 | 24,1536,255,0,M,1,768,0,0,0,0,0.110138,6.024418,12.001165 25 | 25,14600,64,1,MNW,114,1460,0,0,0,0,0.131778,1.129862,3.133843,7.133952,15.13811,31.142519 26 | 26,16384,64,1,MNWNNT,58803,1440,0,0,0,0,0.220473,3.275274,9.275456,21.277785 27 | 27,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.040895,1.439385,3.439453,7.439582,15.43984,31.440353 28 | 28,28960,64,1,MSTNW,6386,1452,0,0,0,0,0.216492,1.61305,3.613112,7.613247,15.613511,31.815195 29 | 29,2800,255,0,M,1,1400,0,0,0,0,0.22235,6.197144,12.181709 30 | 30,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.166725,1.301521,3.301599,7.301737,15.501236,31.501751 31 | 31,1460,64,0,M,1,1400,1,1,1460,1,0.182274,2.133523,4.135525,7.639539,14.145626,26.65969,51.183923 32 | 32,5392,64,1,MSTNW,6386,1360,0,0,0,0,0.029078,3.433486,9.433693,21.437932,45.643788 33 | 33,8192,32,0,MNWNNT,58803,1452,1,1,8192,1,0.274281,3.245075,9.235511,21.21832,45.181992,75.136101 34 | 34,65160,64,1,MSTNW,6386,1460,0,0,0,0,0.274376,3.274457,9.475857,21.468445,45.471155 35 | 35,5792,64,1,MSTNW,6386,1356,0,0,0,0,0.290008,4.087023,10.091101,22.089569,46.090326,94.293064 36 | 36,17376,64,1,MNWNNT,58803,1460,1,1,17376,1,0.06238,3.054666,9.054872,21.05525,30.05556 37 | 37,16384,128,0,MNWNNTNNS,30107572,1460,0,0,0,0,0.43137,4.040861,12.293085 38 | 38,28960,64,1,MSTNW,6386,1460,0,0,0,0,0.131737,1.330985,3.331058,7.331187,15.331445,31.335885 39 | 39,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.025961,1.026004,3.026062,7.026206,15.026454,31.026982 40 | 40,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.135381,1.334694,3.334706,7.334834,15.335096,31.33563 41 | 41,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.037723,1.238928,3.238987,7.438351,15.438588,31.439091 42 | 42,5760,64,1,MSTNW,6386,1412,0,0,0,0,0.074933,4.073131,10.473745,23.274915,47.275731,95.277286 43 | 43,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.049658,1.516505,3.516565,7.516693,15.516961,31.517469 44 | 44,4128,255,0,M,1,536,0,0,0,0,0.050554,2.050599,6.04879,14.047093 45 | 45,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.05149,1.543696,3.541801,7.539999,15.546089,31.545647 46 | 46,2048,64,0,M,1,1460,0,0,0,0,0.154905 47 | 47,16384,64,1,MNWNNT,58803,1460,0,0,0,0,0.057343,3.108223,9.108417,21.110785 48 | 48,8192,128,1,MNWST,7331,1460,0,0,0,0,0.057448,3.053624,9.069442 49 | 49,5792,64,1,MNNT,947,1460,0,0,0,0,0.187198,3.786913,9.787102,21.986759,45.9875,94.190234 50 | 50,8192,128,1,MNWST,7331,1460,0,0,0,0,0.149949,3.152013,9.163932 51 | 51,16384,64,1,MNWNNT,58803,1440,0,0,0,0,0.278052,3.348455,9.348657,21.349043 52 | 52,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.041854,1.215725,3.215787,7.215919,15.216171,31.415923 53 | 53,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.133757,3.131898,9.132092,21.130557,45.330555,93.531329 54 | 54,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.164054,3.36143,9.383084,21.502661,45.743663,94.442495 55 | 55,5808,64,1,MNNSNW,60722,1412,0,0,0,0,0.260635,3.661139 56 | 56,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.132593,1.286909,3.286961,7.287104,15.287367,31.487121 57 | 57,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.141415,1.342607,3.34268,7.342807,15.343071,31.544764 58 | 58,13980,64,1,MSTNW,6386,1410,0,0,0,0,0.161072,1.34081,3.340879,7.342957,15.345168,31.353526 59 | 59,16384,64,1,MNWNNT,58803,1440,0,0,0,0,0.49108,3.48336,9.473775,21.476112 60 | 60,13980,64,1,MSTNW,6386,1410,0,0,0,0,0.251687,1.745878,3.751791,7.751939,15.765868,31.766372 61 | 61,5760,64,1,MSTNW,6386,1412,0,0,0,0,0.113923,3.912868,10.313459,23.112711,47.113484,95.115036 62 | 62,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.13377,1.293949,3.294014,7.294147,15.493637,31.494162 63 | 63,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.178465,3.166864,9.167057,21.16744,45.168216,93.367079 64 | 64,14600,64,1,MNNSNW,60722,1460,0,0,0,0,0.040809,1.439312,3.439365,7.439492,15.439748,31.438334 65 | 65,4128,255,0,M,1,536,0,0,0,0,0.13745,2.143365,6.145444,14.147669 66 | 66,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.172525,1.379603,3.379664,7.379797,15.380055,31.57981 67 | 67,65535,255,1,MNNSNWNNT,31090099,1460,0,0,0,0,0.048426,1.548447,4.56224,10.603455,22.660477 68 | 68,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.08085,3.079,9.48154,22.28078,46.306958,94.306596 69 | 69,5792,64,1,MSTNW,6386,1400,0,0,0,0,0.254717,3.448204,9.848803,22.649997,46.652717,94.656246 70 | 70,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.152915,3.951848,9.952041,21.952426,45.953187,94.15396 71 | 71,4380,255,1,MNNTSEE,485165,1460,0,0,0,0,0.062118,3.060251,9.060445,21.060823 72 | 72,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.053553,1.254747,3.254826 73 | 73,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.035937,4.110285,10.145637,22.417514,46.564745,95.060404 74 | 74,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.18048,3.180577,9.379993,21.382343,45.383106 75 | 75,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.345521,4.144483,10.545068,23.344342,47.345104,95.346674 76 | 76,4140,255,1,MNNTSEE,485165,1380,0,0,0,0,0.017477,3.017579,9.017756,21.035739 77 | 77,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.169605,3.966592,10.37696,23.17813,47.186756,95.172667 78 | 78,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.056544,1.056589,3.05663,7.257919,15.258182,31.258693 79 | 79,32768,64,1,MNWNNTSNN,30107446,1404,1,1,32768,1,0.105122,3.05443,9.019461,20.896803,44.653425,76.048982 80 | 80,16384,64,1,MNWNNT,58803,1440,0,0,0,0,0.354174,3.367918,9.364207,21.356797 81 | 81,5760,64,1,MSTNW,6386,1452,0,0,0,0,0.188378,4.58695,10.591035,22.597275,46.789426,95.00383 82 | 82,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.04855,1.538821,3.536958,7.537088,15.53735,31.537871 83 | 83,14480,64,1,MSTNW,6386,1460,1,0,14480,1,0.150958,1.348261,3.348322,7.348456,15.348718,31.548465,930.716527 84 | 84,5712,64,1,MSTNW,6386,1440,0,0,0,0,0.19421,4.389621,10.792179,23.591452,47.594136 85 | 85,65535,64,1,MNWST,7331,1460,0,0,0,0,0.148349,3.160169,6.166114,9.170131 86 | 86,28960,64,1,MSTNW,6386,1460,0,0,0,0,0.010571,1.209829,3.209895,7.210029,15.210294,31.41004 87 | 87,16384,64,1,MNWNNT,58803,1440,0,0,0,0,0.265402,3.302608,9.302802,21.303188 88 | 88,16384,64,1,MNWNNT,58803,1460,0,0,0,0,0.075017,3.122003,9.126097,21.144084 89 | 89,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.061413,3.133777,9.13397,21.134359 90 | 90,8192,128,1,MNWST,7331,1460,1,0,0,1,0.167775,3.169831,9.17002,21.176286 91 | 91,14600,64,1,MNNSNW,60722,1460,0,0,0,0,1.792714,4.992043,10.751998 92 | 92,5760,64,1,MSTNW,6386,1452,0,0,0,0,0.166615,4.369878,10.770474,23.571655,47.572439,95.60913 93 | 93,8192,128,1,MNWST,7331,1460,1,0,0,1,0.281995,3.276276,9.282319,21.292456 94 | 94,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.120871,1.118953,3.118995,7.318364,15.318628,31.319143 95 | 95,14600,64,1,MNNSNW,60722,1452,0,0,0,0,0.197964,3.598461,9.997116,22.798297,46.799078,94.800621 96 | 96,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.128806,4.128915,10.123257,22.125619,46.329515,94.532252 97 | 97,5712,64,1,MSTNW,6386,1360,0,0,0,0,0.175665,4.562523,10.570527,22.561162,46.774814,94.977539 98 | 98,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.17053,1.356123,3.356208,7.356321,15.356578,31.357116 99 | 99,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.176698,3.374052,9.374251,21.376597,45.58051,93.587916 100 | 100,14480,64,1,MSTNW,6386,1380,0,0,0,0,0.174624,1.57506,3.575123,7.575268,15.575525 101 | 101,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.078919,1.284055,3.346604 102 | 102,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.049694,1.245055,3.245119,7.30579,15.468154,31.445234 103 | 103,5760,64,1,MSTNW,6386,1412,0,0,0,0,0.089803,3.685667,10.0843,22.885483,46.886265,94.88782 104 | 104,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.134637,3.132783,9.132974,21.133369,45.333382,93.338843 105 | 105,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.117026,1.117067,3.117125,7.117255,15.117529,31.317269 106 | 106,16384,64,1,MNWNNT,58803,1440,0,0,0,0,0.225395,3.241137,9.256958,21.241728 107 | 107,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.037847,4.0321,10.034257,22.239725,46.258063,94.482251 108 | 108,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.202838,1.480221,3.480287,7.480415,15.480684,31.481197 109 | 109,6144,128,1,MWN,86,1460,1,1,0,1,0.218607,1.552626,4.519538,10.451357,22.316982,46.046283,55.275091 110 | 110,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.248892,3.831063,10.030482,22.030844,46.029661,94.226546 111 | 111,28960,64,1,MSTNW,6386,1460,0,0,0,0,0.154978,1.153066,3.155084,7.153266,15.155464,31.155989 112 | 112,8192,128,1,MNWST,7331,1452,1,1,65535,1,0.166751,3.151201,9.155339,70.358461 113 | 113,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.042652,3.224443,9.22462,21.223058,45.419163,93.617992 114 | 114,16384,64,1,MNWNNT,58803,1440,0,0,0,0,0.251709,3.288919,9.289112 115 | 115,8192,255,0,M,1,1460,0,0,0,0,0.165896 116 | 116,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.063096,1.426432,3.426497,7.426632,15.426879,31.427403 117 | 117,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.055335,1.453811,3.453889,7.454018,15.454273,31.655966 118 | 118,5760,64,1,MSTNW,6386,1360,0,0,0,0,0.195992,3.596484,9.995145,22.792452,46.789318,94.788949 119 | 119,5808,64,1,M,1,1452,0,0,0,0,0.068037,4.523256,10.871077,23.670346,47.671121,95.672683 120 | 120,1460,128,0,M,1,1460,1,0,1460,1,0.144436,3.535181,7.533358,11.53152 121 | 121,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.049586,1.049598,3.049671,7.04979,15.057869,31.070111 122 | 122,4128,255,0,M,1,536,0,0,0,0,0.260381,2.258493,6.258618,14.258878 123 | 123,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.202913,3.234265,9.232509,21.230951,45.423145 124 | 124,5840,64,1,MNNSNW,60722,1460,0,0,0,0,0.119014,3.318347,9.342006,21.352121,45.583395,93.932616 125 | 125,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.114173,5.655363,17.657666,29.656123,41.654548 126 | 126,8192,128,1,MNWST,7331,1460,0,0,0,0,0.198189,3.19437 127 | 127,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.146094,1.34338,3.343464,7.343576,15.543063,31.5436 128 | 128,16384,128,0,MNWNNTNNS,30107572,1460,0,0,0,0,0.067939,2.939128,10.052639 129 | 129,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.087747,5.843783,17.844172,29.842623,41.843004 130 | 130,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.191169,1.193147,3.193205,7.193341,15.193588,31.194075 131 | 131,8192,128,1,MNWST,7331,1460,1,0,0,1,0.139577,3.15334,9.157428,21.159765 132 | 132,28960,64,1,MSTNW,6386,1460,0,0,0,0,0.154991,1.516359,3.526201,7.536103,15.565659,31.626726 133 | 133,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.039787,1.239048,3.239109,7.239252,15.239527,31.44315 134 | 134,2048,255,0,M,1,1024,0,0,0,0,0.157007 135 | 135,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.374914,3.716802,9.53143,21.69394,45.731792,93.930649 136 | 136,16384,128,0,MNWNNTNNS,30107572,1460,0,0,0,0,0.047453,2.496724,9.27625 137 | 137,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.129513,4.299559,10.297826,22.296262,46.293134,94.548599 138 | 138,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.021317,1.150279,3.150334,7.150463 139 | 139,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.037001,1.533146,3.533206,7.533334,15.533593,31.534113 140 | 140,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.198066,1.248883,3.248943,7.249073,15.249323,31.249817 141 | 141,16384,64,1,MNWNNT,58803,1440,0,0,0,0,0.3219,3.323935,9.322192,21.322593 142 | 142,2800,255,0,M,1,1400,0,0,0,0,0.208656,6.148298,12.130913 143 | 143,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.05135,1.293549,3.293614,7.49298,15.493235,31.49376 144 | 144,4380,255,1,MSEE,813,1460,0,0,0,0,0.210721,3.210817,9.21102,21.21142 145 | 145,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.076891,5.856357,17.854835,29.857146,41.8556 146 | 146,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.257657,1.257678,3.257747 147 | 147,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.161726,3.968486,10.367161,23.170142,47.167174,95.168751 148 | 148,16384,64,1,MNWNNT,58803,1444,1,0,16384,1,0.177553,3.216718,9.216904,21.215354,321.476984 149 | 149,5760,64,1,MSTNW,6386,1412,0,0,0,0,0.318153,4.507764,10.900558,23.729092,47.735726,95.723609 150 | 150,8192,128,1,MNWST,7331,1460,1,0,0,1,0.27237,3.274441,9.282424,21.28282 151 | 151,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.164776,1.487055,3.487133,7.487257 152 | 152,28960,64,1,MSTNW,6386,1460,0,0,0,0,0.170713,1.657091,3.657147,7.65728,15.657549,31.658069 153 | 153,5712,64,1,MSTNW,6386,1440,0,0,0,0,0.163994,3.361376,9.765871,22.688171,46.573717 154 | 154,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.062436,1.26169,3.259813,7.261901,15.258254,31.25682 155 | 155,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.133537,1.33281,3.332877,7.336907,15.339111,31.349407 156 | 156,5760,64,1,MSTNW,6386,1412,0,0,0,0,5.15604,8.751906,15.152486,27.953678,51.954479,99.95603 157 | 157,8192,255,0,M,1,1440,0,0,0,0,0.183209 158 | 158,64240,64,1,MNWNNS,58804,1380,0,0,0,0,0.02793,2.938196,8.973563 159 | 159,8192,128,1,MNWST,7331,1460,1,1,65535,1,0.037786,3.049608,9.065442,40.558665 160 | 160,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.051462,1.436246,3.436314,7.635684,15.635939,31.636443 161 | 161,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.111904,5.676525,17.676905,29.677281,41.675755 162 | 162,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.168661,3.360141,9.360337,21.360753,45.560763,93.763527 163 | 163,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.030137,1.116089,3.118133,7.311646,15.315785,31.314386 164 | 164,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.17181 165 | 165,8192,128,1,MNWST,7331,1460,1,0,0,1,0.04147,3.049372,9.055433,21.067542 166 | 166,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.132378,1.487905,3.487964,7.48809,15.488354,31.488875 167 | 167,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.172728,3.268528,9.268712 168 | 168,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.131708,5.833055,17.831489,29.831853,41.8303 169 | 169,4096,64,0,MNWNNT,58803,1392,1,1,4096,1,0.13934,5.797746,17.79813,29.798518,41.798885 170 | 170,1448,64,1,MSTNW,6386,1452,0,0,0,0,3.35125,9.339735,21.539334,45.325286 171 | 171,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.077761,1.374677,3.374708,7.374857,15.375108,31.375632 172 | 172,4380,255,1,M,1,1460,0,0,0,0,0.122726 173 | 173,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.072995,5.907167,17.905621,29.906009,41.906383 174 | 174,16384,128,0,MNWNNTNNS,30107572,1460,0,0,0,0,0.053537,3.266542,9.938637 175 | 175,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.170824,4.66705,10.66725,22.675464,46.680138,94.898528 176 | 176,5760,64,1,MSTNW,6386,1412,0,0,0,0,0.10935,4.107406,10.508024,23.309193,47.309978,95.311536 177 | 177,14600,64,1,M,1,1380,0,0,0,0,0.216641,4.17185,10.173987,22.174402 178 | 178,5792,64,1,MSTNW,6386,1412,0,0,0,0,0.064255,4.45502,10.45717,22.455595,46.456384 179 | 179,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.129546,1.617874,3.617937,7.618083,15.620267,31.820039 180 | 180,16384,64,1,MNWNNT,58803,1400,0,0,0,0,0.239939,3.253716,9.253922,21.254323 181 | 181,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.365797,1.760391,3.762396 182 | 182,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.13758,1.272372,3.272448,7.272563,15.272826,31.273341 183 | 183,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.044542,1.444969,3.44504,7.44517,15.445428,31.445946 184 | 184,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.042861,1.142516,3.14257,7.142698 185 | 185,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.055544,1.055582,3.055631,7.055762,15.056015,31.056524 186 | 186,16384,64,1,MNWNNT,58803,1452,0,0,0,0,0.244074,3.287143,9.312716,21.289683 187 | 187,16384,128,1,MNNSNW,60722,1460,0,0,0,0,0.236208 188 | 188,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.114173,5.674886,17.675276,29.673724,41.674111 189 | 189,8192,64,0,MNW,114,512,1,1,8192,1,0.164616,5.721436,29.724157,74.727576 190 | 190,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.16887,3.372102,9.368381,21.568015,45.568803,93.769596 191 | 191,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.042626,3.84159,9.841784,21.842167,46.042191,94.244918 192 | 192,17376,64,1,MNWNNT,58803,1460,1,1,17376,1,0.058281,3.050563,9.050751,21.053056,30.053363 193 | 193,4128,255,0,M,1,536,0,0,0,0,0.265497,2.267508,6.267632,14.258134 194 | 194,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.243047,1.625899,3.625962,7.624193,15.825587,31.826107 195 | 195,8192,128,1,MNWST,7331,1460,0,0,0,0,0.156987,3.151258,9.151452 196 | 196,1400,255,1,MNNS,948,1400,1,1,1400,1,0.183523,2.351575,4.189517,6.166126,8.521685,10.392842,12.240552,3386.676764 197 | 197,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.171489,4.57004,10.570205,22.568689,46.770632,94.971455 198 | 198,5760,64,1,MSTNW,6386,1452,0,0,0,0,0.452782,3.452886,9.853467,22.687878,46.704307,94.795694 199 | 199,5760,64,1,MSTNW,6386,1400,0,0,0,0,0.199846,4.432391,10.493131,22.612684,47.052938,95.734185 200 | 200,8192,128,1,MNWST,7331,1440,0,0,0,0,0.215566,3.223479,9.229542 201 | 201,2800,255,0,M,1,1400,0,0,0,0,0.280962,6.222576,12.209095 202 | 202,1536,255,0,M,1,768,0,0,0,0,0.102235,6.047759,12.024519 203 | 203,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.043629,1.625727,3.625798,7.625915,15.632045,31.632554 204 | 204,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.066134,1.191167,3.191227,7.191364,15.191631,31.192143 205 | 205,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.04677,1.413987,3.414061,7.463036,15.463284,31.664966 206 | 206,5392,64,1,MSTNW,6386,1360,0,0,0,0,0.281926,4.102356,10.301801,22.345141,46.40649,94.972521 207 | 207,8192,128,1,MNWST,7331,1460,1,1,8192,1,0.217414,3.227269,9.23138,39.697186 208 | 208,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.14734,1.243088,3.24314,7.245213,15.245471,31.445221 209 | 209,1024,255,0,M,1,512,0,0,0,0,0.179568,6.146543,12.131129 210 | 210,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.049524,1.373793,3.373858,7.373978,15.37424,31.374763 211 | 211,5760,64,1,MSTNW,6386,1452,0,0,0,0,0.280927,3.878706,9.880833,22.078511,46.081235,94.282034 212 | 212,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.18542,3.59958,9.599796,21.801323,45.802095,94.006768 213 | 213,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.03388,1.338615,3.338672,7.33879,15.33905,31.339551 214 | 214,5760,64,1,MSTNW,6386,1420,0,0,0,0,0.163762,3.568169,9.566408,21.574611,45.587095,93.803485 215 | 215,5840,64,1,M,1,1460,0,0,0,0,0.214618,4.029216,10.029404 216 | 216,8192,32,0,MNWNNT,58803,1452,1,1,8192,1,0.321966,3.060357,9.050799,21.033584,44.997271,74.951375 217 | 217,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.158823,1.262366,3.262437,7.26257,15.462062,31.46452 218 | 218,14600,64,1,MNNSNW,60722,1452,0,0,0,0,0.179423,4.388537,10.388726,22.389122,46.589131,94.78992 219 | 219,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.161012,4.459979,10.462123,22.462506,46.6664 220 | 220,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.192123,4.297738,10.700281,23.507327,47.519856,95.546792 221 | 221,8190,255,1,M,1,1360,0,0,0,0,0.122868 222 | 222,13980,64,1,MSTNW,6386,1410,0,0,0,0,0.14912,1.701929,3.701975,7.702125,15.702396,31.702896 223 | 223,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.127678,1.127715,3.127785,7.131825,15.134039,31.138455 224 | 224,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.163744,3.931445,9.933598,21.933991,46.145723 225 | 225,65535,255,0,MNWNNT,58803,1414,1,1,65535,1,0.174474,3.174571,9.184537,21.204469,45.24624,75.296058 226 | 226,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.156034,1.624827,3.624879,7.62502 227 | 227,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.048787,1.449206,3.449262,7.449394,15.449668,31.475553 228 | 228,16384,64,1,MNWNNT,58803,1440,0,0,0,0,0.247809,3.273275,9.271551,21.273889 229 | 229,14600,64,1,MNNSNW,60722,1460,0,0,0,0,0.226216,1.403991,3.404058,7.404185,15.404446,31.403023 230 | 230,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.03973,1.264399,3.266392,7.266525,15.266782,31.267311 231 | 231,16384,64,1,MNWNNT,58803,1440,0,0,0,0,0.283789,3.307327,9.307526,21.307915 232 | 232,16384,64,1,MNWNNT,58803,1440,0,0,0,0,0.348376,3.401215,9.397496,21.397871 233 | 233,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.111098,1.113059,3.11314,7.115207,15.113553,31.319134 234 | 234,8192,128,1,MNWST,7331,1460,1,0,0,1,0.055381,3.055466,9.055667,21.054123 235 | 235,8192,128,1,MNWST,7331,1460,1,0,0,1,0.073139,3.053695,9.053895,21.05428 236 | 236,0,64,1,MSTNW,6386,1460,0,0,0,0,0.161043 237 | 237,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.030097,1.42663,3.426705,7.426819,15.427087,31.427688 238 | 238,5760,64,1,MSTNW,6386,1412,0,0,0,0,0.080887,3.276301,9.676904,22.480038,46.480815,94.482369 239 | 239,8192,128,1,MNWST,7331,1460,0,0,0,0,0.255788,3.259793,9.271719 240 | 240,8192,128,1,MNWST,7331,1460,0,0,0,0,0.31729,3.34277,9.339068 241 | 241,5792,64,1,MSTNW,6386,1460,1,1,0,1,0.045855,4.262756,10.266908,14.911571 242 | 242,5712,64,1,MSTNW,6386,1210,0,0,0,0,0.282926,4.683469,11.086027,23.889171,47.887993,95.88567 243 | 243,17376,64,1,MNWNNT,58803,1460,1,1,17376,1,0.191105,3.040824,9.041023,21.0414,30.043647 244 | 244,8192,128,1,MNWST,7331,1440,1,0,0,1,0.045647,3.051605,9.049834,21.151801 245 | 245,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.17738,3.777085,9.986284,21.98275,45.981581,94.184329 246 | 246,17898,64,1,MSTNW,6386,8961,0,0,0,0,0.050521,1.44706,3.447116,7.449174,15.447497,31.448022 247 | 247,5808,64,1,MNNSNW,60722,1412,0,0,0,0,0.061182,4.057397 248 | 248,8192,128,1,MNWST,7331,1460,1,0,0,1,0.067214,3.057557,9.057744,21.058135 249 | 249,5792,64,1,MSTNW,6386,1460,0,0,0,0,22.227277,94.430793 250 | 250,5792,64,1,MSTNW,6386,1460,0,0,0,0,10.474753 251 | 251,8192,128,1,MNWST,7331,1460,0,0,0,0,0.050433,3.052477,9.076076 252 | 252,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.13947,1.332877,3.332943,7.33307,15.333346,31.335793 253 | 253,1334,64,0,M,1,1334,0,0,0,0,0.16496,1.102501,2.102529,4.102597,8.102718,16.102984 254 | 254,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.079085,5.85271,17.853089,29.85348,41.853848 255 | 255,5792,64,1,MSTNW,6386,1442,0,0,0,0,0.162854,3.961802,9.963932,21.964331,46.164355,94.367078 256 | 256,8192,64,0,M,1,1360,1,1,8192,1,1.2028,6.984224,18.863521,42.844771,76.326337,76.365409,76.406388 257 | 257,4344,64,1,MSTNW,6386,1360,0,0,0,0,0.310339,4.111244 258 | 258,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.073796,6.040816,18.04119,30.041589,42.040038 259 | 259,14600,64,1,MNNSNW,60722,1460,0,0,0,0,0.193106 260 | 260,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.119969,1.493067,3.493122,7.495206,15.495447,31.695178 261 | 261,50400,64,1,NNTMNWNNS,114091444,1412,0,0,0,0,0.186515,3.553793,10.305982,23.814228,50.820965,104.826625 262 | 262,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.042786,1.243969,3.244036,7.244167,15.244427,31.244951 263 | 263,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.086921,5.710123,17.710515,29.710901,41.707393 264 | 264,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.053391,1.293658,3.29373,7.493098,15.493352,31.493883 265 | 265,5520,64,1,MSTNW,6386,1392,0,0,0,0,0.076072,4.275428,10.674044,23.471358,47.465327,95.462984 266 | 266,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.089702,6.08793,18.088313,30.088699,42.089081 267 | 267,16384,128,0,MNWNNTNNS,30107572,1380,0,0,0,0,0.109301,2.628904,8.664259 268 | 268,5760,64,1,MSTNW,6386,1412,0,0,0,0,0.21545,3.608154,10.008745,22.808,46.808777,94.810339 269 | 269,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.027096,1.33377,3.335777,7.351575 270 | 270,5760,64,1,MSTNW,6386,1452,0,0,0,0,0.297504,4.700001,11.098645,23.899821,47.912314,95.939221 271 | 271,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.198143,1.202093,3.20216,7.202281,15.212314,31.212827 272 | 272,65535,64,1,MNWST,7331,1460,0,0,0,0,0.033042,3.033135,9.031394,21.03176 273 | 273,16384,128,0,MNWNNTNNS,30107572,1380,0,0,0,0,0.252828,2.944315,9.50703 274 | 274,14600,64,1,MNNSNW,60722,1452,0,0,0,0,0.163205,4.362576,10.362771,22.363156,46.563154,94.562757 275 | 275,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.159162,5.823416,17.823794,29.824191,41.824564 276 | 276,65535,255,1,MNWNNT,58803,1460,0,0,0,0,0.179481,1.671708,4.671807,10.671997 277 | 277,8192,128,1,MNWST,7331,1460,1,0,0,1,0.203814,3.219523,9.235358,21.233794 278 | 278,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.143215,1.203835,3.203902,7.204024,15.204298,31.40597 279 | 279,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.138392,1.331789,3.331846,7.335879,15.33613,31.338616 280 | 280,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.121963,1.121983,3.122059,7.124133,15.124386,31.128826 281 | 281,8192,64,0,MNW,114,1460,1,1,8192,1,0.058276,5.831896,29.832682,74.836086 282 | 282,14600,64,1,MNNSNW,60722,1460,0,0,0,0,0.033064,1.033195,3.033159 283 | 283,5792,64,1,MSTNW,6386,1414,0,0,0,0,0.177846,4.379013,10.37922,22.580784,46.581579,94.786254 284 | 284,5760,64,1,MSTNW,6386,1452,0,0,0,0,0.328812,4.530116,10.530314,22.530692,46.732622,94.931433 285 | 285,16000,64,0,M,1,1460,0,0,0,0,0.043554,1.072882,2.090501,3.092478,4.10424,5.110128 286 | 286,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.535797,1.735076,3.735154,7.784085,15.784345,31.870819 287 | 287,5840,64,1,MNNSNW,60722,1460,0,0,0,0,0.1736,3.966701 288 | 288,5760,64,1,MSTNW,6386,1452,0,0,0,0,0.068994,4.266373,10.26464,22.266958,46.466966,94.665821 289 | 289,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.119019,1.20696,3.20703,7.207158,15.207419,31.407194 290 | 290,5792,64,1,MSTNW,6386,1460,0,0,0,0,0.317227,4.112297,10.010918,22.112875 291 | 291,14480,64,1,MSTNW,6386,1380,0,0,0,0,0.13372,1.332991,3.33499,7.532418,15.534611 292 | 292,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.202012,3.411099,9.411283,21.610903,45.6234 293 | 293,8190,255,1,M,1,1460,0,0,0,0,0.222443 294 | 294,5760,64,1,MSTNW,6386,1452,0,0,0,0,0.251587,3.849351,9.857363,21.846019,46.048001,94.295662 295 | 295,2896,64,1,MSTNW,6386,1440,0,0,0,0,0.494973,4.40722,10.428888,22.398034 296 | 296,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.214763,1.615199,3.615257,7.615393,15.615664,31.819289 297 | 297,4096,64,0,MNWNNT,58803,1452,1,1,4096,1,0.099361,6.009691,18.008145,30.008543,42.008905 298 | 298,14480,64,1,MSTNW,6386,1460,0,0,0,0,0.066121,1.198941,3.199023,7.19722,15.197487,31.198006 299 | 299,16384,128,0,MNWNNTNNS,30107572,1460,0,0,0,0,0.047557,3.123842,9.674824 300 | 300,1024,255,0,M,1,512,0,0,0,0,0.32128,6.276511,12.276728,18.276912,24.277129,30.277304,36.27752,42.277698,48.277914,54.278088,60.278294,66.278476,72.280602,78.278862,84.281004,90.279258,96.277516,96.779472,97.279487,97.779487 301 | -------------------------------------------------------------------------------- /multi-platform/LiveFingerprinter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Code for using pcap for active fingerprinting 3 | * 4 | */ 5 | 6 | #include "LiveFingerprinter.h" 7 | 8 | unsigned short in_checksum(unsigned short *ptr,int nbytes); 9 | int CreatePacket(int adapterCount, char *adapterName, char *dest, unsigned char *packet); 10 | 11 | char errorBuffer[ PCAP_ERRBUF_SIZE ]; 12 | const int TIMEOUT = 120; //2 mins 13 | 14 | int LiveFingerprinter::setupPcapAdapter(){ 15 | 16 | pcap_if_t* allAdapters; 17 | int crtAdapter; 18 | int adapterNumber; 19 | pcap_if_t* adapter; 20 | vector adapterReadableNames; 21 | 22 | // retrieve the adapters from the computer 23 | if( pcap_findalldevs(&allAdapters, errorBuffer ) == -1 ) 24 | { 25 | printf( "Error in pcap_findalldevs_ex function: %s\n", errorBuffer ); 26 | return -1; 27 | } 28 | 29 | // if there are no adapters, print an error 30 | if( allAdapters == NULL ) 31 | { 32 | printf( "\nNo adapters found! Make sure pcap is installed.\n" ); 33 | return -1; 34 | } 35 | 36 | // print the list of adapters along with basic information about an adapter 37 | printf("Listing system adapters:\n"); 38 | crtAdapter = 0; 39 | for( adapter = allAdapters; adapter != NULL; adapter = adapter->next){ 40 | pcap_addr* addresses = adapter->addresses; 41 | while (addresses != NULL && addresses->addr->sa_family != AF_INET) addresses = addresses->next; 42 | 43 | if (addresses != NULL){ 44 | sockaddr_in * sa = (sockaddr_in *)(addresses->addr); 45 | char* ip = inet_ntoa(sa->sin_addr); 46 | 47 | #ifdef _WIN32 48 | adapterReadableNames.push_back(adapter->description); 49 | #else 50 | adapterReadableNames.push_back(adapter->name); 51 | #endif 52 | 53 | printf("\n%d. %s at %s\n", ++crtAdapter, adapterReadableNames.back(), ip); 54 | 55 | } 56 | 57 | } 58 | printf( "\n" ); 59 | 60 | if (crtAdapter > 1){ 61 | printf( "Enter the adapter number between 1 and %d: ", crtAdapter ); 62 | scanf( "%d", &adapterNumber ); 63 | } 64 | else adapterNumber = 1; 65 | 66 | 67 | printf("\n-----------------------------------------------\n"); 68 | 69 | if( adapterNumber < 1 || adapterNumber > crtAdapter ) 70 | { 71 | printf( "\nAdapter number out of range.\n" ); 72 | // Free the adapter list 73 | pcap_freealldevs( allAdapters ); 74 | return -1; 75 | } 76 | 77 | // parse the list until we reach the desired adapter 78 | adapter = allAdapters; 79 | for( crtAdapter = 0; crtAdapter < adapterNumber - 1; crtAdapter++ ){ 80 | adapter = adapter->next; 81 | } 82 | 83 | //open the adapter 84 | printf("Opening device %s\n", adapterReadableNames[adapterNumber-1]); 85 | adapterHandle = pcap_open_live( adapter->name, // name of the adapter 86 | 65536, // portion of the packet to capture 87 | // 65536 guarantees that the whole 88 | // packet will be captured 89 | 1, // promiscuous mode 90 | TIMEOUT, // read timeout - 2 mins 91 | errorBuffer // error buffer 92 | ); 93 | if( adapterHandle == NULL ){ 94 | printf( "\nUnable to open the adapter %s\n", adapterReadableNames[adapterNumber-1]); 95 | return -1; 96 | } 97 | else printf("Adapter %s opened successfully\n", adapterReadableNames[adapterNumber-1]); 98 | 99 | //store the adapter name for future pcap calls 100 | adapterName = new char[strlen(adapter->name) + 1]; 101 | strcpy(adapterName, adapter->name); 102 | 103 | // Free the adapter list 104 | pcap_freealldevs( allAdapters ); 105 | return 0; 106 | } 107 | 108 | int LiveFingerprinter::getFingerprint(char* target, unsigned short port, Signature& sig){ 109 | 110 | unsigned char packet[65535]; 111 | int retValue; 112 | int srcPort; 113 | struct pcap_pkthdr* packetHeader; 114 | const unsigned char* packetData; 115 | 116 | if (createPacket(target, port, &srcPort, packet) < 0){ 117 | printf("Creation of Send Packet failed\n"); 118 | return -1; 119 | } 120 | 121 | //open output file and set pcap filter 122 | const char* output_file = "fingerprints.txt"; 123 | FILE* ofile = fopen(output_file, "a"); 124 | 125 | struct bpf_program fp; /* The compiled filter expression */ 126 | char filter_exp[100]; /* The filter expression */ 127 | snprintf(filter_exp, sizeof(filter_exp), "ip and tcp and src host %s and src port %d and dst port %d", target, port, srcPort); 128 | //bpf_u_int32 netmask = 0xffffff; /* The netmask of our sniffing device */ 129 | if (pcap_compile(adapterHandle, &fp, filter_exp, 1, -1) < 0){ 130 | printf("\nUnable to compile the packet filter. Check the syntax.\n"); 131 | return -1; 132 | } 133 | 134 | if (pcap_setfilter(adapterHandle, &fp) < 0){ 135 | printf("\nError setting the filter.\n"); 136 | return -1; 137 | } 138 | 139 | //if (pcap_setnonblock(adapterHandle, 1, errorBuffer) < 0){ 140 | // printf("\nError setting pcap to nonblocking\n"); 141 | // return -1; 142 | //} 143 | 144 | //timeval lastTS = {0, 0}; 145 | timeval timeSent; 146 | bool first_packet = true; 147 | 148 | /********************************************************************************************************/ 149 | // send the packet 150 | gettimeofday(&timeSent, NULL); 151 | printf("\nSending a SYN packet to %s on port %d...\n", target, port); 152 | if( pcap_sendpacket(adapterHandle, packet, sizeof(ETHERHeader) + sizeof(IPHeader) + sizeof(TCPHeader)) != 0) //adapter, packet, length of packet 153 | { 154 | printf("\nError sending the packet: %s\n", pcap_geterr(adapterHandle)); 155 | return -1; 156 | } 157 | 158 | //PACKET SENT 159 | /************************************************************************************************************************/ 160 | //NOW RECEIVING 161 | 162 | printf("Listening for responses for 2 minutes (TCP Maximum Segment Life)...\n\n"); 163 | 164 | int remaining_time = TIMEOUT; 165 | time_t start; 166 | time(&start); 167 | 168 | 169 | fd_set rfds; 170 | struct timeval tv; 171 | int fd = pcap_fileno(adapterHandle); 172 | if (fd == -1){ 173 | printf("Error getting pcap file handle: %s\n", pcap_geterr(adapterHandle)); 174 | return -1; 175 | } 176 | 177 | while (remaining_time > 0){ 178 | 179 | //calculate remaining time to wait 180 | time_t elapsed; 181 | time(&elapsed); 182 | double elapsed_seconds = difftime(elapsed, start); 183 | remaining_time = TIMEOUT - elapsed_seconds; 184 | 185 | 186 | //have to split Win and linux here because of inconsistensies in how pcap_next_ex works 187 | //and pcap_fileno not providing a selectable handle for Windows 188 | #ifdef _WIN32 189 | retValue = pcap_next_ex(adapterHandle, &packetHeader, &packetData); 190 | if (retValue > 0) { 191 | #else 192 | FD_ZERO(&rfds); 193 | FD_SET(fd, &rfds); 194 | 195 | tv.tv_sec = remaining_time; 196 | tv.tv_usec = 0; 197 | 198 | //printf("Listening for %d more secs\n", remaining_time); 199 | retValue = select(fd+1, &rfds, NULL, NULL, &tv); 200 | 201 | if (retValue == -1){ 202 | printf("select() on pcap file handle failed!\n"); 203 | return -1; 204 | } 205 | else if (retValue == 0){ 206 | //printf("Timeout reached\n"); 207 | break; 208 | } 209 | else { 210 | pcap_next_ex(adapterHandle, &packetHeader, &packetData); 211 | #endif 212 | //get characteristics 213 | IPHeader *iph = (IPHeader *)(packetData + sizeof(ETHER_HDR)); 214 | u_int srcip = ntohl(iph->ip_srcaddr); 215 | TCPHeader* tcph = (TCPHeader*)(packetData + sizeof(ETHERHeader) + sizeof(IPHeader)); 216 | int len = tcph->data_offset; 217 | int syn = tcph->syn; 218 | int rst = tcph->rst; 219 | int ack = tcph->ack; 220 | u_int seq_val = ntohl(tcph->sequence); 221 | u_int ack_val = ntohl(tcph->acknowledge); 222 | 223 | if (rst){ 224 | if (first_packet){ 225 | printf("Connection was reset without SYN/ACK response! Does %s have port %d open?\n", target, port); 226 | return -1; 227 | } 228 | 229 | if (ack){ sig.rst_ack = 1; sig.rst = 0; } 230 | else sig.rst = 1; 231 | sig.rst_win = tcph->window; 232 | if ( seq_val - srcip > 0 ) sig.rst_seq = 1; 233 | if (ack_val > 0) sig.rst_nonzero = 1; 234 | 235 | //calculate timestamp since the first SYN packet 236 | timeval diff; 237 | timeval_subtract(&diff, &packetHeader->ts, &timeSent); 238 | double ts = (diff.tv_sec * 1000000.0 + diff.tv_usec) / 1000000.0; 239 | sig.packet_arrival_time.push_back(ts); 240 | 241 | } 242 | 243 | if (syn && ack){ 244 | if (first_packet){ 245 | sig.win = ntohs(tcph->window); 246 | sig.ttl = iph->ip_ttl; 247 | sig.df = iph->ip_dont_fragment; 248 | 249 | //Read Options 250 | //Options: 251 | // M: MSS 252 | // W: Window Scale 253 | // N: NOP 254 | // T: Timestamp 255 | // E: EOL 256 | // S: SACK Permitted 257 | // X: No option 258 | 259 | 260 | char options[25] = "\0"; 261 | u_short mss = 0; 262 | //u_short wscale = 0; 263 | int options_bytes_size = len*4 - 20; 264 | if (options_bytes_size > 0){ 265 | struct Option { 266 | unsigned char kind; 267 | unsigned char length; 268 | }; 269 | 270 | int options_read = 0; 271 | int len; 272 | unsigned char* opt_ptr = (unsigned char*)(packetData + sizeof(ETHERHeader) + sizeof(IPHeader) + 20); 273 | while (options_read < options_bytes_size){ 274 | Option* opt = (Option*)opt_ptr; 275 | int kind = opt->kind; 276 | 277 | if (strlen(options) > 20){ 278 | break; 279 | } 280 | 281 | //read kind 282 | switch(kind){ 283 | case 0: //EOL 284 | strcat(options, "E"); 285 | opt_ptr += 1; 286 | options_read += 1; 287 | break; 288 | case 1: //NO-Op 289 | strcat(options, "N"); 290 | opt_ptr += 1; 291 | options_read += 1; 292 | break; 293 | case 2: //MSS 294 | len = opt->length; //get length 295 | strcat(options, "M"); //add to string 296 | opt_ptr += sizeof(Option); //skip past option 297 | mss = ntohs(*((u_short*)opt_ptr)); //get data 298 | opt_ptr += (len - sizeof(Option)); //skip past data 299 | options_read += len; //add to bytes read 300 | break; 301 | case 3: //Window Scale 302 | len = opt->length; //get length 303 | strcat(options, "W"); //add to string 304 | opt_ptr += sizeof(Option); 305 | //wscale = *opt_ptr; 306 | opt_ptr += (len - sizeof(Option)); //skip past data 307 | options_read += len; //add to bytes read 308 | break; 309 | case 4: //SACK 310 | len = opt->length; //get length 311 | strcat(options, "S"); //add to string 312 | opt_ptr += len; //skip forward 313 | options_read += len; //add to bytes read 314 | break; 315 | case 8: //Timestamp 316 | len = opt->length; //get length 317 | strcat(options, "T"); //add to string 318 | opt_ptr += len; //skip forward 319 | options_read += len; //add to bytes read 320 | break; 321 | default: 322 | len = opt->length; //get length 323 | if (len == 0) len = 1; 324 | opt_ptr += len; //skip forward 325 | options_read += len; //add to bytes read 326 | break; 327 | } 328 | } 329 | } 330 | else strcat(options, "X"); 331 | 332 | strcpy(sig.options_str, options); 333 | sig.mss = mss; 334 | 335 | first_packet = false; 336 | } 337 | 338 | // calculate RTO 339 | //if (lastTS.tv_sec != 0){ 340 | // timeval diff; 341 | // diff.tv_sec = packetHeader->ts.tv_sec - lastTS.tv_sec; 342 | // diff.tv_usec = packetHeader->ts.tv_usec - lastTS.tv_usec; 343 | // while(diff.tv_usec<0){ 344 | // diff.tv_usec += 1000000; 345 | // diff.tv_sec -= 1; 346 | // } 347 | // double rto = (diff.tv_sec * 1000000.0 + diff.tv_usec) / 1000000.0; 348 | // sig.rto.push_back(rto); 349 | //} 350 | //lastTS = packetHeader->ts; 351 | 352 | 353 | //calculate timestamp since the first SYN packet 354 | timeval diff; 355 | timeval_subtract(&diff, &packetHeader->ts, &timeSent); 356 | double ts = (diff.tv_sec * 1000000.0 + diff.tv_usec) / 1000000.0; 357 | if (ts < 0) ts *= -1; //make sure ts is positive. This was occurring because of drift in Windows version of gettimeofday. Needs better timing fix 358 | sig.packet_arrival_time.push_back(ts); 359 | 360 | } 361 | 362 | //print running output 363 | printf("\rSignature so far: %d,%d,%d,%s,%d,%d,%d,%d,%d,%d", sig.win, sig.ttl, sig.df, sig.options_str, sig.mss, sig.rst, sig.rst_ack, sig.rst_win, sig.rst_seq, sig.rst_nonzero); 364 | for (u_int r = 0; r < sig.packet_arrival_time.size(); r++) printf(",%lf", sig.packet_arrival_time[r]); 365 | //printf("\n"); 366 | } 367 | } 368 | 369 | if( retValue == -1 ){ 370 | printf("Error reading the packets: %s\n", pcap_geterr(adapterHandle)); 371 | return -1; 372 | } 373 | 374 | if (sig.packet_arrival_time.empty()){ 375 | printf("Did not receive any packets from the target. Is the service reachable?\n"); 376 | return -1; 377 | } 378 | 379 | //output signature to file 380 | fprintf(ofile, "%s,%d,%d,%d,%s,%lld,%d,%d,%d,%d,%d,%d", target, sig.win, sig.ttl, sig.df, sig.options_str, sig.options_int, sig.mss, sig.rst, sig.rst_ack, sig.rst_win, sig.rst_seq, sig.rst_nonzero); 381 | for (u_int r = 0; r < sig.packet_arrival_time.size(); r++) fprintf(ofile, ",%lf", sig.packet_arrival_time[r]); 382 | fprintf(ofile, "\n"); 383 | fclose(ofile); 384 | printf("\nResults appended to file %s\n", output_file); 385 | 386 | return 0; 387 | } 388 | 389 | int LiveFingerprinter::timeval_subtract(timeval *result, timeval *x, timeval *y){ 390 | //Taken from www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html 391 | 392 | /* Perform the carry for the later subtraction by updating y. */ 393 | if (x->tv_usec < y->tv_usec) { 394 | int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; 395 | y->tv_usec -= 1000000 * nsec; 396 | y->tv_sec += nsec; 397 | } 398 | if (x->tv_usec - y->tv_usec > 1000000) { 399 | int nsec = (x->tv_usec - y->tv_usec) / 1000000; 400 | y->tv_usec += 1000000 * nsec; 401 | y->tv_sec -= nsec; 402 | } 403 | 404 | /* Compute the time remaining to wait. 405 | tv_usec is certainly positive. */ 406 | result->tv_sec = x->tv_sec - y->tv_sec; 407 | result->tv_usec = x->tv_usec - y->tv_usec; 408 | 409 | /* Return 1 if result is negative. */ 410 | return x->tv_sec < y->tv_sec; 411 | } 412 | 413 | 414 | unsigned short LiveFingerprinter::in_checksum(unsigned short *ptr,int nbytes) { 415 | register long sum; 416 | unsigned short oddbyte; 417 | register short answer; 418 | 419 | sum=0; 420 | while(nbytes>1) { 421 | sum+=*ptr++; 422 | nbytes-=2; 423 | } 424 | if(nbytes==1) { 425 | oddbyte=0; 426 | *((unsigned char*)&oddbyte)=*(unsigned char*)ptr; 427 | sum+=oddbyte; 428 | } 429 | 430 | sum = (sum>>16)+(sum & 0xffff); 431 | sum = sum + (sum>>16); 432 | answer=(short)~sum; 433 | 434 | return(answer); 435 | } 436 | 437 | int LiveFingerprinter::createPacket(char *target, int target_port, int* srcPort, unsigned char *packet){ 438 | 439 | char src[16]; 440 | ETHER_HDR *ehdr; 441 | IP_HDR *iphdr; 442 | TCP_HDR *tcphdr; 443 | PSEUDO_HDR pseudo_header; 444 | unsigned char seudo[sizeof(PSEUDO_HDR)]; 445 | u_long MACADDRLEN = 6; 446 | 447 | 448 | 449 | //create headers 450 | // ******************* Ethernet Header ***************** 451 | 452 | ehdr = (ETHER_HDR*)packet; 453 | 454 | //long long test_mac = 0x0000db28a9721300; //reverse of 0x001372a928db0000 455 | //long long test_mac = 0x0000dfb181270008; ; //reverse of 0x08002781b1df0000 456 | //memcpy(ehdr->dest, &test_mac, 6); //Destination MAC address 457 | 458 | ehdr->type = htons(0x0800); //IP Frames 459 | 460 | #ifdef _WIN32 461 | //fill Ethernet header on Windows and getsource IP 462 | 463 | //get source mac and IP 464 | unsigned long size = 15000; //15k buffer according to MSDN 465 | char* AdapterAddresses = new char[size]; 466 | 467 | //try and get network adapter information from the OS 468 | int ret = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_GATEWAYS, NULL, (IP_ADAPTER_ADDRESSES *)AdapterAddresses, &size); 469 | if (ret != NO_ERROR){ 470 | if (ret == ERROR_BUFFER_OVERFLOW) printf("Error, could not return adapter addresses\n"); 471 | return -1; 472 | } 473 | 474 | IP_ADAPTER_ADDRESSES* pCurrAddresses = (IP_ADAPTER_ADDRESSES *)AdapterAddresses; 475 | while (pCurrAddresses) { 476 | if (strstr(adapterName, pCurrAddresses->AdapterName) != NULL){ 477 | unsigned char *MAC = (unsigned char*)pCurrAddresses->PhysicalAddress; 478 | printf("Local MAC Address Is: %02X-%02X-%02X-%02X-%02X-%02X\n", MAC[0], MAC[1], MAC[2], MAC[3], MAC[4], MAC[5]); 479 | memcpy_s(ehdr->source, MACADDRLEN, MAC, MACADDRLEN); 480 | SOCKADDR_IN* sa = (SOCKADDR_IN *)(pCurrAddresses->FirstUnicastAddress->Address.lpSockaddr); 481 | strcpy_s(src, inet_ntoa(sa->sin_addr)); 482 | printf("Source IP set to: %s\n", src); 483 | break; 484 | } 485 | pCurrAddresses = pCurrAddresses->Next; 486 | } 487 | 488 | delete AdapterAddresses; 489 | 490 | //then get dest mac 491 | IPAddr destip; 492 | IPAddr srcip; 493 | destip = inet_addr(target); 494 | srcip = inet_addr(src); 495 | ULONG MAC[2]; 496 | 497 | ret = SendARP(destip, srcip, MAC, &MACADDRLEN); 498 | if (ret == NO_ERROR){ 499 | memcpy_s(ehdr->dest, MACADDRLEN, MAC, MACADDRLEN); 500 | } 501 | else { 502 | printf("SendARP failed with error %d. Could not figure out destination MAC addr\n", ret); 503 | return -1; 504 | } 505 | #else 506 | //fill Ethernet header on *nix 507 | 508 | //using getifaddrs 509 | //struct ifaddrs *ifap, *ifa; 510 | //getifaddrs(&ifap); 511 | //for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 512 | //if (ifa->ifa_addr != NULL && strcmp(ifa->ifa_name, adapterName) == 0){ 513 | 514 | ////if adapter name matches and family PF_PACKET, get MAC address 515 | //int family = ifa->ifa_addr->sa_family; 516 | //if (family == PF_PACKET){ 517 | //sockaddr* sa = (struct sockaddr*) ifa->ifa_addr; 518 | //unsigned char* mac = (unsigned char*) sa->sa_data; 519 | //mac += 10; 520 | //printf("Local MAC Address Is: %02X-%02X-%02X-%02X-%02X-%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 521 | //memcpy(ehdr->source, mac, MACADDRLEN); 522 | //} 523 | 524 | ////if adapter name matches and family INET, get IP addresses 525 | //if (family == AF_INET){ 526 | ////get src IP 527 | //char host[NI_MAXHOST]; 528 | //int s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); 529 | //if (s != 0) { 530 | //printf("getnameinfo() failed: %s\n", gai_strerror(s)); 531 | //return -1; 532 | //} 533 | //printf("Local IP: %s\n", host); 534 | //strcpy(src, host); 535 | 536 | //} 537 | //} 538 | //} 539 | //freeifaddrs(ifap); 540 | 541 | //using ioctl and netlink sockets 542 | struct ifconf ifc; 543 | char buf[1024]; 544 | 545 | int fd = socket(AF_INET, SOCK_DGRAM, 0); 546 | if (fd < 0){ 547 | printf("Could not open socket\n"); 548 | return -1; 549 | } 550 | 551 | ifc.ifc_len = sizeof(buf); 552 | ifc.ifc_buf = buf; 553 | if (ioctl(fd, SIOCGIFCONF, &ifc) == -1){ 554 | printf("ioctl SIOCGIFCONF failed! errno: %d\n", errno); 555 | return -1; 556 | } 557 | 558 | struct ifreq* it = ifc.ifc_req; 559 | const struct ifreq* const end = it + (ifc.ifc_len / sizeof(ifreq)); 560 | 561 | while (it != end){ 562 | if (strcmp(it->ifr_name, adapterName) == 0){ 563 | struct ifreq ifr; 564 | strcpy(ifr.ifr_name, it->ifr_name); 565 | 566 | //fire ioctl for local MAC 567 | if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1){ 568 | printf("ioctl SIOCGIFHWADDR failed! errno: %d\n", errno); 569 | return -1; 570 | } 571 | char* mac = ifr.ifr_hwaddr.sa_data; 572 | //printf("Local MAC Address Is: %02X-%02X-%02X-%02X-%02X-%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 573 | memcpy(ehdr->source, mac, MACADDRLEN); 574 | 575 | //fire ioctl for local IP 576 | if (ioctl(fd, SIOCGIFADDR, &ifr) == -1){ 577 | printf("ioctl SIOCGIFADDR failed! errno: %d\n", errno); 578 | return -1; 579 | } 580 | //get src IP 581 | char host[NI_MAXHOST]; 582 | int s = getnameinfo(&ifr.ifr_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); 583 | if (s != 0) { 584 | printf("getnameinfo() failed: %s\n", gai_strerror(s)); 585 | return -1; 586 | } 587 | printf("Local IP: %s\n", host); 588 | strcpy(src, host); 589 | } 590 | it++; 591 | } 592 | 593 | //read destination MAC from system ARP table using ioctl 594 | //assumes your system cache stores the MAC of your gateway. 595 | 596 | //first get gateway IP using Netlink Socket to read system route table 597 | //Netlink documentation: http://smacked.org/docs/netlink.pdf 598 | //code below taken from https://stackoverflow.com/questions/3288065/ 599 | //why is this process so complicated in linux? 600 | 601 | u_int gatewayIP = 0; 602 | struct nlmsghdr *nlMsg; 603 | struct nlmsghdr *nlHdr; 604 | struct rtmsg *rtMsg; 605 | struct route_info *rtInfo; 606 | char msgBuf[8192]; 607 | 608 | int sock, readLen = 0, msgLen = 0, msgSeq=0, pid = getpid(); 609 | 610 | if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0){ 611 | printf("Netlink socket creation failed: %d\n", errno); 612 | return -1; 613 | } 614 | 615 | //create request 616 | memset(msgBuf, 0, 8192); 617 | nlMsg = (struct nlmsghdr *)msgBuf; 618 | rtMsg = (struct rtmsg *)NLMSG_DATA(nlMsg); 619 | 620 | nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); 621 | nlMsg->nlmsg_type = RTM_GETROUTE; 622 | nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; 623 | nlMsg->nlmsg_seq = msgSeq++; 624 | nlMsg->nlmsg_pid = pid; 625 | 626 | //send request 627 | if (send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0){ 628 | printf("Write to netlink socket failed: %d\n", errno); 629 | return -1; 630 | } 631 | 632 | //recv response 633 | memset(msgBuf, 0, 8192); 634 | char* bufptr = msgBuf; 635 | do { 636 | if ((readLen = recv(sock, bufptr, 8192 - msgLen, 0)) < 0){ 637 | printf("Error in receiving Netlink response: %d\n", errno); 638 | return -1; 639 | } 640 | 641 | nlHdr = (struct nlmsghdr *)bufptr; 642 | 643 | //check if error 644 | if ((NLMSG_OK(nlHdr, readLen) == 0) || (nlHdr->nlmsg_type == NLMSG_ERROR)){ 645 | printf("Error in Netlink response packet: %d\n", errno); 646 | return -1; 647 | } 648 | 649 | //if last message, break 650 | if (nlHdr->nlmsg_type == NLMSG_DONE) break; 651 | else { 652 | bufptr += readLen; 653 | msgLen += readLen; 654 | } 655 | 656 | //if not multipart message, break 657 | if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0) break; 658 | 659 | }while((nlHdr->nlmsg_seq != msgSeq) || (nlHdr->nlmsg_pid != pid)); 660 | 661 | //parse response 662 | for (; NLMSG_OK(nlMsg,msgLen); nlMsg = NLMSG_NEXT(nlMsg,msgLen)){ 663 | route_info rtinfo; 664 | struct rtattr *rtAttr; 665 | 666 | rtMsg = (struct rtmsg *)NLMSG_DATA(nlMsg); 667 | 668 | //if not AF_INET or not main routing table, skip 669 | if ((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN)) continue; 670 | 671 | //get attributes 672 | rtAttr = (struct rtattr *)RTM_RTA(rtMsg); 673 | int rtLen = RTM_PAYLOAD(nlMsg); 674 | for (; RTA_OK(rtAttr, rtLen); rtAttr = RTA_NEXT(rtAttr, rtLen)){ 675 | switch(rtAttr->rta_type){ 676 | case RTA_OIF: 677 | if_indextoname(*(int*)RTA_DATA(rtAttr), rtinfo.ifName); 678 | break; 679 | case RTA_GATEWAY: 680 | rtinfo.gateway = *(u_int *)RTA_DATA(rtAttr); 681 | break; 682 | case RTA_PREFSRC: 683 | rtinfo.srcAddr = *(u_int *)RTA_DATA(rtAttr); 684 | break; 685 | case RTA_DST: 686 | rtinfo.dstAddr = *(u_int *)RTA_DATA(rtAttr); 687 | break; 688 | } 689 | } 690 | 691 | //print info 692 | //printf("Interface: %s \n Src: %u \n Dst: %u \n Gateway: %u \n\n", rtinfo.ifName, rtinfo.srcAddr, rtinfo.dstAddr, rtinfo.gateway); 693 | 694 | //if this is for the chosen adapter 695 | if (strcmp(adapterName, rtinfo.ifName) == 0){ 696 | gatewayIP = rtinfo.gateway; 697 | printf("Gateway IP: %s\n", inet_ntoa(*(struct in_addr*) &gatewayIP)); 698 | break; 699 | //Now there could be multiple gateways for this interface, though not common 700 | //We are being lazy and taking the first one we see 701 | //A more correct way would be to do a prefix match against our target and pick that gateway 702 | } 703 | } 704 | 705 | // fire ioctl for ARP table 706 | if (gatewayIP > 0){ 707 | struct arpreq areq; 708 | memset(&areq, 0, sizeof(areq)); 709 | 710 | sockaddr_in* sa; 711 | sa = (sockaddr_in*)&areq.arp_pa; 712 | sa->sin_family = AF_INET; 713 | //inet_aton(target, &sa->sin_addr); 714 | sa->sin_addr = *(struct in_addr*) &gatewayIP; 715 | sa = (sockaddr_in*)&areq.arp_ha; 716 | sa->sin_family = ARPHRD_ETHER; 717 | 718 | strcpy(areq.arp_dev, adapterName); 719 | 720 | if (ioctl(fd, SIOCGARP, (caddr_t) &areq) == -1){ 721 | printf("ioctl SIOCGARP failed! errno: %d\n", errno); 722 | return -1; 723 | } 724 | char* mac = areq.arp_ha.sa_data; 725 | 726 | //printf("Dest MAC Address Is: %02X-%02X-%02X-%02X-%02X-%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 727 | memcpy(ehdr->dest, mac, MACADDRLEN); 728 | } 729 | else { 730 | //did not get a gateway IP, set dest MAC to 0 and cross our fingers 731 | memset(ehdr->dest, 0, MACADDRLEN); 732 | } 733 | 734 | 735 | #endif 736 | 737 | // ******************* IP Header ***************** 738 | 739 | //generate a random number between 1024 and 65535 for the source port 740 | srand ( time(NULL) ); 741 | *srcPort = (rand() % (65535 - 1024)) + 1024; 742 | 743 | iphdr = (IP_HDR*)(packet + sizeof(ETHER_HDR)); 744 | 745 | iphdr->ip_version = 4; 746 | iphdr->ip_header_len = 5; //In double words thats 4 bytes 747 | iphdr->ip_tos = 0; 748 | iphdr->ip_total_length = htons (sizeof(IP_HDR) + sizeof(TCP_HDR)); 749 | iphdr->ip_id = htons(*srcPort); //encode port in IP_ID 750 | iphdr->ip_frag_offset = 0; 751 | iphdr->ip_reserved_zero=0; 752 | iphdr->ip_dont_fragment=1; 753 | iphdr->ip_more_fragment=0; 754 | iphdr->ip_frag_offset1 = 0; 755 | iphdr->ip_ttl = 64; 756 | iphdr->ip_protocol = 6; //tcp 757 | iphdr->ip_srcaddr = inet_addr(src); //srcip.s_addr; 758 | iphdr->ip_destaddr = inet_addr(target); 759 | iphdr->ip_checksum =0; 760 | iphdr->ip_checksum = in_checksum((unsigned short*)iphdr, sizeof(IP_HDR)); 761 | 762 | // ******************* TCP Header ***************** 763 | tcphdr = (TCP_HDR*)(packet + sizeof(ETHER_HDR) + sizeof(IP_HDR)); 764 | 765 | 766 | 767 | tcphdr->source_port = htons(*srcPort); 768 | tcphdr->dest_port = htons(target_port); 769 | tcphdr->sequence=inet_addr(target); 770 | tcphdr->acknowledge=0; 771 | tcphdr->reserved_part1=0; 772 | tcphdr->data_offset=10; 773 | tcphdr->fin=0; 774 | tcphdr->syn=1; 775 | tcphdr->rst=0; 776 | tcphdr->psh=0; 777 | tcphdr->ack=0; 778 | tcphdr->urg=0; 779 | tcphdr->ecn=0; 780 | tcphdr->cwr=0; 781 | tcphdr->window = htons(8192); //8K window size 782 | tcphdr->checksum=0; 783 | tcphdr->urgent_pointer = 0; 784 | tcphdr->opt1 = ntohl(0x020405b4); //M 785 | tcphdr->opt2 = ntohl(0x01030308); //NW 786 | //tcphdr->opt3 = ntohl(0x01010402); //NNS 787 | tcphdr->opt3 = ntohl(0x0402080a); //ST 788 | tcphdr->opt4 = ntohl(0x00000001); //TSval 789 | tcphdr->opt5 = ntohl(0x00000000); //TSecr 790 | 791 | // ******************* Checksum calculation ***************** 792 | pseudo_header.source_address = inet_addr(src); 793 | pseudo_header.dest_address = inet_addr(target); 794 | pseudo_header.placeholder = 0; 795 | pseudo_header.protocol = IPPROTO_TCP; 796 | pseudo_header.tcp_length = htons(sizeof(TCP_HDR)); 797 | memcpy(&pseudo_header.tcp , tcphdr , sizeof(TCP_HDR)); 798 | 799 | memcpy(seudo, &pseudo_header, sizeof(PSEUDO_HDR)); 800 | 801 | tcphdr->checksum = in_checksum((unsigned short*)seudo, sizeof(PSEUDO_HDR)); 802 | 803 | // *************************************************************** 804 | 805 | return 0; 806 | } 807 | 808 | LiveFingerprinter::~LiveFingerprinter(){ 809 | 810 | //clean vars 811 | pcap_close(adapterHandle); 812 | delete[] adapterName; 813 | } 814 | 815 | --------------------------------------------------------------------------------