<?php

/*
 *  A simple class for doing raw IRR queries. We used to ue IRRToolSet, but 
 *  decided to whip this up after not being able to find any network admin 
 *  who could successfully compile IRRToolSet out of the box. :)
 */
class IRRQuery {
	var $host;
	var $port;
	var $fp;
        var $caching;
	var $cache;

	function _multi_mode()
	{
		$this->_send("!!\n");

		return TRUE;
	}

	function _identify()
	{
		$this->_send("!nIRRPowerTools\n");
		$this->_response();

		return TRUE;
	}

	function _send($output)
	{
		if (fwrite($this->fp, $output) == FALSE) {
			status(STATUS_ERROR, "IRR Query - Unexpected write() error on socket.");
			return FALSE;
		}

		return TRUE;
	}

	function _readline()
	{
		if (($data = fgets($this->fp, 256)) == FALSE) {
			status(STATUS_ERROR, "IRR Query - Unexpected read() error on socket.");
			return NULL;
		}

		return $data;
	}

	function _response()
	{
		$data = "";
		$datalen = 0;

		$header = rtrim($this->_readline());

		switch ($header[0]) {
		    case "C":
			return TRUE;
		    case "D":
			status(STATUS_WARNING, "IRR Query - key not found");
			return FALSE;
		    case "E":
			return TRUE;
		    case "F":
			status(STATUS_WARNING, substr($header, 1));
			return FALSE;
		}

		$header = rtrim($header);

		if ($header[0] == 'A')
			$datalen = intval(substr($header,1));
		else {
			status(STATUS_ERROR, "IRR Query - Parse error looking for data length.");
			return FALSE;
		}

		while (strlen($data) < $datalen)
			$data .= $this->_readline();

		if ($datalen != strlen($data))
			status(STATUS_ERROR, "IRR Query - Data read doesn't match expected length.");

		$footer = $this->_readline();

		return rtrim($data);
	}

	/* Not sure why this is a good idea, but IRR still lets people register
         * classful routes with no /prefixlength. Scan for this and fix it. */
	function _classful_fix($routes)
	{
		for($i=0;$i<sizeof($routes);$i++) {
			if (strrpos($routes[$i], "/") == FALSE) {
				$octets = explode(".", $routes[$i]);
				$first = intval($octets[0]);

				if (($first) > 0 && ($first < 128))
					$length = "/8";
				else if (($first) > 0 && ($first < 192))
					$length = "/16";
				else if (($first) > 0 && ($first < 255))
					$length = "/24";
				else {
					status(STATUS_ERROR, "Invalid prefix: {$routes[$i]}");
					unset($routes[$i]);
				}

				$routes[$i] .= $length;
			}
		}

		return $routes;
	}

	function connect($host, $port)
	{
		$this->host = $host;
		$this->port = $port;

		$this->fp = fsockopen($host, $port, $errno, $errstr, 30);

		if (!$this->fp) {
			status_error(STATUS_ERROR, "{$errstr} ({$errno})");
			return FALSE;
		}

		$this->_multi_mode();
		$this->_identify();

		return $this;
	}

	function close()
	{
		$this->_send("!q\n");

		fclose($this->fp);
	}

	function set_cache($mode)
	{
		if ($mode) {
			$this->caching = 1;
		} else {
			$this->caching = 0;
		}
	}

	function clear_cache()
	{
		unset($this->cache);
	}

	function set_sources($sources)
	{
		$this->_send("!s-{$sources}\n");

		if (($results = $this->_response()) == FALSE) {
			return FALSE;
		}

		return explode(" ", $results);
	}

	function get_sources()
	{
		$this->_send("!s-lc\n");

		if (($results = $this->_response()) == FALSE) {
			return FALSE;
		}

		return $results;
	}

	function get_as_set($as_set)
	{
		$this->_send("!i{$as_set},1\n");

		if (($results = $this->_response()) == FALSE) {
			return FALSE;
		}

		return explode(" ", $results);
	}

	function get_route_set($route_set)
	{
		$this->_send("!i{$route_set},1\n");

		if (($results = $this->_response()) == FALSE) {
			return FALSE;
		}

		$results = $this->_classful_fix(explode(" ", $results));

		return $results;
	}

	function get_routes_by_origin($origin)
	{
		if ($this->caching) {
			if (isset($this->cache['origin'][$origin])) {
				/* printf("Cache hit: %s\n", $origin); */
				$this->cache['origin'][$origin]['hits']++;

				return $this->cache['origin'][$origin]['data'];
			}
		}


		$this->_send("!g{$origin}\n");

		if (($results = $this->_response()) == FALSE)
			return FALSE;

		$results = $this->_classful_fix(explode(" ", $results));

		if ($this->caching) {
			$this->cache['origin'][$origin]['data'] = $results;
			$this->cache['origin'][$origin]['time'] = time();
			$this->cache['origin'][$origin]['hits'] = 0;
		}

		return $results;
	}

	function get_routes_by_as_set($as_set)
	{
		$routes = array();

		$autnums = $this->get_as_set($as_set);

		for($i=0;$i<sizeof($autnums);$i++) {
			$results = $this->get_routes_by_origin($autnums[$i]);

			if ($results == FALSE)
				continue;

			$routes = array_merge($routes, $results);
		}

		natsort($routes);
		$routes = array_unique($routes);

		return array_values($routes);
	}

}

?>
