1 // Copyright (c) 2012, Miriam Ruiz <miriam@debian.org>. All rights reserved.
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
6 // 1. Redistributions of source code must retain the above copyright notice,
7 // this list of conditions and the following disclaimer.
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.
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.
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
;
46 static std::ostream
& printWithFormat(std::ostream
& out
, const char * fmt
, ...) {
48 char * buffer
= new char[size
];
53 // Try to print in the allocated space
55 int n
= vsnprintf(buffer
, size
, fmt
, ap
);
58 // If that worked, output the string
59 if (n
> -1 && n
< size
) {
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
69 size
*= 2; // Twice the old size
71 // Allocate a new buffer with the new size
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
89 printWithFormat(out
, "."); //otherwise print a dot
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
]);
112 printWithFormat(out
, ".");
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
));
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
])
140 else if (address
[i
] > other
[i
])
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
])
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] );
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] );
181 inline std::ostream
& operator<< (std::ostream
& out
, const PortNumber
& v
) {
182 return out
<< u_int16_t(v
);
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;
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
);
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] );
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] );
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
, ð
, ethhdrlen
);
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
);
253 case 2: // IGMP Protocol
254 return IgmpHeader::createHeader(payload
, payload_size
);
257 case 6: // TCP Protocol
258 return TcpHeader::createHeader(payload
, payload_size
);
261 case 17: // UDP Protocol
262 return UdpHeader::createHeader(payload
, payload_size
);
265 default: // Other Protocols
266 return UnknownHeader::createHeader(payload
, payload_size
);
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
);
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
);
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
);
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] );
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]);
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] );
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]);