/* $Id: probe.c,v 0.3 2003/10/16 10:38:32 kjc Exp $ */
/*
* Copyright (c) 1996-2000
* Sony Computer Science Laboratories, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms of parts of or the
* whole original or derived work are permitted provided that the above
* copyright notice is retained and the original work is properly
* attributed to the author. The name of the author may not be used to
* endorse or promote products derived from this software without
* specific prior written permission.
* 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.
*/
/* probe.c -- a probe program main module for remote-monitoring. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <netdb.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "ttt.h"
#include "ttt_node.h"
#include "ttt_account.h"
#include "ttt_remote.h"
#include <pcap.h>
extern pcap_t *pd;
extern void (*ttt_netreader)(u_char *user, const struct pcap_pkthdr *h, const u_char *p);
static int sockfd;
static struct sockaddr_in view_addr;
static u_long f_localnet, f_netmask;
static void probe_loop(int pcapfd, int sock_fd);
static int send_report(int sock_fd, int seq_no, struct timeval *tvp);
static int write_record(struct t_node *np, struct ttt_record *trp);
static void probe_cleanup(void);
/* a net_subr compatible procudure just to save localnet address */
void netname_init(u_long netaddr, u_long netmask)
{
/* save localnet address and netmask */
f_localnet = netaddr;
f_netmask = netmask;
}
static void usage(void)
{
printf("usage: probe [options] dest\n");
printf(" or probe [options] -multicast\n");
printf(" options:\n");
printf(" [-interface device]\n");
printf(" [-port dest_port]\n");
printf(" [-ttl time-to-live]\n");
printf(" [-interval msec]\n");
exit(1);
}
int main(int argc, char **argv)
{
struct sockaddr_in my_addr;
int pcapfd;
u_char ttl = 1; /* time-to-live field for mcast */
int port_no = TTT_PORT; /* receiver's port number */
int multicast = 0; /* use multicast */
char *view_name = NULL;
char *my_name = NULL;
while (--argc > 0) {
if (strcmp(*++argv, "-interface") == 0 && --argc > 0)
ttt_interface = *++argv;
else if (strncmp(*argv, "-multicast", 4) == 0)
view_name = TTT_MCASTADDR;
else if (strncmp(*argv, "-port", 4) == 0 && --argc > 0)
port_no = atoi(*++argv);
else if (strcmp(*argv, "-interval") == 0 && --argc > 0)
ttt_interval = atoi(*++argv);
else if (strcmp(*argv, "-ttl") == 0 && --argc > 0)
ttl = atoi(*++argv);
else if (view_name == NULL)
view_name = *argv;
else
usage();
}
if (view_name == NULL) {
printf("no destination specified!\n");
usage();
}
if (name2sockaddrin(my_name, 0, &my_addr) < 0)
fatal_error("can't get my address!");
if (name2sockaddrin(view_name, port_no, &view_addr) < 0)
fatal_error("can't get viewer's address!");
#ifdef IN_MULTICAST
if (IN_MULTICAST(ntohl(view_addr.sin_addr.s_addr)))
multicast = 1;
#endif
if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
fatal_error("sender: can't open socket");
#ifdef IP_MULTICAST_TTL
if (multicast && ttl != 1)
if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
&ttl, sizeof(ttl)) < 0)
fatal_error("can't set ttl");
#endif
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
fatal_error("sender: can't bind");
netacc_init();
pcapfd = open_pf(ttt_interface);
printf("probe started. sending to %s:%d ....\n",
inet_ntoa(view_addr.sin_addr), port_no);
probe_loop(pcapfd, sockfd);
/* never returns */
probe_cleanup();
return 0;
}
static void probe_cleanup(void)
{
close(sockfd);
close_pf();
netacc_cleanup();
}
#define BUFFER_SIZE 4096 /* big enough */
static char buffer[BUFFER_SIZE];
/* timeval macros from Xt */
#define ADD_TIME(dest, src1, src2) { \
if(((dest).tv_usec = (src1).tv_usec + (src2).tv_usec) >= 1000000) {\
(dest).tv_usec -= 1000000;\
(dest).tv_sec = (src1).tv_sec + (src2).tv_sec + 1 ; \
} else { (dest).tv_sec = (src1).tv_sec + (src2).tv_sec ; \
if(((dest).tv_sec >= 1) && (((dest).tv_usec <0))) { \
(dest).tv_sec --;(dest).tv_usec += 1000000; } } }
#define TIMEDELTA(dest, src1, src2) { \
if(((dest).tv_usec = (src1).tv_usec - (src2).tv_usec) < 0) {\
(dest).tv_usec += 1000000;\
(dest).tv_sec = (src1).tv_sec - (src2).tv_sec - 1;\
} else (dest).tv_sec = (src1).tv_sec - (src2).tv_sec; }
#define IS_AFTER(t1, t2) (((t2).tv_sec > (t1).tv_sec) \
|| (((t2).tv_sec == (t1).tv_sec)&& ((t2).tv_usec > (t1).tv_usec)))
#define IS_AT_OR_AFTER(t1, t2) (((t2).tv_sec > (t1).tv_sec) \
|| (((t2).tv_sec == (t1).tv_sec)&& ((t2).tv_usec >= (t1).tv_usec)))
static void probe_loop(int pcapfd, int sock_fd)
{
struct timeval cur_time, wait_time, expr_time, interval;
fd_set rmaskfd;
int seq_no, nfound;
interval.tv_sec = ttt_interval/1000;
interval.tv_usec = (ttt_interval%1000)*1000;
(void) gettimeofday(&cur_time, NULL);
ADD_TIME(expr_time, cur_time, interval);
seq_no = 1;
while (1) {
(void) gettimeofday(&cur_time, NULL);
/* check time to send a ttt report */
if (IS_AT_OR_AFTER(expr_time, cur_time)) {
if (send_report(sockfd, seq_no, &cur_time) > 0)
seq_no++;
ADD_TIME(expr_time, cur_time, interval);
}
wait_time.tv_sec = wait_time.tv_usec = 0;
TIMEDELTA(wait_time, expr_time, cur_time);
FD_ZERO(&rmaskfd);
FD_SET(pcapfd, &rmaskfd);
nfound = select(pcapfd+1, &rmaskfd, NULL, NULL, &wait_time);
if (nfound == -1) {
/* interrupt occured recalculate time value and select again. */
perror("select");
continue;
}
if (FD_ISSET(pcapfd, &rmaskfd)) {
if (pcap_dispatch(pd, 1, ttt_netreader, 0) < 0)
(void)fprintf(stderr, "pcap_dispatch:%s\n", pcap_geterr(pd));
}
}
}
/* create a report packet and send it out */
static int send_report(int sock_fd, int seq_no, struct timeval *tvp)
{
struct ttt_hdr *hdr;
int protos, hosts, rsize, rval;
char *cp;
struct t_node *np;
struct pcap_stat pc_stat;
#if 0
static int last_sent = 1; /* how many records sent last time.
initial value 1 is to send first packet */
#endif
hdr = (struct ttt_hdr *)buffer;
hdr->th_magic = htons(TTT_MAGIC);
hdr->th_version = htons((TTT_MAJOR<<8) | TTT_MINOR);
hdr->th_network = f_localnet;
hdr->th_seqno = htonl(seq_no);
hdr->th_tvsec = htonl(tvp->tv_sec);
hdr->th_tvusec = htonl(tvp->tv_usec);
/* get pcap statistics */
if (pcap_stats(pd, &pc_stat) == 0) {
hdr->th_recvpkts = htonl(pc_stat.ps_recv);
hdr->th_droppkts = htonl(pc_stat.ps_drop);
}
else {
hdr->th_recvpkts = 0;
hdr->th_droppkts = 0;
}
/* get the top 10 traffic of this interval. */
cp = buffer + sizeof(struct ttt_hdr);
for (protos=0, np = node_getbiggest(TTTTYPE_PROTO);
protos<10 && np != NULL; protos++, np = node_getnext(np)) {
rsize = write_record(np, (struct ttt_record *)cp);
cp += rsize;
}
for (hosts=0, np = node_getbiggest(TTTTYPE_HOST);
hosts<10 && np != NULL; hosts++, np = node_getnext(np)) {
rsize = write_record(np, (struct ttt_record *)cp);
cp += rsize;
}
hdr->th_nrecords = htonl(protos + hosts);
node_bumptime(); /* give a time tick to the node module */
#if 0 /* if the traffic is this low, why bothering to send a packet? */
if ((protos+hosts) == 0 && last_sent == 0) {
/* no traffic, nothing to send */
return 0;
}
last_sent = protos + hosts;
#endif
if ((rval = sendto(sock_fd, buffer, cp - buffer, 0,
(struct sockaddr *)&view_addr, sizeof(view_addr))) < 0)
perror("sendto");
return rval;
}
/* write node info to ttt_record */
static int write_record(struct t_node *np, struct ttt_record *trp)
{
struct ttt_record6 *tr6p;
if (np->t_type != TTTTYPE_IPV6HOST) {
trp->tr_type = htonl(np->t_type);
trp->tr_size = htonl(np->t_size);
trp->tr_id[0] = htonl(np->t_id[0]);
return sizeof(struct ttt_record);
}
else {
tr6p = (struct ttt_record6 *)trp;
tr6p->tr_type = htonl(np->t_type);
tr6p->tr_size = htonl(np->t_size);
tr6p->tr_id[0] = htonl(np->t_id[0]);
tr6p->tr_id[1] = htonl(np->t_id[1]);
tr6p->tr_id[2] = htonl(np->t_id[2]);
tr6p->tr_id[3] = htonl(np->t_id[3]);
return sizeof(struct ttt_record6);
}
}
syntax highlighted by Code2HTML, v. 0.9.1