├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── inc ├── includes.h ├── info_gathering.h ├── repl.h ├── sniffer.h └── utils │ ├── f_log.h │ ├── http_parser.h │ └── s_log.h └── src ├── info_gathering.c ├── netmon.c ├── repl.c └── sniffer.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Leonardo Folgoni 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | netmon: 2 | $(CC) src/netmon.c src/repl.c src/info_gathering.c src/sniffer.c -o netmon.out 3 | 4 | clean: 5 | rm netmon.out 6 | if [ -a log.txt ]; then rm log.txt; fi; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # netmon_cli 2 | 3 | A simple, lightweight, terminal packet sniffer written in C. 4 | 5 | ## DISCLAIMER 6 | 7 | This tool was built for **EDUCATIONAL PURPOSES** only, I am not responsible for any damaged caused 8 | by illcit use of this script. 9 | 10 | ## About 11 | 12 | As the header says, this is a dead simple packet sniffer written in C using ONLY built in libs. The 13 | sniffer relies on raw sockets to capture incoming and outgoing packets from your **Linux** machine. 14 | 15 | It has a REPL interface written from scratch and it can dump sniffed packets to a `txt` file. Maybe, 16 | it will eventually support `pcap` files in the future. 17 | 18 | I have developed this tool while studying the C language and Unix related programming so this is not 19 | an advanced tool, it's more of a PoC for me but I have decided to share it anyway. 20 | 21 | It's called `netmon` because it can be developed into a fully featured network monitoring tool, but 22 | for now it's only a packet sniffer. 23 | 24 | ## Requirements 25 | 26 | - Linux machine 27 | - gcc compiler 28 | - root permissions 29 | - make 30 | 31 | ### Note 32 | 33 | I have used special characters to display colors, they may not work in some terminal emulators. 34 | 35 | ## Features 36 | 37 | - `showip [DOMAIN NAME]` --> shows the corresponding IPv4 and IPv6 address of a given domain name 38 | - `sniff -p [NUMBER OF PACKETS] -f [TO FILE OR TO STDOUT]` --> sniff a given number of packets to a 39 | file or to the screen (0 for `stdout`, 1 for log `file`) 40 | 41 | ## Run 42 | 43 | `make netmon` 44 | 45 | `sudo ./netmon` --> **MUST BE ROOT TO USE RAW SOCKETS** 46 | 47 | To clean everything **INCLUDING THE LOG FILE**: 48 | 49 | `make clean` 50 | 51 | ### Note 52 | 53 | The `if` statement to remove `log.txt` in `Makefile` strangely works on Manjaro but not in Xubuntu. 54 | 55 | ## Contributing 56 | 57 | Feel free to add features, make PRs and fix typos in my code! I am still a beginner in C so this 58 | piece of software won't be perfect, any help is appreciated! 59 | -------------------------------------------------------------------------------- /inc/includes.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include // icmp header 9 | #include // udp header 10 | #include // tcp header 11 | #include // ip header 12 | #include // ETH_P_ALL 13 | #include // ether_header 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include -------------------------------------------------------------------------------- /inc/info_gathering.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------+ 3 | | info gathering header | 4 | | | 5 | | see info_gathering.c | 6 | | | 7 | | Author: f0lg0 | 8 | | Date: 01-01-2021 (dd-mm-yyyy) | 9 | +----------------------------------------+ 10 | */ 11 | 12 | #ifndef INFO_GATHERING_H 13 | #define INFO_GATHERING_H 14 | 15 | /* [BEGIN] host info gathering */ 16 | 17 | /** 18 | * hostinfo: information about an host 19 | */ 20 | typedef struct { 21 | char* hostname; 22 | char ipstr_v4[INET_ADDRSTRLEN]; 23 | char ipstr_v6[INET6_ADDRSTRLEN]; 24 | } hostinfo; 25 | 26 | 27 | hostinfo* alloc_hinfo(); 28 | hostinfo* showip(char* host); 29 | 30 | /* [END] host info gathering */ 31 | 32 | #endif -------------------------------------------------------------------------------- /inc/repl.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------+ 3 | | repl header | 4 | | | 5 | | see repl.c | 6 | | | 7 | | Author: f0lg0 | 8 | | Date: 01-01-2021 (dd-mm-yyyy) | 9 | +----------------------------------------+ 10 | */ 11 | 12 | #ifndef REPL_H 13 | #define REPL_H 14 | 15 | /* [BEGIN] Input Buffer Logic [BEGIN] */ 16 | 17 | /** 18 | * input_buffer: buffer to handle user input 19 | */ 20 | typedef struct { 21 | char* buffer; 22 | size_t buffer_length; 23 | ssize_t input_length; 24 | } input_buffer; 25 | 26 | input_buffer* new_input_buffer(); 27 | void print_prompt(); 28 | void print_help(); 29 | void read_input(input_buffer* ibuff); 30 | void close_input_buffer(input_buffer* ibuff); 31 | 32 | /* [END] Input Buffer Logic [END] */ 33 | 34 | /* [BEGIN] Commands Logic [BEGIN] */ 35 | 36 | /** 37 | * meta_command_result: status codes for meta command execution 38 | */ 39 | typedef enum { 40 | META_COMMAND_SUCCESS, 41 | META_COMMAND_UNRECOGNIZED_COMMAND 42 | } meta_command_result; 43 | 44 | /** 45 | * command_type: type of a command 46 | */ 47 | typedef enum { COMMAND_INFO, COMMAND_SNIFFER } command_type; 48 | 49 | /** 50 | * command_payload: the payload of a command like sniff or showip 51 | */ 52 | typedef struct { 53 | char target[256]; 54 | int pckt_num; 55 | int logfile; 56 | } command_payload ; 57 | 58 | /** 59 | * command: a command from the cli 60 | */ 61 | typedef struct { 62 | command_type type; 63 | command_payload payload; 64 | } command; 65 | 66 | /** 67 | * prepare_result: status codes while preparing the execution of a command 68 | */ 69 | typedef enum { PREPARE_SUCCESS, PREPARE_UNRECOGNIZED_COMMAND, PREPARE_SYNTAX_ERROR } prepare_result; 70 | 71 | /** 72 | * execute_result: status codes for executable commands 73 | */ 74 | typedef enum { EXECUTE_SUCCESS, EXECUTE_FAILURE } execute_result; 75 | 76 | meta_command_result parse_meta_command(input_buffer* ibuff); 77 | prepare_result prepare_command(input_buffer* ibuff, command* cmd); 78 | execute_result execute_showip(command* cmd); 79 | execute_result execute_sniff(command* cmd); 80 | execute_result execute_command(command* cmd); 81 | 82 | /* [END] Commands Logic [END] */ 83 | 84 | 85 | #endif -------------------------------------------------------------------------------- /inc/sniffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------+ 3 | | sniffer header | 4 | | | 5 | | see sniffer.c | 6 | | | 7 | | Author: f0lg0 | 8 | | Date: 01-01-2021 (dd-mm-yyyy) | 9 | +----------------------------------------+ 10 | */ 11 | 12 | #ifndef SNIFFER_H 13 | #define SNIFFER_H 14 | #include 15 | 16 | extern FILE* log_f; 17 | int open_rsock(); 18 | unsigned char* alloc_pckts_buffer(); 19 | ssize_t recv_net_pckts(int* rsock, unsigned char* buffer, struct sockaddr* saddr, size_t saddrlen); 20 | void process_pcket(unsigned char* buffer, ssize_t brecv, int totpckts, int logfile); 21 | int run_sniffer(int* rsock, unsigned char* buffer, int pckts_num, int logfile); 22 | 23 | #endif -------------------------------------------------------------------------------- /inc/utils/f_log.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------+ 3 | | file logger header | 4 | | | 5 | | log incoming packets to a | 6 | | txt file | 7 | | | 8 | | Author: f0lg0 | 9 | | Date: 31-12-2020 (dd-mm-yyyy) | 10 | +----------------------------------------+ 11 | */ 12 | 13 | #include "../includes.h" 14 | 15 | // global pointer defined in 'netmon.c' 16 | // I was lazy so I used a global variable instead of passing the pointer to every function 17 | extern FILE* log_f; 18 | 19 | /** 20 | * openlog: open log file to dump packets 21 | * @return 0 if success, 1 if failure 22 | */ 23 | int openlog() { 24 | log_f = fopen("log.txt", "a"); 25 | if (!log_f) return 1; 26 | 27 | return 0; 28 | } 29 | 30 | /** 31 | * dump_ethhdr_to_log: dump sniffed eth header to log file 32 | * @param buffer memory containing the packets 33 | * @return void 34 | */ 35 | void dump_ethhdr_to_log(unsigned char* buffer) { 36 | struct ethhdr* eth = (struct ethhdr *)(buffer); 37 | 38 | fprintf(log_f, "\n\tEthernet Header\n"); 39 | fprintf(log_f, "\t\t├─ Source Address : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",eth->h_source[0],eth->h_source[1],eth->h_source[2],eth->h_source[3],eth->h_source[4],eth->h_source[5]); 40 | fprintf(log_f, "\t\t├─ Destination Address : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",eth->h_dest[0],eth->h_dest[1],eth->h_dest[2],eth->h_dest[3],eth->h_dest[4],eth->h_dest[5]); 41 | fprintf(log_f, "\t\t├─ Protocol : 0x%.2x\n",eth->h_proto); 42 | 43 | } 44 | 45 | /** 46 | * dump_iphdr_to_log: dump sniffed IP header to log file 47 | * @param buffer memory containing the packets 48 | * @return void 49 | */ 50 | void dump_iphdr_to_log(unsigned char* buffer) { 51 | struct iphdr* iphdr = (struct iphdr *)(buffer + sizeof(struct ethhdr)); 52 | 53 | struct sockaddr_in src, dst; 54 | bzero(&src, sizeof(src)); 55 | bzero(&dst, sizeof(dst)); 56 | 57 | src.sin_addr.s_addr = iphdr->saddr; 58 | dst.sin_addr.s_addr = iphdr->daddr; 59 | 60 | fprintf(log_f, "\n\tIP Header\n"); 61 | fprintf(log_f, "\t\t├─ Version : %d\n",(unsigned int)iphdr->version); 62 | fprintf(log_f, "\t\t├─ Internet Header Length : %d DWORDS or %d Bytes\n",(unsigned int)iphdr->ihl,((unsigned int)(iphdr->ihl))*4); 63 | fprintf(log_f, "\t\t├─ Type Of Service : %d\n",(unsigned int)iphdr->tos); 64 | fprintf(log_f, "\t\t├─ Total Length : %d Bytes\n",ntohs(iphdr->tot_len)); 65 | fprintf(log_f, "\t\t├─ Identification : %d\n",ntohs(iphdr->id)); 66 | fprintf(log_f, "\t\t├─ Time To Live : %d\n",(unsigned int)iphdr->ttl); 67 | fprintf(log_f, "\t\t├─ Protocol : %d\n",(unsigned int)iphdr->protocol); 68 | fprintf(log_f, "\t\t├─ Header Checksum : %d\n",ntohs(iphdr->check)); 69 | fprintf(log_f, "\t\t├─ Source IP : %s\n", inet_ntoa(src.sin_addr)); 70 | fprintf(log_f, "\t\t├─ Destination IP : %s\n",inet_ntoa(dst.sin_addr)); 71 | } 72 | 73 | /** 74 | * dump_pckt_payload_to_log: dump sniffed packet payload to log file 75 | * @param buffer memoery containing the packets 76 | * @param brecv amount of data received 77 | * @param iphdrlen length (or size) of the IP header 78 | * @return void 79 | */ 80 | void dump_pckt_payload_to_log(unsigned char* buffer, ssize_t brecv, unsigned int iphdrlen) { 81 | // getting packet payload 82 | unsigned char* data = (buffer + sizeof(struct ethhdr) + iphdrlen + sizeof(struct udphdr)); 83 | int remaining_data = brecv - (sizeof(struct ethhdr) + iphdrlen + sizeof(struct udphdr)); 84 | 85 | fprintf(log_f, "\n\tData\n\t"); 86 | for(int i = 0; i < remaining_data; i++) { 87 | if(i != 0 && i % 16 == 0) { 88 | fprintf(log_f, "\n\t"); 89 | } 90 | fprintf(log_f, " %.2X ", data[i]); 91 | } 92 | fprintf(log_f, "\n"); 93 | } 94 | 95 | /** 96 | * dump_icmppckt_to_log: dump sniffed ICMP packet to log file 97 | * @param buffer memory containing the packets 98 | * @param brecv amount of data received 99 | * @param iphdrlen the length (or size) of the IP header 100 | * @return void 101 | */ 102 | void dump_icmppckt_to_log(unsigned char* buffer, ssize_t brecv, unsigned int iphdrlen) { 103 | struct icmphdr* icmph = (struct icmphdr *)(buffer + sizeof(struct ethhdr) + iphdrlen); 104 | 105 | fprintf(log_f, "\n\tICMP Header\n"); 106 | fprintf(log_f, "\t\t├─ Type : %d", (unsigned int)(icmph->type)); 107 | 108 | if ((unsigned int)(icmph->type) == 11) { 109 | fprintf(log_f, "\t(TTL Expired)\n"); 110 | } else if ((unsigned int)(icmph->type) == ICMP_ECHOREPLY) { 111 | fprintf(log_f, "\t(ICMP Echo Reply)\n"); 112 | } 113 | 114 | fprintf(log_f, "\t\t├─ Code : %d\n", (unsigned int)(icmph->code)); 115 | fprintf(log_f, "\t\t├─ Checksum : %d\n", ntohs(icmph->checksum)); 116 | 117 | unsigned char* data = (buffer + sizeof(struct ethhdr) + iphdrlen + sizeof(struct icmphdr)); 118 | int remaining_data = brecv - (sizeof(struct ethhdr) + iphdrlen + sizeof(struct icmphdr)); 119 | 120 | dump_pckt_payload_to_log(buffer, brecv, iphdrlen); 121 | } 122 | 123 | /** 124 | * dump_tcppckt_to_log: dump sniffed TCP packet to log file 125 | * @param buffer memory containing the packets 126 | * @param brecv amount of data received 127 | * @param iphdrlen the length (or size) of the IP header 128 | * @return void 129 | */ 130 | void dump_tcppckt_to_log(unsigned char* buffer, ssize_t brecv, unsigned int iphdrlen) { 131 | struct tcphdr* tcph = (struct tcphdr *)(buffer + sizeof(struct ethhdr) + iphdrlen); 132 | 133 | fprintf(log_f, "\n\tTCP Header\n"); 134 | fprintf(log_f, "\t\t├─ Source Port : %u\n", ntohs(tcph->source)); 135 | fprintf(log_f, "\t\t├─ Destination Port : %u\n", ntohs(tcph->dest)); 136 | fprintf(log_f, "\t\t├─ Sequence Number : %u\n", ntohl(tcph->seq)); 137 | fprintf(log_f, "\t\t├─ Acknowledge Number : %u\n", ntohl(tcph->ack_seq)); 138 | fprintf(log_f, "\t\t├─ Header Length : %d DWORDS or %d BYTES\n" , (unsigned int)tcph->doff,(unsigned int)tcph->doff*4); 139 | fprintf(log_f, "\t\t├─ Urgent Flag : %d\n", (unsigned int)tcph->urg); 140 | fprintf(log_f, "\t\t├─ Acknowledgement Flag : %d\n", (unsigned int)tcph->ack); 141 | fprintf(log_f, "\t\t├─ Push Flag : %d\n", (unsigned int)tcph->psh); 142 | fprintf(log_f, "\t\t├─ Reset Flag : %d\n", (unsigned int)tcph->rst); 143 | fprintf(log_f, "\t\t├─ Synchronise Flag : %d\n", (unsigned int)tcph->syn); 144 | fprintf(log_f, "\t\t├─ Finish Flag : %d\n", (unsigned int)tcph->fin); 145 | fprintf(log_f, "\t\t├─ Window : %d\n",ntohs(tcph->window)); 146 | fprintf(log_f, "\t\t├─ Checksum : %d\n",ntohs(tcph->check)); 147 | fprintf(log_f, "\t\t├─ Urgent Pointer : %d\n",tcph->urg_ptr); 148 | 149 | dump_pckt_payload_to_log(buffer, brecv, iphdrlen); 150 | } 151 | /** 152 | * dump_udppckt_to_log: dump sniffed UDP packet to log file 153 | * @param buffer memory containing the packets 154 | * @param brecv amount of data received 155 | * @param iphdrlen the length (or size) of the IP header 156 | * @return void 157 | */ 158 | void dump_udppckt_to_log(unsigned char* buffer, ssize_t brecv, unsigned int iphdrlen) { 159 | // getting UDP header 160 | struct udphdr* udph =(struct udphdr *)(buffer + sizeof(struct ethhdr) + iphdrlen); 161 | 162 | fprintf(log_f, "\n\tUDP Header\n"); 163 | fprintf(log_f, "\t\t├─ Source Port : %d\n" , ntohs(udph->source)); 164 | fprintf(log_f, "\t\t├─ Destination Port : %d\n" , ntohs(udph->dest)); 165 | fprintf(log_f, "\t\t├─ UDP Length : %d\n" , ntohs(udph->len)); 166 | fprintf(log_f, "\t\t├─ UDP Checksum : %d\n" , ntohs(udph->check)); 167 | 168 | dump_pckt_payload_to_log(buffer, brecv, iphdrlen); 169 | } 170 | -------------------------------------------------------------------------------- /inc/utils/http_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------+ 3 | | HTTP parser header | 4 | | | 5 | | at the moment this header is not | 6 | | used anywhere | 7 | | | 8 | | might come in handy in the future | 9 | | | 10 | | Author: f0lg0 | 11 | | Date: 27-12-2020 (dd-mm-yyyy) | 12 | +----------------------------------------+ 13 | */ 14 | 15 | #include "../includes.h" 16 | 17 | /** 18 | * contentinfo: get content info (headers) from http response 19 | * TODO: error handling 20 | * @param res pointer to http response in string format 21 | * @param result pointer to string array to store the parsed result 22 | * @return void 23 | */ 24 | void contentinfo(char* res, char** result) { 25 | char* content_length_header = "Content-Length"; 26 | char* content_type_header = "Content-Type"; 27 | 28 | char* parsed_length = NULL; 29 | char* parsed_type = NULL; 30 | 31 | char *token = NULL; 32 | token = strtok(res, "\n"); 33 | 34 | int tlength; 35 | while (token) { 36 | for (int i = 0; i < strlen(content_length_header); i++) { 37 | if (token[i] != content_length_header[i]) { 38 | break; 39 | } else if (i == strlen(content_length_header) - 1) { 40 | tlength = strlen(token); 41 | parsed_length = malloc(tlength); 42 | 43 | strcpy(parsed_length, token); 44 | result[0] = parsed_length; 45 | } 46 | } 47 | 48 | for (int i = 0; i < strlen(content_type_header); i++) { 49 | if (token[i] != content_type_header[i]) { 50 | break; 51 | } else if (i == strlen(content_type_header) - 1) { 52 | tlength = strlen(token); 53 | parsed_type = malloc(tlength); 54 | 55 | strcpy(parsed_type, token); 56 | result[1] = parsed_type; 57 | } 58 | } 59 | 60 | token = strtok(NULL, "\n"); 61 | } 62 | } 63 | 64 | /** 65 | * parse_hcontentlength: get content length as int from content length header 66 | * TODO: error handling 67 | * @param hcontent pointer to content length header 68 | * @return content length as int 69 | */ 70 | int parse_hcontentlength(char* hcontent) { 71 | int content_length; 72 | 73 | hcontent = strtok(hcontent, " "); 74 | hcontent = strtok(NULL, " "); 75 | content_length = strtol(hcontent, NULL, 10); 76 | 77 | return content_length; 78 | } 79 | 80 | /** 81 | * parse_hcontenttype: get content type as string from content type header 82 | * @param hcontent pointer to content type header 83 | * @return content type as string 84 | */ 85 | char* parse_hcontenttype(char* hcontent) { 86 | char* content_type; 87 | 88 | hcontent = strtok(hcontent, " "); 89 | hcontent = strtok(NULL, " "); 90 | content_type = hcontent; 91 | 92 | return content_type; 93 | } -------------------------------------------------------------------------------- /inc/utils/s_log.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------+ 3 | | stdout logger header | 4 | | | 5 | | log incoming packets to | 6 | | stdout | 7 | | | 8 | | Author: f0lg0 | 9 | | Date: 31-12-2020 (dd-mm-yyyy) | 10 | +----------------------------------------+ 11 | */ 12 | 13 | #include "../includes.h" 14 | 15 | /** 16 | * print_pckt_payload: prints the data field of a packet to the screen 17 | * @param buffer memory containing the packets 18 | * @param brecv amount of data received 19 | * @param iphdrlen the length (or size) of the IP header 20 | * @return void 21 | */ 22 | void print_pckt_payload(unsigned char* buffer, ssize_t brecv, unsigned short iphdrlen) { 23 | // getting packet payload 24 | unsigned char* data = (buffer + sizeof(struct ethhdr) + iphdrlen + sizeof(struct udphdr)); 25 | int remaining_data = brecv - (sizeof(struct ethhdr) + iphdrlen + sizeof(struct udphdr)); 26 | 27 | printf("\n\tData\n\t"); 28 | for(int i = 0; i < remaining_data; i++) { 29 | if(i != 0 && i % 16 == 0) { 30 | printf("\n\t"); 31 | } 32 | printf(" %.2X ", data[i]); 33 | } 34 | printf("\n"); 35 | } 36 | 37 | /** 38 | * print_ethhdr: extracts the ethernet header and prints it 39 | * @param buffer memory containing the packets 40 | * @return void 41 | */ 42 | void print_ethhdr(unsigned char* buffer) { 43 | /* 44 | Ethernet Packet 45 | struct ethhdr { 46 | unsigned char h_dest[ETH_ALEN]; 47 | unsigned char h_source[ETH_ALEN]; 48 | __be16 h_proto; --> packet type ID field 49 | } __attribute__((packed)); 50 | */ 51 | struct ethhdr* eth = (struct ethhdr *)(buffer); 52 | printf("\n\t┌─────────────────┐"); 53 | printf("\n\t│ \033[1;31mEthernet Header\033[0m │"); 54 | printf("\n\t└─────────────────┘\n"); 55 | 56 | // %.2X --> at least 2 hex digits, if less itis prefixed with 0s 57 | printf("\t\t├─ Source Address : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",eth->h_source[0],eth->h_source[1],eth->h_source[2],eth->h_source[3],eth->h_source[4],eth->h_source[5]); 58 | printf("\t\t├─ Destination Address : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",eth->h_dest[0],eth->h_dest[1],eth->h_dest[2],eth->h_dest[3],eth->h_dest[4],eth->h_dest[5]); 59 | printf("\t\t├─ Protocol : 0x%.2x\n",eth->h_proto); 60 | } 61 | 62 | /** 63 | * print_iphdr: extracts and prints to the screen the IP header (it comes after the Ethernet header) 64 | * @param buffer memory containing the packets 65 | * @return void 66 | */ 67 | void print_iphdr(unsigned char* buffer) { 68 | struct iphdr* iphdr = (struct iphdr *)(buffer + sizeof(struct ethhdr)); 69 | 70 | struct sockaddr_in src, dst; 71 | bzero(&src, sizeof(src)); 72 | bzero(&dst, sizeof(dst)); 73 | 74 | src.sin_addr.s_addr = iphdr->saddr; 75 | dst.sin_addr.s_addr = iphdr->daddr; 76 | 77 | printf("\n\t┌────────────────┐"); 78 | printf("\n\t│ \033[1;36mIP Header\033[0m │"); 79 | printf("\n\t└────────────────┘\n"); 80 | printf("\t\t├─ Version : %d\n",(unsigned int)iphdr->version); 81 | printf("\t\t├─ Internet Header Length : %d DWORDS or %d Bytes\n",(unsigned int)iphdr->ihl,((unsigned int)(iphdr->ihl))*4); 82 | printf("\t\t├─ Type Of Service : %d\n",(unsigned int)iphdr->tos); 83 | printf("\t\t├─ Total Length : %d Bytes\n",ntohs(iphdr->tot_len)); 84 | printf("\t\t├─ Identification : %d\n",ntohs(iphdr->id)); 85 | printf("\t\t├─ Time To Live : %d\n",(unsigned int)iphdr->ttl); 86 | printf("\t\t├─ Protocol : %d\n",(unsigned int)iphdr->protocol); 87 | printf("\t\t├─ Header Checksum : %d\n",ntohs(iphdr->check)); 88 | printf("\t\t├─ Source IP : %s\n", inet_ntoa(src.sin_addr)); 89 | printf("\t\t├─ Destination IP : %s\n",inet_ntoa(dst.sin_addr)); 90 | } 91 | 92 | /** 93 | * print_udppckt: prints to the screen a UPD packet 94 | * @param buffer memory containing the packets 95 | * @param brecv the amount of data received 96 | * @return void 97 | */ 98 | void print_udppckt(unsigned char* buffer, ssize_t brecv, unsigned int iphdrlen) { 99 | // getting UDP header 100 | struct udphdr* udph =(struct udphdr *)(buffer + sizeof(struct ethhdr) + iphdrlen); 101 | 102 | printf("\n\t┌────────────────┐"); 103 | printf("\n\t│ \033[1;35mUDP Header\033[0m │"); 104 | printf("\n\t└────────────────┘\n"); 105 | printf("\t\t├─ Source Port : %d\n" , ntohs(udph->source)); 106 | printf("\t\t├─ Destination Port : %d\n" , ntohs(udph->dest)); 107 | printf("\t\t├─ UDP Length : %d\n" , ntohs(udph->len)); 108 | printf("\t\t├─ UDP Checksum : %d\n" , ntohs(udph->check)); 109 | 110 | print_pckt_payload(buffer, brecv, iphdrlen); 111 | } 112 | 113 | /** 114 | * print_tcppckt: prints to the screen a TCP packet 115 | * @param buffer memory containing the packets 116 | * @param brecv the amount of data received 117 | */ 118 | void print_tcppckt(unsigned char* buffer, ssize_t brecv, unsigned int iphdrlen) { 119 | struct tcphdr* tcph = (struct tcphdr *)(buffer + sizeof(struct ethhdr) + iphdrlen); 120 | 121 | printf("\n\t┌────────────────┐"); 122 | printf("\n\t│ \033[1;33mTCP Header\033[0m │"); 123 | printf("\n\t└────────────────┘\n"); 124 | printf("\t\t├─ Source Port : %u\n", ntohs(tcph->source)); 125 | printf("\t\t├─ Destination Port : %u\n", ntohs(tcph->dest)); 126 | printf("\t\t├─ Sequence Number : %u\n", ntohl(tcph->seq)); 127 | printf("\t\t├─ Acknowledge Number : %u\n", ntohl(tcph->ack_seq)); 128 | printf("\t\t├─ Header Length : %d DWORDS or %d BYTES\n" , (unsigned int)tcph->doff,(unsigned int)tcph->doff*4); 129 | printf("\t\t├─ Urgent Flag : %d\n", (unsigned int)tcph->urg); 130 | printf("\t\t├─ Acknowledgement Flag : %d\n", (unsigned int)tcph->ack); 131 | printf("\t\t├─ Push Flag : %d\n", (unsigned int)tcph->psh); 132 | printf("\t\t├─ Reset Flag : %d\n", (unsigned int)tcph->rst); 133 | printf("\t\t├─ Synchronise Flag : %d\n", (unsigned int)tcph->syn); 134 | printf("\t\t├─ Finish Flag : %d\n", (unsigned int)tcph->fin); 135 | printf("\t\t├─ Window : %d\n",ntohs(tcph->window)); 136 | printf("\t\t├─ Checksum : %d\n",ntohs(tcph->check)); 137 | printf("\t\t├─ Urgent Pointer : %d\n",tcph->urg_ptr); 138 | 139 | print_pckt_payload(buffer, brecv, iphdrlen); 140 | } 141 | 142 | /** 143 | * print_icmppckt: prints to the screen a ICMP packet 144 | * @param buffer memory containing the packets 145 | * @param brecv the amount of data received 146 | * @return void 147 | */ 148 | void print_icmppckt(unsigned char* buffer, ssize_t brecv, unsigned int iphdrlen) { 149 | struct icmphdr* icmph = (struct icmphdr *)(buffer + sizeof(struct ethhdr) + iphdrlen); 150 | 151 | printf("\n\t┌────────────────┐"); 152 | printf("\n\t│ \033[1;34mICMP Header\033[0m │"); 153 | printf("\n\t└────────────────┘\n"); 154 | printf("\t\t├─ Type : %d", (unsigned int)(icmph->type)); 155 | 156 | if ((unsigned int)(icmph->type) == 11) { 157 | printf("\t(TTL Expired)\n"); 158 | } else if ((unsigned int)(icmph->type) == ICMP_ECHOREPLY) { 159 | printf("\t(ICMP Echo Reply)\n"); 160 | } 161 | 162 | printf("\t\t├─ Code : %d\n", (unsigned int)(icmph->code)); 163 | printf("\t\t├─ Checksum : %d\n", ntohs(icmph->checksum)); 164 | 165 | print_pckt_payload(buffer, brecv, iphdrlen); 166 | } -------------------------------------------------------------------------------- /src/info_gathering.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------+ 3 | | info gathering module | 4 | | | 5 | | host info gathering functions | 6 | | | 7 | | Author: f0lg0 | 8 | | Date: 01-01-2021 (dd-mm-yyyy) | 9 | +----------------------------------------+ 10 | */ 11 | 12 | #include "../inc/includes.h" 13 | #include "../inc/info_gathering.h" 14 | 15 | 16 | /* [BEGIN] host info gathering */ 17 | 18 | /** 19 | * alloc_hinfo: allocate memory for the hinfo struct 20 | * @param void 21 | * @return pointer to a new hinfo struct 22 | */ 23 | hostinfo* alloc_hinfo() { 24 | hostinfo* hinfo = malloc(sizeof(hostinfo)); 25 | if (hinfo == NULL) { 26 | printf("[ FATAL ] Insufficient memory."); 27 | exit(1); 28 | } 29 | 30 | hinfo->hostname = NULL; 31 | hinfo->ipstr_v4[0] = -1; 32 | hinfo->ipstr_v6[0] = -1; 33 | 34 | return hinfo; 35 | } 36 | 37 | /** 38 | * showip: get public ip (v4 and v6) from hostname 39 | * @param host hostname as string 40 | * @return pointer to hinfo struct about the newly analyzed host 41 | */ 42 | hostinfo* showip(char* host) { 43 | hostinfo* hinfo = alloc_hinfo(); 44 | hinfo->hostname = malloc(strlen(host) + 1); 45 | strcpy(hinfo->hostname, host); 46 | 47 | struct addrinfo hints, *res, *idx; 48 | int status; 49 | 50 | memset(&hints, 0, sizeof(hints)); 51 | hints.ai_family = AF_UNSPEC; 52 | hints.ai_socktype = SOCK_STREAM; 53 | 54 | if ((status = getaddrinfo(host, NULL, &hints, &res)) != 0) { 55 | fprintf(stderr, "[ \033[1;31mERROR\033[0m ] getaddrinfo: %s\n", gai_strerror(status)); 56 | free(hinfo->hostname); 57 | free(hinfo); 58 | 59 | return NULL; 60 | } 61 | 62 | for (idx = res; idx != NULL; idx = idx->ai_next) { 63 | void *addr; 64 | 65 | if (idx->ai_family == AF_INET) { 66 | struct sockaddr_in *ipv4 = (struct sockaddr_in *)idx->ai_addr; 67 | addr = &(ipv4->sin_addr); 68 | inet_ntop(idx->ai_family, addr, hinfo->ipstr_v4, sizeof(hinfo->ipstr_v4)); 69 | } else { 70 | struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)idx->ai_addr; 71 | addr = &(ipv6->sin6_addr); 72 | inet_ntop(idx->ai_family, addr, hinfo->ipstr_v6, sizeof(hinfo->ipstr_v6)); 73 | } 74 | 75 | } 76 | 77 | if (hinfo->ipstr_v4[0] == -1) { 78 | memcpy(hinfo->ipstr_v4, "NULL", sizeof("NULL")); 79 | } else if (hinfo->ipstr_v6[0] == -1) { 80 | memcpy(hinfo->ipstr_v6, "NULL", sizeof("NULL")); 81 | } 82 | 83 | freeaddrinfo(res); 84 | 85 | return hinfo; 86 | }; 87 | 88 | /* [END] host info gathering */ -------------------------------------------------------------------------------- /src/netmon.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------+ 3 | | netmon_cli | 4 | | | 5 | | packet sniffer written using | 6 | | raw sockets | 7 | | | 8 | | Author: f0lg0 | 9 | | Date: 31-12-2020 (dd-mm-yyyy) | 10 | +----------------------------------------+ 11 | */ 12 | 13 | #include "../inc/includes.h" 14 | #include "../inc/info_gathering.h" 15 | #include "../inc/sniffer.h" 16 | #include "../inc/repl.h" 17 | 18 | int main(int argc, char *argv[]) { 19 | input_buffer* ibuff = new_input_buffer(); 20 | 21 | printf("Type '.help' to display commands usage.\n"); 22 | 23 | while (1) { 24 | print_prompt(); 25 | read_input(ibuff); 26 | 27 | if (ibuff->buffer[0] == '.') { 28 | switch (parse_meta_command(ibuff)) { 29 | case (META_COMMAND_SUCCESS): 30 | continue; 31 | case (META_COMMAND_UNRECOGNIZED_COMMAND): 32 | printf("Unrecognized command '%s'\n", ibuff->buffer); 33 | continue; 34 | } 35 | } 36 | 37 | command cmd; 38 | switch (prepare_command(ibuff, &cmd)) { 39 | case (PREPARE_SUCCESS): 40 | break; 41 | 42 | case (PREPARE_SYNTAX_ERROR): 43 | printf("Syntax error. Could not parse command.\n"); 44 | continue; 45 | 46 | case (PREPARE_UNRECOGNIZED_COMMAND): 47 | printf("Unrecognized keyword at start of '%s'.\n", ibuff->buffer); 48 | continue; 49 | } 50 | 51 | switch (execute_command(&cmd)) { 52 | case (EXECUTE_SUCCESS): 53 | printf("[\033[1;32mSUCCESS\033[0m] Executed. \n"); 54 | break; 55 | 56 | case (EXECUTE_FAILURE): 57 | printf("[\033[1;31mFAILURE\033[0m] failed to execute. \n"); 58 | break; 59 | } 60 | } 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /src/repl.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------+ 3 | | REPL module | 4 | | | 5 | | this is the command line interface | 6 | | of netmon | 7 | | | 8 | | Author: f0lg0 | 9 | | Date: 31-12-2020 (dd-mm-yyyy) | 10 | +----------------------------------------+ 11 | */ 12 | 13 | #include "../inc/includes.h" 14 | #include "../inc/repl.h" 15 | #include "../inc/info_gathering.h" 16 | #include "../inc/sniffer.h" 17 | 18 | /* [BEGIN] Input Buffer Logic [BEGIN] */ 19 | 20 | /** 21 | * new_input_buffer: creates a new input buffer by allocating the necessary memory 22 | * @param void 23 | * @return a pointer to the newly created buffer 24 | */ 25 | input_buffer* new_input_buffer() { 26 | input_buffer* ibuff = malloc(sizeof(input_buffer)); 27 | if (ibuff == NULL) { 28 | printf("[ FATAL ] Insufficient memory."); 29 | exit(1); 30 | } 31 | 32 | ibuff->buffer = NULL; 33 | ibuff->buffer_length = 0; 34 | ibuff->input_length = 0; 35 | 36 | return ibuff; 37 | } 38 | 39 | /** 40 | * print_prompt: prints the prompt line 41 | * @param void 42 | * @return void 43 | */ 44 | void print_prompt() { printf("[ \033[1;37mnetmon\033[0m ]$ "); } 45 | 46 | /** 47 | * print_help: prints the help screen 48 | * @param void 49 | * @return void 50 | */ 51 | void print_help() { 52 | printf("\nCOMMAND\t\tUSAGE\n"); 53 | printf("\nshowip\t\tshowip [TARGET] --> e.g. 'google.com'. DO NOT SPECIFY THE PROTOCOL (http, https, etc.)\n\n"); 54 | printf("\nsniff\t\tsniff -p [PACKETS NUM] -f [FILE OR STDOUT] --> e.g. sniff -p 10 -f 0 (outputs packet to the screen, if -f is set to 1 it dumps packet to a log file). If -p is set to 0 it will forever run in a loop\n\n"); 55 | printf("\n.exit\t\texit netmon\n\n"); 56 | } 57 | 58 | /** 59 | * read_input: wrapper around getline that reads the input and saves it to the given buffer 60 | * @param ibuff an input buffer 61 | * @return void 62 | */ 63 | void read_input(input_buffer* ibuff) { 64 | ssize_t rbytes = getline(&(ibuff->buffer), &(ibuff->buffer_length), stdin); 65 | 66 | if (rbytes <= 0) { 67 | printf("[ \033[1;31mERROR\033[0m ] Error reading input.\n"); 68 | exit(EXIT_FAILURE); 69 | } 70 | 71 | // Ignore trailing newline 72 | ibuff->input_length = rbytes - 1; 73 | ibuff->buffer[rbytes - 1] = 0; 74 | } 75 | 76 | /** 77 | * close_input_buffer:frees the memory allocated for an input buffer and the buffer element of the respective structure (getline allocates memory for ibuff->buffer) 78 | * @param ibuff an input buffer 79 | * @return void 80 | */ 81 | void close_input_buffer(input_buffer* ibuff) { 82 | free(ibuff->buffer); 83 | free(ibuff); 84 | } 85 | 86 | /* [END] Input Buffer Logic [END] */ 87 | 88 | /** 89 | * parse_meta_command: parse a given meta command 90 | * @param ibuff a pointer to an instance of an input buffer 91 | * @return META_COMMAND status code 92 | */ 93 | meta_command_result parse_meta_command(input_buffer* ibuff) { 94 | if (strcmp(ibuff->buffer, ".exit") == 0) { 95 | close_input_buffer(ibuff); 96 | exit(EXIT_SUCCESS); 97 | } else if (strcmp(ibuff->buffer, ".help") == 0) { 98 | print_help(); 99 | return META_COMMAND_SUCCESS; 100 | } else { 101 | return META_COMMAND_UNRECOGNIZED_COMMAND; 102 | } 103 | } 104 | 105 | /** 106 | * prepare_command: prepare a given command for execution 107 | * @param ibuff a pointer to an instance of an input buffer 108 | * @param command a pointer to a command 109 | * @return PREPARE status code 110 | */ 111 | prepare_result prepare_command(input_buffer* ibuff, command* cmd) { 112 | if (strncmp(ibuff->buffer, "showip", 5) == 0) { 113 | cmd->type = COMMAND_INFO; 114 | 115 | int args = sscanf(ibuff->buffer, "showip %255s", cmd->payload.target); 116 | if (args < 1) { 117 | return PREPARE_SYNTAX_ERROR; 118 | } 119 | return PREPARE_SUCCESS; 120 | } 121 | 122 | if (strncmp(ibuff->buffer, "sniff", 5) == 0) { 123 | cmd->type = COMMAND_SNIFFER; 124 | 125 | int args = sscanf(ibuff->buffer, "sniff -p %d -f %d", &(cmd->payload.pckt_num), &(cmd->payload.logfile)); 126 | if (args < 2) { 127 | return PREPARE_SYNTAX_ERROR; 128 | } 129 | 130 | return PREPARE_SUCCESS; 131 | } 132 | 133 | return PREPARE_UNRECOGNIZED_COMMAND; 134 | } 135 | 136 | /** 137 | * execute_showip: executes the command 'showip' 138 | * @param cmd instance of the 'command' structure 139 | * @return EXECUTE status code 140 | */ 141 | execute_result execute_showip(command* cmd) { 142 | hostinfo* hinfo = showip(cmd->payload.target); 143 | 144 | if (hinfo) { 145 | printf("IP addresses for %s:\n\n", cmd->payload.target); 146 | printf("\tIPv4: %s\n", hinfo->ipstr_v4); 147 | printf("\tIPv6: %s\n", hinfo->ipstr_v6); 148 | 149 | free(hinfo->hostname); 150 | free(hinfo); 151 | } else { 152 | return EXECUTE_FAILURE; 153 | } 154 | 155 | return EXECUTE_SUCCESS; 156 | } 157 | 158 | /** 159 | * execute_sniff. executes the command 'sniff' that triggers the packet sniffer 160 | * @param void (in the future we will have to pass the command) 161 | * @return EXECUTE status code 162 | */ 163 | execute_result execute_sniff(command* cmd) { 164 | int rsock = open_rsock(); 165 | if (rsock == -1) return EXECUTE_FAILURE; 166 | 167 | // allocating buffer to receive data 168 | unsigned char* buffer = alloc_pckts_buffer(); 169 | 170 | int status = run_sniffer(&rsock, buffer, cmd->payload.pckt_num, cmd->payload.logfile); 171 | if (status != 0) return EXECUTE_FAILURE; 172 | 173 | close(rsock); 174 | 175 | return EXECUTE_SUCCESS; 176 | } 177 | 178 | 179 | /** 180 | * execute_command: wrapper around the possible command operations (showip, sniff, etc) 181 | * @param command a pointer to a command structure 182 | * @return EXECUTE status code 183 | */ 184 | execute_result execute_command(command* cmd) { 185 | switch (cmd->type) { 186 | case (COMMAND_SNIFFER): 187 | return execute_sniff(cmd); 188 | case (COMMAND_INFO): 189 | return execute_showip(cmd); 190 | default: 191 | printf("[ \033[1;31mERROR\033[0m ] Unrecognized command.\n"); 192 | break; 193 | } 194 | } -------------------------------------------------------------------------------- /src/sniffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------+ 3 | | sniffer module | 4 | | | 5 | | packet sniffer written using | 6 | | raw sockets | 7 | | | 8 | | Author: f0lg0 | 9 | | Date: 01-01-2021 (dd-mm-yyyy) | 10 | +----------------------------------------+ 11 | */ 12 | 13 | #include "../inc/includes.h" 14 | #include "../inc/utils/f_log.h" 15 | #include "../inc/utils/s_log.h" 16 | #include "../inc/sniffer.h" 17 | #define BUFF_SIZE 65536 // 0x10000 18 | 19 | // global pointer defined in 'netmon.c' 20 | // I was lazy so I used a global variable instead of passing the pointer to every function 21 | FILE* log_f; 22 | 23 | /** 24 | * open_sock: open a raw socket 25 | * ! NEED ROOT PERMISSIONS 26 | * @param void 27 | * @return raw socket if success, -1 if failure 28 | */ 29 | int open_rsock() { 30 | printf("[ \033[1;33mLOG\033[0m ] Opening raw socket...\n"); 31 | 32 | int rsock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 33 | if (rsock < 0) return -1; 34 | 35 | printf("[ \033[1;33mLOG\033[0m ] Raw socket opened.\n"); 36 | return rsock; 37 | } 38 | 39 | /** 40 | * alloc_pckts_buffer: allocate huge buffer for packets 41 | * @param void 42 | * @return pointer to the newly allocated buffer 43 | */ 44 | unsigned char* alloc_pckts_buffer() { 45 | unsigned char* buffer = malloc(BUFF_SIZE); 46 | if (buffer == NULL) { 47 | printf("[ FATAL ] Insufficient memory."); 48 | exit(1); 49 | } 50 | bzero(buffer, BUFF_SIZE); 51 | 52 | return buffer; 53 | } 54 | 55 | /** 56 | * recv_net_pckts: stream net packets 57 | * @param rsock pointer to a raw socket 58 | * @param buffer memory to store packets 59 | * @param saddr pointer to an instance of the sockaddr structure 60 | * @param saddrlen size of the saddr instance 61 | * @return received bytes if success, -1 if failure 62 | */ 63 | ssize_t recv_net_pckts(int* rsock, unsigned char* buffer, struct sockaddr* saddr, size_t saddrlen) { 64 | // using recvfrom because "it permits the application to retrieve the source address of received data" (man) 65 | ssize_t brecv = recvfrom(*rsock, buffer, BUFF_SIZE, 0, saddr, (socklen_t *)&saddrlen); 66 | 67 | if (brecv < 0) { 68 | printf("[ERROR] (recv_net_pckts: %ld) Failed to receive data.\n", brecv); 69 | return -1; 70 | } 71 | return brecv; 72 | } 73 | 74 | /** 75 | * process_pcket: sorts an incoming packet 76 | * @param buffer memory containing packets 77 | * @param brecv amount of data received 78 | * @param totpckts the number of packets received (increases) 79 | */ 80 | void process_pcket(unsigned char* buffer, ssize_t brecv, int totpckts, int logfile) { 81 | // getting the IP header 82 | struct iphdr* iphdr = (struct iphdr *)(buffer + sizeof(struct ethhdr)); 83 | 84 | // getting size from IHL (Internet Header Length), which is the number of 32-bit words. 85 | // multiply by 4 to get the size in bytes 86 | unsigned int iphdrlen = iphdr->ihl * 4; 87 | 88 | if (logfile == 0) { 89 | printf("\n\033[1;32m[>] Sniffed Packet #%d\033[0m\n", totpckts); 90 | 91 | print_ethhdr(buffer); 92 | print_iphdr(buffer); 93 | 94 | /* vim /etc/protocols */ 95 | switch (iphdr->protocol) { 96 | // ICMP 97 | case 1: 98 | print_icmppckt(buffer, brecv, iphdrlen); 99 | break; 100 | 101 | // TCP 102 | case 6: 103 | print_tcppckt(buffer, brecv, iphdrlen); 104 | break; 105 | 106 | // UDP 107 | case 17: 108 | print_udppckt(buffer, brecv, iphdrlen); 109 | break; 110 | 111 | default: 112 | break; 113 | } 114 | } else { 115 | fprintf(log_f, "\n[>] Sniffed Packet #%d\n", totpckts); 116 | dump_ethhdr_to_log(buffer); 117 | dump_iphdr_to_log(buffer); 118 | 119 | /* vim /etc/protocols */ 120 | switch (iphdr->protocol) { 121 | // ICMP 122 | case 1: 123 | dump_icmppckt_to_log(buffer, brecv, iphdrlen); 124 | break; 125 | 126 | // TCP 127 | case 6: 128 | dump_tcppckt_to_log(buffer, brecv, iphdrlen); 129 | break; 130 | 131 | // UDP 132 | case 17: 133 | dump_udppckt_to_log(buffer, brecv, iphdrlen); 134 | break; 135 | 136 | default: 137 | break; 138 | } 139 | 140 | fflush(log_f); 141 | 142 | // I don't know why but \r wasn't working as expected here... 143 | printf("Sniffed packets : %d\n", totpckts); 144 | } 145 | 146 | } 147 | 148 | /** 149 | * run_sniffer: receive network packets 150 | * @param rsock pointer to a raw socket file descriptor 151 | * @return 0 if success, -1 if failure 152 | */ 153 | int run_sniffer(int* rsock, unsigned char* buffer, int pckts_num, int logfile) { 154 | if (logfile != 0 && logfile != 1) { 155 | return -1; 156 | } else if (logfile == 1) { 157 | openlog(); 158 | }; 159 | 160 | struct sockaddr saddr; 161 | struct sockaddr* p_saddr = &saddr; 162 | size_t saddrlen = sizeof(saddr); 163 | 164 | ssize_t brecv; 165 | if (pckts_num > 0) { 166 | for (int i = 0; i < pckts_num; i++) { 167 | if ((brecv = recv_net_pckts(rsock, buffer, p_saddr, saddrlen)) == -1) return -1; 168 | process_pcket(buffer, brecv, i, logfile); 169 | } 170 | } else if (pckts_num == 0) { 171 | int i = 0; 172 | while (1) { 173 | if ((brecv = recv_net_pckts(rsock, buffer, p_saddr, saddrlen)) == -1) return -1; 174 | process_pcket(buffer, brecv, i, logfile); 175 | i++; 176 | } 177 | } else { 178 | return -1; 179 | } 180 | 181 | free(buffer); 182 | return 0; 183 | } 184 | --------------------------------------------------------------------------------