<?php
###############################################################################
# whois.php
# Watch My Domains SED v3
# (c) Softnik Technologies. All rights reserved.
###############################################################################

require_once('whois.generic.php');

###############################################################################

function getDomainPartsFromURL($url, &$tld, &$domain, &$subdomain, &$wserver)
{
	$pdo = init_db();
	if($pdo !== false)
	{
		$domain = $url;
		$url = idn_convert($domain);
		$parts = parse_url($url);
		if($parts !== false)
		{
			if(isset($parts['host']))
			{
				$domain = $parts['host'];
				$domain = idn_reconvert($domain);
			}
		}
		$tlds = $pdo->getTldsInfo();
		foreach($tlds as $info)
		{
			$tld = $info['tld'];
			$server = $info['server'];
			$lookfor = "." . $tld;
			$domaintail = mb_substr($domain, -mb_strlen($lookfor));
			if(!strcasecmp($domaintail, $lookfor))
			{ 
				$tld = ltrim($tld, ".");
				$domainhead = mb_substr($domain, 0, mb_strlen($domain)-strlen($tld)-1); 
				$domain_parts = explode(".", $domainhead);
				$domain = array_pop($domain_parts);
				$subdomain  = implode(".", $domain_parts);
				$wserver = $server;
				return true;
			}
		}
	}
	return false;
}

###############################################################################

function createWhoisQuery($prefix, $domain)
{
	$query = $domain;
	$prefix = trim($prefix);
	if($prefix != "")
	{
		$query = $prefix;
		if(strstr($query, "{D}"))
			$query = str_replace("{D}", $domain, $query);
		else if(strstr($query, "{d}"))
		{
			$pos = mb_strrpos($domain, ".");
			if($pos !== false)
			{
				$nameonly = mb_substr($domain, 0, $pos);
			$query = str_replace("{d}", $nameonly, $query);
			}
			else
				$query .= " " . $domain;
		}
		else
			$query .= " " . $domain;
	}
	return $query;
}

###############################################################################

function whoisLookupDomain($domain, $whoisserver)
{
	$pdo = init_db();
	if($pdo === false)
		return "";
	
	$whoisserver = strtolower($whoisserver);
	$domain = idn_convert($domain);
	$sinfo = $pdo->getWhoisServerInfo($whoisserver);
	if($sinfo !== false)
	{
		$proxy = trim($sinfo['proxy']);
		if($proxy != "")
		{
			$turl = str_replace("{D}", $domain, $proxy);
			$turl = str_replace("{S}", $whoisserver, $turl);
			
			// Handle URL of the form json:whois:http://......
			$jskey = "";
			$tp = strpos($turl, "json:");
			if($tp !== false && $tp == 0)
			{
				$tp1 = strpos($turl, ":http");
				if($tp1 !== false)
				{
					$jskey = substr($turl, $tp+5, $tp1-5);
					$turl = substr($turl, $tp1+1);
				}
			}
			
			$data = file_get_contents($turl);
			if($data === false)
				$data = "Error - unable to connect to $turl";
			else if($jskey != "")
			{
				$jdata = json_decode($data);
				if(isset($jdata[$jskey]))
					$data = $jdata[$jskey];
			}
			// August 2017
			// In some cases the proxy lookup may return specific errors and we
			// may want to revert to original port 43 whois. Since we don't know
			// when this could happen, we will use a custom hook function
			// to make the decision. The "validate_whois_proxy_output" function
			// will look at the $data and return FALSE if the regular port 43 
			// whois should happen.
			if(function_exists("validate_whois_proxy_output"))
			{
				if(validate_whois_proxy_output($domain, $whoisserver, $proxy, $data))
					return strip_tags($data);
			}
			else
				return strip_tags($data);
		}
	}
	
	$query = createWhoisQuery($sinfo['query'], $domain);	
	$m_connectiontimeout = 10;
	$m_sockettimeout = 30;
	$port = $sinfo['port'] > 0 ? $sinfo['port'] : 43;
	$bannedtext = $sinfo['bannedtext'];
	
	$data = "";
	if($query != '' && $whoisserver != '' ) 
	{
		$pdo->setLastConnectTimeForExternalServerToNow($whoisserver);
		$hip = gethostbyname($whoisserver);
		$fp = @fsockopen($hip, $port, $errno, $errstr, $m_connectiontimeout);
		if( $fp )
		{
			@fputs($fp, $query."\r\n");
			@socket_set_timeout($fp, $m_sockettimeout);
			while( !@feof($fp) )
				$data .= @fread($fp, 4096);
			@fclose($fp);
		}
		else
		{
			$extramsg = "";
			if($errno == 13)
				$extramsg = "Please <b>check if SELinux is enabled</b>. ";
			$extramsg .= "You may want to see <a target=\"_blank\" href=\"https://domainpunch.com/sed/guide/troubleshooting.php\">the trouble shooting page</a>";
			$data = "Error - unable to connect to $whoisserver.\n\n$errstr.\n\n$extramsg";
		}
	}
	
	if(strlen($data) > 0 && strlen($bannedtext) > 0)
	{
		if(stristr($data, $bannedtext) !== false)
			$pdo->setBlockedFromTimestampForExternalServerToNow($whoisserver);
	}
	
	return $data;
}

