1
0
Files
2022-09-29 17:59:04 +03:00

847 lines
19 KiB
C++

/*
* event.c++ - The user visible portion of the netvis event library.
*
* The primary classes are EV_event and EV_handler. This library is used
* both by the event server and and client.
*
* $Revision: 1.9 $
*/
/*
* Copyright 1992 Silicon Graphics, Inc. All rights reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h> // for uint, time_t
#include <string.h>
#include <pwd.h>
#include <sys/param.h> //for MAXHOSTNAMELEN
#include <osfcn.h> //for gethostname
#include <libc.h> //for bzero
#include <time.h> //for cftime
#include <errno.h> //for errno
#include "event.h"
#include "daemonName.h"
#include "msg.h"
#ifdef EV_DEBUG
int EV_debugging = 1;
#else
int EV_debugging = 0;
#endif
static int amEventServer = 0;
#define D_PRINTF(stuff) \
if (EV_debugging) fprintf stuff;
/*
* The following classed taken together along with the EV_event class totally
* define the information in a netvis event.
*/
/*
* The application class is used by the library to determine whether it is
* operating on behalf of the client or server.
*/
EV_application::EV_application (void) {
struct passwd *pwdent;
appName = NULL;
userName = NULL;
pid = getpid();
uid = getuid();
pwdent = getpwuid(uid);
if (pwdent && pwdent->pw_name)
userName = strdup(pwdent->pw_name);
}
EV_application::~EV_application(void) {
delete [] appName;
delete [] userName;
}
EV_application::EV_application(char *n) {
setAppName(n);
}
void
EV_application::setAppName (char *n) {
if (appName) { // already pointing to a name
delete [] appName; // deallocate that space
}
if (n) { // make sure a name is passed
appName = strdup (n); // allocate and copy
}
else {
appName = NULL;
}
}
void
EV_application::setUserName (char *n) {
if (userName) { // already pointing to a name
delete [] userName; // deallocate that space
}
if (n) { // make sure a name is passed
userName = strdup (n); // allocate and copy
}
else {
userName = NULL;
}
}
char *
EV_application::getAppName(void) {
return (appName);
}
char *
EV_application::getUserName(void) {
return (userName);
}
/*
* The EV_data class contains the snoop filter and a place for arbitrary opaque
* user data. All events contain this info.
*/
EV_data::EV_data (void) {
filter = NULL;
otherData = NULL;
}
EV_data::~EV_data(void) {
delete filter;
delete otherData;
}
void
EV_data::setFilter (char *f) {
if (filter) { // already pointing to a filter
delete [] filter; // deallocate that space
}
if (f) { // make sure use supplied a filter
filter = strdup (f); // allocate and copy
}
else {
filter = NULL;
}
}
void
EV_data::setOtherData (char *o) {
if (otherData) { // already pointing to data
delete [] otherData; // deallocate old space
}
if (o) { // make sure user supplied data
otherData = strdup (o); // allocate and copy
}
else {
otherData = NULL;
}
}
char *
EV_data::getFilter() {
return (filter);
}
char *
EV_data::getOtherData() {
return (otherData);
}
/*
* This class defines the detection of network object or a protocol or a
* converstaion between two network objects.
*/
EV_obj_detect::EV_obj_detect() {
protocol = NULL;
objType = OBJ_OTHER;
converseBytes = 0;
conversePkts = 0;
}
EV_obj_detect::EV_obj_detect (objectType obj) {
objType = obj;
protocol = NULL;
converseBytes = 0;
conversePkts = 0;
}
void
EV_obj_detect::setProto(char *p) {
if (protocol) { // already pointing to protocol
delete [] protocol; // deallocate old space
}
if (p) { // make sure user supplied protocol
protocol = strdup (p); // allocate and copy
}
else {
protocol = NULL;
}
}
char *
EV_obj_detect::getProto () {
return (protocol);
}
/*
* EV_rate defines the fundamental information if a rate event.
*/
EV_rate::EV_rate() {
rate = 0.0;
thresholdRate = 0.0;
base = BYTE_BASED;
baseRate = 0.0;
topNList = NULL;
}
EV_rate::EV_rate(float r, float t, rateBase b, float bofrate, objectList *olist) {
rate = r;
thresholdRate = t;
base = b;
baseRate = bofrate;
// copy object list
//XXXX topNList = olist; temporarily user the line below
topNList = olist;
}
EV_rate::~EV_rate(void) {
//delete topNList;
}
void
EV_rate::setTopNList ( objectList *olist) {
// copy the list
// topNList = olist;
// XXXX temporarily use the line below
topNList = olist;
}
/*
* The EV_event class defines the direct user API for constructing an event
* and retrieving data from it.
*
* There is a different constructor for each general category of event.
*/
EV_event::EV_event(void) {
evType = NV_OTHER;
srcApp = NULL;
pid = 0;
userName = NULL;
uid = 32767;
alarmLevel = EV_LEVEL_INFO;
timeSent = 0;
}
/*
* constructor for the basic event with no additional info
*/
EV_event::EV_event(const eventID id, EV_objID *intrfce,
char *flt) {
evType = id;
srcApp = NULL;
pid = 0;
userName = NULL;
uid = 32767;
alarmLevel = EV_LEVEL_INFO;
timeSent = 0;
if (intrfce) {
interface.setName(intrfce->getName());
interface.setAddr(intrfce->getAddr());
}
setFilter(flt);
}
/*
* constructor for the basic event with no additional info.
* allow user to specify interface as a string rather than EV_objId
*/
EV_event::EV_event(const eventID id, char *intrfce,
char *flt) {
evType = id;
srcApp = NULL;
pid = 0;
userName = NULL;
uid = 32767;
alarmLevel = EV_LEVEL_INFO;
timeSent = 0;
interface.setName(intrfce);
setFilter(flt);
}
/*
* Constructor for object detection events
*/
EV_event::EV_event(const eventID id, objectType obj,
EV_objID *intrfce, char *flt, EV_objID *nd,
EV_objID *network, EV_objID *n1, EV_objID *n2,
uint bytes, uint pkts, char *proto) {
evType = id;
srcApp = NULL;
pid = 0;
userName = NULL;
uid = 32767;
alarmLevel = EV_LEVEL_INFO;
timeSent = 0;
objType = obj;
if (intrfce) {
interface.setName(intrfce->getName());
interface.setAddr(intrfce->getAddr());
}
setFilter(flt);
if (nd) {
node.setName(nd->getName());
node.setAddr(nd->getAddr());
node.setMACAddr(nd->getMACAddr());
}
if (network) {
net.setName(network->getName());
net.setAddr(network->getAddr());
}
/*
* XXXX should make sure that the object type is a OBJ_CONVERSE
* and reconcile this with n1 and n2 parameters. They don't make sense
* otherwise
*
*/
if (n1) {
pair1.setName(n1->getName());
pair1.setAddr(n1->getAddr());
pair1.setMACAddr(n1->getMACAddr());
}
if (n2) {
pair2.setName(n2->getName());
pair2.setAddr(n2->getAddr());
pair2.setMACAddr(n2->getMACAddr());
}
converseBytes = bytes;
conversePkts = pkts;
setProto(proto);
}
/*
* Constructor for object detection events.
* Allows the user to specify strings rather than EV_objIDs
*/
EV_event::EV_event(const eventID id, objectType obj,
char *intrfce, char *flt, char *nd,
char *network, char *n1, char *n2,
uint bytes, uint pkts, char *proto) {
evType = id;
srcApp = NULL;
pid = 0;
userName = NULL;
uid = 32767;
alarmLevel = EV_LEVEL_INFO;
timeSent = 0;
objType = obj;
interface.setName(intrfce);
setFilter(flt);
node.setName(nd);
net.setName(network);
/*
* XXXX should make sure that the object type is a OBJ_CONVERSE
* and reconcile this with n1 and n2 parameters. They don't make sense
* otherwise
*
*/
pair1.setName(n1);
pair2.setName(n2);
converseBytes = bytes;
conversePkts = pkts;
setProto(proto);
}
/*
* Rate event constructor
*/
EV_event::EV_event(const eventID id, float rt, float thresh,
rateBase rbase, rateType bofrate,
EV_objID *intrfce, char *flt,
objectList *olist)
{
evType =id;
srcApp = NULL;
userName = NULL;
uid = 32767;
alarmLevel = EV_LEVEL_INFO;
timeSent = 0;
base = rbase;
if (intrfce) {
interface.setName(intrfce->getName());
interface.setAddr(intrfce->getAddr());
}
setFilter(flt);
setRate(rt);
setThreshRate(thresh);
setRateOfBase(bofrate);
setTopNList(olist);
}
/*
* Rate event constructor.
* Allows user to specify strings rather than EV_objIDs
*/
EV_event::EV_event(const eventID id, float rt, float thresh,
rateBase rbase, rateType bofrate,
char *intrfce, char *flt,
objectList *olist)
{
evType =id;
srcApp = NULL;
userName = NULL;
uid = 32767;
alarmLevel = EV_LEVEL_INFO;
timeSent = 0;
base = rbase;
interface.setName(intrfce);
setFilter(flt);
setRate(rt);
setThreshRate(thresh);
setRateOfBase(bofrate);
setTopNList(olist);
}
EV_event::~EV_event() {
delete [] srcApp;
delete [] userName;
}
void
EV_event::setSrcApp (char *n) {
if (srcApp) { // already pointing to a name
delete [] srcApp; // deallocate that space
}
if (n) { // make sure a name is passed
srcApp = strdup (n); // allocate and copy
}
else {
srcApp = NULL;
}
}
void
EV_event::setUserName (char *n) {
if (userName) { // already pointing to a name
delete [] userName; // deallocate that space
}
if (n) { // make sure a name is passed
userName = strdup (n); // allocate and copy
}
else {
userName = NULL;
}
}
void
EV_event::setNodeName (char *n) {
node.setName(n);
}
void
EV_event::setNodeAddr (char *a) {
node.setAddr(a);
}
void
EV_event::setNodeMACAddr (char *m) {
node.setMACAddr(m);
}
void
EV_event::setNetName (char *n) {
net.setName(n);
}
void
EV_event::setNetAddr (char *a) {
net.setAddr(a);
}
void
EV_event::setInterfaceName (char *n) {
interface.setName(n);
}
void
EV_event::setInterfaceAddr (char *a) {
interface.setAddr(a);
}
void
EV_event::setEndPt1Name (char *n) {
pair1.setName(n);
}
void
EV_event::setEndPt1Addr (char *a) {
pair1.setAddr(a);
}
void
EV_event::setEndPt1MACAddr (char *m) {
pair1.setMACAddr(m);
}
void
EV_event::setEndPt2Name (char *n) {
pair2.setName(n);
}
void
EV_event::setEndPt2Addr (char *a) {
pair2.setAddr(a);
}
void
EV_event::setEndPt2MACAddr (char *m) {
pair2.setMACAddr(m);
}
char *
EV_event::getSrcApp(void) {
return (srcApp);
}
char *
EV_event::getUserName(void) {
return (userName);
}
char *
EV_event::getSrcHostName (void) {
return (srcHost.getName());
}
char *
EV_event::getSrcHostAddr (void) {
return (srcHost.getAddr());
}
char *
EV_event::getNodeName () {
return(node.getName());
}
char *
EV_event::getNodeAddr () {
return(node.getAddr());
}
char *
EV_event::getNodeMACAddr () {
return(node.getMACAddr());
}
char *
EV_event::getNetName () {
return(net.getName());
}
char *
EV_event::getNetAddr () {
return(net.getAddr());
}
char *
EV_event::getInterfaceName () {
return(interface.getName());
}
char *
EV_event::getInterfaceAddr () {
return(interface.getAddr());
}
char *
EV_event::getEndPt1Name () {
return(pair1.getName());
}
char *
EV_event::getEndPt1Addr () {
return(pair1.getAddr());
}
char *
EV_event::getEndPt1MACAddr () {
return(pair1.getMACAddr());
}
char *
EV_event::getEndPt2Name () {
return(pair2.getName());
}
char *
EV_event::getEndPt2Addr () {
return(pair2.getAddr());
}
char *
EV_event::getEndPt2MACAddr () {
return(pair2.getMACAddr());
}
/*
*
is used during debugging. The user can tell the event to print itself.
*/
void EV_event::dump( FILE *fd) {
char tbuf[28];
EV_timeStamp ts;
ts = timeSent;
cftime (tbuf, "%x %X", &ts);
fprintf(fd, "\nEVENT DUMP:\n");
fprintf(fd, "\tCOMMON type %d, timeStamp '%s', srcApp '%s', \
app pid %d, user %s, uid %d, srcHost.name '%s', \
srcHost.addr '%s', filter '%s', interface.name '%s', interface.addr '%s', \
otherData '%s'\n",
evType, tbuf,
srcApp, pid, userName, uid, srcHost.getName(), srcHost.getAddr(), filter,
interface.getName(), interface.getAddr(),
otherData);
fprintf(fd, "\tDETECT objType %d\n", objType);
fprintf(fd, "node.name, %s, node.addr %s, node.MACAddr %s \
net.name %s, net.addr %s, pair1.name '%s', pair1.addr '%s', \
pair1.MACAddr '%s', pair2.name '%s', pair2.addr '%s', \
pair2.MACAddr '%s', bytes %d, pkts %d\n",
node.getName(), node.getAddr(), node.getMACAddr(), net.getName(),
net.getAddr(),
pair1.getName(), pair1.getAddr(), pair1.getMACAddr(),
pair2.getName(), pair2.getAddr(), pair2.getMACAddr(),
converseBytes, conversePkts);
fprintf(fd, "\tRATE rate %f, threshold %f, base %d, baseRate %f, \
topNList '%x'\n", rate, thresholdRate, base, baseRate, topNList);
if (topNList) {
int i = 0;
while (topNList[i]) {
fprintf(fd, "topN%d %s ", i, topNList[i]);
i++;
}
fprintf(fd, "\n");
}
}
/* EV_handler class is instantiated by the application to start up the event
* handling engine.
*
* Inintialize the static class variable to make sure there is never more that
* one handler per application.
*/
EV_handle EV_handler::handle = NULL; // initialize to show no connection
/*
* The EV_handler constructor is repsonsible for establishing/initializing the
* communications channel. The most important thing that it does on behalf of
* the user is to exchange configuration information between the client and
* server. In particular, if being used by the client, it asks the server for
* the list of events not to send because they are not currently configured
* as being of interest or because there are just too many of them.
*
* XXXX currently the handler sends a request and then waits for a reply.
* In the future it will do this asynchronously so that if server
* communication fails, it will not wait for the timeout.
*
*/
EV_handler::EV_handler (EV_handle *h, char *app, struct timeval *t) {
fd_set fds;
int ready;
struct timeval timeout;
EV_stat rslt = -1;
#define EV_REG_MSG_TIMEOUT 2
if (handle) return; // protect user from duplicating connection to server
bzero(regList, sizeof regList);
bzero (noSendList, sizeof noSendList);
setAppName (app); // This must be passed by user
if (strcmp (app, eventDaemon) == 0) {
amEventServer = 1;
msg = new EV_srvr_msg();
}
else {
msg = new EV_clnt_msg();
}
*h = handle = msg->open(/*XXXX session?*/);
if (handle <= 0) {
*h = handle = NULL;
D_PRINTF((stderr,
"EV_handler::EV_handler: cannot open communication channel.\n"));
return;
}
if ( !amEventServer) {
// send the initial registration message to the event daemon
// This is the pseudo event
EV_event *e = new EV_event(NV_REGISTER);
// EV_handler::send normally would do this for all my users
// here I do it directly for myself.
e->setSrcApp (getAppName());
e->pid = getPID();
e->uid = (int) getUID();
e->setUserName (getUserName());
e->srcHost.setName(localHost.getName());
e->timeSent = time ((time_t *)NULL);
msg->send(e);
int iter = 0;
// set up and wait for a reply
while (rslt && iter < 3) {
D_PRINTF((stderr, "EV_handler::EV_handler iter %d\n", iter));
iter++;
FD_ZERO (&fds);
FD_SET (handle, &fds);
timeout.tv_sec = (t) ? t->tv_sec : EV_REG_MSG_TIMEOUT;
timeout.tv_usec = (t) ? t->tv_usec : 0;
ready = select (FD_SETSIZE, &fds, 0, 0, &timeout);
if (ready == -1) {
D_PRINTF((stderr, "EV_handler: select: %d\n", errno));
handle = NULL;
break;
}
else if (! ready) {
D_PRINTF((stderr, "EV_handler: timed out connecting to server\n"));
handle = NULL;
continue;
}
else {
// the reply should tell me what events not to send.
// This is the only time that receive has this extra
// parameter. This is the EV_handler noSendList. See
// EV_handler_send for its use.
rslt = msg->recv(e, noSendList);
}
}
if (rslt != EV_OK)
handle = NULL;
delete e;
}
}
EV_handler::~EV_handler(void) {
delete msg;
}
/*
* These methods are used by a client to (un)register for events of interest.
* It is not implemented in the first release.
*/
void
EV_handler::reg (const eventID event) {
regList[event] = 1;
}
void
EV_handler::unregister (const eventID event) {
regList[event] = 0;
}
EV_stat
EV_handler::send (EV_event *event) {
/*
* I have the event and I have the localHost and application from the
* handler. What I do is construct the event msg and send it on.
*
*/
char noSnds[NV_MAX_EVENT + 1];
int cnt = 0;
// Check to see if comm channel is open.
if (!handle) {
return (EV_OK);
}
// clients only send events that are not proscibed
if (noSendList[event->evType] && !amEventServer) {
// configured not to send this one
return (EV_OK);
}
if (amEventServer && event->evType == NV_REGISTER) {
// fill in list of events not to send
// pack the list into minimum space for the message
// note that this is a reply and therfore the client's message
// is reflected back unchanged
for (int i = 0; i < NV_MAX_EVENT; i++) {
if (noSendList[i]) {
noSnds[cnt++] = i;
}
}
// 0 terminate the list
noSnds[cnt] = 0;
D_PRINTF ((stderr, "EV_handler::send replying with cnt %d noSends\n",
cnt));
}
else {
// standard event send where the handler fills in this default info
event->setSrcApp (getAppName());
event->pid = getPID();
event->uid = (int) getUID();
event->setUserName (getUserName());
event->srcHost.setName(localHost.getName());
event->timeSent = time ((time_t *)NULL);
}
return(msg->send(event, (cnt) ? noSnds : NULL));
}
EV_stat
EV_handler::receive (EV_event *event) {
/*
* XXXX Should this routine be generalized to use the noSendList as the
* optional second parameter to msg::receive so that EV_handler::EV_handler
* does not special case the initial NV_REGISTER event?
*/
if (! handle) {
return (EV_OK);
}
return (msg->recv(event));
}
/*
* This method is used by the server to set the noSendList of the handler to a
* given configuration.
*/
void EV_handler::setNoSends(char *noSends) {
if (noSends) {
bcopy (noSends, noSendList, NV_MAX_EVENT);
}
}