コード例 #1
0
 public function check_record_content($content)
 {
     $prefix = "Record content is not valid. ";
     if (empty($content)) {
         return array("message" => $prefix . "Content may never be empty.", "code" => "RECORD_RHS_EMPTY");
     }
     if (!isset($this->type) || empty($this->type)) {
         return $prefix . "Type may never be empty.";
     }
     if (strlen($content) > 4096) {
         return array("message" => $prefix . "Content is too long, must be less than 4096 characters.", "code" => "RECORD_RHS_TOO_LONG");
     }
     switch ($this->type) {
         case "A":
             if (preg_match(VALID_IPV4, $content) === 0) {
                 return array("message" => $prefix . "An A record requires a valid IPv4 address without trailing dot.", "code" => "RECORD_RHS_INVALID_IPV4");
             }
             break;
         case "AAAA":
             if (preg_match(VALID_IPV6, $content) === 0) {
                 return array("message" => $prefix . "An AAAA record requires a valid IPv6 address without trailing dot. IPv4 addresses in IPv6 notation are not supported.", "code" => "RECORD_RHS_INVALID_IPV6");
             }
             break;
         case "MX":
             if (!isset($this->priority)) {
                 return array("message" => $prefix . "A MX record must also specify a priority.", "code" => "RECORD_RHS_MISSING_PRIORITY");
             }
             if (!isset($type)) {
                 $type = "MX";
             }
         case "NS":
             if (!isset($type)) {
                 $type = "NS";
             }
         case "PTR":
             if (!isset($type)) {
                 $type = "PTR";
             }
         case "CNAME":
             if (!isset($type)) {
                 $type = "CNAME";
             }
             if ($this->record_type === "TEMPLATE" && preg_match(VALID_TEMPLATE_DOMAIN, $content) === 0) {
                 return array("message" => $prefix . "A {$type} template record must contain a valid FQDN without trailing dot. May also end with [ZONE].", "code" => "RECORD_RHS_INVALID_FQDN");
             } else {
                 if ($this->record_type !== "TEMPLATE" && preg_match(VALID_DOMAIN, $content) === 0) {
                     return array("message" => $prefix . "A {$type} record must contain a valid FQDN without trailing dot.", "code" => "RECORD_RHS_INVALID_FQDN");
                 }
             }
             break;
         case "NAPTR":
             $parts = explode(" ", $content);
             if (count($parts) !== 6) {
                 return array("message" => $prefix . "A NAPTR record must provide all 6 parts (note the quotes and trailing dot): <order> <preference> \"<flags>\" \"<service>\" \"<regexp>\" replacement.", "code" => "RECORD_RHS_NAPTR_PARTS_MISSING");
             }
             $naptr_terminal = false;
             $naptr_regex = false;
             for ($i = 0; $i < count($parts); $i++) {
                 switch ($i) {
                     case 0:
                         // Order
                     // Order
                     case 1:
                         // Preference
                         if (!ctype_digit($parts[$i])) {
                             return array("message" => $prefix . sprintf("NAPTR record part %d must be a valid integer.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                         }
                         break;
                     case 2:
                         // Flags
                         if (preg_match(VALID_QUOTED, $parts[$i], $p) === 0) {
                             return array("message" => $prefix . sprintf("NAPTR record part %d must be a valid quoted string.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                         }
                         if (preg_match(NAPTR_FLAGS_VALID, $p[1]) === 0) {
                             return array("message" => $prefix . sprintf("NAPTR record part %d contains invalid characters. May only contain alphanumeric characters.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                         }
                         if (preg_match_all(NAPTR_FLAGS_EXCLUSIVE, $p[1], $q) > 1) {
                             return array("message" => $prefix . sprintf("NAPTR record part %d contains too many multiple exclusive FLAGS: S, A, U). Use only one at a time.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                         }
                         switch (strtolower($p[1])) {
                             case "s":
                             case "a":
                             case "u":
                                 $naptr_terminal = true;
                                 break;
                             default:
                                 $naptr_terminal = false;
                                 break;
                         }
                         unset($p);
                         unset($q);
                         break;
                     case 3:
                         // Service
                         if (preg_match(VALID_QUOTED, $parts[$i], $p) === 0) {
                             return array("message" => $prefix . sprintf("NAPTR record part %d must be a valid quoted string.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                         }
                         if ($naptr_terminal && empty($p[1])) {
                             return array("message" => $prefix . sprintf("NAPTR record part %d is invalid. A SERVICE must be specified if the FLAGS include a terminal flag.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                         }
                         if (preg_match(NAPTR_SERVICE_VALID, $p[1]) === 0) {
                             return array("message" => $prefix . sprintf("NAPTR record part %d is invalid.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                         }
                         unset($p);
                         break;
                     case 4:
                         // Regexp
                         if (preg_match(VALID_QUOTED, $parts[$i], $p) === 0) {
                             return array("message" => $prefix . sprintf("NAPTR record part %d must be a valid quoted string.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                         }
                         if (!empty($p[1])) {
                             $naptr_regex = true;
                             $delimiter = substr($p[1], 0, 1);
                             $reg = substr($p[1], 1);
                             if (preg_match(NAPTR_REGEX_VALID_DELIMITER, $delimiter) === 0) {
                                 return array("message" => $prefix . sprintf("NAPTR record part %d contains an invalid POSIX replacement regexp. Delimiter may be any character except 'i', '\\' and may not be a digit. ", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                             }
                             $partz = explode($delimiter, $reg);
                             if (count($partz) !== 3) {
                                 return array("message" => $prefix . sprintf("NAPTR record %d contains an invalid POSIX replacement regexp. Not all parts were specified.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                             }
                             if (preg_match(NAPTR_REGEX_VALID_BACKREF, $partz[1]) === 0) {
                                 return array("message" => $prefix . sprintf("NAPTR record part %d contains an invalid POSIX replacement regexp. May only contain one backref in the form of '\\1'.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                             }
                             if (preg_match(NAPTR_REGEX_VALID_FLAG, $partz[2]) === 0) {
                                 return array("message" => $prefix . sprintf("NAPTR record part %d contains an invalid POSIX regexp flag. May optionally contain 'i', or nothing at all.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                             }
                             unset($delimiter);
                             unset($partz);
                         }
                         unset($p);
                         break;
                     case 5:
                         // Replacement
                         if (preg_match(VALID_NOTEMPTY, $parts[$i], $p) === 0) {
                             return array("message" => $prefix . sprintf("NAPTR record part %d must be a valid record pointer, or a single dot (.).", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                         }
                         if (ValidatorConfig::BIND_COMPATABILITY === true) {
                             $replacement = $p[1];
                             if ($naptr_regex && $replacement != ".") {
                                 return array("message" => $prefix . sprintf("NAPTR record part %d is invalid. REGEXP and REPLACEMENT should not be used at the same time.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                             }
                         } else {
                             $replacement = HelperFunctions::str_replace_last(".", "", $p[1]);
                             if ($naptr_regex && $replacement != "") {
                                 return array("message" => $prefix . sprintf("NAPTR record part %d is invalid. REGEXP and REPLACEMENT should not be used at the same time.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                             }
                         }
                         if (!empty($replacement) && preg_match(VALID_DOMAIN, $replacement) === 0 && preg_match(VALID_EMPTY_DOMAIN, $replacement) === 0) {
                             return array("message" => $prefix . sprintf("NAPTR record part %d is invalid. REPLACEMENT must be either '.' or a valid FQDN.", $i + 1), "code" => "RECORD_RHS_NAPTR_INVALID_PART_" . $i);
                         }
                         unset($replacement);
                         unset($p);
                         break;
                 }
             }
             break;
         case "RP":
             $parts = explode(" ", $content);
             if (count($parts) !== 2) {
                 return array("message" => $prefix . "A RP record must provide all 2 parts: <mailbox name> <more-info pointer>", "code" => "RECORD_RHS_RP_PARTS_MISSING");
             }
             if ($this->record_type === "TEMPLATE") {
                 if (preg_match(VALID_TEMPLATE_DOMAIN, $parts[0]) === 0) {
                     return array("message" => $prefix . "A RP records mailbox name must be an email address with the at-sign replaced by a dot (.). May also end with [ZONE]", "code" => "RECORD_RHS_RP_INVALID_PART_0");
                 }
                 if (preg_match(VALID_TEMPLATE_DOMAIN, $parts[1]) === 0) {
                     return array("message" => $prefix . "A RP records more-info pointer must be a valid FQDN. May also end with [ZONE]", "code" => "RECORD_RHS_RP_INVALID_PART_1");
                 }
             } else {
                 if (preg_match(VALID_DOMAIN, $parts[0]) === 0) {
                     return array("message" => $prefix . "A RP records mailbox name must be an email address with the at-sign replaced by a dot (.).", "code" => "RECORD_RHS_RP_INVALID_PART_0");
                 }
                 if (preg_match(VALID_DOMAIN, $parts[1]) === 0) {
                     return array("message" => $prefix . "A RP records more-info pointer must be a valid FQDN.", "code" => "RECORD_RHS_RP_INVALID_PART_1");
                 }
             }
             break;
         case "SOA":
             $parts = explode(" ", $content);
             if (count($parts) !== 7) {
                 return array("message" => $prefix . "A SOA record must provide all 7 parts: <primary> <hostmaster> <serial> <refresh> <retry> <expire> <default_ttl>", "code" => "RECORD_RHS_SOA_PARTS_MISSING");
             }
             for ($i = 0; $i < count($parts); $i++) {
                 switch ($i) {
                     case 0:
                         if (preg_match(VALID_DOMAIN, $parts[$i]) === 0) {
                             return array("message" => $prefix . "A SOA record must provide a valid FQDN as primary hostname.", "code" => "RECORD_RHS_SOA_INVALID_PART_" . $i);
                         }
                         break;
                     case 1:
                         if (filter_var($parts[$i], FILTER_VALIDATE_EMAIL) === false && preg_match(VALID_DOMAIN, $parts[$i]) === 0) {
                             return array("message" => $prefix . "A SOA record must provide a valid email address as hostmaster.", "code" => "RECORD_RHS_SOA_INVALID_PART_" . $i);
                         }
                         break;
                     case 2:
                     case 3:
                     case 4:
                     case 5:
                     case 6:
                         if (!ctype_digit($parts[$i])) {
                             return array("message" => sprintf("SOA record part %d must be a valid integer.", $i + 1), "code" => "RECORD_RHS_SOA_INVALID_PART_" . $i);
                         }
                         break;
                 }
             }
             break;
         case "SPF":
             if (!isset($type)) {
                 $type = "SPF";
             }
         case "TXT":
             if (!isset($type)) {
                 $type = "TXT";
             }
             if (preg_match(VALID_QUOTED, $content) === 0) {
                 return array("message" => $prefix . "A {$type} record must provide a valid quoted string.", "code" => "RECORD_RHS_INVALID_QUOTED_STRING");
             }
             break;
         case "SSHFP":
             $parts = explode(" ", $content);
             if (count($parts) !== 3) {
                 return array("message" => $prefix . "A SSHFP record must provide all 3 parts: <algorithm> <fp-type> <fingeprint>", "code" => "RECORD_RHS_SSHFP_PARTS_MISSING");
             }
             for ($i = 0; $i < count($parts); $i++) {
                 switch ($i) {
                     case 0:
                         if ($parts[$i] != "1" && $parts[$i] != "2" && $parts[$i] != "3") {
                             return array("message" => $prefix . "A SSHFP record must provide either 1 (RSA), 2 (DSA) or 3 (ECDSA) as algorithm.", "code" => "RECORD_RHS_SSHFP_INVALID_PART_0");
                         }
                         break;
                     case 1:
                         if ($parts[$i] != "1" && $parts[$i] != "2") {
                             return array("message" => $prefix . "A SSHFP record must provide 1 (SHA-1) or 2 (SHA-256) as fp-type.", "code" => "RECORD_RHS_SSHFP_INVALID_PART_1");
                         }
                         break;
                     case 2:
                         if ($parts[1] == "1" && strlen($parts[$i]) !== 40) {
                             return array("message" => $prefix . "A SSHFP record must provide a SHA-1 fingerprint as a 40 character ASCII hexadecimal string.", "code" => "RECORD_RHS_SSHFP_INVALID_PART_2");
                         } else {
                             if ($parts[1] == "2" && strlen($parts[$i]) !== 64) {
                                 return array("message" => $prefix . "A SSHFP record must provide a SHA-256 fingerprint as a 64 character ASCII hexadecimal string.", "code" => "RECORD_RHS_SSHFP_INVALID_PART_2");
                             }
                         }
                         break;
                 }
             }
             break;
         case "SRV":
             if (!isset($this->priority)) {
                 return array("message" => $prefix . "A SRV record must also provide a priority.", "code" => "RECORD_RHS_MISSING_PRIORITY");
             }
             $parts = explode(" ", $content);
             if (count($parts) !== 3) {
                 return array("message" => $prefix . "A SRV record must provide all 3 parts: <weight> <port> <service>", "code" => "RECORD_RHS_SRV_PARTS_MISSING");
             }
             for ($i = 0; $i < count($parts); $i++) {
                 switch ($i) {
                     case 0:
                     case 1:
                         if (!ctype_digit($parts[$i])) {
                             return array("message" => $prefix . sprintf("SRV record part %d must be a valid integer.", $i + 1), "code" => "RECORD_RHS_SRV_INVALID_PART_" . $i);
                         }
                         break;
                     case 2:
                         if ($this->record_type === "TEMPLATE" && preg_match(VALID_TEMPLATE_DOMAIN, $parts[$i]) === 0) {
                             return array("message" => $prefix . "A SRV record must provide a valid FQDN as service. May also end with [ZONE]", "code" => "RECORD_RHS_SRV_INVALID_PART_" . $i);
                         } else {
                             if ($this->record_type !== "TEMPLATE" && preg_match(VALID_DOMAIN, $parts[$i]) === 0) {
                                 return array("message" => $prefix . "A SRV record must provide a valid FQDN as service.", "code" => "RECORD_RHS_SRV_INVALID_PART_" . $i);
                             }
                         }
                         break;
                 }
             }
             break;
         default:
             break;
     }
     return true;
 }