Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Please Compile

Status
Not open for further replies.

JackSkellington

Technical User
Jul 28, 2005
86
0
0
GB
Currently away from a Linux box could someone plase try and compile this for me.

[/code] /*
* Proof Of Concept : counting host behind a NAT using timestamp
* To compile this file, you will need the libpcap
* Copyright Elie Bursztein (lupin@zonart.net)
* Successfully compiled on FreeBSD 5.X and Linux 2.6.X
*
* $gcc natcount.c -o natcount -I/usr/local/include -L/usr/local/lib
* -lpcap
*/

#define __USE_BSD 1

#include <sys/time.h>
#include <time.h>
#include <netinet/in.h>
#include <net/ethernet.h>
#ifdef __FreeBSD__
# include <netinet/in_systm.h>
#endif /* __FreeBSD__ */
#ifdef __linux__
# include <linux/if_ether.h>
#endif /* __linux__ */

#include <netinet/ip.h>
#include <stdlib.h>
#include <string.h>
#include <pcap.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>

#ifdef __linux__
# define th_off doff
#endif /* __linux__ */

u_int32_t addr = 0;

/* chain lists structures */
typedef struct listes_s {
struct listes_s *next;
void *elt;
} listes_t;

/* Structures for TCP options */
typedef struct { u_int32_t ts, ts_r; } timestamp_t;
typedef struct { timestamp_t *ts; } tcp_opt_t;

/* Structures for datas storage */
typedef struct { u_int32_t from, first_timestamp; struct timeval
first_seen; } machine_t;
typedef struct { u_int32_t host, nat; struct timeval first_seen; }
nat_box_t;

#define TIMESTAMP_ERROR_MARGIN 0.5
#define DELAY 1

/*
* List functions
*/
int add_in_list(listes_t **list, void * elt) {
listes_t *lst;
lst = malloc(sizeof (listes_t));
lst->next = *list;
lst->elt = elt;
*list = lst;
return (1);
}

