[feladat @ 246]
authorrejo
Thu, 24 Apr 2008 21:07:27 +0000
changeset 140 e68c3d6094d1
parent 139 98ce0ffae5b8
child 141 1ede5203910d
[feladat @ 246] Improvement of DNS validation code. See also [wiki:Documentation documentation on standards]. Closes ticket:6, trailing dot not allowed in content field (it is now stripped automagically as PowerDNS doesnt want it). Closes ticket:40, error shown if priority field was empty and record type was not MX (prio field is now ignored if record type is not MX).
add_record.php
delete_record.php
docs/i18n-template-php.pot
edit.php
edit_record.php
inc/dns.inc.php
inc/error.inc.php
inc/record.inc.php
locale/nl_NL/LC_MESSAGES/messages.mo
locale/nl_NL/LC_MESSAGES/nl.po
--- a/add_record.php	Wed Apr 16 17:53:40 2008 +0000
+++ b/add_record.php	Thu Apr 24 21:07:27 2008 +0000
@@ -61,7 +61,7 @@
 
 $user_is_zone_owner = verify_user_is_owner_zoneid($zone_id);
 $zone_type = get_domain_type($zone_id);
-$zone_name = get_domain_name_from_id($zone_id);
+$zone_name = get_zone_name_from_id($zone_id);
 
 if ($_POST["commit"]) {
 	if ( $zone_type == "SLAVE" || $perm_content_edit == "none" || $perm_content_edit == "own" && $user_is_zone_owner == "0" ) {
--- a/delete_record.php	Wed Apr 16 17:53:40 2008 +0000
+++ b/delete_record.php	Thu Apr 24 21:07:27 2008 +0000
@@ -48,7 +48,7 @@
 		}
 	} else {
 		$zone_id = recid_to_domid($record_id);
-		$zone_name = get_domain_name_from_id($zone_id);
+		$zone_name = get_zone_name_from_id($zone_id);
 		$user_is_zone_owner = verify_user_is_owner_zoneid($zone_id);
 		$record_info = get_record_from_id($record_id);
 	
--- a/docs/i18n-template-php.pot	Wed Apr 16 17:53:40 2008 +0000
+++ b/docs/i18n-template-php.pot	Thu Apr 24 21:07:27 2008 +0000
@@ -534,8 +534,20 @@
 msgid "Invalid hostname."
 msgstr ""
 
-#: inc/error.inc.php:65
-msgid "Invalid record type! You should not even been able to get that here."
+
+msgid "You have invalid characters in your hostname."
+msgstr ""
+
+msgid "A hostname can not start or end with a dash."
+msgstr ""
+
+msgid "Given hostname or one of the labels is too short or too long."
+msgstr ""
+
+msgid "Given hostname has too many slashes."
+msgstr ""
+
+msgid "Unknown record type."
 msgstr ""
 
 #: inc/error.inc.php:66
@@ -554,18 +566,28 @@
 msgid "This is not a valid CNAME. Did you assign an MX or NS record to the record?"
 msgstr ""
 
-#: inc/error.inc.php:70
-msgid "You can not point a NS record to a CNAME record. Remove or rename the CNAME record first or take another name."
+msgid "You can not point a NS or MX record to a CNAME record. Remove or rame the CNAME record first, or take another name."
+msgstr ""
+
+msgid "Invalid value for name field of SOA record. It should be the name of the zone."
+msgstr ""
+
+msgid "Invalid value for content field of HINFO record."
+msgstr ""
+
+msgid "Invalid value for content field of TXT record."
+msgstr ""
+
+msgid "Invalid value for TTL field. It should be numeric."
+msgstr ""
+
+msgid "Invalid value for prio field. It should be numeric."
 msgstr ""
 
 #: inc/error.inc.php:71
 msgid "NS records must be a hostnames."
 msgstr ""
 
-#: inc/error.inc.php:72
-msgid "You can not point a MX record to a CNAME record. Remove or rename the CNAME record first or take another name."
-msgstr ""
-
 #: inc/error.inc.php:73
 msgid "A prio field should be numeric."
 msgstr ""
--- a/edit.php	Wed Apr 16 17:53:40 2008 +0000
+++ b/edit.php	Thu Apr 24 21:07:27 2008 +0000
@@ -72,7 +72,7 @@
 $domain_type=get_domain_type($zone_id);
 $record_count=count_zone_records($zone_id);
 
-echo "   <h2>" . _('Edit zone') . " \"" . get_domain_name_from_id($zone_id) . "\"</h2>\n";
+echo "   <h2>" . _('Edit zone') . " \"" . get_zone_name_from_id($zone_id) . "\"</h2>\n";
 
 if ( $perm_view == "none" || $perm_view == "own" && $user_is_zone_owner == "0" ) {
 	error(ERR_PERM_VIEW_ZONE);
--- a/edit_record.php	Wed Apr 16 17:53:40 2008 +0000
+++ b/edit_record.php	Thu Apr 24 21:07:27 2008 +0000
@@ -38,7 +38,7 @@
 
 $user_is_zone_owner = verify_user_is_owner_zoneid($zid);
 $zone_type = get_domain_type($zid);
-$zone_name = get_domain_name_from_id($zid);
+$zone_name = get_zone_name_from_id($zid);
 
 if ($_POST["commit"]) {
 	if ( $zone_type == "SLAVE" || $perm_content_edit == "none" || $perm_content_edit == "own" && $user_is_zone_owner == "0" ) {
--- a/inc/dns.inc.php	Wed Apr 16 17:53:40 2008 +0000
+++ b/inc/dns.inc.php	Thu Apr 24 21:07:27 2008 +0000
@@ -19,381 +19,82 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-function validate_input($zid, $type, &$content, &$name, &$prio, &$ttl)
-{
-	global $db;
-	$domain = get_domain_name_from_id($zid);
-	$nocheck = array('SOA', 'HINFO', 'NAPTR', 'URL', 'MBOXFW', 'TXT');
-	$hostname = false;
-	$ip4 = false;
-	$ip6 = false;
+function validate_input($zid, $type, &$content, &$name, &$prio, &$ttl) {
+
+	$zone = get_zone_name_from_id($zid);				// TODO check for return
 
-	if(!in_array(strtoupper($type), $nocheck)) {
-		if(!is_valid_ip6($content)) {
-			if(!is_valid_ip($content)) {
-				if(!is_valid_hostname($content)) {
-					error(ERR_DNS_CONTENT);
-					return false;
-				} else {
-					$hostname = true;
-				}
-			} else {
-				$ip4 = true;
-			}
+	if (!(preg_match("/$zone$/i", $name))) {
+		if (isset($name) && $name != "") {
+			$name = $name . "." . $zone;
 		} else {
-			$ip6 = true;
-		}
-	}
-
-	// Prepare total hostname.
-	if ($name == '*') {
-		$wildcard = true;
-	} else {
-		$wildcard = false;
-	}
-
-	if (preg_match("/@/", $name)) {
-		$name = $domain ;
-	} elseif ( !(preg_match("/$domain$/i", $name))) {
-
-		if ( isset($name) && $name != "" ) {
-			$name = $name . "." . $domain ;
-		} else {
-			$name = $domain ;
+			$name = $zone;
 		}
 	}
+	
+	switch ($type) {
 
-	if(!$wildcard) {
-		if(!is_valid_hostname($name)) {
-			error(ERR_DNS_HOSTNAME);
-			return false;
-		}
-	}
+		case "A":
+			if (!is_valid_ipv4($content)) return false;
+			break;
+
+		case "AAAA":
+			if (!is_valid_ipv6($content)) return false;
+			break;
 
-	// Check record type (if it exists in our allowed list.
-	if (!in_array(strtoupper($type), get_record_types())) {
-		error(ERR_DNS_RECORDTYPE);
-		return false;
-	}
+		case "CNAME":
+			if (!is_valid_rr_cname_name($name)) return false;
+			if (!is_valid_hostname_fqdn($content,0)) return false;
+			break;
 
-	// Start handling the demands for the functions.
-	// Validation for IN A records. Can only have an IP. Nothing else.
-	if ($type == 'A' && !$ip4) {
-		error(ERR_DNS_IPV4);
-		return false;
-	}
+		case "HINFO":
+			if (!is_valid_rr_hinfo_content($content)) return false;
+			break;
+
+		case "MX":
+			if (!is_valid_hostname_fqdn($contenti,0)) return false;
+			if (!is_valid_mx_or_ns_target($content)) return false;
+			break;
 
-	if ($type == 'AAAA' && !$ip6) {
-		error(ERR_DNS_IPV6);
-		return false;
-	}
+		case "NS":
+			if (!is_valid_hostname_fqdn($content,0)) return false;
+			if (!is_valid_mx_or_ns_target($content)) return false;
+			break;
+
+		case "PTR":
+			if (!is_valid_hostname_fqdn($content,0)) return false;
+			break;
+
+		case "SOA":
+			if (!is_valid_rr_soa_name($name,$zone)) return false;
+			if (!is_valid_rr_soa_content($content)) return false;
+			break;
 
-	if ($type == 'CNAME' && $hostname) {
-		if(!is_valid_cname($name)) {
-			error(ERR_DNS_CNAME);
+		case "TXT":
+			if (!is_valid_rr_txt_content($content)) return false;
+			break;
+
+		case "MBOXFW":
+		case "NAPTR":
+		case "URL":
+			// These types are supported by PowerDNS, but there is not
+			// yet code for validation. Validation needs to be added 
+			// for these types. One Day Real Soon Now. [tm]
+			break;
+
+		default:
+			error(ERR_DNS_RR_TYPE);
 			return false;
-		}
-	}
-
-	if ($type == 'NS') {
-		$status = is_valid_ns($content, $hostname);
-		if($status == -1) {
-			error(ERR_DNS_NS_HNAME);
-			return false;
-		}
-		elseif($status == -2) {
-			error(ERR_DNS_NS_CNAME);
-			return false;
-		}
 	}
 
-	if ($type == 'SOA' && !is_valid_rr_soa($content)) {
-		return false;
-	}
-
-	// HINFO and TXT require no validation.
-
-	if ($type == 'URL') {
-		if(!is_valid_url($content)) {
-			error(ERR_INV_URL);
-			return false;
-		}
-	}
-	if ($type == 'MBOXFW') 	{
-		if(!is_valid_mboxfw($content)) {
-			error(ERR_INV_EMAIL);
-			return false;
-		}
-	}
-
-	// NAPTR has to be done.
-	// Do we want that?
-	// http://www.ietf.org/rfc/rfc2915.txt
-	// http://www.zvon.org/tmRFC/RFC2915/Output/chapter2.html
-	// http://www.zvon.org/tmRFC/RFC3403/Output/chapter4.html
-
-	// See if the prio field is valid and if we have one.
-	// If we dont have one and the type is MX record, give it value '10'
-	if($type == 'NAPTR') {
+	if (!is_valid_hostname_fqdn($name,1)) return false;
+	if (!is_valid_rr_prio($prio,$type)) return false;
+	if (!is_valid_rr_ttl($ttl)) return false;
 
-	}
-	
-	if($type == 'MX') {
-		if($hostname) {
-			$status = is_valid_mx($content, $prio);
-			if($status == -1) {
-				error(ERR_DNS_MX_CNAME);
-				return false;
-			}
-			elseif($status == -2) {
-				error(ERR_DNS_MX_PRIO);
-				return false;
-			}
-		} else {
-			error( _('If you specify an MX record it must be a hostname.') ); // TODO make error
-			return false;
-		}
-	} else {
-		$prio=0;
-	}
-	// Validate the TTL, it has to be numeric.
-	$ttl = (!isset($ttl) || !is_numeric($ttl)) ? $dns_ttl : $ttl;
-	
-	return true;
-}
-
-/*
- * Validatis a CNAME record by the name it will have and its destination
- *
- */
-function is_valid_cname($dest)
-{
-	/*
-	 * This is really EVIL.
-	 * If the new record (a CNAME) record is being pointed to by a MX record or NS record we have to bork.
-	 * this is the idea.
-	 *
-	 * MX record: blaat.nl MX mail.blaat.nl
-	 * Now we look what mail.blaat.nl is
-	 * We discover the following:
-	 * mail.blaat.nl CNAME bork.blaat.nl
-	 * This is NOT allowed! mail.onthanet.nl can not be a CNAME!
-	 * The same goes for NS. mail.blaat.nl must have a normal IN A record.
-	 * It MAY point to a CNAME record but its not wished. Lets not support it.
-	 */
-
-	global $db;
-
-	// Check if there are other records with this information of the following types.
-	// P.S. we might add CNAME to block CNAME recursion and chains.
-	$blockedtypes = " AND (type='MX' OR type='NS')";
-
-	$cnamec = "SELECT type, content FROM records WHERE content=".$db->quote($dest) . $blockedtypes;
-	$result = $db->query($cnamec);
-
-	if($result->numRows() > 0)
-	{
-		return false;
-		// Lets inform the user he is doing something EVIL.
-		// Ok we found a record that has our content field in their content field.
-	}
 	return true;
 }
 
-
-/*
- * Checks if something is a valid domain.
- * Checks for domainname with the allowed characters <a,b,...z,A,B,...Z> and - and _.
- * This part must be followed by a 2 to 4 character TLD.
- */
-function is_valid_domain($domain)
-{
-	if ((eregi("^[0-9a-z]([-.]?[0-9a-z])*\\.[a-z]{2,4}$", $domain)) && (strlen($domain) <= 128))
-	{
-		return true;
-	}
-	return false;
-}
-
-
-/*
- * Validates if given hostname is allowed.
- * returns true if allowed.
- */
-function is_valid_hostname($host)
-{
-	if(count(explode(".", $host)) == 1)
-	{
-		return false;
-	}
-
-	// Its not perfect (in_addr.int is allowed) but works for now.
-
-	if(preg_match('!(ip6|in-addr).(arpa|int)$!i', $host))
-	{
-		if(preg_match('!^(([A-Z\d]|[A-Z\d][A-Z\d-]*[A-Z\d])\.)*[A-Z\d]+$!i', $host))
-		{
-			return true;
-		}
-		return false;
-	}
-
-	// Validate further.
-	return (preg_match('!^(([A-Z\d]|[A-Z\d][A-Z\d-]*[A-Z\d])\.)*[A-Z\d]+$!i', $host)) ? true : false;
-}
-
-
-/*
- * Validates an IPv4 IP.
- * returns true if valid.
- */
-function is_valid_ip($ip)
-{
-	// Stop reading at this point. Scroll down to the next function...
-	// Ok... you didn't stop reading... now you have to rewrite the whole function! enjoy ;-)
-	// Trance unborked it. Twice even!
-	return ($ip == long2ip(ip2long($ip))) ? true : false;
-
-}
-
-
-/*
- * Validates an IPv6 IP.
- * returns true if valid.
- */
-function is_valid_ip6($ip)
-{
-	// Validates if the given IP is truly an IPv6 address.
-	// Precondition: have a string
-	// Postcondition: false: Error in IP
-	//                true: IP is correct
-	// Requires: String
-	// Date: 10-sep-2002
-	if(preg_match('!^[A-F0-9:]{1,39}$!i', $ip) == true)
-	{
-		// Not 3 ":" or more.
-		$p = explode(':::', $ip);
-		if(sizeof($p) > 1)
-		{
-			return false;
-		}
-		// Find if there is only one occurence of "::".
-		$p = explode('::', $ip);
-		if(sizeof($p) > 2)
-		{
-			return false;
-		}
-		// Not more than 8 octects
-		$p = explode(':', $ip);
-
-		if(sizeof($p) > 8)
-		{
-			return false;
-		}
+function is_valid_hostname_fqdn($hostname, $wildcard) {
 
-		// Check octet length
-		foreach($p as $checkPart)
-		{
-			if(strlen($checkPart) > 4)
-			{
-				return false;
-			}
-		}
-		return true;
-	}
-	return false;
-}
-
-
-/*
- * FANCY RECORD.
- * Validates if the fancy record mboxfw is an actual email address.
- */
-function is_valid_mboxfw($email)
-{
-	return is_valid_email($email);
-}
-
-
-/*
- * Validates MX records.
- * an MX record cant point to a CNAME record. This has to be checked.
- * this function also sets a proper priority.
- */
-function is_valid_mx($content, &$prio)
-{
-	global $db;
-	// See if the destination to which this MX is pointing is NOT a CNAME record.
-	// Check inside our dns server.
-	if($db->queryOne("SELECT count(id) FROM records WHERE name=".$db->quote($content)." AND type='CNAME'") > 0)
-	{
-		return -1;
-	}
-	else
-	{
-		// Fix the proper priority for the record.
-		// Bugfix, thanks Oscar :)
-		if(!isset($prio))
-		{
-			$prio = 10;
-		}
-		if(!is_numeric($prio))
-		{
-			if($prio == '')
-			{
-				$prio = 10;
-			}
-			else
-			{
-				return -2;
-			}
-		}
-	}
-	return 1;
-}
-
-/*
- * Validates NS records.
- * an NS record cant point to a CNAME record. This has to be checked.
- * $hostname directive means if its a hostname or not (this to avoid that NS records get ip fields)
- * NS must have a hostname, it is not allowed to have an IP.
- */
-function is_valid_ns($content, $hostname)
-{
-	global $db;
-	// Check if the field is a hostname, it MUST be a hostname.
-	if(!$hostname)
-	{
-		return -1;
-		// "an IN NS field must be a hostname."
-	}
-
-	if($db->queryOne("SELECT count(id) FROM records WHERE name=".$db->quote($content)." AND type='CNAME'") > 0)
-	{
-		return -2;
-		// "You can not point a NS record to a CNAME record. Remove/rename the CNAME record first or take another name."
-
-	}
-	return 1;
-}
-
-
-function is_valid_hostname_label($hostname_label) {
-
-        // See <https://www.poweradmin.org/trac/wiki/Documentation/DNS-hostnames>.
-        if (!preg_match('/^[a-z\d]([a-z\d-]*[a-z\d])*$/i',$hostname_label)) {
-		return false;
-        } elseif (preg_match('/^[\d]+$/i',$hostname_label)) {
-                return false;
-        } elseif ((strlen($hostname_label) < 2) || (strlen($hostname_label) > 63)) {
-                return false;
-        }
-        return true;
-}
-
-function is_valid_hostname_fqdn($hostname) {
-
-        // See <https://www.poweradmin.org/trac/wiki/Documentation/DNS-hostnames>.
 	global $dns_strict_tld_check;
 	global $valid_tlds;
 
@@ -407,31 +108,168 @@
         $hostname_labels = explode ('.', $hostname);
         $label_count = count($hostname_labels);
 
+	foreach ($hostname_labels as $hostname_label) {
+		if ($wildcard == 1 && !isset($first)) {
+			if (!preg_match('/^(\*|[\w-\/]+)$/',$hostname_label)) { error(ERR_DNS_HN_INV_CHARS); return false; }
+			$first = 1;
+		} else {
+			if (!preg_match('/^[\w-\/]+$/',$hostname_label)) { error(ERR_DNS_HN_INV_CHARS); return false; }
+		}
+		if (substr($hostname_label, 0, 1) == "-") { error(ERR_DNS_HN_DASH); return false; }
+		if (substr($hostname_label, -1, 1) == "-") { error(ERR_DNS_HN_DASH); return false; }
+		if (strlen($hostname_label) < 1 || strlen($hostname_label) > 63) { error(ERR_DNS_HN_LENGTH); return false; }
+	}
+	
+	if ($hostname_labels[$label_count-1] == "arpa" && (substr_count($hostname_labels[0], "/") == 1 XOR substr_count($hostname_labels[1], "/") == 1)) {
+		if (substr_count($hostname_labels[0], "/") == 1) { 
+			$array = explode ("/", $hostname_labels[0]);
+		} else {
+			$array = explode ("/", $hostname_labels[1]);
+		}
+		if (count($array) != 2) { error(ERR_DNS_HOSTNAME) ; return false; }
+		if (!is_numeric($array[0]) || $array[0] < 0 || $array[0] > 255) { error(ERR_DNS_HOSTNAME) ; return false; }
+		if (!is_numeric($array[1]) || $array[1] < 25 || $array[1] > 31) { error(ERR_DNS_HOSTNAME) ; return false; }
+	} else {
+		if (substr_count($hostname, "/") > 0) { error(ERR_DNS_HN_SLASH) ; return false; }
+	}
+	
 	if ($dns_strict_tld_check == "1" && !in_array($hostname_labels[$label_count-1], $valid_tlds)) {
-		error(ERR_DNS_INV_TLD);
-		return false;
+		error(ERR_DNS_INV_TLD); return false;
 	}
 
-	if ($hostname_labels[$label_count-1] == "arpa") {
-		// FIXME
-	} else {
-		foreach ($hostname_labels as $hostname_label) {
-			if (!is_valid_hostname_label($hostname_label)) {
-				error(ERR_DNS_HOSTNAME);
-				return false;
-			}
+	return true;
+}
+
+function is_valid_ipv4($ipv4) {
+
+// 20080424/RZ: The current code may be replaced by the following if() 
+// statement, but it will raise the required PHP version to ">= 5.2.0". 
+// Not sure if we want that now.
+//
+//	if(filter_var($ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === FALSE) {
+//		error(ERR_DNS_IPV4); return false;
+//	}
+
+	if (preg_match("/^[0-9\.]{7,15}$/", $ipv4)) {
+		error(ERR_DNS_IPV4); return false;
+	}
+
+	$quads = explode('.', $ipv4);
+	$numquads = count($quads);
+	
+	if ($numquads != 4) {
+		error(ERR_DNS_IPV4); return false;
+	}
+
+	for ($i = 0; $i < 4; $i++) {
+		if ($quads[$i] > 255) {
+			error(ERR_DNS_IPV4); return false;
 		}
 	}
+
 	return true;
 }
 
-function is_valid_rr_soa(&$content) {
+function is_valid_ipv6($ipv6) {
+
+// 20080424/RZ: The current code may be replaced by the following if() 
+// statement, but it will raise the required PHP version to ">= 5.2.0". 
+// Not sure if we want that now.
+//
+//	if(filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === FALSE) {
+//		error(ERR_DNS_IPV6); return false;
+//	}
+
+	if (preg_match("/^[0-9a-f]{0,4}:([0-9a-f]{0,4}:){0,6}[0-9a-f]{0,4}$/i", $ipv6)) {
+		error(ERR_DNS_IPV6); return false;
+	}
+
+	$quads = explode(':', $ipv6);
+	$numquads = count ($quads);
+
+	if ($numquads > 8 || $numquads < 3) {
+		error(ERR_DNS_IPV6); return false;
+	}
+
+	$emptyquads = 0;
+	for ($i = 1; $i < $numquads-1; $i++) {
+		if ($quads[$i] == "") $emptyquads++;
+	}
+
+	if ($emptyquads > 1) {
+		error(ERR_DNS_IPV6); return false;
+	}
+
+	if ($emptyquads == 0 && $numquads != 8) {
+		error(ERR_DNS_IPV6); return false;
+	}
+
+	return true;
+}
+
+function is_valid_rr_cname_name($name) {
+	global $db;
+
+	$query = "SELECT type, content 
+			FROM records 
+			WHERE content = " . $db->quote($name) . "
+			AND (type = 'MX' OR type = 'NS')";
+	
+	$response = $db->query($query);
+	if (PEAR::isError($response)) { error($response->getMessage()); return false; };
 
-	// TODO move to appropiate location
-//	$return = get_records_by_type_from_domid("SOA", $zid);
-//	if($return->numRows() > 1) {
-//		return false;
-//	}
+	if ($response->numRows() > 0) {
+		error(ERR_DNS_CNAME); return false;
+	}
+
+	return true;
+}
+
+function is_valid_mx_or_ns_target($content) {
+	global $db;
+	
+	$query = "SELECT type, name
+			FROM records
+			WHERE name = " . $db->quote($content) . "
+			AND TYPE = 'CNAME'";
+
+	$response = $db->query($query);
+	if (PEAR::isError($response)) { error($response->getMessage()); return false; };
+
+	if ($response->numRows() > 0) {
+		error(ERR_DNS_MX_NS_TO_CNAME); return false;
+	}
+
+	return true;
+}
+
+function is_valid_rr_txt_content($content) {
+
+	if (!preg_match("/^([^\s]{1,1000}|\"([^\"]{1,998}\"))$/i", $content)) {
+		error(ERR_DNS_TXT_INV_CONTENT); return false;
+	}
+
+	return true;
+}
+
+function is_valid_rr_hinfo_content($content) {
+
+	if ($content[0] == "\"") {
+		$fields = preg_split('/(?<=") /', $content, 2);
+	} else {
+		$fields = preg_split('/ /', $content, 2);
+	}
+
+	for ($i = 0; ($i < 2); $i++) {
+		if (!preg_match("/^([^\s]{1,1000}|\"([^\"]{1,998}\")$/i", $fields[$i])) {
+			error(ERR_DNS_HINFO_INV_CONTENT); return false;
+		}
+	}
+
+	return true;
+}
+
+function is_valid_rr_soa_content(&$content) {
 
 	$fields = preg_split("/\s+/", trim($content));
         $field_count = count($fields);
@@ -487,14 +325,42 @@
 	return true;
 }
 
-
-function is_valid_url($url)
-{
-	return preg_match('!^(http://)(([A-Z\d]|[A-Z\d][A-Z\d-]*[A-Z\d])\.)*[A-Z\d]+([//]([0-9a-z//~#%&\'_\-+=:?.]*))?$!i',  $url);
+function is_valid_rr_soa_name($name, $zone) {
+	if ($name != $zone) {
+		error(ERR_DNS_SOA_NAME); return false;
+	}
+	return true;
 }
 
-function is_valid_search($holygrail)
-{
+function is_valid_rr_prio(&$prio, $type) {
+
+	if ($type == "MX" ) {
+		if (!is_numeric($prio) || $prio < 0 || $prio > 65535 ) {
+			error(ERR_DNS_INV_PRIO); return false;
+		}
+	} else {
+		$prio = "";
+	}
+
+	return true;
+}
+
+function is_valid_rr_ttl(&$ttl) {
+
+	if (!isset($ttl) || $ttl == "" ) {
+		global $dns_ttl;
+		$ttl = $dns_ttl;
+	}
+	
+	if (!is_numeric($ttl) ||  $prio < 0 || $prio > 2147483647 ) {
+		error(ERR_DNS_INV_TTL);	return false;
+	}
+
+	return true;
+}
+
+function is_valid_search($holygrail) {
+
 	// Only allow for alphanumeric, numeric, dot, dash, underscore and 
 	// percent in search string. The last two are wildcards for SQL.
 	// Needs extension probably for more usual record types.
@@ -502,5 +368,4 @@
 	return preg_match('/^[a-z0-9.\-%_]+$/i', $holygrail);
 }
 
-
 ?>
--- a/inc/error.inc.php	Wed Apr 16 17:53:40 2008 +0000
+++ b/inc/error.inc.php	Thu Apr 24 21:07:27 2008 +0000
@@ -69,18 +69,26 @@
 /* DNS */
 define("ERR_DNS_CONTENT", _('Your content field doesnt have a legit value.'));
 define("ERR_DNS_HOSTNAME", _('Invalid hostname.'));
-define("ERR_DNS_RECORDTYPE", _('Invalid record type! You should not even been able to get that here.'));
+define("ERR_DNS_HN_INV_CHARS", _('You have invalid characters in your hostname.'));
+define("ERR_DNS_HN_DASH", _('A hostname can not start or end with a dash.'));
+define("ERR_DNS_HN_LENGTH", _('Given hostname or one of the labels is too short or too long.'));
+define("ERR_DNS_HN_SLASH", _('Given hostname has too many slashes.'));
+define("ERR_DNS_RR_TYPE", _('Unknown record type.'));
 define("ERR_DNS_IP", _('This is not a valid IPv4 or IPv6 address.')); 
 define("ERR_DNS_IPV6", _('This is not a valid IPv6 address.'));
 define("ERR_DNS_IPV4", _('This is not a valid IPv4 address.'));
 define("ERR_DNS_CNAME", _('This is not a valid CNAME. Did you assign an MX or NS record to the record?'));
-define("ERR_DNS_NS_CNAME", _('You can not point a NS record to a CNAME record. Remove or rename the CNAME record first or take another name.'));
+define("ERR_DNS_MX_NS_TO_CNAME", _('You can not point a NS or MX record to a CNAME record. Remove or rame the CNAME record first, or take another name.'));
 define("ERR_DNS_NS_HNAME", _('NS records must be a hostnames.'));
-define("ERR_DNS_MX_CNAME", _('You can not point a MX record to a CNAME record. Remove or rename the CNAME record first or take another name.'));
 define("ERR_DNS_MX_PRIO", _('A prio field should be numeric.'));
+define("ERR_DNS_SOA_NAME", _('Invalid value for name field of SOA record. It should be the name of the zone.'));
 define("ERR_DNS_SOA_MNAME", _('You have an error in the MNAME field of the SOA record.'));
+define("ERR_DNS_HINFO_INV_CONTENT", _('Invalid value for content field of HINFO record.'));
+define("ERR_DNS_TXT_INV_CONTENT", _('Invalid value for content field of TXT record.'));
 define("ERR_DNS_HN_TOO_LONG", _('The hostname is too long.'));
 define("ERR_DNS_INV_TLD", _('You are using an invalid top level domain.'));
+define("ERR_DNS_INV_TTL", _('Invalid value for TTL field. It should be numeric.'));
+define("ERR_DNS_INV_PRIO", _('Invalid value for prio field. It should be numeric.'));
 
 /* GOOD! */
 define("SUC_ZONE_ADD", _('Zone has been added successfully.')); 
--- a/inc/record.inc.php	Wed Apr 16 17:53:40 2008 +0000
+++ b/inc/record.inc.php	Thu Apr 24 21:07:27 2008 +0000
@@ -561,17 +561,13 @@
 }
 
 
-/*
- * Get domain name from a given id
- * return values: the name of the domain associated with the id.
- */
-function get_domain_name_from_id($id)
+function get_zone_name_from_id($zid)
 {
 	global $db;
 
-	if (is_numeric($id))
+	if (is_numeric($zid))
 	{
-		$result = $db->query("SELECT name FROM domains WHERE id=".$db->quote($id));
+		$result = $db->query("SELECT name FROM domains WHERE id=".$db->quote($zid));
 		$rows = $result->numRows() ;
 		if ($rows == 1) {
  			$r = $result->fetchRow();
@@ -580,17 +576,17 @@
 			error(sprintf("Zone does not exist."));
 			return false;
 		} else {
-	 		error(sprintf(ERR_INV_ARGC, "get_domain_name_from_id", "more than one domain found?! whaaa! BAD! BAD! Contact admin!"));
+	 		error(sprintf(ERR_INV_ARGC, "get_zone_name_from_id", "more than one domain found?! whaaa! BAD! BAD! Contact admin!"));
 			return false;
 		}
 	}
 	else
 	{
-		error(sprintf(ERR_INV_ARGC, "get_domain_name_from_id", "Not a valid domainid: $id"));
+		error(sprintf(ERR_INV_ARGC, "get_zone_name_from_id", "Not a valid domainid: $id"));
 	}
 }
 
-function get_zone_info_from_id($zone_id) {
+function get_zone_info_from_id($zid) {
 
 	if (verify_permission('zone_content_view_others')) { $perm_view = "all" ; } 
 	elseif (verify_permission('zone_content_view_own')) { $perm_view = "own" ; }
@@ -606,7 +602,7 @@
 					domains.master AS master_ip,
 					count(records.domain_id) AS record_count
 					FROM domains LEFT OUTER JOIN records ON domains.id = records.domain_id 
-					WHERE domains.id = " . $db->quote($zone_id) . "
+					WHERE domains.id = " . $db->quote($zid) . "
 					GROUP BY domains.id, domains.type, domains.name, domains.master";
 		$result = $db->query($query);
 		if (PEAR::isError($result)) { error($result->getMessage()); return false; }
Binary file locale/nl_NL/LC_MESSAGES/messages.mo has changed
--- a/locale/nl_NL/LC_MESSAGES/nl.po	Wed Apr 16 17:53:40 2008 +0000
+++ b/locale/nl_NL/LC_MESSAGES/nl.po	Thu Apr 24 21:07:27 2008 +0000
@@ -530,8 +530,20 @@
 msgstr "Ongeldige hostname."
 
 #: inc/error.inc.php:71
-msgid "Invalid record type! You should not even been able to get that here."
-msgstr "Ongeldig record type. In theorie had u deze foutmelding nooit kunnen zien."
+msgid "You have invalid characters in your hostname."
+msgstr "Er staan ongeldige characters in de hostname."
+
+msgid "A hostname can not start or end with a dash."
+msgstr "Een hostname kan niet met een streepje beginnen of eindigen."
+
+msgid "Given hostname or one of the labels is too short or too long."
+msgstr "De opgegeven hostname of een van de componenten is te kort of te lang."
+
+msgid "Given hostname has too many slashes."
+msgstr "De opgegeven hostname bevat teveel slashes."
+
+msgid "Unknown record type."
+msgstr "Onbekend record type."
 
 #: inc/error.inc.php:72
 msgid "This is not a valid IPv4 or IPv6 address."
@@ -550,17 +562,28 @@
 msgstr "Dit is geen geldige CNAME. Heeft u een MX of NS record hiernaar verwijzen?"
 
 #: inc/error.inc.php:76
-msgid "You can not point a NS record to a CNAME record. Remove or rename the CNAME record first or take another name."
-msgstr "Een NS record mag niet naar een CNAME record verwijzen. Verwijder of hernoem het CNAME record eerst, of verwijs naar ene ander record."
+msgid "You can not point a NS or MX record to a CNAME record. Remove or rame the CNAME record first, or take another name."
+msgstr "Een NS of MX record mag niet naar een CNAME record verwijzen. Verwijder of hernoem het CNAME record eerst, of verwijs naar een ander record."
+
+msgid "Invalid value for name field of SOA record. It should be the name of the zone."
+msgstr "Ongeldige waarde voor het naam veld van het SOA record. Het moet de naam van de zone zijn."
+
+msgid "Invalid value for content field of HINFO record."
+msgstr "Ongeldige waarde voor het Content veld van het HINFO record."
+
+msgid "Invalid value for content field of TXT record."
+msgstr "Ongeldige waarde voor het content veld van het TXT record."
+
+msgid "Invalid value for TTL field. It should be numeric."
+msgstr "Ongeldige waarde het TTL veld. Het moet numeriek zijn."
+
+msgid "Invalid value for prio field. It should be numeric."
+msgstr "Ongeldige waarde het prio veld. Het moet numeriek zijn."
 
 #: inc/error.inc.php:77
 msgid "NS records must be a hostnames."
 msgstr "De waarde van een NS record moet een hostname zijn."
 
-#: inc/error.inc.php:78
-msgid "You can not point a MX record to a CNAME record. Remove or rename the CNAME record first or take another name."
-msgstr "Een MX record mag niet naar een CNAME record verwijzen. Verwijder of hernoem het CNAME record eerst, of verwijs naar ene ander record."
-
 #: inc/error.inc.php:79
 msgid "A prio field should be numeric."
 msgstr "Het prioriteit veld behoort numeriek te zijn."