/*
* Written by Pejman Moghadam / 1401-02-30
* Public domain.
*
*/
/* gcc src.c -lpcap */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <pcap/pcap.h>
#include <netinet/ether.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <stdint.h>
// The size of datalink header is constant in pcap file
// so the variable is global and will be user for all packets
int datalink_header_len;
struct byte {
unsigned int a:1;
unsigned int b:1;
unsigned int c:1;
unsigned int d:1;
unsigned int e:1;
unsigned int f:1;
unsigned int g:1;
unsigned int h:1;
};
char *ether_ntoa_padded(const struct ether_addr *addr, char *buf)
{
sprintf (buf, "%02x:%02x:%02x:%02x:%02x:%02x",
addr->ether_addr_octet[0], addr->ether_addr_octet[1],
addr->ether_addr_octet[2], addr->ether_addr_octet[3],
addr->ether_addr_octet[4], addr->ether_addr_octet[5]);
return buf;
}
void show_ethernet_header(char *packet, int len)
{
/* man 3 ether_aton */
/* /usr/include/linux/if_ether.h */
struct ethhdr *h;
h = (struct ethhdr *)packet;
struct ether_addr *dst;
dst = (struct ether_addr *)(h->h_dest);
struct ether_addr *src;
src = (struct ether_addr *)(h->h_source);
char addr_str[INET6_ADDRSTRLEN];
printf("Ethernet header info:\n");
printf("\tdst: %s (%s)\n", ether_ntoa(dst),
ether_ntoa_padded(dst, addr_str));
printf("\tsrc: %s (%s)\n", ether_ntoa(src),
ether_ntoa_padded(src, addr_str));
printf("\ttype: 0x%04X\n", ntohs(h->h_proto));
printf("\n");
}
void show_endianness()
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
printf("Endianness : Little Endian\n");
#elif __BYTE_ORDER == __BIG_ENDIAN
printf("Endianness : Big Endian\n");
#else
printf("Endianness : Unknown\n");
#endif
}
void show_ip_header(const u_char *packet, int len)
{
/* /usr/include/netinet/ip.h */
struct ip *h;
//h = (struct ip *)(packet + sizeof(struct ethhdr));
h = (struct ip *)(packet + datalink_header_len);
printf("\nIP Header\n");
printf("\tver : %X\n",h->ip_v);
printf("\tihl : %X\n", h->ip_hl);
printf("\ttos : 0x%X\n", h->ip_tos);
printf("\tlen : %u\n", ntohs(h->ip_len));
printf("\tid : %u\n", ntohs(h->ip_id));
printf("\tfrag : %X ", ntohs(h->ip_off));
if(ntohs(h->ip_off) == 0x4000)
printf("(DF)");
if(ntohs(h->ip_off) == 0x2000)
printf("(MF)");
printf("\n");
printf("\tttl : %u\n", h->ip_ttl);
printf("\tproto : %u\n", h->ip_p);
printf("\tsum : 0x%X\n", ntohs(h->ip_sum));
char ipv4str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &h->ip_src, ipv4str, INET_ADDRSTRLEN);
printf("\tsaddr : %X (%s)\n", ntohl(*(uint32_t *)(&h->ip_src)),
ipv4str);
inet_ntop(AF_INET, &h->ip_dst, ipv4str, INET_ADDRSTRLEN);
printf("\tdaddr : %X (%s)\n", ntohl(*(uint32_t *)(&h->ip_dst)),
ipv4str);
printf("\n");
}
void show_ports(const u_char *packet, int len)
{
/* Source and Destination ports are in same place */
/* /usr/include/netinet/tcp.h */
/* /usr/include/netinet/udp.h */
struct udphdr *h;
h = (struct udphdr *)(packet + datalink_header_len +
sizeof(struct ip));
printf("TCP/UDP Ports:\n");
printf("\tsrc port : 0x%X (%u)\n",
ntohs(h->source), ntohs(h->source));
printf("\tdst port : 0x%X (%u)\n",
ntohs(h->dest), ntohs(h->dest));
printf("\n");
}
// DNS Header Structure (RFC 1035)
struct dnshdr {
uint16_t id; // Identification number
// Flags fields (bit fields)
#if __BYTE_ORDER == __LITTLE_ENDIAN
uint8_t rd :1; // Recursion desired
uint8_t tc :1; // Truncated
uint8_t aa :1; // Authoritative answer
uint8_t opcode :4; // Operation code
uint8_t qr :1; // Query/response flag
uint8_t rcode :4; // Response code
uint8_t z :3; // Reserved (zero)
uint8_t ra :1; // Recursion available
#else
uint8_t qr :1; // Query/response flag
uint8_t opcode :4; // Operation code
uint8_t aa :1; // Authoritative answer
uint8_t tc :1; // Truncated
uint8_t rd :1; // Recursion desired
uint8_t ra :1; // Recursion available
uint8_t z :3; // Reserved (zero)
uint8_t rcode :4; // Response code
#endif
uint16_t qdcount; // Question count
uint16_t ancount; // Answer count
uint16_t nscount; // Authority count
uint16_t arcount; // Additional count
} __attribute__((packed));
void show_datalink_type_name(pcap_t *p)
{
int datalink_type = pcap_datalink(p);
printf("datalink type: %d\n", datalink_type);
printf("datalink name: %s\n",
pcap_datalink_val_to_name(datalink_type));
printf("datalink description: %s\n",
pcap_datalink_val_to_description_or_dlt(datalink_type));
}
int get_datalink_header_len(pcap_t *p)
{
int datalink_type = pcap_datalink(p);
int datalink_header_len;
switch(datalink_type) {
case DLT_EN10MB:
// Ethernet
datalink_header_len = 14;
break;
case DLT_LINUX_SLL:
// Linux cooked-mode capture sockaddr_ll
datalink_header_len = 16;
break;
case DLT_LINUX_SLL2:
// Linux cooked-mode capture sockaddr_ll Ver2
datalink_header_len = 20;
break;
case DLT_NULL:
// Loopback
datalink_header_len = 4;
break;
default:
printf("Unknown header size for DLT %d\n", datalink_type);
printf("Check pcap-linktype(7) man page"
"and https://www.tcpdump.org/linktypes.html"
"then update get_datalink_header_len() fuinction\n");
exit(EXIT_FAILURE);
break;
}
return datalink_header_len;
}
void show_packet(const u_char *packet, int len)
{
int j = 0;
char s[17] = {0};
printf("\n");
for(int i=0; i<len; i++) {
if(j==0)
printf("0x%04x: ", i);
printf("%02x", *(packet+i));
if(*(packet+i) >= 32 && *(packet+i) <=127)
s[j] = *(packet+i);
else
s[j] = '.';
if((j%2)!=0)
printf(" ");
if(j==15) {
s[16] = '\0';
printf(" %s\n", s);
j = 0;
}
else
j++;
}
s[j] = '\0';
int space = 39-(j*2)+(j/2)-1;
printf(" %*s\n", space+2, s);
}
void show_dns_header(const u_char *packet, int len)
{
struct dnshdr *h;
h = (struct dnshdr *)(packet + datalink_header_len +
sizeof(struct ip) + sizeof(struct udphdr));
printf("\nDNS Header\n");
printf("\tID : ");
printf("0x%x (%d)\n", htons(h->id), htons(h->id));
printf("\tMessage type : ");
if(h->qr == 0) puts("Query");
if(h->qr == 1) puts("Response");
printf("\tQuery type : ");
if(h->opcode == 0) puts("Standard query (QUERY)");
if(h->opcode == 1) puts("Inverse query (IQUERY)");
if(h->opcode == 2) puts("Server status request (STATUS)");
printf("\tAuthorization : ");
if(h->qr == 1) {
// Response
if(h->aa == 1)
puts("Authoritative answer");
if(h->aa == 0)
puts("Non-authoritative answer");
} else {
// Query
if(h->aa == 1)
puts("ANOMALY (AA bit set in query message)");
if(h->aa == 0)
puts("Not set");
}
printf("\tTrunCation : ");
if(h->tc == 1) puts("Truncated");
if(h->tc == 0) puts("Not truncated");
printf("\tRecursion Desired : ");
if(h->rd == 1) puts("Yes");
if(h->rd == 0) puts("No");
printf("\tRecursion Available : ");
if(h->qr == 1) {
// Response
if(h->ra == 1)
puts("Yes");
if(h->ra == 0)
puts("No");
} else {
// Query
if(h->aa == 1)
puts("ANOMALY (RA bit set in query message)");
if(h->aa == 0)
puts("Not set");
}
printf("\tReserved : ");
if(h->z == 0) puts("Not set");
if(h->z != 0) puts("ANOMALY (Z bit not zero)");
printf("\tResponse code : ");
if(h->qr == 1) {
// Response
if(h->rcode == 0) puts("No error");
if(h->rcode == 1) puts("Format error");
if(h->rcode == 2) puts("Server failure");
if(h->rcode == 3) {
if(h->aa == 1) // Authoritative answer
puts("Name error");
if(h->aa == 0)
puts("ANOMALY (RCODE bit set in Non-authoritative answer)");
}
if(h->rcode == 4) puts("Not Implemented");
if(h->rcode == 5) puts("Refused");
if((h->rcode >= 6) && (h->rcode <= 15)) puts("Reserved");
} else {
// Query
if(h->rcode == 0)
puts("Not set");
if(h->rcode != 0)
puts("ANOMALY (RCODE bit set in query message)");
}
printf("\tQuestion entries : %d\n", ntohs(h->qdcount));
printf("\tAnswer RRs : %d\n", ntohs(h->ancount));
printf("\tAuthority RRs : %d\n", ntohs(h->nscount));
printf("\tAdditional RRs : %d\n", ntohs(h->arcount));
}
void packet_handler(u_char *user, const struct pcap_pkthdr *h,
const u_char *bytes)
{
static int packet_count = 0;
printf("--------------------------------------"
"--------------------------------------\n");
printf("# Packet: %d, Size: %d\n", ++packet_count, h->len);
show_packet(bytes, h->len);
//show_ethernet_header((char *)bytes, h->len);
show_ip_header(bytes, h->len);
show_ports(bytes, h->len);
show_dns_header(bytes, h->len);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "\nUsage: %s <pcap_file>\n", argv[0]);
return 1;
}
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t *p = pcap_open_offline(argv[1], errbuf);
if (p == NULL) {
fprintf(stderr, "\npcap_open_offline() failed: %s\n", errbuf);
exit(EXIT_FAILURE);
}
show_endianness();
show_datalink_type_name(p);
datalink_header_len = get_datalink_header_len(p);
if (pcap_loop(p, 0, packet_handler, NULL) < 0) {
fprintf(stderr, "\npcap_loop() failed: %s\n", pcap_geterr(p));
exit(EXIT_FAILURE);
}
return 0;
}
|