// -*-c++-*- /* $Id: rawnet.h,v 1.15 2005/10/19 21:38:06 dm Exp $ */ /* * * Copyright (C) 2004 David Mazieres (dm@uun.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #ifndef _RAWNET_H_ #define _RAWNET_H_ 1 #include "async.h" #include "qhash.h" #include "list.h" #include "bitvec.h" #define __FAVOR_BSD 1 #include #include #include #include #ifndef PLANET_LAB # define PLANET_LAB 0 #endif /* PLANET_LAB */ inline u_int16_t cksum (const void *data, size_t len, u_int32_t sum = 0, bool flip = false) { const u_int8_t *dp = static_cast (data); if (reinterpret_cast (dp) & 1) sum += ntohs (*dp) + cksum (dp + 1, len - 1, 0, true); else { for (const u_int8_t *ep = dp + (len & ~1); dp < ep; dp += sizeof (u_int16_t)) sum += *reinterpret_cast (dp); if (len & 1) sum += ntohs (*dp << 8); } while (sum > 0xffff) sum = (sum & 0xffff) + (sum >> 16); return flip ? (sum >> 8) | ((sum & 0xff) << 8) : sum; } /* synfp.C */ #if USE_SYNFP extern "C" { #include } struct synfp { pcap_t *pch; int hdrlen; int fd; synfp (); ~synfp (); bool setfilter (str dev, str filter); bool init (str dev, in_addr addr, int port); bool init (str dev, const vec &addrs); void close (); int getfp (str *fp, sockaddr_in *sinp, sockaddr_in *dsinp = NULL); bool sethdrlen (const u_char *ip, const u_char *end); static bool pktok (const u_char *ip, const u_char *end); static bool ifnames (vec *ifs, in_addr a); static bool ifaddrs (vec *addrs, str ifname); }; template struct synfp_state { struct synfp_entry { const sockaddr_in sin; T val; ihash_entry hlink; tailq_entry tlink; synfp_entry (const sockaddr_in &sin, const T &val) : sin (sin), val (val) {} }; u_int size; ihash tab; tailq lru; void insert (const sockaddr_in &addr, const T &val) { synfp_entry *se = dup ? NULL : tab[addr]; if (se) { lru.remove (se); se->val = val; } else { se = New synfp_entry (addr, val); tab.insert (se); size++; } lru.insert_tail (se); } void dealloc (synfp_entry *se) { lru.remove (se); tab.remove (se); delete se; size--; } synfp_state () : size (0) {} ~synfp_state () { tab.deleteall (); } }; class synfp_collect { struct tcbs { timespec ts; cbs cb; tcbs (cbs cb) : ts (tsnow), cb (cb) {} }; typedef synfp_state::synfp_entry cbentry_t; typedef synfp_state::synfp_entry fpentry_t; vec > pfv; synfp_state fps; synfp_state cbs; timecb_t *tmo; fd_set *fds; void input (int i); void service (); void timeout (); public: timespec delay; const u_int bufsize; synfp_collect (u_int msec, u_int bufsize); ~synfp_collect (); bool init (const sockaddr_in &sin); bool init (const vec &av); void lookup (const sockaddr_in &sin, ::cbs cb); str lookup (const sockaddr_in &sin); }; void synfp_test (int argc, char **argv); #endif /* USE_SYNFP */ /* netpath.C */ class icmpsock : public virtual refcount { public: struct icmp_info { struct ip *pkthdrp; int type; int code; struct icmp *icmpp; struct ip *iphp; struct udphdr *udphp; }; typedef callback::ref cb_t; class icmpclnt { friend class icmpsock; const cb_t cb; protected: icmpclnt (ref is, in_addr a, cb_t cb); ~icmpclnt (); public: const ref is; const in_addr addr; ihash_entry hlink; }; friend class icmpclnt; private: struct outpkt { struct ip iph; struct udphdr udph; char payload[64]; }; union inpkt { struct ip iph; char data[512]; }; int icmpfd; int udpfd; sockaddr_in fromaddr; ihash cbtab; static bool icmp_parse (icmp_info *infop, inpkt *inp, int size); void rcb (); void closefds (); void portalloc (); public: int ipfd; icmpsock () : icmpfd (-1), udpfd (-1), ipfd (-1) {} ~icmpsock () { closefds (); } bool init (const sockaddr_in *fromaddr); #if PLANET_LAB bool init_plab (const sockaddr_in *fromaddr); #else /* !PLANET_LAB */ bool init_plab (const sockaddr_in *fromaddr) { return false; } #endif /* !PLANET_LAB */ void sendpkt (const sockaddr_in *sinp, u_int ttl, u_int16_t datasize, u_int16_t id = 0, u_int16_t cksum = 0, const sockaddr_in *fromp = NULL); ref setcb (in_addr a, cb_t cb) { return New refcounted (mkref (this), a, cb); } }; struct traceroute { enum { baseport = 33434 }; enum { maxhops = 64 }; enum { maxprobes = 5 }; /* cb (int total_hops, in_addr *addresses, int addresses_size) */ typedef callback::ref cb_t; private: struct zin_addr : in_addr { zin_addr () { s_addr = 0; } }; sockaddr_in dest; sockaddr_in src; bool use_dstport; bool use_src; int hops_req; // Signed request argument int hops_max; // highest hop number seen int hops_total; // confirmed last hop (by ICMP_UNREACH) or -1 int hops_found; vec hops; bitvec xmit_ttls; bitvec oxmit_ttls; vec ids; int xmit_count; vec cbvec; ref ic; int ntmo; int tmo_lastfound; timecb_t *tmo; #if NETPATH_VERBOSE strbuf verbose; #endif /* NETPATH_VERBOSE */ void probe (u_int8_t ttl); inline bool shouldprobe (int prio, int ttl); void proberange (int start, int low, int high); void timeout (); void xmit (); void rcb (icmpsock::icmp_info *ii); void finish (); void getpkt (int hops, in_addr addr, bool last); public: traceroute (ref s, const sockaddr_in *dest, int nhops, cb_t cb, const sockaddr_in *src = NULL); ~traceroute (); void addcb (cb_t cb) { cbvec.push_back (cb); } void fail (); }; /* (*cb) (int total_hops, in_addr *addresses, int addresses_size) */ typedef callback::ref netpathcb_t; /* hops = 0 => full path * hops < 0 => distance from destination * hops > 0 => distance from source */ traceroute *netpath (const sockaddr_in *dest, int hops, netpathcb_t, const sockaddr_in *srcp = NULL); void netpath_addcb (traceroute *trp, netpathcb_t cb); void netpath_cancel (traceroute *trp); void netpath_reset (); void netpath_test (int argc, char **argv); /* osguess.C */ const char *synos_guess (str synfp); #endif /* !_RAWNET_H_ */