Logo Search packages:      
Sourcecode: mailavenger version File versions  Download package

rawnet.h

// -*-c++-*-
/* $Id$ */

/*
 *
 * 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_ */


Generated by  Doxygen 1.6.0   Back to index