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