/* 1620, Mon 23 Nov 98 NF_FWD.C: Packet forwarder for NetFlow data Copyright (C) 1998-2002 by Nevil Brownlee, CAIDA | University of Auckland */ /* * $Log: nf_fwd.c,v $ * Revision 1.1.4.1.2.10 2002/02/23 01:57:34 nevil * Moving srl examples to examples/ directory. Modified examples/Makefile.in * * Revision 1.1.4.1.2.8 2001/05/24 02:19:57 nevil * LfapMet implemented by Remco Poortinga. * MinPDUs implemented by Nevil. * * Revision 1.1.4.1.2.6 2000/08/08 19:44:55 nevil * 44b8 release * * Revision 1.1.4.1.2.4 2000/06/06 03:38:22 nevil * Combine NEW_ATR with TCP_ATR, various bug fixes * * Revision 1.1.4.1.2.1 2000/01/12 02:57:13 nevil * Implement 'packet pair matched' turnaroundtime distribution attributes. * Fix ASN-related bugs in NeTraMet, distribution-related bugs in fd_filter. * * Revision 1.1.4.1 1999/10/03 21:06:26 nevil * *** empty log message *** * * Revision 1.1.2.4 1999/09/22 05:38:44 nevil * Improve code to work properly on 64-bit machines * - Add OS=ALPHA handling to configure.in * - Clean up the Alpha compiler warnings * - Change all the snmp-related code to use Bit32 instead of unsigned long * * Revision 1.1.2.3 1999/09/14 00:45:30 nevil * 4.3 Release .. * - Implement -D option to run NeTraMet as a daemon * - Tidy up the on-line help displays * * Revision 1.1.2.2 1999/01/08 01:31:56 nevil * Implementation of TCP attributes, part 3 * * Revision 1.1.2.1 1998/12/22 23:59:00 nevil * Add new program to distribution * */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #if HAVE_SYS_SELECT_H #include #endif #include #include #include #include #include #include #include #define MXINTERFACES 4 /* Max nbr of interfaces to meter */ #include "ausnmp.h" /* Bit8, Bit16, .. */ #include "flowdata.h" /* Cisco's file */ #define SZ_IFNAME 64 struct interface_info { u_char nbr; /* Interface number (for Surce/DestInterface attributes) */ char name[SZ_IFNAME+1]; /* Interface name, e.g. nf0 */ int fd; struct sockaddr_in from; char *nf_buf; }; struct interface_info *pci[MXINTERFACES]; int n_interfaces; /* Nbr of active interfaces */ int sd; /* Target socket */ struct sockaddr_in to; char to_host[SZ_IFNAME], to_port[SZ_IFNAME]; int pkts = 1; int display_enabled, kb_enabled; void interface_read(struct interface_info *pi) { int flen, j; char msg[60]; flen = sizeof(pi->from); if (recvfrom(pi->fd, pi->nf_buf, MAX_FLOW_PAK_SIZE, 0, (struct sockaddr *)&pi->from, &flen) < 0) { printf("nf_read(%s): recvfrom failed\n", pi->name); return; } if (display_enabled && --pkts == 0) { pkts = 10; printf("+"); fflush(stdout); } sendto(sd, pi->nf_buf, MAX_FLOW_PAK_SIZE, 0, (struct sockaddr *)&to, sizeof(to)); } int init_interface(struct interface_info *pi) { int soc; struct sockaddr_in socadr; struct in_addr netid; ushort port; if (pi->name[0] == '\0') strcpy(pi->name, "9996"); port = atoi(pi->name); /* Open a UDP port from the NetFlow router */ socadr.sin_family = AF_INET; socadr.sin_addr.s_addr = htonl(INADDR_ANY); socadr.sin_port = htons(port); netid.s_addr = socadr.sin_addr.s_addr; if ((soc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { printf("interface %d: couldn't get socket, errno %d\n", pi->nbr, (errno)); return 0; /* Fail */ } /* Bind the socket */ if (bind(soc, (struct sockaddr *)&socadr, sizeof(socadr)) < 0) { printf("interface %d: couldn't bind socket, errno %d\n", pi->nbr, (errno)); return 0; /* Fail */ } sprintf(pi->name, "udp-%u", port); pi->fd = soc; pi->nf_buf = (char *)malloc(MAX_FLOW_PAK_SIZE); return 1; /* OK */ } char *strmov(char *d, char *s) { while (*s != '\0') *d++ = *s++; return d; } /* Help screen. Add any new command line options here */ void print_help(void) { fprintf(stderr, "\nUsage: NetFwd [OPTION]...\n"); fprintf(stderr, "A redirector/consolidator for NetFlow data streams:\n\n" " -t HST \t Host to send packets to\n" " -p PRT \t Port nbr to send packets to (default 9996)\n" "\n" " -i IFN \t UDP port to read from (maximum of 4)\n" "\n" " -k \t Disable keyboard input processing\n" " -s \t Disable screen display\n" "\n" " >>> Hit ESC CR to terminate NetFwd while it's running <<<\n" "\n" "Report bugs to netramet@auckland.ac.nz\n"); } int main(int argc, char *argv[]) { int arg,c; char *ap; struct utsname name; struct hostent *hp; char interface_name[64] = ""; if (argc < 2) { /* Help Screen when called with no args */ print_help(); exit(-1); } display_enabled = kb_enabled = 1; /* Enabled by default */ for (n_interfaces = 0; n_interfaces != MXINTERFACES; ++n_interfaces) pci[n_interfaces] = NULL; n_interfaces = 0; to_host[0] = to_port[0] = '\0'; for (c = 0, arg = 1; arg < argc; ++arg) { if (argv[arg][0] == '-') { ap = argv[arg]+2; switch (argv[arg][1]) { case 'i': /* -i name of interface to monitor */ if (*ap == '\0') ap = argv[++arg]; pci[n_interfaces] = (struct interface_info *)calloc( sizeof(struct interface_info), 1); strncpy(pci[n_interfaces]->name,ap,SZ_IFNAME); pci[n_interfaces]->name[SZ_IFNAME] = '\0'; pci[n_interfaces]->nbr = n_interfaces+1; /* 1-org */ ++n_interfaces; break; case 'k': kb_enabled = 0; /* -k to disable keyboard */ break; case 'p': if (*ap == '\0') ap = argv[++arg]; /* 'to' Port nbr */ strncpy(to_port,ap,SZ_IFNAME); break; case 's': display_enabled = 0; /* -s to disable screen */ break; case 't': if (*ap == '\0') ap = argv[++arg]; /* 'To' host */ strncpy(to_host,ap,SZ_IFNAME); break; default: printf("Invalid option: -%c\n", argv[arg][1]); exit(0); } } } /* Set up connection to target host */ if (to_host[0] == '\0') { printf("No target host specified <<<\n"); print_help(); exit(-2); } hp = gethostbyname(to_host); if (hp == NULL) { printf("Unknown host %s <<<\n", to_host); exit(-3); } to.sin_family = AF_INET; memcpy((char *)&to.sin_addr.s_addr, hp->h_addr, hp->h_length); to.sin_port = htons(to_port[0] == '\0' ? 9996 : atoi(to_port)); sd = socket(AF_INET, SOCK_DGRAM, 0); if (sd < 0){ perror("socket"); exit(1); } if (connect(sd, (struct sockaddr *)&to, sizeof(to)) != 0) { perror("connect"); exit(2); } if (n_interfaces == 0) { pci[0] = (struct interface_info *)calloc(sizeof(struct interface_info),1); pci[0]->nbr = n_interfaces = 1; } uname(&name); if (display_enabled) printf("Running on %s", name.nodename); ap = interface_name; for (c = 0; c != n_interfaces; ++c) { if (!init_interface(pci[c])) exit(-4); if (c != 0) ap = strmov(ap,", "); ap = strmov(ap,pci[c]->name); *ap = '\0'; if (display_enabled) printf(", port %s",pci[c]->name); } if (display_enabled) printf("\n"); receive(sd,n_interfaces); } handle_keyboard() { char kb_buf[25]; int ch; fgets(kb_buf, sizeof kb_buf, stdin); if ((ch = kb_buf[0]) == 27) { /* ESC */ printf("Shutting down\n"); exit(0); } switch (tolower(ch)) { case 'v': printf("NetFwd version v" ver_str "\n"); break; } } receive(int sd,int n_interfaces) { fd_set fdset; int j, width, count; struct timeval t; width = 0; /* Determine size of fd_set */ for (j = 0; j != n_interfaces; ++j) if (pci[j]->fd > width) width = pci[j]->fd; ++width; for (;;) { FD_ZERO(&fdset); for (j = 0; j != n_interfaces; ++j) FD_SET(pci[j]->fd,&fdset); if (kb_enabled) FD_SET(0, &fdset); /* stdin */ t.tv_sec = 0; t.tv_usec = 250000; /* 0.25 seconds */ count = select(width, &fdset, 0, 0, &t); if (count > 0) { for (j = 0; j != n_interfaces; ++j) { if (FD_ISSET(pci[j]->fd, &fdset)) interface_read(pci[j]); } if (FD_ISSET(0, &fdset)) /* stdin */ handle_keyboard(); } else switch (count) { case 0: break; case -1: if (errno == EINTR) continue; else perror("select"); return -1; default: printf("select returned %d\n", count); return -1; } } }