1 /*** This Programs/Libraries are (C)opyright by Sebastian Krahmer.
2  *** You may use it under the terms of the GPL. You should have
3  *** already received the file COPYING that shows you your rights.
4  *** Please look at COPYING for further license-details.
5  ***
6  *** THERE IS ABSOLUTELY NO WARRANTY. SO YOU USE IT AT YOUR OWN RISK.
7  *** IT WAS WRITTEN IN THE HOPE THAT IT WILL BE USEFULL. I AM NOT RESPONSIBLE
8  *** FOR ANY DAMAGE YOU MAYBE GET DUE TO USING MY PROGRAMS.
9  ***/
10 
11 #include "usi++/usi-structs.h"
12 #include "usi++/datalink.h"
13 #include "usi++/ip.h"
14 
15 #include "config.h"
16 #include <iostream>
17 #include <string.h>
18 #include <cstdlib>
19 #include <errno.h>
20 #include <new>
21 #include <vector>
22 
23 namespace usipp {
24 
25 /*  Create a IP-packet, with 'dst' for destination-adress.
26  *  Set the protocol-filed in the IP-header to 'proto'.
27  *  This is used by the derived classes (TCP etc.) to set
28  *  the correct protocol (IPPROTO_TCP etc.)
29  */
IP(const char * dst,u_int8_t proto)30 IP::IP(const char *dst, u_int8_t proto)
31    	: Layer2()
32 {
33 	memset(&iph, 0, sizeof(iph));
34 	memset(ipOptions, 0, sizeof(ipOptions));
35 		srand(time(NULL));
36         iph.ttl = 64;
37         iph.version = 4;
38         iph.ihl = 5;
39 //        iph.id = 0;
40 		/* We set the IP ID
41 		 * since for fingerprinting we
42 		 * need to be able to know what
43 		 * was the IP ID of the packet we
44 		 * sent, cuz if we don't we'll get 0
45 		 */
46 		iph.id = rand();
47 		iph.check = 0;
48         iph.protocol = proto;
49 		iph.tot_len = 0;
50 
51 	memset(host, 0, sizeof(host));
52 
53 	// ask for local hostname
54 	/*
55         if (gethostname(host, sizeof(host)-1) < 0) {
56 		perror("gethostname");
57 		fprintf(stderr, "using INADDR_ANY for src-IP.");
58 		set_src(INADDR_ANY);
59 	}
60 	  * by meder: we dont' want to set the src host here,
61 	  * as it causes problem when there's no entry in /etc/hosts
62 	  * for the localhost.
63 	  * user just has to make sure he/she calls set_src();
64 		else
65 		set_src(host);
66 		*/
67 
68 	set_dst(dst);
69 
70         // what in sendpack must be set is:
71         // tot_len, check, frag_off
72 }
73 
74 /*  Same as above, but use networkbyte-ordered int32 for destination-adress.
75  *  This is usefull in case you do sth. like ip.set_src(ip2.get_src())
76  */
IP(u_int32_t dst,u_int8_t proto)77 IP::IP(u_int32_t dst, u_int8_t proto)
78    	: Layer2()
79 {
80    	memset(&iph, 0, sizeof(iph));
81 	memset(ipOptions, 0, sizeof(ipOptions));
82 
83 		srand(time(NULL));
84         iph.ttl = 64;
85         iph.version = 4;
86         iph.ihl = 5;
87         //iph.id = 0;
88 		iph.id = rand();
89         iph.protocol = proto;
90 
91 	memset(host, 0, sizeof(host));
92 
93 	// ask for local hostname
94 	 /*
95         if (gethostname(host, sizeof(host)-1) < 0) {
96 		perror("gethostname");
97 		fprintf(stderr, "using INADDR_ANY for src-IP.");
98 		set_src(INADDR_ANY);
99 		}
100 	  * by meder: we dont' want to set the src host here,
101 	  * as it causes problem when there's no entry in /etc/hosts
102 	  * for the localhost.
103 	  * user just has to make sure he/she calls set_src();
104 		else
105 		set_src(host);
106 		*/
107 
108         set_dst(dst);
109 }
110 
111 
112 /*  Same as above
113  */
IP(iphdr & iphh)114 IP::IP(iphdr &iphh)
115    	: Layer2()
116 {
117    	memcpy(&iph, &iphh, sizeof(iphh));
118 	memset(ipOptions, 0, sizeof(ipOptions));
119 
120 }
121 
122 
123 /* Assign-operator
124  */
operator =(const IP & rhs)125 IP& IP::operator=(const IP &rhs)
126 {
127 	if (this == &rhs)
128 		return *this;
129 
130 	Layer2::operator=(rhs);
131 
132 	// and just copy header and such
133 	memcpy(host, rhs.host, sizeof(host));
134 	memcpy(&iph, &rhs.iph, sizeof(iph));
135 	memcpy(ipOptions, rhs.ipOptions, sizeof(ipOptions));
136 	memcpy(&saddr, &rhs.saddr, sizeof(saddr));
137 	return *this;
138 }
139 
140 /* copy-construktor
141  */
IP(const IP & rhs)142 IP::IP(const IP &rhs)
143     : Layer2(rhs)
144 {
145 	if (this == &rhs)
146 		return;
147 
148 	memcpy(host, rhs.host, sizeof(host));
149 	memcpy(&iph, &rhs.iph, sizeof(iph));
150 	memcpy(ipOptions, rhs.ipOptions, sizeof(ipOptions));
151 	memcpy(&saddr, &rhs.saddr, sizeof(saddr));
152 }
153 
~IP()154 IP::~IP()
155 {
156 }
157 
158 /*  Get IP header-length
159  */
get_hlen() const160 u_int8_t IP::get_hlen() const
161 {
162    	return iph.ihl;
163 }
164 
165 /* Set IP-header-length.
166  */
set_hlen(u_int8_t l)167 int IP::set_hlen(u_int8_t l)
168 {
169         iph.ihl = l;
170 	return 0;
171 }
172 
173 /* Get Ip-version field.
174  */
get_vers() const175 u_int8_t IP::get_vers() const
176 {
177    	return iph.version;
178 }
179 
180 /* Set version field in IP-header.
181  */
set_vers(u_int8_t v)182 int IP::set_vers(u_int8_t v)
183 {
184    	iph.version = v;
185         return 0;
186 }
187 
get_tos() const188 u_int8_t IP::get_tos() const
189 {
190    	return iph.tos;
191 }
192 
set_tos(u_int8_t tos)193 int IP::set_tos(u_int8_t tos)
194 {
195    	iph.tos = tos;
196         return 0;
197 }
198 
199 /* Get total length of IP-packet.
200  */
get_totlen() const201 u_int16_t IP::get_totlen() const
202 {
203    	return ntohs(iph.tot_len);
204 }
205 
206 /* Set total length of IP-packet.
207  *  If you set the total length by yourself, you will prevent the
208  *  sendpack() routine to do it. This is normally _not_ needed.
209  */
set_totlen(u_int16_t t)210 int IP::set_totlen(u_int16_t t)
211 {
212 	/* XXX meder: we move handling of all
213 	 * os the BROKEN_BSD cases into sendpack()
214 	 * because now for example if you do set_totlen()
215 	 * or set_fragoff() and then right after that
216 	 * you do get_fragoff() it will return different value
217 	 * on BROKEN_BSD, this is because on BROKEN_BSD those
218 	 * values are in host byte order and get_*() return
219 	 * ntoh'ed values
220 	 * Basically we want to enforce network byte order in
221 	 * those fields and then just change byte order when
222 	 * calling sendpack() to approriate if run on BROKEN_BSD
223 	 */
224 /*
225 #ifdef BROKEN_BSD
226 	iph.tot_len = t;
227 #else
228 	iph.tot_len = htons(t);
229 #endif
230 */
231 	iph.tot_len = htons(t);
232    	return 0;
233 }
234 
235 /* Get the IP id field.
236  */
get_id() const237 u_int16_t IP::get_id() const
238 {
239    	return ntohs(iph.id);
240 }
241 
242 /* Set the IP id field.
243  */
set_id(u_int16_t id)244 int IP::set_id(u_int16_t id)
245 {
246    	iph.id = htons(id);
247         return 0;
248 }
249 
250 /* Get the IP-fragmentation offset */
get_fragoff() const251 u_int16_t IP::get_fragoff() const
252 {
253    	return ntohs(iph.frag_off);
254 }
255 
256 /* Set the IP-fragmentation offset */
set_fragoff(u_int16_t f)257 int IP::set_fragoff(u_int16_t f)
258 {
259 	/* XXX meder: see comment for set_totlen */
260 /*
261 #ifdef BROKEN_BSD
262 	iph.frag_off = f;
263 #else
264    	iph.frag_off = htons(f);
265 #endif
266 */
267 	iph.frag_off = htons(f);
268 	return  0;
269 }
270 
271 /* Get time to live.
272  */
get_ttl() const273 u_int8_t IP::get_ttl() const
274 {
275    	return iph.ttl;
276 }
277 
278 /* Set 'time to live'
279  */
set_ttl(u_int8_t ttl)280 int IP::set_ttl(u_int8_t ttl)
281 {
282    	iph.ttl = ttl;
283         return 0;
284 }
285 
286 /* Obtain the actuall protocol.
287  */
get_proto() const288 u_int8_t IP::get_proto() const
289 {
290    	return iph.protocol;
291 }
292 
293 /* Change the protocol-filed of IP header to 'p' in case
294  * you need to.
295  */
set_proto(u_int8_t p)296 int IP::set_proto(u_int8_t p)
297 {
298         iph.protocol = p;
299         return 0;
300 }
301 
302 /* Get IP-header checksum
303  */
get_sum() const304 u_int16_t IP::get_sum() const
305 {
306 	   	return iph.check;
307 }
308 
309 /* Calculate IP-header checksum
310  * calculated over ip header
311  * only calcs, doesn't set anything
312  */
calc_ipsum()313 u_int16_t IP::calc_ipsum()
314 {
315 	u_int16_t csum;
316 /*
317 #ifdef BROKEN_BSD
318 	iph.tot_len = htons(iph.tot_len);
319 	iph.frag_off = htons(iph.frag_off);
320 #endif
321 */
322 
323 	csum = in_cksum ( (unsigned short *) &iph, sizeof(iph), 0 );
324 
325 /*
326 #ifdef BROKEN_BSD
327 	iph.tot_len = ntohs(iph.tot_len);
328 	iph.frag_off = ntohs(iph.frag_off);
329 #endif
330 */
331 
332 	return csum;
333 }
334 
335 /* Set IP-header checksum
336  *  Should not be used as long as you don't want to
337  *  insert bad checksums into the header.
338  */
set_sum(u_int16_t s)339 int IP::set_sum(u_int16_t s)
340 {
341    	iph.check = s;
342         return 0;
343 }
344 
345 /* Get the destination-adress in networkbyteorder.
346  */
get_dst() const347 u_int32_t IP::get_dst() const
348 {
349 	return iph.daddr;
350 }
351 
352 /* Get the destination-adress in human-readable form.
353  *  If resolv == 1, then resolve to a hostname if possible,
354  *  otherwise give back IP (resolv == 0).
355  */
get_dst(int resolv,char * s,size_t len)356 char *IP::get_dst(int resolv, char *s, size_t len)
357 {
358    	 struct in_addr in;
359          struct hostent *he;
360 
361          memset(s, 0, len);
362          in.s_addr = iph.daddr;
363          if (!resolv || (he = gethostbyaddr((char*)&in, sizeof(in), AF_INET)) == NULL)
364             	strncpy(s, inet_ntoa(in), len);
365          else
366             	strncpy(s, he->h_name, len);
367          return s;
368 }
369 
370 /* Return the source-adress of actuall IP-packet
371  * in network-byte order.
372  */
get_src() const373 u_int32_t IP::get_src() const
374 {
375    	return iph.saddr;
376 }
377 
378 /* Get the sourceadress in human-readable form.
379  *  If 'resolv' == 1, return hostname, if 0 only IP-adress.
380  */
get_src(int resolv,char * s,size_t len)381 char *IP::get_src(int resolv, char *s, size_t len)
382 {
383    	 struct in_addr in;
384          struct hostent *he;
385 
386          memset(s, 0, len);
387          in.s_addr = iph.saddr;
388          if (!resolv || (he = gethostbyaddr((char*)&in, sizeof(in), AF_INET)) == NULL)
389             	strncpy(s, inet_ntoa(in), len);
390          else
391             	strncpy(s, he->h_name, len);
392          return s;
393 }
394 
395 /* Set the source-adress, use networkbyteorderes adress.
396  */
set_src(u_int32_t s)397 int IP::set_src(u_int32_t s)
398 {
399    	iph.saddr = s;
400         return 0;
401 }
402 
403 /* Set the sourceadress, use hostname or IP.
404  */
set_src(const char * host)405 int IP::set_src(const char* host)
406 {
407    	struct hostent *he;
408 
409         if ((he = gethostbyname(host)) == NULL) {
410 				herror("IP::set_src::gethostbyname");
411                 exit(errno);
412         }
413         memcpy(&iph.saddr, he->h_addr, he->h_length);
414         return 0;
415 }
416 
417 /* Set destination adress.
418  */
set_dst(u_int32_t d)419 int IP::set_dst(u_int32_t d)
420 {
421 	iph.daddr = d;
422 	return 0;
423 }
424 
425 /*! Set destinationadress, similar to set_src()
426  */
set_dst(const char * host)427 int IP::set_dst(const char* host)
428 {
429    	struct hostent *he;
430 
431         if ((he = gethostbyname(host)) == NULL) {
432 		herror("IP::set_dst::gethostbyname");
433                 exit(errno);
434         }
435         memcpy(&iph.daddr, he->h_addr, he->h_length);
436         return 0;
437 }
438 
get_iphdr() const439 iphdr IP::get_iphdr() const
440 {
441 	return iph;
442 }
443 
set_iphdr(struct iphdr _iph)444 int IP::set_iphdr(struct iphdr _iph) {
445 	iph = _iph;
446 	return 0;
447 }
448 
449 /* Send a packet, containing 'paylen' bytes of data.
450  */
sendpack(void * payload,size_t paylen)451 int IP::sendpack(void *payload, size_t paylen)
452 {
453 
454 	// get mem for packet
455 	char *s = new char[paylen+sizeof(iph)+1];
456 	memset(s, 0, paylen+sizeof(iph)+1);
457 
458 
459 	// We give luser the chance to set wrong length's
460 	// if he really want's to ...
461 	if (get_totlen() == 0)
462 		set_totlen(paylen + sizeof(iph));		// how long ?
463 
464 #ifdef BROKEN_BSD
465 	iph.tot_len = ntohs(iph.tot_len);
466 	iph.frag_off= ntohs(iph.frag_off);
467 #endif
468 
469 	/* If checksum is 0, kernel will set it. */
470 	if (iph.check != 0)
471 		iph.check = in_cksum((unsigned short*)&iph, sizeof(iph), 0);
472 
473 	memcpy(s, &iph, sizeof(iph));
474 	memcpy(s + sizeof(iph), payload, paylen);
475 
476 	sockaddr_in saddr;
477 	saddr.sin_family = AF_INET;
478 	saddr.sin_port = 0;
479 	saddr.sin_addr.s_addr = iph.daddr;
480 
481 	Layer2::sendpack(s, paylen + sizeof(iph), (struct sockaddr*)&saddr);
482 
483 #ifdef BROKEN_BSD
484 	iph.tot_len = htons(iph.tot_len);
485 	iph.frag_off = htons(iph.frag_off);
486 #endif
487 
488 	delete [] s;
489 	return 0;
490 }
491 
492 
sendpack(char * payload)493 int IP::sendpack(char *payload)
494 {
495 	return sendpack((void*)payload, strlen(payload));
496 }
497 
498 
499 /*! Handle packets, that are NOT actually for the
500  *  local adress!
501  */
sniffpack(void * buf,size_t len)502 int IP::sniffpack(void *buf, size_t len)
503 {
504 	int r = 0;
505 	int xlen = len + sizeof(iph) + sizeof(ipOptions);
506 	struct usipp::iphdr *i = NULL;
507 
508 	char *tmp = new char[xlen];
509 	memset(tmp, 0, xlen);
510 	memset(buf, 0, len);
511 
512 	/* until we assembled fragments or we received and unfragemented packet
513 	 */
514 	while (i == NULL) {
515 		memset(tmp, 0, xlen);
516            	if ((r = Layer2::sniffpack(tmp, xlen)) == 0 &&
517 		    Layer2::timeout()) {
518 			delete[] tmp;
519 			return 0;	// timeout
520 		}
521 #ifdef USI_REASSEMBLE
522 		i = (struct usipp::iphdr*)reassemble(tmp, len, &r);
523 #else
524 		i = (struct usipp::iphdr*)tmp;
525 #endif
526         }
527 
528 #ifdef USI_DEBUG
529 	cerr<<"IP::r="<<r<<endl;
530 	cerr<<"IP::ihlen="<<(i->ihl<<2)<<endl;
531 #endif
532 
533         unsigned int iplen = i->ihl<<2;
534 	// Copy header without options
535 	memcpy(&iph, (char*)i, sizeof(iph));
536 
537 	// Copy ip-options if any
538 	if (iplen > sizeof(iph))
539 		memcpy(ipOptions, tmp+sizeof(iph), iplen-sizeof(iph));
540 
541 	if (buf)
542 		memcpy(buf, (char*)i + iplen, len);
543 
544 	delete [] tmp;
545 	return get_totlen() - iplen;
546 }
547 
548 /*! Initialize a device ("eth0" for example) for packet-
549  *  capturing. It MUST be called before sniffpack() is launched.
550  *  Set 'promisc' to 1 if you want the device running in promiscous mode.
551  *  Fetch at most 'snaplen' bytes per call.
552  */
init_device(char * dev,int promisc,size_t snaplen)553 int IP::init_device(char *dev, int promisc, size_t snaplen)
554 {
555         int r = Layer2::init_device(dev, promisc, snaplen);
556 
557 	if (r < 0)
558 		die("IP::init_device", STDERR, 1);
559 	r = Layer2::setfilter("ip");
560 
561 	if (r < 0)
562 		die("IP::init_device::setfilter", STDERR, 1);
563 
564         return r;
565 }
566 
567 /*! Assembles IP-fragments.
568  */
reassemble(char * packet,int len,int * resultLen)569 char *IP::reassemble(char *packet, int len, int *resultLen)
570 {
571    	static vector<fragments*> pending;
572 	fragments *f = NULL;
573 	int ihl = 0, xlen = 0, offset = 0;
574 	unsigned int i = 0;
575 
576         struct usipp::iphdr *ip = (struct usipp::iphdr*)(packet);
577 	ihl = ip->ihl<<2;
578 
579 	/* can't be > 60 */
580 	if (ihl > 60)
581 		ihl = 60;
582 
583         /* if fragment-offset and DF-bit not set */
584         if (ntohs(ip->frag_off) != 0 &&
585 	   (ntohs(ip->frag_off) & IP_DF) != IP_DF) {
586 
587 		/* for all pending fragments */
588 		for (i = 0; i < pending.size(); i++) {
589 			if (pending[i] == NULL)
590 				continue;
591 
592 			/* if we already have something that belongs to
593 			 * _this_ fragment
594                          */
595 			if (ntohs(ip->id) == pending[i]->id) {
596 				f = pending[i];
597 				break;
598 			}
599 		}
600 
601 		/* otherwise its the first one */
602 		if (f == NULL) {
603 			f = new fragments;
604 			f->id = ntohs(ip->id);
605          		f->data = new char[len + ihl];
606 			f->len = 0;			// # of bytes that are captured yet
607 			f->origLen = 0xffff;		// # of bytes IP-packet once contained
608 			f->userLen = 0;			// # of bytes saved
609 			memset(f->data, 0, len + ihl);
610 			memcpy(f->data, packet, ihl);
611 			pending.push_back(f);
612 		}
613 
614 		offset = 8*(ntohs(ip->frag_off) & IP_OFFMASK);
615 
616 		if (offset + ntohs(ip->tot_len) - ihl <= len)
617 			xlen = ntohs(ip->tot_len) - ihl;
618 		else
619 			xlen = len - offset;
620 
621 
622 		/* Copy IP-data to the right offset.
623 		 * It may happen, that offset points out of our data-area.
624 		 * In this case is xlen < 0 and we ignore it.
625 		 */
626 		if (xlen > 0) {
627 			memcpy(f->data + offset + ihl,
628 		               packet + ihl,
629 		               xlen
630 		              );
631 			/* This is for the caller; how much was
632 			 * fetched AND COPIED for her.
633 			 */
634 			f->userLen += xlen;
635 		}
636 
637 		/* We even count the not copied data! */
638 		f->len += ntohs(ip->tot_len) - ihl;
639 
640 
641 		/* OK, we received the last fragment with this id, so calculate
642 		 * how the original size of this packet was
643 		 */
644 		if ((ntohs(ip->frag_off) != 0 &&
645 		    (ntohs(ip->frag_off) & IP_MF) == 0)) {
646 			f->origLen = ntohs(ip->tot_len) + offset - ihl;
647 		}
648 
649 		/* In case we reached the original len -> all fragments
650 		 * are received and assembled.
651 		 * NOTE that f->len counts the # of bytes _received_, not saved!
652 		 * The # of saved bytes is in f->userLen.
653 		 */
654 		if (f->len == f->origLen) {
655 			/* should not be necessary, but */
656 			if (i >= 0 && i < pending.size())
657 				pending[i] = NULL;
658 			struct usipp::iphdr *ih = (struct usipp::iphdr*)(f->data);
659 			ih->frag_off = 0;
660 
661 			ih->tot_len = htons(ihl + f->len);
662 			*resultLen = ihl + f->userLen;
663 
664 			/* packet must at least be 'len+ihl' bytes big,
665 			 * where 'ihl' is max. 60.
666 			 */
667 			memset(packet, 0, len+ihl);
668 			memcpy(packet, f->data, len+ihl);
669 
670 			delete [] f->data;
671 			delete f;
672 			return packet;
673 		} else  {
674 			*resultLen = 0;
675 			return NULL;
676 		}
677 
678         /* else, packet is not fragmented  */
679         } else {
680 		*resultLen = ntohs(ip->tot_len);
681 		/* return IP-packet, hw-frame skipped */
682 		return packet;
683         }
684 }
685 
to_string(void)686 std::string IP::to_string(void) {
687 	char buf[4096], src_str[256], dst_str[256];
688 	string retval;
689 
690 	memset(buf, 0, sizeof(buf));
691 	// hrm using inet_ntoa() two times in a row in one snprintf statement
692 	// cases it to display the same IP for both, while they are actually different
693 	snprintf(buf, sizeof(buf), "+--------------------------------[ IP ]\n| src=%s dst=%s hlen=%d totlen=%d tos=0x%x fragoff=0x%x ttl=%d id=%d\n+--------------------------------\n", get_src(0, src_str, sizeof(src_str)), get_dst(0, dst_str, sizeof(dst_str)), get_hlen(), get_totlen(), get_tos(), get_fragoff(), get_ttl(), get_id());
694 	retval = buf;
695 	return retval;
696 }
697 
698 } // namespace usipp
699 
700