Commit 54711915 authored by Robert Ricci's avatar Robert Ricci

Added preliminary support for version 3 of libnetmon output. In this

version, the unique identifier is the pid + fd, rather than anything
involving port numbers. UDP sockets won't necessarily have any of
that.

I've made a few tweaks to Jon's v3 format. The format is not
finalized, so some details could still change.

Added preliminary support for UDP sockets. Right now, only handles
sockets that are connect()ed, not ones that are used with sendto().
We need to decide what the best way to report on sendto() is.  UDP
support can be enabled by passing the new '-u' argument to netmond.

Needs support for handling applications that fork(), since the PID
changes. Shouldn't be too hard, just one more syscall to wrap.

At some point, we should stop supporting earlier output versions,
because that will allow me to clean up a lot of code.
parent e53e402f
......@@ -9,16 +9,15 @@ Line format 3 for libnetmon:
Possible commands and their values:
New (no value)
Protocol (value is 'TCP' or 'UDP')
DestIP (value is a dotted quadruplet describing destination IP address)
New (value is 'TCP' or 'UDP')
RemoteIP (value is a dotted quadruplet describing destination IP address)
RemotePort (value is a number representing the remote port of the connection)
LocalPort (value is a number representing the local port of the connection)
TCP_NODELAY (int)
TCP_MAXSEG (int)
SO_RCVBUF (int)
SO_SNDBUF (int)
Connected (no value)
Connected (no value) (RemoteIP and RemotePort MUST be sent before this command)
Write (value is the size of the write or sendto)
Closed (no value)
......@@ -62,6 +62,12 @@ void lnm_init() {
fdSize = 0;
allocFDspace();
/*
* By default, monitor TCP sockets only
*/
monitor_tcp = true;
monitor_udp = false;
/*
* Figure out which version of the output format we're supposed to use
*/
......@@ -76,6 +82,32 @@ void lnm_init() {
}
DEBUG(printf("Using output version %i\n",output_version));
/*
* Find out if we're supposed to monitor UDP sockets. Set to a non-zero
* int to monitor
*/
char *monitor_udp_s;
monitor_udp_s = getenv("LIBNETMON_MONITORUDP");
if (monitor_udp_s) {
int flag;
if (!sscanf(outversion_s,"%i",&flag) == 1) {
croak1("Bad value for LIBNETMON_MONITORUDP: %s\n",
monitor_udp_s);
}
if (flag) {
monitor_udp = true;
} else {
monitor_udp = false;
}
}
/*
* Get our PID
* TODO: We need to handle fork() and its variants - our children could
* get different PIDs
*/
pid = getpid();
#define FIND_REAL_FUN(FUN) \
real_##FUN = (FUN##_proto_t*)dlsym(RTLD_NEXT,#FUN); \
if (!real_##FUN) { \
......@@ -418,14 +450,15 @@ void startFD(int fd) {
}
*/
/*
* Check to make sure it's a TCP socket
* Check to make sure it's a type of socket we're supposed to be monitoring
*/
typesize = sizeof(unsigned int);
if (getsockopt(fd,SOL_SOCKET,SO_TYPE,&socktype,&typesize) != 0) {
croak1("Unable to get socket type: %s\n",strerror(errno));
}
if (socktype != SOCK_STREAM) {
DEBUG(printf("Ignoring a non-TCP socket\n"));
if (!((monitor_tcp && socktype == SOCK_STREAM) ||
(monitor_udp && socktype == SOCK_DGRAM))) {
DEBUG(printf("Ignoring a type socket we're not monitoring\n"));
return;
}
......@@ -464,8 +497,30 @@ void startFD(int fd) {
forced_bufsize, rcvsize);
}
/*
* For version 3 and up, port numbers are not used for socket identifiers,
* so we can report a New event now. For earlier output versions, this gets
* reported in informConnect()
*/
if (output_version >= 3) {
fprintf(outstream,"New: ");
fprintID(outstream,fd);
fprintf(outstream," ");
fprintTime(outstream);
fprintf(outstream," ");
if (socktype == SOCK_STREAM) {
fprintf(outstream,"TCP");
} else if (socktype == SOCK_DGRAM) {
fprintf(outstream,"UDP");
} else {
fprintf(outstream,"UNKNOWN");
}
fprintf(outstream,"\n");
}
monitorFDs[fd].monitoring = true;
monitorFDs[fd].connected = false;
monitorFDs[fd].socktype = socktype;
DEBUG(printf("Watching FD %i\n",fd));
......@@ -513,13 +568,19 @@ void stopWatchingAll() {
*/
void fprintID(FILE *f, int fd) {
/*
* Note, we've switched from local_port to FD for the first field - this is
* so that we can report on a connection before connect() finishes
*/
fprintf(f,"%i:%s:%i", fd,
monitorFDs[fd].remote_hostname,
monitorFDs[fd].remote_port);
if (output_version <= 2) {
/*
* Note, we've switched from local_port to FD for the first field - this is
* so that we can report on a connection before connect() finishes
*/
fprintf(f,"%i:%s:%i", fd,
monitorFDs[fd].remote_hostname,
monitorFDs[fd].remote_port);
} else if (output_version == 3) {
fprintf(f,"%i:%i",pid,fd);
} else {
croak0("Improper output version");
}
}
......@@ -546,6 +607,7 @@ void process_control_packet(generic_m *m) {
max_socket_m *maxmsg;
out_ver_m *vermsg;
reports_m *reportmsg;
monitorudp_m *monitorudpmsg;
DEBUG(printf("Processing control packet\n"));
......@@ -597,9 +659,25 @@ void process_control_packet(generic_m *m) {
lnm_parse_reportopt(reportmsg->reports);
break;
case CM_MONITORDUP:
/*
* The server is telling us whether it wants us to monitor UDP
* sockets
*/
monitorudpmsg = (monitorudp_m*)m;
if (monitorudpmsg->enable) {
DEBUG(printf("Enabling UDP monitoring\n"));
monitor_udp = true;
} else {
DEBUG(printf("Disabling UDP monitoring\n"));
monitor_udp = false;
}
break;
default:
croak1("Got an unexepected control message type: %i\n",
croak1("Got an unexpected control message type: %i\n",
(void *)m->type);
}
}
......@@ -756,6 +834,7 @@ void log_packet(int fd, size_t len) {
monitorFDs[fd].remote_port, len);
break;
case 2:
case 3:
fprintf(outstream,"%lu.%06lu > ", time.tv_sec, time.tv_usec);
fprintID(outstream,fd);
fprintf(outstream," (%i)\n", len);
......@@ -770,7 +849,7 @@ void log_packet(int fd, size_t len) {
* Inform the user that the nodelay flag has been changed
*/
void informNodelay(int fd) {
if (output_version >= 2) {
if (monitorFDs[fd].socktype == SOCK_STREAM && output_version >= 2) {
fprintf(outstream,"TCP_NODELAY: ");
fprintID(outstream,fd);
fprintf(outstream," %i\n",monitorFDs[fd].tcp_nodelay);
......@@ -778,7 +857,7 @@ void informNodelay(int fd) {
}
void informMaxseg(int fd) {
if (output_version >= 2) {
if (monitorFDs[fd].socktype == SOCK_STREAM && output_version >= 2) {
fprintf(outstream,"TCP_MAXSEG: ");
fprintID(outstream,fd);
fprintf(outstream," %i\n",monitorFDs[fd].tcp_maxseg);
......@@ -806,13 +885,37 @@ void informBufsize(int fd, int which) {
void informConnect(int fd) {
if (output_version >= 2) {
/*
* Let the monitor know about it
* Let the monitor know about it - note: if it's a UDP socket, we've
* already reported on it in startFD. Note that, for version 3, we
* report the existence of the socket earler, in startFD
*/
fprintf(outstream,"New: ");
fprintID(outstream,fd);
fprintf(outstream," ");
fprintTime(outstream);
fprintf(outstream,"\n");
if ((output_version < 3) && monitorFDs[fd].socktype == SOCK_STREAM) {
fprintf(outstream,"New: ");
fprintID(outstream,fd);
fprintf(outstream," ");
fprintTime(outstream);
fprintf(outstream,"\n");
}
/*
* New versions of the output no longer include port numbers in the
* identifier. So, report those now
*/
if (output_version >= 3){
fprintf(outstream,"RemoteIP: ");
fprintID(outstream,fd);
fprintf(outstream," ");
fprintTime(outstream);
fprintf(outstream," %s",monitorFDs[fd].remote_hostname);
fprintf(outstream,"\n");
fprintf(outstream,"RemotePort: ");
fprintID(outstream,fd);
fprintf(outstream," ");
fprintTime(outstream);
fprintf(outstream," %i",monitorFDs[fd].remote_port);
fprintf(outstream,"\n");
}
/*
* Some things we report on for every connection
......@@ -874,7 +977,6 @@ int socket(int domain, int type, int protocol) {
* connecting to some host.
*
* TODO: Allow for some filters:
* Only TCP connections
* Only certain hosts? (eg. not loopback)
*/
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) {
......@@ -930,7 +1032,7 @@ int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) {
*/
/*
* Get the local port number so that we can monitor about it
* Get the local port number so that we can monitor it
*/
struct sockaddr_in localaddr;
int namelen = sizeof(localaddr);
......
......@@ -43,7 +43,6 @@
/*
* Just a few things for convience
*/
typedef enum {true = 1, false = 0} bool;
const unsigned int FD_ALLOC_SIZE = 8;
/*
......@@ -107,6 +106,8 @@ typedef struct {
bool connected; /* Is this FD currently connected or not? */
int socktype; /* Socket type - normally SOCK_STREAM or SOCK_DGRAM */
/*
* Socket options we keep track of
*/
......@@ -182,6 +183,18 @@ static void control_query();
*/
static unsigned int output_version;
/*
* Our PID
*/
static pid_t pid;
/*
* These describe the types of sockets we're monitoring - basically, are we
* monitoring TCP, UDP, or both?
*/
static bool monitor_tcp;
static bool monitor_udp;
/*
* These describe which things we need to report on. report_all is sort of a
* meta-option - at the end of initialization, if it's set, we turn on the
......
......@@ -14,6 +14,11 @@
#define SOCKPATH "/var/tmp/netmon.sock"
#define CONTROLSOCK SOCKPATH ".control"
/*
* For convience
*/
typedef enum {true = 1, false = 0} bool;
/*
* Control messages
*/
......@@ -27,6 +32,7 @@ typedef enum {
CM_MAXSOCKSIZE = 0,
CM_OUTPUTVER,
CM_REPORTS,
CM_MONITORDUP,
CM_SOCKSIZE = 64,
CM_QUERY
......@@ -75,6 +81,14 @@ typedef struct {
unsigned char reports[CONTROL_MESSAGE_PAYLOAD_SIZE];
} reports_m;
/*
* Boolean: are we supposed to monitor UDP sockets?
*/
typedef struct {
unsigned int type;
unsigned char enable;
} monitorudp_m;
/*
* Socket size change report
*/
......
......@@ -56,6 +56,11 @@ unsigned int forced_socksize = 0;
*/
char *reports = NULL;
/*
* Enable UDP mointoring
*/
bool monitor_udp = false;
/*
* Give a client a report on what settings it should use.
*
......@@ -67,6 +72,7 @@ unsigned int write_status(int fd) {
max_socket_m *sockrep;
out_ver_m *verrep;
reports_m *reprep;
monitorudp_m *udprep;
/*
* Report on the maximum socket size
......@@ -120,6 +126,22 @@ unsigned int write_status(int fd) {
}
}
/*
* Report on whether or not we want to monitor UDP sockets. Older versions
* of libnetmon won't know what to do with this, so only report if it's
* turned on
*/
if (monitor_udp) {
udprep = (monitorudp_m *)&(message);
udprep->type = CM_MONITORDUP;
udprep->enable = true;
if (write(fd,&message,CONTROL_MESSAGE_SIZE) != CONTROL_MESSAGE_SIZE) {
/* Client probably disconnected */
return 1;
}
}
return 0;
}
......@@ -129,6 +151,7 @@ void usage() {
fprintf(stderr," -l size Maximum socket buffer size\n");
fprintf(stderr," -f size Force a socket buffer size\n");
fprintf(stderr," -r reports Enable listed reports\n");
fprintf(stderr," -u Monitor UDP sockets\n");
exit(-1);
}
......@@ -147,7 +170,7 @@ int main(int argc, char **argv) {
/*
* Process command-line args
*/
while ((ch = getopt(argc, argv, "f:l:v:r:")) != -1) {
while ((ch = getopt(argc, argv, "f:l:v:r:u")) != -1) {
switch(ch) {
case 'f':
if (sscanf(optarg,"%i",&forced_socksize) != 1) {
......@@ -168,6 +191,9 @@ int main(int argc, char **argv) {
reports = (char*)malloc(strlen(optarg) + 1);
strcpy(reports,optarg);
break;
case 'u':
monitor_udp = true;
break;
default:
usage();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment