/* // Copyright (c) 2001,2002 RIPE NCC // // All Rights Reserved // // Permission to use, copy, modify, and distribute this software and its // documentation for any purpose and without fee is hereby granted, // provided that the above copyright notice appear in all copies and that // both that copyright notice and this permission notice appear in // supporting documentation, and that the name of the author not be // used in advertising or publicity pertaining to distribution of the // software without specific, written prior permission. // // THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING // ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL // AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY // DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // $Id: netraw.cc,v 4.9 2002/04/09 11:48:47 katie Exp $ // // Copyright (c) 1994 by the University of Southern California // All rights reserved. // // Permission to use, copy, modify, and distribute this software and its // documentation in source and binary forms for lawful non-commercial // purposes and without fee is hereby granted, provided that the above // copyright notice appear in all copies and that both the copyright // notice and this permission notice appear in supporting documentation, // and that any documentation, advertising materials, and other materials // related to such distribution and use acknowledge that the software was // developed by the University of Southern California, Information // Sciences Institute. The name of the USC may not be used to endorse or // promote products derived from this software without specific prior // written permission. // // THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY // REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY // PURPOSE. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, // TITLE, AND NON-INFRINGEMENT. // // IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT, TORT, // OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH, THE USE // OR PERFORMANCE OF THIS SOFTWARE. // // Questions concerning this software should be directed to // ratoolset@isi.edu. // // Author(s): eddy@isi.edu */ #include "config.h" #include "netraw.hh" //////////////////////////////////////////////////////////////////////// rawIP::rawIP (char *remote, int protocol) : rawPacket () { extern char *progname; struct ifaddrlist *al; char errbuf[132]; // cause traceroute.c uses 132... int n; if (error()) return; ip_hdr = (struct ip *) packet_data; /* Get the interface address list */ n = ifaddrlist(&al, errbuf); if (n < 0) { ::fprintf(stderr, "%s: ifaddrlist: %s\n", progname, errbuf); exit(1); } if (n == 0) { ::fprintf(stderr, "%s: Can't find any network interfaces\n", progname); exit(1); } // this error handling bites. src_ipaddr = new ipAddr (al->addr); if (src_ipaddr->error()) { error = src_ipaddr->error; // XXX: test this return; } dst_ipaddr = new ipAddr (remote); if (dst_ipaddr->error()) { error = dst_ipaddr->error; // XXX: test this return; } struct in_addr in; #ifdef STRUCT_IP_USES_VHL ip_hdr->ip_vhl = (4 << 4) + 5; #else // STRUCT_IP_USES_VHL ip_hdr->ip_v = 4; ip_hdr->ip_hl = 5; #endif // STRUCT_IP_USES_VHL ip_hdr->ip_len = 20; ip_hdr->ip_tos = 0; ip_hdr->ip_id = 0; ip_hdr->ip_off = 0; ip_hdr->ip_ttl = MAXTTL; ip_hdr->ip_p = protocol; ip_hdr->ip_sum = 0; ip_hdr->ip_src.s_addr = src_ipaddr->getInaddr(); ip_hdr->ip_dst.s_addr = dst_ipaddr->getInaddr(); set_srcInaddr (src_ipaddr->getInaddr()); set_dstInaddr (dst_ipaddr->getInaddr()); ip_size = sizeof (struct ip); packet_size += ip_size; ip_data = ip_hdr + 1; ip_opts = NULL; optflags = 0; optlen = 0; } rawIP::rawIP (int protocol) : rawPacket (protocol) { ip_hdr = (struct ip *) packet_data; ip_data = ip_hdr + 1; ip_opts = NULL; // remain NULL unless they are used ip_size = sizeof (struct ip); packet_size += ip_size; } // when adding LSRR, the first node of the source_routes goes // into the IP dst field and the dst goes into the last position // of the source route list. also the dst of the Socket class // must be changed to the first hop of the source list. // NOTE: i stole this from VJ's traceroute. int rawIP::addLSRR (int nroutes, ipAddr **source_routes) { char ipopts[MAX_IPOPTLEN], *ptr = (char *) &ipopts; int size = sizeof (u_long); optlen = IPOPT_MINOFF-1 + ((nroutes + 1) * size); bzero ((char *) &ipopts, sizeof (ipopts)); optflags |= IPOPT_LSRR; *ptr++ = IPOPT_LSRR; *ptr++ = optlen; *ptr++ = IPOPT_MINOFF; // pointer to LSRR addresses u_long hex = (u_long) source_routes[0]->getInaddr(); bcopy ((char *) &hex, ptr, size); for (int i = 1; i < nroutes; i++, ptr += size) { hex = source_routes[i]->getInaddr(); bcopy ((char *) &hex, ptr, size); } ptr += size; hex = dst_ipaddr->getInaddr(); bcopy ((char *) &hex, ptr, size); optlen += 4 - (optlen % 4); while ((ptr - ipopts) & 3) ptr++; // pad to even boundry packet_size = ip_hdr->ip_len; setsockopt (IPPROTO_IP, IP_OPTIONS, (char *) &ipopts, optlen); return error(); } // XXX add error int rawIP::wait_for_reply (int timeout = 0) { int cc = rawPacket::wait_for_reply (timeout); if (!error()) { src_ipaddr = new ipAddr (ip_hdr->ip_src.s_addr); dst_ipaddr = new ipAddr (ip_hdr->ip_dst.s_addr); } return cc; } #define phdr(ppp, fld, val) printf ("%10s - %s: 0x%x\n", ppp, fld, val) #define phdrd(ppp, fld, val) printf ("%10s - %s: 0x%x == %d\n", ppp, fld, val, val) void rawIP::print () { #define pip(fld, val) phdr("IP", fld, val) #define pipd(fld,val) phdrd("IP", fld, val) #ifdef STRUCT_IP_USES_VHL pip ("Version", ip_hdr->ip_vhl & 0xF0); pip ("Hdr Len", ip_hdr->ip_vhl & 0xF); #else // STRUCT_IP_USES_VHL pip ("Version", ip_hdr->ip_v); pip ("Hdr Len", ip_hdr->ip_hl); #endif // STRUCT_IP_USES_VHL pipd("Length", ip_hdr->ip_len); pipd("TOS", ip_hdr->ip_tos); pip ("ID", ip_hdr->ip_id); pip ("Offset", ip_hdr->ip_off); pipd("TTL", ip_hdr->ip_ttl); pipd("Proto", ip_hdr->ip_p); pip ("Cksum", ip_hdr->ip_sum); pip ("Source", ip_hdr->ip_src.s_addr); pip ("Dest", ip_hdr->ip_dst.s_addr); } //////////////////////////////////////////////////////////////////////// void rawUDP::init_udp (int sport = -1, int dport = -1) { if (error()) return; udp_hdr = (struct udphdr *) ip_data; udp_size = sizeof (struct udphdr); udp_data = udp_hdr + 1; packet_size += udp_size; udp_hdr->uh_sport = htons(sport); udp_hdr->uh_dport = htons(dport); udp_hdr->uh_ulen = htons(sizeof (struct udphdr)); udp_hdr->uh_sum = 0; // now retrofit some ip stuff, not great oo practice, but hey, // were nethacks!!! B-) ip_hdr->ip_p = IPPROTO_UDP; ip_hdr->ip_len += udp_size; packet_size = ip_hdr->ip_len; } void rawUDP::print () { #define pudp(fld, val) phdr ("UDP", fld, val) #define pudpd(fld, val) phdrd("UDP", fld, val) rawIP::print(); pudpd("Source port", udp_hdr->uh_sport); pudpd("Dest port", udp_hdr->uh_dport); pudpd("Len", udp_hdr->uh_ulen); pudp ("Cksum", udp_hdr->uh_sum); } //////////////////////////////////////////////////////////////////////// ICMP::ICMP () : rawIP (IPPROTO_ICMP) { if (error()) return; icmp_hdr = (struct icmp *) ip_data; icmp_dat = ip_hdr + 1; icmp_size = 0; } void ICMP::icmp_print () { #define picmp(fld, val) phdr("ICMP", fld, val); #define picmpd(fld, val) phdrd("ICMP", fld, val); //rawIP::print(); picmpd ("Type", icmp_hdr->icmp_type); picmpd ("Code", icmp_hdr->icmp_code); picmp ("Cksum", icmp_hdr->icmp_cksum); // now do packet specific stuff } char * ICMP::icmp_type_string () { char *str = "???"; switch (icmp_hdr->icmp_type) { case ICMP_ECHOREPLY: return (str = "Echo Reply"); case ICMP_UNREACH: return (str = "Destination unreachable"); case ICMP_SOURCEQUENCH: return (str = "Source quench"); case ICMP_REDIRECT: return (str = "Redirect"); case ICMP_ECHO: return (str = "Echo"); case ICMP_TIMXCEED: return (str = "Time exceeded"); case ICMP_PARAMPROB: return (str = "Bad IP header"); case ICMP_TSTAMP: return (str = "Time stamp request"); case ICMP_TSTAMPREPLY: return (str = "Time stamp reply"); case ICMP_IREQ: return (str = "Information Request"); case ICMP_IREQREPLY: return (str = "Information Reply"); case ICMP_MASKREQ: return (str = "Mask request"); case ICMP_MASKREPLY: return (str = "Mask reply"); default: return (str = "Unknown type"); } return str; } char * ICMP::icmp_code_string () { return ("not yet"); }