###############################################################################
# Sort of a hack. Can fail for many second level country code domains. This is acceptable because the
# purpose of this function is to mitigate bad user inputs (www.domain.com instead of domain.com)
# as much as possible. Also, this will be used only if it is manually configured in config.php.

function getRealDomainName($fulldomain)
{
	$fix_host_domain_names = getConfigData('fix_host_domain_names', null);
	if($fix_host_domain_names === true)
	{
		$newdomain = str_replace("www.", "", $fulldomain);
		if(substr_count($newdomain, ".") != 0 && $newdomain != "com.au" && $newdomain != "net.au" && $newdomain != "co.uk" && $newdomain != "co.in")
			return $newdomain;
	}
	return $fulldomain;
}

###############################################################################
// Will lookup the registrar whois server

function doDomainRegistrarWhois($domain_name, $rserver, $spit_out=false)
{
	$pdo = init_db();
	if($pdo === false)
		return false;
	
	// Make sure that only actual domain is passed.
	// Things like www.domain.com will create problems.
	$fulldomain = $domain_name; //$domain . "." . $tld;
	
	// Is the server ready to allow connection?
	if(!$pdo->isOkToConnectoToExternalServer($rserver))
		return false;
	
	$ludomain = getRealDomainName($fulldomain);
	$whois02 = whoisLookupDomain($ludomain, $rserver);
	if($whois02 == "")
	{
		$whois02 = "Whois returned an empty result!";
		$requeue_on_empty_whois = getConfigData('requeue_on_empty_whois', null);
		if($requeue_on_empty_whois === true)
			return false;
	}

	$data_array02 = array();
	do_whois_post2ndlookup($fulldomain, $rserver, $whois02, $data_array02);
	if(is_array($data_array02))
	{
		if(function_exists("sedf_after_registrar_whois_check"))
			sedf_after_registrar_whois_check($fulldomain, $rserver, $whois02, $data_array02, $spit_out);
		if(isDataHistoryEnabled("whois"))
			$pdo->updateDataHistory($fulldomain,intval(LOOKUP_SEC_DOMAIN_WHOIS), $data_array02['registrar_whois']);
		update_domain_table($data_array02, $fulldomain);
		if($spit_out)
		{
			debug_out_domain_data($data_array02);
		}
		return true;
	}
	else
	{
		$wlines     = explode("\n", $whois02);
		$rwdata = implode("<br>", $wlines);
		if(preg_match('!!u', $rwdata) === false)
			$rwdata = utf8_encode($rwdata);
		$data_array['registrar_whois']  = $rwdata;
		update_domain_table($data_array, $domain_name);
		return true;
	}
}

###############################################################################
// Will lookup the registrar whois server

