// -*-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 <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
#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<const u_int8_t *> (data);
if (reinterpret_cast<u_long> (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<const u_int16_t *> (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 <pcap.h>
}
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<sockaddr_in> &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<str> *ifs, in_addr a);
static bool ifaddrs (vec<in_addr> *addrs, str ifname);
};
template<class T, bool dup> struct synfp_state {
struct synfp_entry {
const sockaddr_in sin;
T val;
ihash_entry<synfp_entry> hlink;
tailq_entry<synfp_entry> tlink;
synfp_entry (const sockaddr_in &sin, const T &val)
: sin (sin), val (val) {}
};
u_int size;
ihash<const sockaddr_in, synfp_entry, &synfp_entry::synfp_entry::sin,
&synfp_entry::synfp_entry::hlink> tab;
tailq<synfp_entry, &synfp_state::synfp_entry::tlink> 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<tcbs, true>::synfp_entry cbentry_t;
typedef synfp_state<str, false>::synfp_entry fpentry_t;
vec<ref<synfp> > pfv;
synfp_state<str, false> fps;
synfp_state<tcbs, true> 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<sockaddr_in> &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<void, icmp_info *>::ref cb_t;
class icmpclnt {
friend class icmpsock;
const cb_t cb;
protected:
icmpclnt (ref<icmpsock> is, in_addr a, cb_t cb);
~icmpclnt ();
public:
const ref<icmpsock> is;
const in_addr addr;
ihash_entry<icmpclnt> 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<const in_addr, icmpclnt, &icmpsock::icmpclnt::addr,
&icmpsock::icmpclnt::hlink> 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<icmpclnt> setcb (in_addr a, cb_t cb)
{ return New refcounted<icmpclnt> (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<void, int, in_addr *, int>::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<zin_addr> hops;
bitvec xmit_ttls;
bitvec oxmit_ttls;
vec<u_int16_t> ids;
int xmit_count;
vec<cb_t, 1> cbvec;
ref<icmpsock::icmpclnt> 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<icmpsock> 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<void, int, in_addr *, int>::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_ */
syntax highlighted by Code2HTML, v. 0.9.1