/*** 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. If not, *** you can get it at http://www.cs.uni-potsdam.de/homepages/students/linuxer *** the logit-package. You will also find some other nice utillities there. *** *** 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++/icmp.h" #include "usi++/ip.h" #include #include #include namespace usipp { ICMP::ICMP(const char* host) #ifndef IPPROTO_ICMP #define IPPROTO_ICMP 1 #endif : IP(host, IPPROTO_ICMP) { // clear memory memset(&icmphdr, 0, sizeof(icmphdr)); } ICMP::ICMP(u_int32_t dst) : IP(dst, IPPROTO_ICMP) { memset(&icmphdr, 0, sizeof(icmphdr)); } ICMP::~ICMP() { } ICMP::ICMP(const ICMP &rhs) : IP(rhs) { if (this == &rhs) return; this->icmphdr = rhs.icmphdr; } ICMP &ICMP::operator=(const ICMP &rhs) { if (this == &rhs) return *this; IP::operator=(rhs); this->icmphdr = rhs.icmphdr; return *this; } ICMP &ICMP::operator=(const IP &rhs) { iphdr iph; if (this == &rhs) return *this; IP::operator=(rhs); iph = IP::get_iphdr(); icmphdr = *(struct icmphdr *)((char *)&iph + IP::get_hlen() * 4); return *this; } /* Set the type-field in the actuall ICMP-packet. */ int ICMP::set_type(u_int8_t t) { icmphdr.type = t; return 0; } /*! Get the type-field from the actuall ICMP-packet. */ u_int8_t ICMP::get_type() { return icmphdr.type; } /* Set ICMP-code. */ int ICMP::set_code(u_int8_t c) { icmphdr.code = c; return 0; } /* Get ICMP-code. */ u_int8_t ICMP::get_code() { return icmphdr.code; } int ICMP::set_gateway(u_int32_t g) { icmphdr.un.gateway = htonl(g); return 0; } u_int32_t ICMP::get_gateway() { return ntohl(icmphdr.un.gateway); } int ICMP::set_mtu(u_int16_t mtu) { icmphdr.un.frag.mtu = mtu; return 0; } u_int16_t ICMP::get_mtu() { return icmphdr.un.frag.mtu; } /* Set id field in the actuall ICMP-packet */ int ICMP::set_icmpId(u_int16_t id) { icmphdr.un.echo.id = id; return 0; } /* Get the id field from actuall ICMP-packet. */ u_int16_t ICMP::get_icmpId() { return icmphdr.un.echo.id; } /* Set the sequecenumber of the actuall ICMP-packet. */ int ICMP::set_seq(u_int16_t s) { icmphdr.un.echo.sequence = s; return 0; } /* Get the sequence-number of actuall ICMP-packet */ u_int16_t ICMP::get_seq() { return icmphdr.un.echo.sequence; } /* get orig datagram from icmp unreachable * */ iphdr ICMP::get_orig() { iphdr iph = *(iphdr *)((char *)(&icmphdr + 1)); return iph; } /* send an ICMP-packet containing 'payload' which * is 'paylen' bytes long */ int ICMP::sendpack(void *payload, size_t paylen) { size_t len = sizeof(struct icmphdr) + paylen; // the packetlenght struct icmphdr *i; // s will be our packet char *s = new char[len]; memset(s, 0, len); // copy ICMP header to packet memcpy((char*)s, (struct icmphdr*)&this->icmphdr, sizeof(icmphdr)); if (payload) memcpy(s+sizeof(icmphdr), payload, paylen); i = (struct icmphdr*)s; // calc checksum over packet //i->sum = 0; if (i->sum == 0) i->sum = in_cksum((unsigned short*)s, len, 0); int r = IP::sendpack(s, len); delete[] s; return r; } /* send a ICMP-packet with string 'payload' as payload. */ int ICMP::sendpack(char *payload) { return sendpack(payload, strlen(payload)); } /* send standard UNIX-like ICMP echo request payload */ int ICMP::send_ping_payload() { struct _Timestamp { u_int sec; u_int usec; } Timestamp; struct timeval tv; int tocopy, iii=0; char payload[PING_PAYLOAD_SIZE]; if ((gettimeofday(&tv, NULL)) < 0) die ("ICMP::send_ping_payload: gettimeofday()", PERROR, 1); Timestamp.sec = htonl(tv.tv_sec); Timestamp.usec = htonl(tv.tv_usec); tocopy = PING_PAYLOAD_SIZE; while (tocopy > 0) { payload[iii] = iii; tocopy--; iii++; } memcpy (payload, &Timestamp, sizeof(Timestamp)); return sendpack(payload, PING_PAYLOAD_SIZE); } int ICMP::send_timestamp_payload() { struct timeval tv; char payload[TIMESTAMP_PAYLOAD_SIZE]; if ((gettimeofday(&tv, NULL)) < 0) die("ICMP::send_timestamp_payload: gettimeofday()", PERROR, 1); memset (payload, 0, TIMESTAMP_PAYLOAD_SIZE); tv.tv_usec = htonl(tv.tv_usec); memcpy(payload, &tv.tv_usec, sizeof(tv.tv_usec)); return sendpack(payload, TIMESTAMP_PAYLOAD_SIZE); } int ICMP::send_addrmask_payload() { char payload[ADDRMASK_PAYLOAD_SIZE]; memset (payload, 0, ADDRMASK_PAYLOAD_SIZE); return sendpack(payload, ADDRMASK_PAYLOAD_SIZE); } /* handle packets, that are NOT actually for the * local adress! */ int ICMP::sniffpack(void *s, size_t len) { size_t plen = len + sizeof(struct icmphdr); char *tmp = new char[plen]; int r = 0; memset(s, 0, len); memset(tmp, 0, plen); r = IP::sniffpack(tmp, plen); if (r == 0 && Layer2::timeout()) { // timeout delete[] tmp; return 0; } // point to ICMP header struct icmphdr *icmph = (struct icmphdr*)(tmp); memset(&icmphdr, 0, sizeof(icmphdr)); // save ICMP header for public functions memcpy(&icmphdr, icmph, sizeof(struct icmphdr)); // and give user the payload if (s) memcpy(s, ++icmph, len); delete[] tmp; return r - sizeof(struct icmphdr); } /* 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 ICMP::init_device(char *dev, int promisc, size_t snaplen) { int r = Layer2::init_device(dev, promisc, snaplen); if (r < 0) die("ICMP::init_device", STDERR, 1); r = Layer2::setfilter("icmp"); if (r < 0) die("ICMP::init_device", STDERR, 1); return r; } } // namespace usipp