dnsniff.c (5680B)
1#include <asm-generic/socket.h> 2#include <net/if.h> 3#include <netinet/in.h> 4#include <netinet/udp.h> 5#include <netinet/ip.h> 6#include <netpacket/packet.h> 7#include <linux/filter.h> 8#include <linux/if_ether.h> 9#include <arpa/inet.h> 10#include <sys/socket.h> 11#include <sys/ioctl.h> 12#include <err.h> 13#include <errno.h> 14 15#include <stdlib.h> 16#include <stdio.h> 17#include <string.h> 18#include <stdint.h> 19#include <stdbool.h> 20 21#define PACKETBUFLEN (1024 * 1024) 22#define HDRLEN (sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr)) 23 24struct dnshdr { 25 uint16_t id; 26 struct { 27 uint16_t qr : 1; 28 uint16_t op : 4; 29 uint16_t aa : 1; 30 uint16_t tc : 1; 31 uint16_t rd : 1; 32 uint16_t ra : 1; 33 uint16_t zr : 3; 34 uint16_t rc : 4; 35 } flags; 36 uint16_t questions; 37 uint16_t answers; 38 uint16_t authorities; 39 uint16_t additionals; 40} __attribute__((packed)); 41 42struct dnsdec { 43 struct dnshdr *hdr; 44 size_t pos; 45 46 char *qname; 47 uint16_t type; 48 uint16_t class; 49}; 50 51struct packet { 52 struct ethhdr *eth; 53 struct iphdr *ip; 54 struct udphdr *udp; 55 uint8_t *data; 56 size_t len; 57}; 58 59struct filter { 60 uint32_t src_ip, dst_ip; 61 uint16_t dst_port; 62}; 63 64static struct sock_filter udp_filter[] = { 65 { BPF_LD + BPF_H + BPF_ABS, 0, 0, 12 }, 66 { BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0x800 }, 67 { BPF_LD + BPF_B + BPF_ABS, 0, 0, 23 }, 68 { BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0x11 }, 69 { BPF_RET + BPF_K, 0, 0, 0xffff }, 70 { BPF_RET + BPF_K, 0, 0, 0x0000 }, 71}; 72 73static int sock, ifid; 74 75void 76usage(void) 77{ 78 printf("Usage: dnsniff IFACE\n"); 79 exit(0); 80} 81 82void 83hexdump(const uint8_t *data, size_t len) 84{ 85 size_t i; 86 87 for (i = 0; i < len; i++) { 88 printf("%02X ", data[i]); 89 if ((i + 1) % 16 == 0) 90 printf("\n"); 91 } 92 if (len % 16 != 0) 93 printf("\n"); 94} 95 96void 97sniff_init(const char *ifname) 98{ 99 struct ifreq ifreq; 100 struct packet_mreq mreq; 101 struct sock_fprog prog; 102 struct sockaddr_ll sa; 103 int ret; 104 105 sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 106 if (sock < 0) err(1, "failed to open socket"); 107 108 /* get interface index */ 109 strncpy(ifreq.ifr_name, ifname, IFNAMSIZ); 110 ret = ioctl(sock, SIOCGIFINDEX, &ifreq); 111 if (ret) err(1, "failed to lookup interface index"); 112 ifid = ifreq.ifr_ifindex; 113 114 /* enable promiscuous mode on interface */ 115 mreq.mr_ifindex = ifid; 116 mreq.mr_type = PACKET_MR_PROMISC; 117 ret = setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, 118 &mreq, sizeof(mreq)); 119 if (ret) err(1, "failed to enable promiscuous mode"); 120 121 /* filter for udp */ 122 prog.len = sizeof(udp_filter) / sizeof(struct sock_filter); 123 prog.filter = udp_filter; 124 ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, 125 &prog, sizeof(prog)); 126 if (ret) err(1, "failed to attach udp filter"); 127 128 /* bind socket to interface */ 129 sa.sll_family = AF_PACKET; 130 sa.sll_ifindex = ifid; 131 sa.sll_protocol = htons(ETH_P_ALL); 132 ret = bind(sock, (struct sockaddr *)&sa, sizeof(sa)); 133 if (ret) err(1, "failed to bind interface"); 134} 135 136bool 137sniff(struct packet *pkt, struct filter *flt, uint8_t *buf, size_t len) 138{ 139 char src_tmp[INET_ADDRSTRLEN]; 140 ssize_t res; 141 142 while (true) { 143 res = recvfrom(sock, buf, len, 0, NULL, 0); 144 if (res < 0 && errno == EINTR) 145 return false; 146 147 if (res < 0) err(1, "failed to read packet"); 148 149 if (res < HDRLEN) continue; 150 151 pkt->eth = (struct ethhdr *) buf; 152 pkt->ip = (struct iphdr *) (&pkt->eth[1]); 153 pkt->udp = (struct udphdr *) (&pkt->ip[1]); 154 pkt->data = (uint8_t *) (&pkt->udp[1]); 155 pkt->len = htons(pkt->udp->len) - sizeof(struct udphdr); 156 157 if (flt->src_ip && flt->src_ip != pkt->ip->saddr) 158 continue; 159 160 if (flt->dst_ip && flt->dst_ip != pkt->ip->daddr) 161 continue; 162 163 if (flt->dst_port && flt->dst_port != pkt->udp->dest) 164 continue; 165 166 break; 167 } 168 169 return true; 170} 171 172void 173sniff_deinit(void) 174{ 175 struct packet_mreq mreq; 176 int ret; 177 178 /* disable promiscuous mode on interface */ 179 mreq.mr_ifindex = ifid; 180 mreq.mr_type = PACKET_MR_PROMISC; 181 ret = setsockopt(sock, SOL_PACKET, PACKET_DROP_MEMBERSHIP, 182 &mreq, sizeof(mreq)); 183 if (ret) err(1, "failed to enable promiscuous mode"); 184} 185 186void 187decode_init(struct dnsdec *dec) 188{ 189 memset(dec, 0, sizeof(struct dnsdec)); 190} 191 192bool 193decode_query(struct dnsdec *dec, const uint8_t *data, size_t len) 194{ 195 const uint8_t *end; 196 char *c; 197 198 if (!dec->pos) { 199 dec->hdr = (struct dnshdr *) data; 200 dec->hdr->questions = ntohs(dec->hdr->questions); 201 dec->pos = sizeof(struct dnshdr); 202 } 203 204 end = memchr(data + dec->pos, '\0', len - dec->pos); 205 if (!end || end + 5 > data + len) return false; 206 dec->qname = strndup((const char *) data + dec->pos, 207 end - data - dec->pos); 208 if (!dec->qname) err(1, "strndup"); 209 for (c = dec->qname; *c; c++) { 210 if (*c == 0x0a) *c = '.'; 211 if (*c == 0x03) *c = '.'; 212 if (*c == 0x09) *c = '.'; 213 } 214 215 dec->type = ntohs(*(uint16_t *)(end + 1)); 216 dec->class = ntohs(*(uint16_t *)(end + 3)); 217 dec->pos = end + 5 - data; 218 219 return true; 220} 221 222void 223decode_deinit(struct dnsdec *dec) 224{ 225 free(dec->qname); 226} 227 228int 229main(int argc, const char **argv) 230{ 231 const char *ifname; 232 char src_ip[INET_ADDRSTRLEN]; 233 char dst_ip[INET_ADDRSTRLEN]; 234 struct dnsdec dec; 235 struct filter flt; 236 struct packet pkt; 237 uint8_t *buf; 238 239 if (argc != 2) usage(); 240 ifname = argv[1]; 241 242 buf = malloc(PACKETBUFLEN); 243 if (!buf) err(1, "malloc"); 244 245 sniff_init(ifname); 246 247 flt.dst_ip = 0; 248 flt.src_ip = 0; 249 flt.dst_port = htons(53); 250 while (sniff(&pkt, &flt, buf, PACKETBUFLEN)) { 251 inet_ntop(AF_INET, (struct in_addr *) &pkt.ip->saddr, 252 src_ip, INET_ADDRSTRLEN); 253 inet_ntop(AF_INET, (struct in_addr *) &pkt.ip->daddr, 254 dst_ip, INET_ADDRSTRLEN); 255 printf("%s -> %s\n", src_ip, dst_ip); 256 decode_init(&dec); 257 while (decode_query(&dec, pkt.data, pkt.len)) 258 printf(" %s\n", dec.qname); 259 decode_deinit(&dec); 260 printf("\n"); 261 } 262 263 free(buf); 264 sniff_deinit(); 265}