void show_nated(listes_t *list) {
nat_box_t *nat;
struct in_addr addr;

printf("-- Begin of nated IP list --\n");
while (list)
{
nat = (nat_box_t *) list->elt;
if (nat->nat > 1) {
addr.s_addr = nat->host;
printf("I've guess %i computers sharing the same IP address
(%s)\n", nat->nat, inet_ntoa(addr));
}
list = list->next;
}
printf("-- End of nated IP list --\n");
}

/*
* Function used to get all TCP options
* Simple TCP options parser
*/
int tcp_option_parser(const u_char *options,
tcp_opt_t *parsed,
unsigned int size) {
u_int8_t kind, len, i;

bzero(parsed, sizeof(tcp_opt_t));
i = 0;
kind = *(options + i);
while (kind != 0) /* EO */
{
switch (kind) {
case 1: i++; break; /* NOP byte */
case 2: i += 4; break;
case 3: i += 3; break;
case 4: i += 2; break;
case 5: /* skipping SACK options */
len = (*options + ++i) - 1;
i += len;
break;
case 6: i += 6; break;
case 7: i += 6; break;
case 8:
i += 2;
parsed->ts = (timestamp_t *) (options + i);
i += 8;
return (1);
break;
default:
i++;
}
kind = *(options + i);
}
return (0);
}

/*
* Most interesting function ... Here we can know if a TCP packet is
* coming from someone we already know !
* Algo :
* finc (seconds) = current_packet_time - first_packet_time <- time
* between 2 packets
* ts_inc = inc_table * finc <- our supposed timestamp increment
* between 2 packets
* new_ts = first_timestamp + ts_inc <- new = timestamp we should have
* now !
*
* Now we just have to compare new_ts with current timestamp
* We can authorize an error margin of 0.5%
*
* Our inc_table contain timestamp increment per second for most
* Operating System
*/
int already_seen(machine_t *mach, tcp_opt_t *opt,
struct timeval temps)
{
int inc_table[4] = {2, 10, 100, 1000};
unsigned int new_ts;
float finc, tmp, ts_inc;
int i, diff;

finc = ((temps.tv_sec - mach->first_seen.tv_sec) * 1000000.
+ (temps.tv_usec - mach->first_seen.tv_usec)) / 1000000.;
for (i = 0; i < 4; i++) {
ts_inc = inc_table * finc;
new_ts = ts_inc + mach->first_timestamp;
diff = ntohl(opt->ts->ts) - new_ts;
if (diff == 0) { /* Perfect shoot ! */
return (2);
}
tmp = 100. - (new_ts * 100. / ntohl(opt->ts->ts));
if (tmp < 0.)
tmp *= -1.;
if (tmp <= TIMESTAMP_ERROR_MARGIN) { /* Update timestamp and time */
mach->first_seen = temps;
mach->first_timestamp = ntohl(opt->ts->ts);
return (1);
}
}
return (0);
}


/*
* Simple function to check if an IP address is already in our list
* If not, it's only a new connection
*/
int is_in_list(listes_t *lst, u_int32_t addr) {
machine_t *mach;

while (lst) {
mach = (machine_t *) lst->elt;
if (mach->from == addr)
return (1);
lst = lst->next;
}
return (0);
}

/*
* This function should be call if a packet from an IP address have been
* found,
* is address is already in the list, but doesn't match any timestamp
* value
*/
int update_nat(listes_t *list, u_int32_t addr)
{
nat_box_t *box;

while (list)
{
box = (nat_box_t *) list->elt;
if (box->host == addr)
{
box->nat++;
return (1);
}
list = list->next;
}
return (0);
}

int check_host(listes_t **list, listes_t **nat, u_int32_t
from,
tcp_opt_t *opt, struct timeval temps) {
listes_t *lst;
machine_t *mach;
int found, zaped;

found = zaped = 0;

lst = *list;
while (lst && !(found)) {
mach = (machine_t *) lst->elt;
if (mach->from == from) {
if ( temps.tv_sec - mach->first_seen.tv_sec > DELAY ) {
found = already_seen(mach, opt, temps);
} else zaped = 1;
}
lst = lst->next;
}
if (!(zaped) && !(found)) {
mach = malloc(sizeof (machine_t));
mach->from = from;
mach->first_seen = temps;
mach->first_timestamp = ntohl(opt->ts->ts);
add_in_list(list, mach);
update_nat(*nat, from);
show_nated(*nat);
return (1);
}
return (0);
}


void callback_sniffer(u_char *useless,
const struct pcap_pkthdr* pkthdr,
const u_char *packet)
{
static listes_t *list_machines = 0;
static listes_t *list_nat = 0;
const struct ip *ip_h;
const struct tcphdr *tcp_h;
tcp_opt_t tcp_opt;
machine_t *mach;
nat_box_t *nat;
struct in_addr my_addr;

ip_h = (struct ip *) (packet + sizeof(struct ether_header));
if (ip_h->ip_p == IPPROTO_TCP)
{
tcp_h = (struct tcphdr *) (packet + sizeof(struct ether_header) +
sizeof(struct ip));
if (tcp_h->th_off * 4 > 20) {
if (tcp_option_parser((u_char *) (packet + sizeof(struct
ether_header)
+ sizeof(struct ip) +
sizeof(struct tcphdr)),
&tcp_opt, tcp_h->th_off * 4 - 20))
{
if (is_in_list(list_machines, (ip_h->ip_src).s_addr)) {
check_host(&list_machines, &list_nat, (u_int32_t)
(ip_h->ip_src).s_addr, &tcp_opt, pkthdr->ts);
} else {
if (ntohl(tcp_opt.ts->ts) != 0)
{
addr = (ip_h->ip_src).s_addr;
my_addr.s_addr = addr;
mach = malloc(sizeof (machine_t));
mach->from = (ip_h->ip_src).s_addr;
mach->first_seen = pkthdr->ts;
mach->first_timestamp = ntohl(tcp_opt.ts->ts);
nat = malloc(sizeof (nat_box_t));
nat->host = (u_int32_t) (ip_h->ip_src).s_addr;
nat->nat = 1;
nat->first_seen = mach->first_seen;
add_in_list(&list_machines, mach);
add_in_list(&list_nat, nat);
}
}
}
}
}
}


int main(int ac, char *argv[])
{
pcap_t *sniff;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
char *device;
bpf_u_int32 maskp, netp;
struct in_addr my_ip_addr;
char filter[250];

if (getuid() != 0) {
printf("You must be root to use this tool.\n");
exit (2);
}
if (--ac != 1)
{
printf("Usage: ./natcount xl0\n");
return (1);
}
device = (++argv)[0];
pcap_lookupnet(device, &netp, &maskp, errbuf);
my_ip_addr.s_addr = (u_int32_t) netp;
printf("Using interface %s IP : %s\n", device, inet_ntoa(my_ip_addr));
if ((sniff = pcap_open_live(device, BUFSIZ, 1, 1000, errbuf)) == NULL)
{
printf("ERR: %s\n", errbuf);
exit(1);
}
bzero(filter, 250);
snprintf(filter, 250, "not src net %s", inet_ntoa(my_ip_addr));
if(pcap_compile(sniff,&fp, filter, 0, netp) == -1) {
fprintf(stderr,"Error calling pcap_compile\n");
exit(1);
}
if(pcap_setfilter(sniff,&fp) == -1) {
fprintf(stderr,"Error setting filter\n");
exit(1);
}
pcap_loop(sniff, -1, callback_sniffer, NULL);
return (0);
}
Code:
 
sorry

Code:
/*
   * Proof Of Concept : counting host behind a NAT using timestamp
   * To compile this file, you will need the libpcap
   * Copyright Elie Bursztein (lupin@zonart.net)
   * Successfully compiled on FreeBSD 5.X and Linux 2.6.X
   *
   * $gcc natcount.c -o natcount -I/usr/local/include -L/usr/local/lib
   * -lpcap
   */
  
  #define __USE_BSD 1
  
  #include <sys/time.h>
  #include <time.h>
  #include <netinet/in.h>
  #include <net/ethernet.h>
  #ifdef __FreeBSD__
  # include <netinet/in_systm.h>
  #endif /* __FreeBSD__ */
  #ifdef __linux__
  # include <linux/if_ether.h>
  #endif /* __linux__ */
  
  #include <netinet/ip.h>
  #include <stdlib.h>
  #include <string.h>
  #include <pcap.h>
  #include <sys/socket.h>
  #include <netinet/in.h>
  #include <netinet/ip.h>
  #include <net/if.h>
  #include <netinet/tcp.h>
  #include <netinet/udp.h>
  
  #ifdef __linux__
  # define th_off doff
  #endif /* __linux__ */
  
  u_int32_t       addr = 0;
  
  /* chain lists structures */
  typedef struct listes_s {
    struct listes_s *next;
    void  *elt;
  } listes_t;
  
  /* Structures for TCP options */
  typedef struct { u_int32_t ts, ts_r; } timestamp_t;
  typedef struct { timestamp_t *ts; } tcp_opt_t;
  
  /* Structures for datas storage */
  typedef struct { u_int32_t from, first_timestamp; struct timeval
first_seen; } machine_t;
  typedef struct { u_int32_t host, nat; struct timeval first_seen; }
nat_box_t;
  
  #define TIMESTAMP_ERROR_MARGIN  0.5
  #define DELAY                   1
  
  /*
   * List functions
   */
  int     add_in_list(listes_t **list, void * elt) {
    listes_t *lst;
    lst = malloc(sizeof (listes_t));
    lst->next = *list;
    lst->elt = elt;
    *list = lst;
    return (1);
  }
  
  void            show_nated(listes_t *list) {
    nat_box_t     *nat;
    struct in_addr addr;
    
    printf("-- Begin of nated IP list --\n");
    while (list)
      {
         nat = (nat_box_t *) list->elt;
        if (nat->nat > 1) {
         addr.s_addr = nat->host;
         printf("I've guess %i computers sharing the same IP address
(%s)\n", nat->nat, inet_ntoa(addr));
        }
        list = list->next;
      }
    printf("-- End of nated IP list --\n");
  }
  
  /* 
   * Function used to get all TCP options
   * Simple TCP options parser
   */
  int             tcp_option_parser(const u_char *options,
                                    tcp_opt_t *parsed, 
                                    unsigned int size) {
    u_int8_t       kind, len, i;
    
    bzero(parsed, sizeof(tcp_opt_t));
    i = 0; 
    kind = *(options + i);
    while (kind != 0) /* EO */
      {
        switch (kind) {
        case 1: i++; break; /* NOP byte */
        case 2: i += 4; break;
        case 3: i += 3; break;
        case 4: i += 2; break;
        case 5: /* skipping SACK options */
          len = (*options + ++i) - 1;
          i += len;
          break;
        case 6: i += 6; break;
        case 7: i += 6; break;
        case 8:
          i += 2;
          parsed->ts = (timestamp_t *) (options + i);
          i += 8;
          return (1);
          break;
        default:
          i++;
        }
        kind = *(options + i);
      }
    return (0);
  }
  
  /*
   * Most interesting function ... Here we can know if a TCP packet is
   * coming from someone we already know !
   * Algo :
   * finc (seconds) = current_packet_time - first_packet_time <- time
   * between 2 packets
   * ts_inc = inc_table[i] * finc <- our supposed timestamp increment
   * between 2 packets
   * new_ts = first_timestamp + ts_inc <- new = timestamp we should have
   * now !
   *
   *  Now we just have to compare new_ts with current timestamp
   *  We can authorize an error margin of 0.5%
   *
   * Our inc_table contain timestamp increment per second for most
   * Operating System
   */
  int                     already_seen(machine_t *mach, tcp_opt_t *opt,
struct timeval temps)
  {
    int                   inc_table[4] = {2, 10, 100, 1000};
    unsigned int          new_ts;
    float                 finc, tmp, ts_inc;
    int                   i, diff;
  
    finc = ((temps.tv_sec - mach->first_seen.tv_sec) * 1000000.
  + (temps.tv_usec - mach->first_seen.tv_usec)) / 1000000.;
    for (i = 0; i < 4; i++) {
      ts_inc = inc_table[i] * finc;
      new_ts =  ts_inc + mach->first_timestamp;
      diff = ntohl(opt->ts->ts) - new_ts;
      if (diff == 0) { /* Perfect shoot ! */
        return (2);
      }
      tmp = 100. - (new_ts * 100. / ntohl(opt->ts->ts));
      if (tmp < 0.)
        tmp *= -1.;
      if (tmp <= TIMESTAMP_ERROR_MARGIN) { /* Update timestamp and time */
        mach->first_seen = temps;
        mach->first_timestamp = ntohl(opt->ts->ts);
        return (1);
      }
    }
    return (0);
  }
  
  
  /*
   * Simple function to check if an IP address is already in our list
   * If not, it's only a new connection
   */
  int             is_in_list(listes_t *lst, u_int32_t addr) {
    machine_t     *mach;
  
    while (lst) {
      mach = (machine_t *) lst->elt;
      if (mach->from == addr)
        return (1);
      lst = lst->next;
    }
    return (0);
  }
  
  /*
   * This function should be call if a packet from an IP address have been
   * found,
   * is address is already in the list, but doesn't match any timestamp
   * value
   */
  int             update_nat(listes_t *list, u_int32_t addr)
  {
    nat_box_t             *box;
  
    while (list)
      {
        box = (nat_box_t *) list->elt;
        if (box->host == addr)
          {
            box->nat++;
            return (1);
          }
        list = list->next;
      }
    return (0);
  }
  
  int             check_host(listes_t **list, listes_t **nat, u_int32_t
from,
                             tcp_opt_t *opt, struct timeval temps) {
    listes_t      *lst;
    machine_t     *mach;
    int           found, zaped;
  
    found = zaped = 0;
  
    lst = *list;
    while (lst && !(found)) {
      mach = (machine_t *) lst->elt;
      if (mach->from == from) {
        if ( temps.tv_sec - mach->first_seen.tv_sec > DELAY ) {
          found = already_seen(mach, opt, temps);
        } else zaped = 1;
      }
      lst = lst->next;
    }
    if (!(zaped) && !(found)) {
      mach = malloc(sizeof (machine_t));
      mach->from = from;
      mach->first_seen = temps;
      mach->first_timestamp = ntohl(opt->ts->ts);
      add_in_list(list, mach);
      update_nat(*nat, from);
      show_nated(*nat);
      return (1);
    }
    return (0);
  }
  
  
  void    callback_sniffer(u_char *useless,
  const struct pcap_pkthdr* pkthdr,
  const u_char *packet)
  {
    static listes_t               *list_machines = 0;
    static listes_t               *list_nat = 0;
    const struct ip               *ip_h;
    const struct tcphdr           *tcp_h;
    tcp_opt_t                     tcp_opt;
    machine_t                     *mach;
    nat_box_t                     *nat;
    struct in_addr                my_addr;
  
    ip_h = (struct ip *) (packet + sizeof(struct ether_header));
    if (ip_h->ip_p == IPPROTO_TCP)
      {
        tcp_h = (struct tcphdr *) (packet + sizeof(struct ether_header) +
sizeof(struct ip));
        if (tcp_h->th_off * 4 > 20) {
          if (tcp_option_parser((u_char *) (packet + sizeof(struct
ether_header)
                                            + sizeof(struct ip) +
sizeof(struct tcphdr)),
                                &tcp_opt, tcp_h->th_off * 4 - 20))
            {
              if (is_in_list(list_machines, (ip_h->ip_src).s_addr)) {
                check_host(&list_machines, &list_nat, (u_int32_t)
(ip_h->ip_src).s_addr, &tcp_opt, pkthdr->ts);
              } else {
                if (ntohl(tcp_opt.ts->ts) != 0)
  {
  addr = (ip_h->ip_src).s_addr;
  my_addr.s_addr = addr;
  mach = malloc(sizeof (machine_t));
  mach->from = (ip_h->ip_src).s_addr;
  mach->first_seen = pkthdr->ts;
  mach->first_timestamp = ntohl(tcp_opt.ts->ts);
  nat = malloc(sizeof (nat_box_t));
  nat->host = (u_int32_t) (ip_h->ip_src).s_addr;
  nat->nat = 1;
  nat->first_seen = mach->first_seen;
  add_in_list(&list_machines, mach);
  add_in_list(&list_nat, nat);
  }
  }
            }
        }
      }
  }
  
  
  int             main(int ac, char *argv[])
  {
    pcap_t        *sniff;
    char          errbuf[PCAP_ERRBUF_SIZE];
    struct bpf_program fp;
    char          *device;
    bpf_u_int32   maskp, netp;
    struct in_addr my_ip_addr;
    char          filter[250];
  
    if (getuid() != 0) {
      printf("You must be root to use this tool.\n");
      exit (2);
    }
    if (--ac != 1)
      {
        printf("Usage: ./natcount xl0\n");
        return (1);
      }
    device = (++argv)[0];
    pcap_lookupnet(device, &netp, &maskp, errbuf);
    my_ip_addr.s_addr = (u_int32_t) netp;
    printf("Using interface %s IP : %s\n", device, inet_ntoa(my_ip_addr));
    if ((sniff = pcap_open_live(device, BUFSIZ, 1, 1000, errbuf)) == NULL)
{
      printf("ERR: %s\n", errbuf);
      exit(1);
    }
    bzero(filter, 250);
    snprintf(filter, 250, "not src net %s", inet_ntoa(my_ip_addr));
    if(pcap_compile(sniff,&fp, filter, 0, netp) == -1) {
        fprintf(stderr,"Error calling pcap_compile\n");
       exit(1);
      }
    if(pcap_setfilter(sniff,&fp) == -1) {
        fprintf(stderr,"Error setting filter\n");
        exit(1);
      }
    pcap_loop(sniff, -1, callback_sniffer, NULL);
    return (0);
  }
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top