#!/usr/bin/perl -w

use IO::Socket;
use Net::hostent;# for OO version of gethostbyaddr
use Net::MySQL;
use Validate::Net;
use Digest::MD5 qw(md5);
 
$PORT = 8850;# pick something not in use

$support_email = 'support@3d-computers.co.uk';
$web_url = 'http://dev.genestate.com/php/dyndns/';

$username = '';
$password = '';
$domain = '';
$newip = '';

$| = 1;
$EOL1 = "\012";
$EOL2 = "\015";

$mysql = Net::MySQL->new(
			hostname => '127.0.0.1',
			database => 'pdns',
			user	 => 'pdns',
			password => 'cr34t1v3'
			);
  
$server = IO::Socket::INET->new( Proto => 'tcp',
				LocalPort => $PORT,
				Listen=> SOMAXCONN,
				Reuse => 1);
 
die "can't setup server: $!\n" unless $server;

open (LOG, '>>server.log') || die "couldn't open file, $!\n";

$date = `date`;
chomp($date);
print LOG "[$date]: Server maiden.genestate.com:8850 accepting clients\n";
print "[$date]: Server maiden.genestate.com:8850 accepting clients\n";
   
while ($client = $server->accept())
{
	$client->autoflush(1);
	$hostinfo = gethostbyaddr($client->peeraddr);
	
	$date = `date`;
	chomp($date);
	printf "[$date]: Connect from %s\n", $hostinfo->name || $client->peerhost;
	printf LOG "[$date]: Connect from %s\n", $hostinfo->name || $client->peerhost;
	
	print $client "3d Computers Dynamic DNS Update Server\n";

	USERNAME:
	print $client "Username?\n";
	while ($input = <$client>)
	{
		chomp($input);
		$input =~ s/$EOL1//g;
		$input =~ s/$EOL2//g;
		
		if ($input eq '')
		{
			print $client "Empty username. Retry\n";
			goto USERNAME;
		}
		else
		{
			$username = $input;
			last;
		}
	}

	PASSWORD:
	print $client "Password?\n";
	while ($input = <$client>)
	{
		chomp($input);
		$input =~ s/$EOL1//g;
		$input =~ s/$EOL2//g;
		
		if ($input eq '')
		{
			print $client "Empty password. Retry\n";
			goto PASSWORD;
		}
		else
		{
			$password = $input;
			last;
		}
	}

	$mysql->query("SELECT uid FROM users WHERE username = '$username' AND passkey = ENCODE('$password','mykey')");
	$record_set = $mysql->create_record_iterator;
	$record = $record_set->each;

	$date = `date`;
	chomp($date);
	if ($record->[0] eq '')
	{
		printf "[%s]: Failed Login by %s from %s\n", $date, $username, $hostinfo->name || $client->peerhost;
		printf LOG "[%s]: Failed Login by %s from %s\n", $date, $username, $hostinfo->name || $client->peerhost;
		print $client "400: Invalid Login - Your username/password was invalid on this server. Please check and try again.\n";
		close $client;
	}
	else
	{
		printf "[%s]: Successful Login by %s from %s\n", $date, $username, $hostinfo->name || $client->peerhost;
		printf LOG "[%s]: Successful Login by %s from %s\n", $date, $username, $hostinfo->name || $client->peerhost;
		print $client "200: Login OK\n";
		$uid = $record->[0];
	}

	DOMAIN:
	print $client "Domain?\n";
	while ($input = <$client>)
	{
		chomp($input);
		$input =~ s/$EOL1//g;
		$input =~ s/$EOL2//g;
		
		if ($input eq '')
		{
			print $client "Empty domain name. Retry\n";
			goto DOMAIN;
		}
		else
		{
			$date = `date`;
			chomp($date);
			
			$domain = $input;
			$mysql->query("SELECT domain_id, uid FROM domains WHERE domain_name = '$domain'");
			$record_set = $mysql->create_record_iterator;
			$record = $record_set->each;

			$domain_id = $record->[0];
			$domain_uid = $record->[1];

			if ($domain_id eq '')
			{
				print $client "403: Invalid Domain - This domain does not exist. If you have not yet registered it with us, please go to $web_url\n";
				printf "[%s]: Non-existent Domain by %s from %s\n", $date, $username, $hostinfo->name || $client->peerhost;
				printf LOG "[%s]: Non-existent Domain by %s from %s\n", $date, $username, $hostinfo->name || $client->peerhost;
				close $client;
			}
			elsif($domain_uid ne $uid)
			{
				print $client "401 ($uid,$domain_uid): Invalid Domain - This domain is not owned by you. If this is incorrect, please email $support_email\n";
				printf "[%s]: Bad Domain Ownership by %s from %s\n", $date, $username, $hostinfo->name || $client->peerhost;
				printf LOG "[%s]: Bad Domain Ownership by %s from %s\n", $date, $username, $hostinfo->name || $client->peerhost;
				close $client;
			}
			else
			{
				print $client "201: Domain OK\n";
				printf "[%s]: Good Domain by %s from %s\n", $date, $username, $hostinfo->name || $client->peerhost;
				printf LOG "[%s]: Good Domain by %s from %s\n", $date, $username, $hostinfo->name || $client->peerhost;
			}
			last;
		}
	}

	NEWIP:
	print $client "New IP (or 'current' for current ip)?\n";
	while ($input = <$client>)
	{
		chomp($input);
		$input =~ s/$EOL1//g;
		$input =~ s/$EOL2//g;
		
		if ($input eq 'current')
		{
			$newip = $client->peerhost;
			last;
		}
		elsif (Validate::Net->ip($input))
		{
			$newip = $input;
			last;
		}
		else
		{
			print $client "Invalid IP address format - Retry\n";
			goto NEWIP;
		}
	
	}
	
	$date = `date`;
	chomp($date);
	printf "[%s]: Updated %s to %s by %s\n", $date, $domain, $newip, $username;
	printf LOG "[%s]: Updated %s to %s by %s\n", $date, $domain, $newip, $username;
	printf $client "Updated %s to %s\n", $domain, $newip;

	$mysql->query("UPDATE records SET content = '$newip' WHERE type = 'A'");
	$mysql->query("UPDATE records SET content = '$newip' WHERE type = 'MX'");

	
	
	close $client;
}

close LOG;
