#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


#define CFILE "/proc/net/ip_conntrack"
#define MATCHCMD "/usr/local/bin/match"

#define BLEN 255



#ifdef DEBUG
#define DBG(x...) fprintf(stderr,## x)
#else
#define DBG(x...)
#endif

/*
 * Handles ident request
 */


void _err(char *err)
{
	DBG("Error \"%s\" occured!\n",err);
	exit(5);
}
/*
 * finds the ip of the masq. connection
 */
int find_ip(int lport,int dport, char *ipaddr)
{
	
#define SKIPSPACES(x) while ((*x)==' ') x++
#define SKIPNOSPACES(x) while ((*x)!=' ') x++ ; x++
	FILE *conntr;

	char buffer[1024];
	char tmpip[18];
	int tip_pos;
	char *tmp;
	int i,tmpp;
	
	if(  ( conntr=fopen(CFILE,"r") )==NULL) return -1;
	while ( (!feof(conntr)) && fgets(buffer,1024,conntr) )
	{
		DBG("%s",buffer);
		/*
		 * string parsing of the ip_conntrack file. The format is:
		 * tcp      6 431933 ESTABLISHED src=192.168.0.6 dst=213.222.51.196 sport=32995 dport=993 src=213.222.51.196 dst=194.12.255.254 sport=993 dport=32995 [ASSURED] use=1
		 * PROTO  sth bytes  state       orig. source    orig.dest.         orig.sport  orig.dport nat src            nat.dst           nat.dport   nat.sport etc.
		 */

		if (strncmp(buffer,"tcp",3)!=0) continue;
		tmp=buffer;
		tmp+=4;
		SKIPSPACES(tmp);
		SKIPNOSPACES(tmp);
		SKIPNOSPACES(tmp);
		if (strncmp(tmp,"ESTABLISHED",11)!=0) continue;
		tmp+=16;
		/* record ip, if we need it (orig.source) */
		memset(tmpip,sizeof(char),18);
		tip_pos=0;
		while (*tmp!=' ') 
		{
			tmpip[tip_pos]=*tmp;
			tip_pos++;
			tmp++;
		}
		tmp++;
		tmpip[tip_pos]='\0';
		for (i=0;i<5;i++) SKIPNOSPACES(tmp);
		tmp+=6;
		sscanf(tmp,"%d",&tmpp);
		if (tmpp!=lport) continue;
		SKIPNOSPACES(tmp);
		tmp+=6;
		sscanf(tmp,"%d",&tmpp);
		if (tmpp!=dport) continue;
		/* if we reached here, we have a winner :) */
		strcpy(ipaddr,tmpip);
		fclose(conntr);
		return 0;
					
	}
	
	fclose(conntr);
	
	return -1;
#undef SKIPSPACES
#undef SKIPNOSPACES
}

int match_ip(char *ip,char *uname)
{
	FILE *cmd;
	char command[1024];

	snprintf(command,1024,"%s '%s' 2>/dev/null",MATCHCMD, ip);
	DBG("%s\n",command);
	if(  ( cmd=popen(command,"r") )==NULL) return -1;
	fscanf(cmd,"%s",uname);

	if (pclose(cmd)!=0) return -1;
	
	return 0;
}


void tohex(char *ip, char *out)
{
	struct in_addr tmp;

	if (inet_aton(ip,&tmp)!=0)
	{
		snprintf(out,18,"%lx",(unsigned long) tmp.s_addr);
	}
	else
	{
		strcpy(out,"error");
	}
}

void handle_request(int ifd,int ofd)
{

#define REPLY(x...) snprintf(outbuff,1024,## x); write(ofd,outbuff,strlen(outbuff))

	char buffer[BLEN]; /* We don't process bigger requests.*/
	char outbuff[1024];
	int len,lport, dport;
	char ipaddr[18];
	char uname[255];
	
	/* read request */
	memset(buffer,sizeof(char),BLEN);
	memset(ipaddr,sizeof(char),18);
	len=read(ifd,buffer,BLEN-1);
	/* I Love string parsing */
	
	sscanf(buffer,"%5d , %5d",&lport,&dport);
	DBG("lport %d, dport %d\n",lport,dport);	
	if ((lport<1) || (lport>65535) || (dport<1) || (dport>65535))
	{
		REPLY("%d , %d : ERROR : INVALID-PORT\r\n",lport,dport);
		_err("wrong port");
	}
	if (find_ip(lport,dport,ipaddr)==-1)
	{
		REPLY("%d , %d : ERROR : INVALID-USER\r\n",lport,dport);
		_err("uid not found");
	};
	if (match_ip(ipaddr,uname)==-1) tohex(ipaddr,uname);

	REPLY("%d , %d : USERID : UNIX : %s\r\n",lport,dport,uname);
	
	return;
#undef REPLY
}


int main()
{

	handle_request(0,1);
	return 0;
}