function doDomainRegistryWhois($domain_name, $spit_out=false)
{
    $pdo = init_db();
	if($pdo === false)
		return false;
        
	$dpcheck = getDomainPartsFromURL($domain_name, $tld, $domain, $subdomain, $wserver);
	if($dpcheck === false)
	{
		$wserver = findAndConfigureWhoisServer($domain_name);
		if($wserver != "" && $wserver != "unknown")
			$dpcheck = true;
	}
	if($dpcheck === true)
	{
		// Make sure that only actual domain is passed.
		// Things like www.domain.com will create problems.
		$fulldomain = $domain_name; //$domain . "." . $tld;
		
		// Is the server ready to allow connection?
		if(!$pdo->isOkToConnectoToExternalServer($wserver))
		{
			if($spit_out)
				echo "<p>Server ($wserver) not ready.</p>";
			return false;
		}
		
		$ludomain = getRealDomainName($fulldomain);
		$whois01 = whoisLookupDomain($ludomain, $wserver);
		
		if($whois01 == "")
		{
			$whois01 = "Whois returned an empty result!";
			$requeue_on_empty_whois = getConfigData('requeue_on_empty_whois', null);
			if($requeue_on_empty_whois === true)
				return false;
		}
	
		$data_array01 = array();
		doWhoisPostProcessing($fulldomain, $wserver, $whois01, $data_array01, $deeplookup, $secserver);
		if(is_array($data_array01))
		{
			if(function_exists("sedf_after_registry_whois_check"))
				sedf_after_registry_whois_check($fulldomain, $wserver, $whois01, $data_array01, $spit_out);
			if(isDataHistoryEnabled("whois"))
				$pdo->updateDataHistory($fulldomain, intval(LOOKUP_DOMAIN_WHOIS), $data_array01['registry_whois']);
			reset_domain_table($fulldomain);
			update_domain_table($data_array01, $fulldomain);
			if($spit_out)
			{
				debug_out_domain_data($data_array01);
			}
		}
		
		if($deeplookup)
		{
			$status = doDomainRegistrarWhois($domain_name, $secserver, $spit_out);
			if($status === false)
			{
				// Add the registrar lookup to the queue
				$sid = $pdo->getSingleEntry($pdo->getDomainTableName(), "domain", $domain_name, "sid"); 
				$pdo->addToRegistrarWhoisLookupQueue($sid, $secserver, 0);
			}
		}
		return true;
	}
	else
	{
		$whoisdata  = "\nTLD not setup\n";
		$wlines     = explode("\n", $whoisdata);
		$data_array['status']          = "Setup Error";
		$data_array['lookedup']        = date("Y-m-d H:i:s");
		$data_array['whois_server']    = "unknown";
		$data_array['registry_whois']  = implode("<br>", $wlines);
		update_domain_table($data_array, $domain_name);
		return true;
	}
}

###############################################################################

function findAndConfigureWhoisServer($domain_name)
{
	$winfo = findWhoisServerFromIANA($domain_name);
    $wserver = isset($winfo['whoisserver']) ? $winfo['whoisserver'] : "";
	if($wserver != "" && $wserver != "unknown")
        set_whois_server_for_tld($winfo['tld'], $wserver);
    return $wserver;
}

###############################################################################

function whoisLookupIP($ip, $whoisserver, $port=43)
{
	$whoisserver = strtolower($whoisserver);
	$query = trim($ip);
	$validip = filter_var($query, FILTER_VALIDATE_IP);
	if($whoisserver == "whois.arin.net" && $validip == $query && $query != "")
		$query = "n " . $query;
	else if($whoisserver == "whois.arin.net" && $query != "")
		$query = "z " . $query;
	
	$m_connectiontimeout = 10;
	$m_sockettimeout = 30;
	
	$data = "";
	if($query != '' && $whoisserver != '' ) 
	{
		$fp = @fsockopen($whoisserver, $port, $errno, $errstr, $m_connectiontimeout);
		if( $fp )
		{
			@fputs($fp, $query."\r\n");
			@socket_set_timeout($fp, $m_sockettimeout);
			while( !@feof($fp) )
				$data .= @fread($fp, 4096);
			@fclose($fp);
		}
		else
			$data = "Error - unable to connect to $whoisserver";
	}
	
	return $data;
}

###############################################################################

