#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include uint32_t crc32_table[256]; void precompute_crc32_table(void) { for (size_t index = 0; index < 256; index++) { uint32_t value = index; for (size_t i = 0; i < 8; i++) { uint32_t low_bit = value & 1; value = value >> 1; if (low_bit) { value ^= 0xEDB88320; } } crc32_table[index] = value; } } uint32_t crc32(unsigned char *buf, size_t len) { uint32_t value = 0xffffffff; for (size_t index = 0; index < len; index++) { value = crc32_table[(value & 0xff) ^ buf[index]] ^ (value >> 8); } return value ^ 0xffffffff; } char hexify(int nybble) { assert(0 <= nybble && nybble <= 16); return "0123456789abcdef"[nybble]; } void format_mac(const unsigned char binary_address[6], char formatted[18]) { for (size_t i = 0; i < 6; i++) { unsigned char byte = binary_address[i]; formatted[3*i] = hexify(byte >> 4); formatted[3*i + 1] = hexify(byte & 0xf); formatted[3*i + 2] = ':'; } formatted[17] = '\0'; } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "Usage: %s interface\n", argv[0]); exit(1); } // Set up CRC32 precompute_crc32_table(); // Create a packet socket errno = 0; int packet_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (packet_socket == -1) { err(1, "socket"); } // Find the index of the network interface struct ifreq ifr; strncpy(ifr.ifr_name, argv[1], IFNAMSIZ); errno = 0; if (ioctl(packet_socket, SIOCGIFINDEX, &ifr) == -1) { err(1, "ioctl"); } // Bind to the network interface struct sockaddr_ll sll; sll.sll_family = AF_PACKET; sll.sll_protocol = htons(ETH_P_ALL); sll.sll_ifindex = ifr.ifr_ifindex; errno = 0; if (bind(packet_socket, (const struct sockaddr*)&sll, sizeof(sll)) == -1) { err(1, "bind"); } for(;;) { unsigned char frame[1522]; // 1522 is the largest a 802.3 frame can be if (fflush(stdout) == -1) { err(1, "fflush"); } errno = 0; ssize_t frame_length = recv(packet_socket, frame, sizeof(frame), MSG_TRUNC); if (frame_length == -1) { err(1, "recv"); } size_t frame_data_length = frame_length <= 1522 ? frame_length : 1522; if (frame_length < 64) { errno = 0; if (printf("Runt frame (%zdB)\n", frame_length) == -1) { err(1, "printf"); } continue; } // Compute the CRC32 of the frame uint32_t crc32_residue = crc32(frame, frame_data_length); if (crc32_residue != 0xc704dd7b) { errno = 0; if (printf("CRC failed (%04"PRIx32")\n", crc32_residue) == -1) { err(1, "printf"); } continue; } // Extract the MACs // 012345 012345 // dest source char destination_mac[18], source_mac[18]; format_mac(&frame[0], destination_mac); format_mac(&frame[6], source_mac); // Extract EtherType / length field // 012345 012345 01 // dest source ^^ // It is stored in the network byte order, that is, high byte 1st uint16_t ethertype = (frame[12] << 8) | frame[13]; const char *ethertype_meaning = NULL; if (ethertype <= 1500) { ethertype_meaning = "packet length"; } else if (ethertype < 0x0600) { ethertype_meaning = "undefined"; } else if (ethertype == 0x0800) { ethertype_meaning = "IPv4"; } else if (ethertype == 0x0806) { ethertype_meaning = "ARP"; } else if (ethertype == 0x86dd) { ethertype_meaning = "IPv6"; } errno = 0; if(printf("%s -> %s ethertype: %04" PRIx16, source_mac, destination_mac, ethertype) == -1) { err(1, "printf"); } errno = 0; if (ethertype_meaning == NULL) { if (printf(", length: %zd\n", frame_length) == -1) { err(1, "printf"); } } else { if (printf(" (%s), length: %zd\n", ethertype_meaning, frame_length) == -1) { err(1, "printf"); } } } return 0; }