Added headers with license text
[sniffer.git] / headers.cpp
blobcece7c72e27cb6c25d906ef9631dfd5a9283f058
1 // Copyright (c) 2012, Miriam Ruiz <miriam@debian.org>. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 // 1. Redistributions of source code must retain the above copyright notice,
7 // this list of conditions and the following disclaimer.
8 //
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 //
13 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS", AND ANY EXPRESS
14 // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
16 // NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
17 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 #include "headers.h"
26 #include <iostream>
27 #include <iomanip>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
33 #include <sys/socket.h>
34 #include <arpa/inet.h>
35 #include <net/ethernet.h>
36 #include <netinet/ip_icmp.h>
37 #include <netinet/udp.h>
38 #include <netinet/tcp.h>
39 #include <netinet/ip.h>
40 #include <net/if_arp.h>
42 using namespace filter;
44 // Helper Functions
46 static std::ostream& printWithFormat(std::ostream& out, const char * fmt, ...) {
47 int size = 512;
48 char * buffer = new char[size];
50 va_list ap;
52 while (1) {
53 // Try to print in the allocated space
54 va_start(ap, fmt);
55 int n = vsnprintf(buffer, size, fmt, ap);
56 va_end(ap);
58 // If that worked, output the string
59 if (n > -1 && n < size ) {
60 out << buffer;
61 delete[] buffer;
62 return out;
65 // If not, try again with more space
66 if (n > -1) // glibc 2.1
67 size = n+1; // precisely what is needed, including +1 for /0
68 else // glibc 2.0
69 size *= 2; // Twice the old size
71 // Allocate a new buffer with the new size
72 delete[] buffer;
73 buffer = NULL;
74 buffer = new char[size];
78 static void printRawData (std::ostream& out, const void * pointer, int size)
80 const u_char * data = (const u_char *) pointer;
82 for(int i = 0 ; i < size ; i++) {
83 if( i!=0 && i%16==0) { //if one line of hex printing is complete...
84 printWithFormat(out , " ");
85 for(int j = i-16 ; j < i ; j++) {
86 if(data[j]>=32 && data[j]<=128) {
87 printWithFormat(out , "%c",(unsigned char)data[j]); //if its a number or alphabet
88 } else {
89 printWithFormat(out , "."); //otherwise print a dot
92 out << std::endl;
95 if(i%16==0) {
96 printWithFormat(out , " ");
99 printWithFormat(out , " %02X",(unsigned int)data[i]);
101 if(i==size-1) { // Print the last spaces
102 for(int j = 0 ; j < 15-i%16 ; j++) {
103 printWithFormat(out , " "); //extra spaces
106 printWithFormat(out , " ");
108 for(int j = i-i%16 ; j <= i ; j++) {
109 if(data[j]>=32 && data[j]<=128) {
110 printWithFormat(out , "%c",(unsigned char)data[j]);
111 } else {
112 printWithFormat(out , ".");
116 out << std::endl;
121 // Basic Types
123 inline MacAddress::MacAddress() {
124 memset(address, 0, sizeof(address));
127 inline MacAddress::MacAddress(const unsigned char * v) {
128 memcpy(address, v, sizeof(address));
131 const unsigned char * MacAddress::operator=(const unsigned char * v) {
132 memcpy(address, v, sizeof(address));
133 return address;
136 bool MacAddress::less (const unsigned char * other, bool equal) const {
137 for (int i = 0; i < ETH_ALEN ; i++)
138 if (address[i] < other[i])
139 return true;
140 else if (address[i] > other[i])
141 return false;
142 return equal;
145 bool MacAddress::equal (const unsigned char * other) const {
146 for (int i = ETH_ALEN-1; i >= 0 ; i--)
147 if (address[i] != other[i])
148 return false;
149 return true;
152 std::ostream& operator<< (std::ostream& out, const MacAddress & v) {
153 const unsigned char *address = v;
154 printWithFormat(out, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
155 address[0], address[1], address[2], address[3], address[4], address[5] );
156 return out;
159 inline std::ostream& operator<< (std::ostream& out, const IpAddress & v) {
160 struct sockaddr_in sa;
161 memset(&sa, 0, sizeof(struct sockaddr_in));
162 sa.sin_addr.s_addr = in_addr_t(v);
163 return out << inet_ntoa(sa.sin_addr);
166 inline Ip6Address::Ip6Address() {
167 memset(&address, 0, sizeof(address));
170 inline Ip6Address::Ip6Address(const struct in6_addr & a) {
171 memcpy(&address, &a, sizeof(address));
174 std::ostream& operator<< (std::ostream& out, const Ip6Address & v) {
175 const uint16_t *bytes = ( const uint16_t* ) &v.getAddress();
176 printWithFormat( out, "%x:%x:%x:%x:%x:%x:%x:%x", bytes[0], bytes[1], bytes[2],
177 bytes[3], bytes[4], bytes[5], bytes[6], bytes[7] );
178 return out;
181 inline std::ostream& operator<< (std::ostream& out, const PortNumber & v) {
182 return out << u_int16_t(v);
185 // Abstract Header
187 void AbstractHeader::print(std::ostream& where) const {
188 where << "Raw Data (" << getHeaderName() << ")" << std::endl;
189 printRawData(where, data, data_len);
192 unsigned int AbstractHeader::next_id = 0;
194 template<typename DERIVED>
195 unsigned int HeaderAux<DERIVED>::id = 0;
197 // Ethernet Header
199 AbstractHeader * EthernetHeader::createNextHeader() const {
200 const struct ethhdr * eth = (const struct ethhdr *) data;
201 unsigned short ethhdrlen = sizeof(struct ethhdr);
202 const unsigned char * payload = data + ethhdrlen;
203 unsigned int payload_size = data_len - ethhdrlen;
205 switch (htons(eth->h_proto)) {
206 case ETH_P_IP: // IP Protocol
207 return IpHeader::createHeader(payload, payload_size);
208 case ETH_P_ARP: // ARP Protocol
209 return ArpHeader::createHeader(payload, payload_size);
210 default:
211 return UnknownHeader::createHeader(payload, payload_size);
215 void EthernetHeader::print(std::ostream& where) const {
216 const struct ethhdr * eth = (const struct ethhdr *) data;
217 unsigned short ethhdrlen = sizeof(struct ethhdr);
219 const unsigned char * src_mac = eth->h_source; // Source Mac Address
220 const unsigned char * tgt_mac = eth->h_dest; // Target Mac Address
222 where << "Ethernet Header" << std::endl;
223 printWithFormat(where, " |-Destination Address : %.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
224 tgt_mac[0], tgt_mac[1], tgt_mac[2], tgt_mac[3], tgt_mac[4], tgt_mac[5] );
225 where << std::endl;
226 printWithFormat(where, " |-Source Address : %.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
227 src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5] );
228 where << std::endl;
229 where << " |-Protocol : " << htons(eth->h_proto);
230 switch(ntohs(eth->h_proto)) {
231 case ETH_P_IP: where << " (IP, Internet Protocol)" << std::endl; break;
232 case ETH_P_ARP: where << " (ARP, Address Resolution Protocol)" << std::endl; break;
233 case ETH_P_PAE: where << " (PAE, Port Access Entity)" << std::endl; break;
234 default: where << " (Unknown)" << std::endl;
236 where << "Ethernet Header (Raw Data)" << std::endl;
237 printRawData(where, &eth, ethhdrlen);
240 // IP Header
242 AbstractHeader * IpHeader::createNextHeader() const {
243 const struct iphdr *iph = (const struct iphdr*) data;
244 unsigned short iphdrlen = iph->ihl*4;
245 const unsigned char * payload = data + iphdrlen;
246 unsigned int payload_size = data_len - iphdrlen;
248 switch (iph->protocol) {
249 case 1: // ICMP Protocol
250 return IcmpHeader::createHeader(payload, payload_size);
251 break;
253 case 2: // IGMP Protocol
254 return IgmpHeader::createHeader(payload, payload_size);
255 break;
257 case 6: // TCP Protocol
258 return TcpHeader::createHeader(payload, payload_size);
259 break;
261 case 17: // UDP Protocol
262 return UdpHeader::createHeader(payload, payload_size);
263 break;
265 default: // Other Protocols
266 return UnknownHeader::createHeader(payload, payload_size);
267 break;
271 void IpHeader::print(std::ostream& where) const {
272 const struct iphdr *iph = (const struct iphdr*) data;
273 unsigned short iphdrlen = iph->ihl*4;
275 struct sockaddr_in src;
276 memset(&src, 0, sizeof(struct sockaddr_in));
277 src.sin_addr.s_addr = iph->saddr;
279 struct sockaddr_in dst;
280 memset(&dst, 0, sizeof(struct sockaddr_in));
281 dst.sin_addr.s_addr = iph->daddr;
283 where << "IP Header" << std::endl;
284 where << " |-IP Version : " << (unsigned int)iph->version << std::endl;
285 where << " |-IP Header Length : " << (unsigned int)iph->ihl << " DWORDS or "
286 << (unsigned int)((iph->ihl)*4) << " Bytes" << std::endl;
287 where << " |-Type Of Service : " << (unsigned int)iph->tos << std::endl;
288 where << " |-IP Total Length : " << ntohs(iph->tot_len) << " Bytes(Size of Packet" << std::endl;
289 where << " |-Identification : " << ntohs(iph->id) << std::endl;
290 //where << " |-Reserved ZERO Field : " <<(unsigned int)iphdr->ip_reserved_zero << std::endl;
291 //where << " |-Dont Fragment Field : " <<(unsigned int)iphdr->ip_dont_fragment << std::endl;
292 //where << " |-More Fragment Field : " <<(unsigned int)iphdr->ip_more_fragment << std::endl;
293 where << " |-TTL : " << (unsigned int)iph->ttl << std::endl;
294 where << " |-Protocol : " << (unsigned int)iph->protocol << std::endl;
295 where << " |-Checksum : " << ntohs(iph->check) << std::endl;
296 where << " |-Source IP : " << inet_ntoa(src.sin_addr) << std::endl;
297 where << " |-Destination IP : " << inet_ntoa(dst.sin_addr) << std::endl;
299 where << "IP Header (Raw Data)" << std::endl;
300 printRawData(where, &iph, iphdrlen);
303 // TCP Header
305 AbstractHeader * TcpHeader::createNextHeader() const {
306 const struct tcphdr *tcph=(const struct tcphdr*) data;
307 unsigned short tcphdrlen = tcph->doff*4;
308 const unsigned char * payload = data + tcphdrlen;
309 unsigned int payload_size = data_len - tcphdrlen;
310 if (!payload_size) return NULL;
311 else return PayloadData::createHeader(payload, payload_size);
314 void TcpHeader::print(std::ostream& where) const {
315 const struct tcphdr *tcph=(const struct tcphdr*) data;
316 unsigned short tcphdrlen = tcph->doff*4;
318 where << "TCP Header" << std::endl;
319 where << " |-Source Port : " << ntohs(tcph->source) << std::endl;
320 where << " |-Destination Port : " << ntohs(tcph->dest) << std::endl;
321 where << " |-Sequence Number : " << ntohl(tcph->seq) << std::endl;
322 where << " |-Acknowledge Number : " << ntohl(tcph->ack_seq) << std::endl;
323 where << " |-Header Length : " << (unsigned int)tcph->doff << " DWORDS or "
324 << (unsigned int)(tcph->doff*4) << " BYTES" << std::endl;
325 //where << " |-CWR Flag : " << (unsigned int)tcph->cwr << std::endl;
326 //where << " |-ECN Flag : ",<< (unsigned int)tcph->ece << std::endl;
327 where << " |-Urgent Flag : " << (unsigned int)tcph->urg << std::endl;
328 where << " |-Acknowledgement Flag : " << (unsigned int)tcph->ack << std::endl;
329 where << " |-Push Flag : " << (unsigned int)tcph->psh << std::endl;
330 where << " |-Reset Flag : " << (unsigned int)tcph->rst << std::endl;
331 where << " |-Synchronise Flag : " << (unsigned int)tcph->syn << std::endl;
332 where << " |-Finish Flag : " << (unsigned int)tcph->fin << std::endl;
333 where << " |-Window : " << ntohs(tcph->window) << std::endl;
334 where << " |-Checksum : " << ntohs(tcph->check) << std::endl;
335 where << " |-Urgent Pointer : " << tcph->urg_ptr << std::endl;
337 where << "TCP Header (Raw Data)" << std::endl;
338 printRawData(where, &tcph, tcphdrlen);
341 // UDP Header
343 AbstractHeader * UdpHeader::createNextHeader() const {
344 //const struct udphdr *udph = (const struct udphdr*) data;
345 unsigned short udphdrlen = sizeof(struct udphdr);
346 const unsigned char * payload = data + udphdrlen;
347 unsigned int payload_size = data_len - udphdrlen;
348 if (!payload_size) return NULL;
349 else return PayloadData::createHeader(payload, payload_size);
352 void UdpHeader::print(std::ostream& where) const {
353 const struct udphdr *udph = (const struct udphdr*) data;
354 unsigned short udphdrlen = sizeof(struct udphdr);
356 where << "UDP Header" << std::endl;
357 where << " |-Source Port : " << ntohs(udph->source) << std::endl;
358 where << " |-Destination Port : " << ntohs(udph->dest) << std::endl;
359 where << " |-UDP Length : " << ntohs(udph->len) << std::endl;
360 where << " |-UDP Checksum : " << ntohs(udph->check) << std::endl;
362 where << "UDP Header (Raw Data)" << std::endl;
363 printRawData(where, &udph, udphdrlen);
366 // ICMP Header
368 AbstractHeader * IcmpHeader::createNextHeader() const {
369 //const struct icmphdr *icmph = (const struct icmphdr *) data;
370 unsigned short icmphdrlen = sizeof(struct icmphdr);
371 const unsigned char * payload = data + icmphdrlen;
372 unsigned int payload_size = data_len - icmphdrlen;
373 if (!payload_size) return NULL;
374 else return PayloadData::createHeader(payload, payload_size);
377 void IcmpHeader::print(std::ostream& where) const {
378 const struct icmphdr *icmph = (const struct icmphdr *) data;
379 unsigned short icmphdrlen = sizeof(struct icmphdr);
381 where << "ICMP Header" << std::endl;
382 where << " |-Type : " << (unsigned int)icmph->type << std::endl;
384 switch ((unsigned int)icmph->type) {
385 case ICMP_ECHOREPLY: where << " (Echo Reply)" << std::endl; break;
386 case ICMP_DEST_UNREACH: where << " (Destination Unreachable)" << std::endl; break;
387 case ICMP_SOURCE_QUENCH: where << " (Source Quench)" << std::endl; break;
388 case ICMP_REDIRECT: where << " (Redirect: change route)" << std::endl; break;
389 case ICMP_ECHO: where << " (Echo Request)" << std::endl; break;
390 case ICMP_TIME_EXCEEDED: where << " (Time Exceeded)" << std::endl; break;
391 case ICMP_PARAMETERPROB: where << " (Parameter Problem)" << std::endl; break;
392 case ICMP_TIMESTAMP: where << " (Timestamp Request)" << std::endl; break;
393 case ICMP_TIMESTAMPREPLY: where << " (Timestamp Reply)" << std::endl; break;
394 case ICMP_INFO_REQUEST: where << " (Information Request)" << std::endl; break;
395 case ICMP_INFO_REPLY: where << " (Information Reply)" << std::endl; break;
396 case ICMP_ADDRESS: where << " (Address Mask Request)" << std::endl; break;
397 case ICMP_ADDRESSREPLY: where << " (Address Mask Reply)" << std::endl; break;
398 default: where << " (Unknown)" << std::endl;
401 where << " |-Code : " << (unsigned int)icmph->code << std::endl;
402 where << " |-Checksum : " << ntohs(icmph->checksum) << std::endl;
403 //where << " |-ID : " << ntohs(icmph->id) << std::endl;
404 //where << " |-Sequence : " << ntohs(icmph->sequence) << std::endl;
406 where << "ICMP Header (Raw Data)" << std::endl;
407 printRawData(where, &icmph, icmphdrlen);
410 void ArpHeader::print(std::ostream& where) const {
411 const struct arphdr * arph = (const struct arphdr *) data;
412 //unsigned short arphdrlen = sizeof(struct arphdr); // ARP header Lenght
413 //unsigned short arphdrhwlen = arph->ar_hln; // Hardware Length
414 //unsigned short arphdrprlen = arph->ar_pln; // Protocol Length
416 where << "ARP Header" << std::endl;
417 where << " |-Hardware type : " << ntohs(arph->ar_hrd);
418 switch(ntohs(arph->ar_hrd)) { // Defined in if_arp.h
419 case ARPHRD_ETHER: where << " (Ethernet 10/100Mbps)" << std::endl; break;
420 default: where << " (Unknown)" << std::endl;
423 where << " |-Protocol type : " << ntohs(arph->ar_pro);
424 switch(ntohs(arph->ar_pro)) { // Defined in ethernet.h
425 case ETHERTYPE_IP: where << " (IPv4)" << std::endl; break;
426 case ETHERTYPE_IPV6: where << " (IPv6)" << std::endl; break;
427 default: where << " (Unknown)" << std::endl;
430 where << " |-Operation : " << ntohs(arph->ar_op);
431 switch(ntohs(arph->ar_op)) { // Defined in if_arp.h
432 case ARPOP_REQUEST: where << " (ARP request)" << std::endl; break;
433 case ARPOP_REPLY: where << " (ARP reply)" << std::endl; break;
434 case ARPOP_RREQUEST: where << " (RARP request)" << std::endl; break;
435 case ARPOP_RREPLY: where << " (RARP reply)" << std::endl; break;
436 case ARPOP_InREQUEST: where << " (InARP request)" << std::endl; break;
437 case ARPOP_InREPLY: where << " (InARP reply)" << std::endl; break;
438 case ARPOP_NAK: where << " (ARP NAK)" << std::endl; break;
439 default: where << " (Unknown)" << std::endl;
443 AbstractHeader * ArpHeader::createHeader(const void * buffer, unsigned int len) {
444 const struct arphdr * arph = (const struct arphdr *) buffer;
445 if (ntohs(arph->ar_hrd) == ARPHRD_ETHER && ntohs(arph->ar_pro) == ETHERTYPE_IP)
446 return new ArpEthIpHeader(buffer, len);
447 return new ArpHeader(buffer, len);
450 void ArpEthIpHeader::print(std::ostream& where) const {
451 ArpHeader::print(where);
452 //const struct arphdr * arph = (const struct arphdr *) data;
453 unsigned short arphdrlen = sizeof(struct arphdr); // ARP header Lenght
454 const struct arphdr_eth_ipv4 * eth_ipv4 = (const struct arphdr_eth_ipv4 *)(data + arphdrlen);
456 printWithFormat(where, " |-Sender MAC : %.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
457 eth_ipv4->ar_sha[0], eth_ipv4->ar_sha[1], eth_ipv4->ar_sha[2],
458 eth_ipv4->ar_sha[3], eth_ipv4->ar_sha[4], eth_ipv4->ar_sha[5] );
459 where << std::endl;
461 printWithFormat(where, " |-Sender IP : %u.%u.%u.%u",
462 eth_ipv4->ar_spa[0], eth_ipv4->ar_spa[1], eth_ipv4->ar_spa[2], eth_ipv4->ar_spa[3]);
463 where << std::endl;
465 printWithFormat(where, " |-Target MAC : %.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
466 eth_ipv4->ar_tha[0], eth_ipv4->ar_tha[1], eth_ipv4->ar_tha[2],
467 eth_ipv4->ar_tha[3], eth_ipv4->ar_tha[4], eth_ipv4->ar_tha[5] );
468 where << std::endl;
470 printWithFormat(where, " |-Sender IP : %u.%u.%u.%u",
471 eth_ipv4->ar_tpa[0], eth_ipv4->ar_tpa[1], eth_ipv4->ar_tpa[2], eth_ipv4->ar_tpa[3]);
472 where << std::endl;