function doWhoisForIP($ip)
{
	$whoisserver = "whois.arin.net";
	$data = whoisLookupIP($ip, $whoisserver);
	if(stristr($data, "ReferralServer:"))
	{
		$port = 43;
		$p1 = Trim(get_string_between($data, "ReferralServer:", "\n"));
		$p1 = str_replace("rwhois://", "", $p1);
		$p1 = str_replace("whois://", "", $p1);
		$s1 = strpos($p1, ":");
		if($s1 !== false)
		{
			$port = substr($p1, $s1+1);
			$p1 = substr($p1, 0, strlen($p1)-strlen($port)-1);
		}
		$whoisserver = $p1;
		$ndata = whoisLookupIP($ip, $whoisserver, $port);
		if(strlen($ndata) > 200)
			$data = $ndata;
	}
	else if(stristr($data, "Allocated to APNIC"))
	{
		$whoisserver = "whois.apnic.net";
		$data = whoisLookupIP($ip, $whoisserver);
	}
	else if(stristr($data, "Allocated to RIPE"))
	{
		$whoisserver = "whois.ripe.net";
		$data = whoisLookupIP($ip, $whoisserver);
	}
	else if(stristr($data, "Allocated to AfriNIC"))
	{
		$whoisserver = "whois.afrinic.net";
		$data = whoisLookupIP($ip, $whoisserver);
	}
	else if(stristr($data, "Allocated to LACNIC"))
	{
		$whoisserver = "whois.lacnic.net";
		$data = whoisLookupIP($ip, $whoisserver);
	}
	else if(stristr($data, "NetHandle:"))
	{
		$handle = Trim(get_string_between($data, "NetHandle:", "\n"));
		$data = whoisLookupIP($handle, $whoisserver);
	}
	else
	{
		$dcopy = $data;
		$netblocks = array();
		while(1)
		{
			$p1 = Trim(get_string_between($dcopy, "(NET", ")", true));
			if($p1 != "")
			{
				$netblocks[] = substr($p1, 1, strlen($p1)-2);
				$dcopy = str_replace($p1, "", $dcopy);
			}
			else
				break;
		}
		$count = count($netblocks);
		if($count)
		{
			$lookup = $netblocks[$count-1];
			$data = whoisLookupIP($lookup, $whoisserver);
		}
	}
	$data_array = array();
	generic_ipwhois_parser($whoisserver, $data, $data_array);
	return $data_array;
}

###############################################################################

function doWhoisForDomainIP($domain_name, $spit_out=false)
{
	$pdo = init_db();
	if($pdo === false)
		return false;
	
	$ip = $pdo->getSingleEntry($pdo->getDomainTableName(), "domain", $domain_name, "ip");
	if($ip === false || $ip == "")
	{
		$sid = $pdo->getSingleEntry($pdo->getDomainTableName(), "domain", $domain_name, "sid"); 
		if($sid > 0)
		{
			do_ip_lookup($domain_name);
			$ip = $pdo->getSingleEntry($pdo->getDomainTableName(), "domain", $domain_name, "ip");
		}
	}
	
	if($ip != "" && $ip != "-" && $ip != "error")
	{
		$data_array = doWhoisForIP($ip);
		if($spit_out)
		{
			debug_out_domain_data($data_array);
		}
		update_domain_table($data_array, $domain_name);
	}
	else 
	{
		if($spit_out)
			echo $ip . " " . $domain_name . "<br>";
	}
}

###############################################################################

function parseWhoisAgain($domain_name, $spit_out=false)
{
	if(isset($_REQUEST['debug']))
		$spit_out = true;
	
	$dpcheck = getDomainPartsFromURL($domain_name, $tld, $domain, $subdomain, $wserver);
	if($dpcheck === false)
	{
		$wserver = findAndConfigureWhoisServer($domain_name);
		if($wserver != "" && $wserver != "unknown")
			$dpcheck = true;
	}
	if($dpcheck === true)
	{
		$whoisdata = get_whoisdata_for_domain($domain_name);
		if(isset($whoisdata['ip_whois']))
		{
			$data_array = array();
			generic_ipwhois_parser("", $whoisdata['ip_whois'], $data_array);
			if(is_array($data_array))
			{
				unset($data_array['ip_whois_at']);
				unset($data_array['ip_whois']);
				if(count($data_array))
				{
					update_domain_table($data_array, $domain_name);
					if($spit_out)
						debugPrintArray($data_array);
				}
			}
		}
		$deeplookup = false;
		if(isset($whoisdata['registry_whois']))
		{
			$data_array_01 = array();
			doWhoisPostProcessing($domain_name, $wserver, $whoisdata['registry_whois'], $data_array_01, $deeplookup, $secserver);
			if(is_array($data_array_01))
			{
				unset($data_array_01['lookedup']);
				unset($data_array_01['registry_whois']);
				update_domain_table($data_array_01, $domain_name);
				if($spit_out)
					debugPrintArray($data_array_01);
			}
		}
		if($deeplookup && isset($whoisdata['registrar_whois']))
		{
			$data_array_02 = array();
			do_whois_post2ndlookup($domain_name, $secserver, $whoisdata['registrar_whois'], $data_array_02);
			if(is_array($data_array_02))
			{
				unset($data_array_02['lookedup']);
				unset($data_array_02['registrar_whois']);
				update_domain_table($data_array_02, $domain_name);
				if($spit_out)
					debugPrintArray($data_array_02);
			}
		}
	}
}

###############################################################################
?>
