📄 ip.cc
字号:
/*** This Programs/Libraries are (C)opyright by Sebastian Krahmer. *** You may use it under the terms of the GPL. You should have *** already received the file COPYING that shows you your rights. *** Please look at COPYING for further license-details. *** *** THERE IS ABSOLUTELY NO WARRANTY. SO YOU USE IT AT YOUR OWN RISK. *** IT WAS WRITTEN IN THE HOPE THAT IT WILL BE USEFULL. I AM NOT RESPONSIBLE *** FOR ANY DAMAGE YOU MAYBE GET DUE TO USING MY PROGRAMS. ***/ #include "usi++/usi-structs.h"#include "usi++/datalink.h"#include "usi++/ip.h"#include "config.h"#include <iostream>#include <string.h>#include <errno.h>#include <new>#include <vector>namespace usipp {/* Create a IP-packet, with 'dst' for destination-adress. * Set the protocol-filed in the IP-header to 'proto'. * This is used by the derived classes (TCP etc.) to set * the correct protocol (IPPROTO_TCP etc.) */IP::IP(const char *dst, u_int8_t proto) : Layer2(){ memset(&iph, 0, sizeof(iph)); memset(ipOptions, 0, sizeof(ipOptions)); srand(time(NULL)); iph.ttl = 64; iph.version = 4; iph.ihl = 5;// iph.id = 0; /* We set the IP ID * since for fingerprinting we * need to be able to know what * was the IP ID of the packet we * sent, cuz if we don't we'll get 0 */ iph.id = rand(); iph.check = 0; iph.protocol = proto; iph.tot_len = 0; memset(host, 0, sizeof(host)); // ask for local hostname if (gethostname(host, sizeof(host)-1) < 0) { perror("gethostname"); fprintf(stderr, "using INADDR_ANY for src-IP."); set_src(INADDR_ANY); } else set_src(host); set_dst(dst); // what in sendpack must be set is: // tot_len, check, frag_off}/* Same as above, but use networkbyte-ordered int32 for destination-adress. * This is usefull in case you do sth. like ip.set_src(ip2.get_src()) */IP::IP(u_int32_t dst, u_int8_t proto) : Layer2(){ memset(&iph, 0, sizeof(iph)); memset(ipOptions, 0, sizeof(ipOptions)); srand(time(NULL)); iph.ttl = 64; iph.version = 4; iph.ihl = 5; //iph.id = 0; iph.id = rand(); iph.protocol = proto; memset(host, 0, sizeof(host)); // ask for local hostname if (gethostname(host, sizeof(host)-1) < 0) { perror("gethostname"); fprintf(stderr, "using INADDR_ANY for src-IP."); set_src(INADDR_ANY); } else set_src(host); set_dst(dst);}/* Same as above */IP::IP(iphdr &iphh) : Layer2(){ memcpy(&iph, &iphh, sizeof(iphh)); memset(ipOptions, 0, sizeof(ipOptions)); }/* Assign-operator */IP& IP::operator=(const IP &rhs){ if (this == &rhs) return *this; Layer2::operator=(rhs); // and just copy header and such memcpy(host, rhs.host, sizeof(host)); memcpy(&iph, &rhs.iph, sizeof(iph)); memcpy(ipOptions, rhs.ipOptions, sizeof(ipOptions)); memcpy(&saddr, &rhs.saddr, sizeof(saddr)); return *this;}/* copy-construktor */IP::IP(const IP &rhs) : Layer2(rhs){ if (this == &rhs) return; memcpy(host, rhs.host, sizeof(host)); memcpy(&iph, &rhs.iph, sizeof(iph)); memcpy(ipOptions, rhs.ipOptions, sizeof(ipOptions)); memcpy(&saddr, &rhs.saddr, sizeof(saddr));}IP::~IP(){}/* Get IP header-length */u_int8_t IP::get_hlen(){ return iph.ihl;}/* Set IP-header-length. */int IP::set_hlen(u_int8_t l){ iph.ihl = l; return 0;}/* Get Ip-version field. */u_int8_t IP::get_vers(){ return iph.version;}/* Set version field in IP-header. */int IP::set_vers(u_int8_t v){ iph.version = v; return 0;} u_int8_t IP::get_tos(){ return iph.tos;}int IP::set_tos(u_int8_t tos){ iph.tos = tos; return 0;}/* Get total length of IP-packet. */u_int16_t IP::get_totlen(){ return ntohs(iph.tot_len);}/* Set total length of IP-packet. * If you set the total length by yourself, you will prevent the * sendpack() routine to do it. This is normally _not_ needed. */int IP::set_totlen(u_int16_t t){ /* XXX meder: we move handling of all * os the BROKEN_BSD cases into sendpack() * because now for example if you do set_totlen() * or set_fragoff() and then right after that * you do get_fragoff() it will return different value * on BROKEN_BSD, this is because on BROKEN_BSD those * values are in host byte order and get_*() return * ntoh'ed values * Basically we want to enforce network byte order in * those fields and then just change byte order when * calling sendpack() to approriate if run on BROKEN_BSD *//*#ifdef BROKEN_BSD iph.tot_len = t;#else iph.tot_len = htons(t);#endif*/ iph.tot_len = htons(t); return 0;}/* Get the IP id field. */u_int16_t IP::get_id(){ return ntohs(iph.id);}/* Set the IP id field. */int IP::set_id(u_int16_t id){ iph.id = htons(id); return 0;}/* Get the IP-fragmentation offset */u_int16_t IP::get_fragoff(){ return ntohs(iph.frag_off);}/* Set the IP-fragmentation offset */int IP::set_fragoff(u_int16_t f){ /* XXX meder: see comment for set_totlen *//*#ifdef BROKEN_BSD iph.frag_off = f;#else iph.frag_off = htons(f);#endif*/ iph.frag_off = htons(f); return 0;}/* Get time to live. */u_int8_t IP::get_ttl(){ return iph.ttl;}/* Set 'time to live' */int IP::set_ttl(u_int8_t ttl){ iph.ttl = ttl; return 0;}/* Obtain the actuall protocol. */u_int8_t IP::get_proto(){ return iph.protocol;}/* Change the protocol-filed of IP header to 'p' in case * you need to. */int IP::set_proto(u_int8_t p){ iph.protocol = p; return 0;}/* Get IP-header checksum */u_int16_t IP::get_sum(){ return iph.check;}/* Calculate IP-header checksum * calculated over ip header * only calcs, doesn't set anything */u_int16_t IP::calc_ipsum(){ u_int16_t csum;/*#ifdef BROKEN_BSD iph.tot_len = htons(iph.tot_len); iph.frag_off = htons(iph.frag_off);#endif*/ csum = in_cksum ( (unsigned short *) &iph, sizeof(iph), 0 );/*#ifdef BROKEN_BSD iph.tot_len = ntohs(iph.tot_len); iph.frag_off = ntohs(iph.frag_off);#endif*/ return csum;}/* Set IP-header checksum * Should not be used as long as you don't want to * insert bad checksums into the header. */int IP::set_sum(u_int16_t s){ iph.check = s; return 0;}/* Get the destination-adress in networkbyteorder. */u_int32_t IP::get_dst(){ return iph.daddr;}/* Get the destination-adress in human-readable form. * If resolv == 1, then resolve to a hostname if possible, * otherwise give back IP (resolv == 0). */char *IP::get_dst(int resolv, char *s, size_t len){ struct in_addr in; struct hostent *he; memset(s, 0, len); in.s_addr = iph.daddr; if (!resolv || (he = gethostbyaddr((char*)&in, sizeof(in), AF_INET)) == NULL) strncpy(s, inet_ntoa(in), len); else strncpy(s, he->h_name, len); return s;}/* Return the source-adress of actuall IP-packet * in network-byte order. */u_int32_t IP::get_src(){ return iph.saddr;}/* Get the sourceadress in human-readable form. * If 'resolv' == 1, return hostname, if 0 only IP-adress. */char *IP::get_src(int resolv, char *s, size_t len){ struct in_addr in; struct hostent *he; memset(s, 0, len); in.s_addr = iph.saddr; if (!resolv || (he = gethostbyaddr((char*)&in, sizeof(in), AF_INET)) == NULL) strncpy(s, inet_ntoa(in), len); else strncpy(s, he->h_name, len); return s;}/* Set the source-adress, use networkbyteorderes adress. */int IP::set_src(u_int32_t s){ iph.saddr = s; return 0;}/* Set the sourceadress, use hostname or IP. */int IP::set_src(const char* host){ struct hostent *he; if ((he = gethostbyname(host)) == NULL) { herror("IP::set_src::gethostbyname"); exit(errno); } memcpy(&iph.saddr, he->h_addr, he->h_length); return 0;}/* Set destination adress. */int IP::set_dst(u_int32_t d){ iph.daddr = d; return 0;}/*! Set destinationadress, similar to set_src() */int IP::set_dst(const char* host){ struct hostent *he; if ((he = gethostbyname(host)) == NULL) { herror("IP::set_dst::gethostbyname"); exit(errno); } memcpy(&iph.daddr, he->h_addr, he->h_length); return 0;}iphdr IP::get_iphdr(){ return iph;}/* Send a packet, containing 'paylen' bytes of data. */int IP::sendpack(void *payload, size_t paylen){ // get mem for packet char *s = new char[paylen+sizeof(iph)+1]; memset(s, 0, paylen+sizeof(iph)+1); // We give luser the chance to set wrong length's // if he really want's to ... if (get_totlen() == 0) set_totlen(paylen + sizeof(iph)); // how long ?#ifdef BROKEN_BSD iph.tot_len = ntohs(iph.tot_len); iph.frag_off= ntohs(iph.frag_off);#endif /* If checksum is 0, kernel will set it. */ if (iph.check != 0) iph.check = in_cksum((unsigned short*)&iph, sizeof(iph), 0); memcpy(s, &iph, sizeof(iph)); memcpy(s + sizeof(iph), payload, paylen); sockaddr_in saddr; saddr.sin_family = AF_INET; saddr.sin_port = 0; saddr.sin_addr.s_addr = iph.daddr; Layer2::sendpack(s, paylen + sizeof(iph), (struct sockaddr*)&saddr); #ifdef BROKEN_BSD iph.tot_len = htons(iph.tot_len); iph.frag_off = htons(iph.frag_off);#endif delete [] s; return 0;}int IP::sendpack(char *payload){ return sendpack((void*)payload, strlen(payload));}/*! Handle packets, that are NOT actually for the * local adress! */int IP::sniffpack(void *buf, size_t len){ int r = 0; int xlen = len + sizeof(iph) + sizeof(ipOptions); struct usipp::iphdr *i = NULL; char *tmp = new char[xlen]; memset(tmp, 0, xlen); memset(buf, 0, len); /* until we assembled fragments or we received and unfragemented packet */ while (i == NULL) { memset(tmp, 0, xlen); if ((r = Layer2::sniffpack(tmp, xlen)) == 0 && Layer2::timeout()) { delete[] tmp; return 0; // timeout }#ifdef USI_REASSEMBLE i = (struct usipp::iphdr*)reassemble(tmp, len, &r);#else i = (struct usipp::iphdr*)tmp;#endif } #ifdef USI_DEBUG cerr<<"IP::r="<<r<<endl; cerr<<"IP::ihlen="<<(i->ihl<<2)<<endl;#endif unsigned int iplen = i->ihl<<2; // Copy header without options memcpy(&iph, (char*)i, sizeof(iph)); // Copy ip-options if any if (iplen > sizeof(iph)) memcpy(ipOptions, tmp+sizeof(iph), iplen-sizeof(iph)); if (buf) memcpy(buf, (char*)i + iplen, len); delete [] tmp; return get_totlen() - iplen;}/*! Initialize a device ("eth0" for example) for packet- * capturing. It MUST be called before sniffpack() is launched. * Set 'promisc' to 1 if you want the device running in promiscous mode. * Fetch at most 'snaplen' bytes per call. */int IP::init_device(char *dev, int promisc, size_t snaplen){ int r = Layer2::init_device(dev, promisc, snaplen); if (r < 0) die("IP::init_device", STDERR, 1); r = Layer2::setfilter("ip"); if (r < 0) die("IP::init_device::setfilter", STDERR, 1); return r;}/*! Assembles IP-fragments. */char *IP::reassemble(char *packet, int len, int *resultLen){ static vector<fragments*> pending; fragments *f = NULL; int ihl = 0, xlen = 0, offset = 0; unsigned int i = 0; struct usipp::iphdr *ip = (struct usipp::iphdr*)(packet); ihl = ip->ihl<<2; /* can't be > 60 */ if (ihl > 60) ihl = 60; /* if fragment-offset and DF-bit not set */ if (ntohs(ip->frag_off) != 0 && (ntohs(ip->frag_off) & IP_DF) != IP_DF) { /* for all pending fragments */ for (i = 0; i < pending.size(); i++) { if (pending[i] == NULL) continue; /* if we already have something that belongs to * _this_ fragment */ if (ntohs(ip->id) == pending[i]->id) { f = pending[i]; break; } } /* otherwise its the first one */ if (f == NULL) { f = new fragments; f->id = ntohs(ip->id); f->data = new char[len + ihl]; f->len = 0; // # of bytes that are captured yet f->origLen = 0xffff; // # of bytes IP-packet once contained f->userLen = 0; // # of bytes saved memset(f->data, 0, len + ihl); memcpy(f->data, packet, ihl); pending.push_back(f); } offset = 8*(ntohs(ip->frag_off) & IP_OFFMASK); if (offset + ntohs(ip->tot_len) - ihl <= len) xlen = ntohs(ip->tot_len) - ihl; else xlen = len - offset; /* Copy IP-data to the right offset. * It may happen, that offset points out of our data-area. * In this case is xlen < 0 and we ignore it. */ if (xlen > 0) { memcpy(f->data + offset + ihl, packet + ihl, xlen ); /* This is for the caller; how much was * fetched AND COPIED for her. */ f->userLen += xlen; } /* We even count the not copied data! */ f->len += ntohs(ip->tot_len) - ihl; /* OK, we received the last fragment with this id, so calculate * how the original size of this packet was */ if ((ntohs(ip->frag_off) != 0 && (ntohs(ip->frag_off) & IP_MF) == 0)) { f->origLen = ntohs(ip->tot_len) + offset - ihl; } /* In case we reached the original len -> all fragments * are received and assembled. * NOTE that f->len counts the # of bytes _received_, not saved! * The # of saved bytes is in f->userLen. */ if (f->len == f->origLen) { /* should not be necessary, but */ if (i >= 0 && i < pending.size()) pending[i] = NULL; struct usipp::iphdr *ih = (struct usipp::iphdr*)(f->data); ih->frag_off = 0; ih->tot_len = htons(ihl + f->len); *resultLen = ihl + f->userLen; /* packet must at least be 'len+ihl' bytes big, * where 'ihl' is max. 60. */ memset(packet, 0, len+ihl); memcpy(packet, f->data, len+ihl); delete [] f->data; delete f; return packet; } else { *resultLen = 0; return NULL; } /* else, packet is not fragmented */ } else { *resultLen = ntohs(ip->tot_len); /* return IP-packet, hw-frame skipped */ return packet; }} } // namespace usipp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -