/* 
 * Query lsof for open TCP connections. Assumes lsof, awk, sort, and uniq
 # are accessible via the current path.
 *
 * $Id: lsof.c,v 1.6 1996/11/21 02:02:00 jdd Exp $
 */

#include <stdio.h>

#ifdef LSOF 

#include <stdlib.h>
#include <pwd.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "tcplist.h"
#include "utils.h"

#ifndef LSOFCMD
#ifdef OLDLSOF
/* Older versions of lsof use -H instead of -n */
#define LSOFCMD  "lsof -HPsli TCP | awk '{print $3,$NF}' | sort | uniq"
#else /* !OLDLSOF */
/* These use the current (as of 3.62W, at least) parameters for lsof */
#define LSOFCMD  "lsof -nPsli TCP | awk '{print $3,$(NF - 1)}' | sort | uniq"
#endif /* !OLDLSOF */
#endif /* LSOFCMD */

#ifndef WHITESPACE
#define WHITESPACE " \t\n"
#endif /* WHITESPACE */

struct hostlist *make_hostlist(localaddr, servershow)
u_long *localaddr;
int servershow;
{
	FILE *fp;
	char buff[BUFSIZ], *cp;
	int i, lport, fport, uid;
	u_long laddr, faddr;
	struct passwd *pw;
	struct hostlist *hlist = NUL(struct hostlist *);

	buff[sizeof(buff)-1]='\0'; /* make sure we have null termination */

#ifndef INSECURE
	(void)setuid(getuid());  /* just in case installed setuid/setgrpid */
#endif /* ndef INSECURE */

	signal(SIGPIPE, SIG_IGN);
	if(NULL==(fp=popen(LSOFCMD, "r"))){
		Error("Can't run lsof.  Check your $PATH.");
	}

	/* grab and throw away initial header */
	if(NULL==fgets(buff, sizeof(buff)-1,fp)){
		Error("Can't get lsof output header");
	}

	while(NULL!=fgets(buff,sizeof(buff)-1,fp)){
                struct connection *cn;
                struct hostlist *hl;
                int found;

		buff[strlen(buff)-1]='\0';  /* strip trailing newline */
#ifdef DEBUG
		dfprintf(3, stderr, ">> %s\n", buff);
#endif /* DEBUG */

		/* get uid */
		if(NULL==(cp=strtok(buff, WHITESPACE))) continue;
		uid=atoi(cp);
		if(0==uid && '0'!=*cp) continue;

		/* we split the next field as follows:         */
		/* Syntax: sourceaddr:lport->destaddr:destport */
		/*     or: *:lport                             */
		/*     or: sourceaddr->destaddr:destport       */

		if(NULL==(cp=strtok(NULL, WHITESPACE))) continue;

		if('*'==*cp){
			/* *:lport case */

			if(!servershow) continue;
			laddr=*localaddr;

			/* source port */
			lport=atoi(cp+2);
			if(0==lport) continue;
			faddr=INADDR_ANY;
			fport=PORT_ANY;
		} else {
			char *p1, *p2;
	
			/* split field into local and remote halves */
			if(NULL==(p1=strtok(cp, "->"))) continue;
			if(NULL==(p2=strtok(NULL, "->"))) continue;

			/* split halves */
			if(NULL==(cp=strtok(p1, ":"))) continue;
			laddr=inet_addr(cp);
#ifdef DEBUG
			dfprintf(5, stderr, "Local address is %s\n", cp);
#endif /* DEBUG */
			cp=strtok(NULL, ":");
			if(NULL==cp) {
				lport=PORT_ANY;
			} else {
				lport=atoi(cp);
			}
#ifdef DEBUG
			dfprintf(5, stderr, "Local port is %u\n", lport);
#endif /* DEBUG */

			/* split halves */
			if(NULL==(cp=strtok(p2, ":"))) continue;
			faddr=inet_addr(cp);
#ifdef DEBUG
			dfprintf(5, stderr, "Foreign address is %s\n", cp);
#endif /* DEBUG */
			cp=strtok(NULL, ":");
			if(NULL==cp) {
				fport=PORT_ANY;
			} else {
				fport=atoi(cp);
			}
#ifdef DEBUG
			dfprintf(5, stderr, "Foreign port is %u\n", lport);
#endif /* DEBUG */
		}

		pw=getpwuid(uid);
		if(NULL==pw){
			pw=new(struct passwd);
			pw->pw_name=mem(10); 
			sprintf(pw->pw_name, "#%d", uid);
			pw->pw_uid=uid;
		}
#ifdef DEBUG
		dfprintf(3, stderr, "user id is %d and user is %s\n", 
			 uid, pw->pw_name);
#endif /* DEBUG */

		/* is this host already on the hostlist? */
		found = FALSE;
		for(hl=hlist;NULL!=hl;hl=hl->next){
			if(faddr == hl->addr){
				/* found it */
				found = TRUE; 
				break;
			}
		}
		if(!found){
			/* create new hostlist entry */
			hl=new(struct hostlist);
			hl->addr = faddr; 
			*localaddr = laddr; 
			hl->conn = NUL(struct connection *);
			hl->next = hlist;
			hlist = hl;
		}
		/* create new connection entry */
		cn=new(struct connection);
		cn->remote=fport;
		cn->local=lport;
		cn->user=s(pw->pw_name);
		cn->next=hl->conn;
		hl->conn=cn;
	}
	(void)fclose(fp);
	return(hlist);
}

#endif /* LSOF */


syntax highlighted by Code2HTML, v. 0.9.1