#!/usr/bin/perl

use strict;
use Socket;

my $logfile = '/var/log/nidentd.log'; # logfile, must be writable by the user nidentd is running as
my $default = 'unknown'; # the userid to use when the masqueraded connection is from an unknown host

my $local_port;
my $remote_ip;
my $remote_port;


# get the request data
sysread(STDIN,my $input,128);
my $local_ip  = sprintf("%d.%d.%d.%d", unpack("x2 x2 C C C C x8", getsockname(STDOUT)));
my $remote_ip = sprintf("%d.%d.%d.%d", unpack("x2 x2 C C C C x8", getpeername(STDOUT)));
$input =~ s/[^0-9,]//g;
($local_port,$remote_port) = split(/,/,$input);

Log("Request: $local_ip:$local_port -> $remote_ip:$remote_port");

# basic error checking, is the client providing bogus info?
if ($local_port<1 || $local_port>65535 || $remote_port<1 || $remote_port>65535) {
	SendResponse("$local_port , $remote_port : ERROR : INVALID-PORT");
	exit;
}

# check the local connections first
open PNT, "/proc/net/tcp"; <PNT>;
while (<PNT>) {
	s/:/ /g;
	s/^\s*|\s*$//g;
	my @line = split /\s+/;
	my ($lp,$ra,$rp,$uid) = ($line[2],$line[3],$line[4],$line[11]);
	$ra = sprintf("%d.%d.%d.%d",hex(substr($ra,6,2)),hex(substr($ra,4,2)),hex(substr($ra,2,2)),hex(substr($ra,0,2)));
	if ((hex($lp) == $local_port) && ($ra eq $remote_ip) && (hex($rp) == $remote_port)) {
		my $userid = getpwuid($uid);
		Log("Local user: $userid");
		SendResponse("$local_port , $remote_port : USERID : UNIX : $userid");
		exit;
	}
}
close PNT;


# then the masqueraded ones
open PNI, "/proc/net/ip_conntrack";
while (<PNI>) {
	if (/^tcp.*?src=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) dst=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) sport=(\d{1,5}) dport=(\d{1,5})/) {
		my ($src,$dst,$sport,$dport) = ($1,$2,$3,$4);
		if (($dst == $remote_ip) && ($sport == $local_port) && ($dport == $remote_port)) {
			Log("Masquerade: $src:$sport -> $dst:$dport");
			if (my $host = gethostbyaddr(pack("C4",split(/\./,$src)),AF_INET)) {
				my ($host1) = $host =~ /([^\.]+)/;
				Log("Resolved $src to $host, using $host1");
				SendResponse("$local_port , $remote_port : USERID : UNIX : $host1");
			} else {
				Log("Could not resolve $src, using default");
				SendResponse("$local_port , $remote_port : USERID : UNIX : $default");
			}
			exit;
		}
	}
}
close PNI;

# can't find the proper user!
SendResponse("$local_port , $remote_port : ERROR : NO-USER");
exit;


# basic logging functionality
sub Log {
	my $msg = shift;
	if (open(LOG,">>$logfile")) {
		my $date = `date`;
		chop $date;
		print LOG "$date - [$$] - $msg\n";
		close LOG;
	}
}

# sending the actual response
sub SendResponse {
	my $msg = shift;
	Log("Response: $msg");
	print "$msg\n";
}
