From 0d16c41a27ab059ddf046755e53d14819682f43b Mon Sep 17 00:00:00 2001 From: DrMaxNix Date: Sat, 8 May 2021 19:57:27 +0200 Subject: [PATCH] :sparkles: add backend/api code (#14) --- config/cache.php | 6 + config/lookup.php | 15 ++ config/nameserver.php | 15 ++ functions/lookup.php | 604 ++++++++++++++++++++++++++++++++++++++++++ lookup/index.php | 63 +++++ 5 files changed, 703 insertions(+) create mode 100644 config/cache.php create mode 100644 config/lookup.php create mode 100644 config/nameserver.php create mode 100644 functions/lookup.php create mode 100644 lookup/index.php diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000..46e4085 --- /dev/null +++ b/config/cache.php @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/config/lookup.php b/config/lookup.php new file mode 100644 index 0000000..897b91b --- /dev/null +++ b/config/lookup.php @@ -0,0 +1,15 @@ + "cname", "cname" => "notice.cuii.info."]]; +?> \ No newline at end of file diff --git a/config/nameserver.php b/config/nameserver.php new file mode 100644 index 0000000..fcc5b8d --- /dev/null +++ b/config/nameserver.php @@ -0,0 +1,15 @@ + "Cloudflare", "address" => ["1.1.1.1", "1.0.0.1"]]; + $§DNSWATCH_NAMESERVER_REFERENCE["google"] = ["name" => "Google", "address" => ["8.8.8.8", "8.8.4.4"]]; + $§DNSWATCH_NAMESERVER_REFERENCE["digitalcourage"] = ["name" => "digitalcourage", "address" => ["dns2.digitalcourage.de"]]; + $§DNSWATCH_NAMESERVER_REFERENCE["ccc_berlin"] = ["name" => "CCC Berlin", "address" => ["dnscache.berlin.ccc.de"]]; + $§DNSWATCH_NAMESERVER_REFERENCE["uncensoreddns"] = ["name" => "UncensoredDNS", "address" => ["unicast.censurfridns.dk"]]; + + + // CHECK DNS // + $§DNSWATCH_NAMESERVER["telekom_de"] = ["name" => "Telekom DE", "address" => ["dns.telekom.de"]]; + $§DNSWATCH_NAMESERVER["vodafone_de"] = ["name" => "Vodafone DE", "address" => ["dns1.vodafone-ip.de", "dns2.vodafone-ip.de"]]; + $§DNSWATCH_NAMESERVER["netaachen"] = ["name" => "Netaachen", "address" => ["na-dns-p01.netaachen.com"]]; + $§DNSWATCH_NAMESERVER["quad9"] = ["name" => "Quad9", "address" => ["9.9.9.9", "149.112.112.112"]]; +?> \ No newline at end of file diff --git a/functions/lookup.php b/functions/lookup.php new file mode 100644 index 0000000..d572ca1 --- /dev/null +++ b/functions/lookup.php @@ -0,0 +1,604 @@ + 0){ + $__hostcmd_string .= " "; + } + + //add host-cmd + $__hostcmd_string .= "\"host " . $DOMAIN . " " . $nameserver_address . " > " . $__tmp_dir_path . "/" . $reference . " 2>&1\""; + } + + + // ADD COMMANDS FOR SEARCH // + for($q = 0; $q < sizeof($§DNSWATCH_NAMESERVER); $q++){ + $this_nameserver = array_keys($§DNSWATCH_NAMESERVER)[$q]; + + //get random nameserver address + $nameserver_address = $§DNSWATCH_NAMESERVER[$this_nameserver]["address"]; + $rand = rand(0, sizeof($nameserver_address) - 1); + $nameserver_address = $nameserver_address[$rand]; + + //remember used address for later + $__used_nameserver_address[$this_nameserver] = $nameserver_address; + + //maybe prepend space + if(strlen($__hostcmd_string) > 0){ + $__hostcmd_string .= " "; + } + + //add host-cmd + $__hostcmd_string .= "\"host " . $DOMAIN . " " . $nameserver_address . " > " . $__tmp_dir_path . "/" . $this_nameserver . " 2>&1\""; + } + + + // PLACE INTO 'PARALLEL' COMMAND // + $cmd = "parallel ::: " . $__hostcmd_string . " > /dev/null 2>&1"; + + + // EXECUTE COMMAND // + shell_exec($cmd); + + + // GET CMD-RESPONSES // + $indir = indir($__tmp_dir_path); //get dir contents but without '.' and '..' + + //read every tmp nameserver file + $__nameserver_response = []; + for($q = 0; $q < sizeof($indir); $q++){ + $this_nameserver = $indir[$q]; + + //read file + $response = FILE_read($__tmp_dir_path . "/" . $this_nameserver); //basically a file_get_contents() + + //add to nameserver response-list + $__nameserver_response[$this_nameserver] = $response; + } + + + + + + ///////////////////////////////////////// + // P A R S E D N S - R E S P O N S E // + ///////////////////////////////////////// + + for($q = 0; $q < sizeof($__nameserver_response); $q++){ + $this_response = array_keys($__nameserver_response)[$q]; + $response = $__nameserver_response[$this_response]; + + $__lookup[$this_response] = DNSWATCH_LOOKUP_parse($response); + } + + + + + + ///////////////////////////////////////// + // C O M P A R E R E F E R E N C E S // + ///////////////////////////////////////// + + // RESET SOME STUFF // + $__randomized_response = NULL; + + + // KICK OUT REFERENCES WITHOUT RESULTS // + $__useable_references = []; + for($q = 0; $q < sizeof($__reference_random); $q++){ + $reference = $__reference_random[$q]; + + if($__lookup[$reference] !== NULL and sizeof($__lookup[$reference]) > 0){ + $__useable_references[] = $reference; + } + } + + + // CHECK IF WE HAVE ENOUGH USEABLE REFERENCES // + $__found = (sizeof($__useable_references) >= $§DNSWATCH_LOOKUP_REFERENCE_USEABLE_MIN); + + + // COMPARE FOUND RESULTS FROM REFERENCES (TO CHECK IF THE DOMAIN USES RANDOMIZED RASPONSES) // + if($__found){ + //compare all other entries with the first one + $compare_with = $__useable_references[0]; + + //start negative and switch to positive if found + $__randomized_response = false; + + //compare + for($q = 1; $q < sizeof($__useable_references); $q++){ + $this_reference = $__useable_references[$q]; + + //check $compare_with with this reference + if($__lookup[$compare_with] != $__lookup[$this_reference]){ + //found another response => this domain uses randomized responses + $__randomized_response = true; + + //stop searching + $q = sizeof($__useable_references); + } + } + } + + + + + + ///////////////////////////////////////// + // I N T E R P R E T D N S D A T A // + ///////////////////////////////////////// + + // START WITH EMPTY ARRAY // + $__data = []; + + + // ADD SOME FLAGS // + //did the references find something? + $__data["found"] = (sizeof($__useable_references) >= $§DNSWATCH_LOOKUP_REFERENCE_USEABLE_MIN); + + //does this domain use randomized responses? + $__data["randomized_response"] = $__randomized_response; + + + // ADD REFERENCES // + $__data["reference"] = []; + for($q = 0; $q < sizeof($__reference_random); $q++){ + $this_reference = $__reference_random[$q]; + $reference = $__lookup[$this_reference]; + + //get provider's used nameserver-address + $address = $__used_nameserver_address[$this_reference]; + + + // CHECK IF THE NAMESERVER WAS OFFLINE // + if($reference === NULL){ + $status = NULL; + } else { + //check if the reference has found entries + $status = ($reference !== NULL and sizeof($reference) > 0); + } + + //add to output-data + $__data["reference"][] = ["nameserver" => $this_reference, "address" => $address, "status" => $status]; + } + + + if($__found){ + // INTERPRET SEARCHES // + //start with empty buffer + $__search = []; + + //check if search should get compared or only checked for patterns + if(!$__randomized_response){ + // CHECK ALL SEARCH RESULTS WITH REFERENCE // + //compare with the first useable reference + $compare_with = $__useable_references[0]; + $compare_with_lookup = $__lookup[$compare_with]; + + //compare + for($q = 0; $q < sizeof($§DNSWATCH_NAMESERVER); $q++){ + $this_search = array_keys($§DNSWATCH_NAMESERVER)[$q]; + $search = $__lookup[$this_search]; + + // CHECK IF THIS NAMESERVER WAS OFFLINE // + if($search === NULL){ + $status = NULL; + } else { + //compare results with reference + $status = ($search === $compare_with_lookup); + } + + //maybe try to guess the cause + if($status === false){ + $cause = DNSWATCH_LOOKUP_cause_guess($search); + } else { + $cause = NULL; + } + + //save for later + $__search[$this_search] = ["status" => $status, "cause" => $cause]; + } + + + } else { + // CHECK SEARCH RESULTS FOR CAUSE-PATTERNS // + for($q = 0; $q < sizeof($§DNSWATCH_NAMESERVER); $q++){ + $this_search = array_keys($§DNSWATCH_NAMESERVER)[$q]; + $search = $__lookup[$this_search]; + + // CHECK IF THIS NAMESERVER WAS OFFLINE // + if($search === NULL){ + $status = NULL; + $cause = NULL; + + } else { + //search for cause-patterns + $cause = DNSWATCH_LOOKUP_cause_guess($search); + + //status is just if we didn't find a cause + $status = ($cause === NULL); + } + + //save for later + $__search[$this_search] = ["status" => $status, "cause" => $cause]; + } + } + + + // ADD SEARCHES // + $__data["search"] = []; + for($q = 0; $q < sizeof($__search); $q++){ + $this_search = array_keys($__search)[$q]; + $search = $__search[$this_search]; + + //get provider's used nameserver-address + $address = $__used_nameserver_address[$this_search]; + + //add to output-data + $__data["search"][] = ["nameserver" => $this_search, "address" => $address, "status" => $search["status"], "cause" => $search["cause"]]; + } + } + + + + + + + + + + + + + + // SAVE IN CACHE // + DNSWATCH_LOOKUP_cache_store($DOMAIN, $__data); + + + // CLEAN UP SESSION // + PATH_unlink($__tmp_dir_path); //unlink whole dir recursively with files in it + + + // RETURN LOOKUP DATA // + return($__data); + } + + + + + + + + + + + + + + + + + + + + + + + + + /* + Search cache for DOMAIN + - if found: return cached data + - else: return 'false' + */ + function DNSWATCH_LOOKUP_cache($DOMAIN){ + require(CMS_path("//config/cache.php")); //load config file at 'dnswatch/config/cache.php' + + + // GET CLEANED UP CACHE // + $__cache = DNSWATCH_LOOKUP_cache_cleanup(); + + + // LOOK FOR AN ENTRY // + if(isset($__cache[$DOMAIN])){ + //return entry's data + return($__cache[$DOMAIN]["data"]); + + } else { + //nothing found + return(false); + } + } + + /* + Store DATA for DOMAIN in the cache + */ + function DNSWATCH_LOOKUP_cache_store($DOMAIN, $DATA){ + require(CMS_path("//config/cache.php")); //load config file at 'dnswatch/config/cache.php' + + + // STORE // + //get time + $__time = time(); + + //save + DAT_set($§DNSWATCH_CACHE_DAT, $DOMAIN, ["time" => $__time, "data" => $DATA]); //store into database called $§DNSWATCH_CACHE_DAT (filesystem-path) at $DOMAIN (db internal path) + + + // RETURN // + return(true); + } + + /* + Do cleanup of cache (maybe with given CACHE data) + */ + function DNSWATCH_LOOKUP_cache_cleanup($CACHE = NULL){ + require(CMS_path("//config/cache.php")); //load config file at 'dnswatch/config/cache.php' + + + // MAYBE READ CACHE BY OURSELVES // + if($CACHE === NULL){ + $CACHE = dat($§DNSWATCH_CACHE_DAT); //get whole database called $§DNSWATCH_CACHE_DAT (filesystem-path) + } + + + // CHECK ALL CACHED ENTRIES // + //get time + $__time = time(); + + //new cache starts empty, valid entries will get added + $__cache = []; + + //check + for($q = 0; $q < sizeof($CACHE); $q++){ + $this_entry = array_keys($CACHE)[$q]; + $entry = $CACHE[$this_entry]; + + //check if still valid + if($entry["time"] + $§DNSWATCH_CACHE_DURATION >= $__time){ + $__cache[$this_entry] = $entry; + } + } + + + // MAYBE SAVE NEW CACHE // + if($__cache !== $CACHE){ + DAT_set($§DNSWATCH_CACHE_DAT, "/", $__cache); //store into database called $§DNSWATCH_CACHE_DAT (filesystem-path) at / (db internal path) + } + + + // RETURN NEW CACHE // + return($__cache); + } + + + + + + + + + + + + + + + + + /* + Parse an output string from 'host' command + */ + function DNSWATCH_LOOKUP_parse($RESPONSE){ + // GET LINES // + $line = explode("\n", $RESPONSE); + + + // PARSE LINE BY LINE // + $__data = []; + for($q = 0; $q < sizeof($line); $q++){ + $this_line = $line[$q]; + + //nameserver not reachable + if(preg_match("/^;;\sconnection\stimed\sout;\sno\sservers\scould\sbe\sreached$/", $this_line)){ + $__data = NULL; + break; + } + if(preg_match("/^host:\scouldn't\sget\saddress\sfor\s'[a-z0-9.\-]+':\snot\sfound$/", $this_line)){ + $__data = NULL; + break; + } + if(preg_match("/^Host\s[a-z0-9.\-]+\snot\sfound:\s5\(REFUSED\)$/", $this_line)){ + $__data = NULL; + break; + } + + //a / ipv4 + if(preg_match("/^[a-z0-9.\-]+\shas\saddress\s([0-9]{1,3}\.){3}[0-9]{1,3}$/", $this_line)){ + preg_match("/(?<=has\saddress\s)([0-9]{1,3}\.){3}[0-9]{1,3}$/", $this_line, $a); + $a = $a[0]; + + $__data[] = ["type" => "a", "a" => $a]; + } + + //aaaa / ipv6 + if(preg_match("/^[a-z0-9.\-]+\shas\sIPv6\saddress\s([0-9a-f]{0,4}:)+[0-9a-f]{0,4}$/", $this_line)){ + preg_match("/(?<=has\sIPv6\saddress\s)([0-9a-f]{0,4}:)+[0-9a-f]{0,4}$/", $this_line, $aaaa); + $aaaa = $aaaa[0]; + + $__data[] = ["type" => "aaaa", "aaaa" => $aaaa]; + } + + //mx / mailserver + if(preg_match("/^[a-z0-9.\-]+\smail\sis\shandled\sby\s[0-9]+\s[a-z0-9.\-]+$/", $this_line)){ + preg_match("/(?<=mail\sis\shandled\sby\s)[0-9]+/", $this_line, $mx_prio); + $mx_prio = (int)$mx_prio[0]; + + preg_match("/(?<=mail\sis\shandled\sby\s" . $mx_prio . "\s)[a-z0-9.\-]+$/", $this_line, $mx_host); + $mx_host = $mx_host[0]; + + $__data[] = ["type" => "mx", "prio" => $mx_prio, "host" => $mx_host]; + } + + //cname + if(preg_match("/^[a-z0-9.\-]+\sis\san\salias\sfor\s[a-z0-9.\-]+$/", $this_line)){ + preg_match("/(?<=is\san\salias\sfor\s)[a-z0-9.\-]+$/", $this_line, $cname); + $cname = $cname[0]; + + $__data[] = ["type" => "cname", "cname" => $cname]; + } + } + + + // RETURN // + return($__data); + } + + /* + Try to guess the cause of a blockage (by checking for predifened patterns) + */ + function DNSWATCH_LOOKUP_cause_guess($SEARCH){ + require(CMS_path("//config/lookup.php")); //load config file at 'dnswatch/config/lookup.php' + + + // COMPARE ALL POSSIBLE CAUSES... (MATCH FIRST) // + for($a = 0; $a < sizeof($§DNSWATCH_LOOKUP_CAUSE_GUESS); $a++){ + $this_cause = array_keys($§DNSWATCH_LOOKUP_CAUSE_GUESS)[$a]; + + //start positive and fail on negative found + $cAUSE_FOUND = true; + + //...and all of this cause's entries (match all) + for($s = 0; $s < sizeof($§DNSWATCH_LOOKUP_CAUSE_GUESS[$this_cause]); $s++){ + $this_cause_entry = $§DNSWATCH_LOOKUP_CAUSE_GUESS[$this_cause][$s]; + + + // SEARCH IN RESULT'S ENTRIES FOR THIS CAUSE-ENTRY // + if(!in_array($this_cause_entry, $SEARCH)){ + //fail entire test for this cause + $cAUSE_FOUND = false; + + //stop checking this case + $s = sizeof($§DNSWATCH_LOOKUP_CAUSE_GUESS[$this_cause]); + } + } + + + // CHECK IF THIS CAUSE'S CONDITIONS ARE MET // + if($cAUSE_FOUND === true){ + //found a cause! + return($this_cause); + } + } + + + // DIDN'T FIND A CAUSE // + return(NULL); + } +?> \ No newline at end of file diff --git a/lookup/index.php b/lookup/index.php new file mode 100644 index 0000000..73d076c --- /dev/null +++ b/lookup/index.php @@ -0,0 +1,63 @@ + "success", "data" => $__data]; + + } else { + $Response = ["type" => "error", "error" => "malformed_domain"]; + } + + + // RESPOND WITH JSON // + echo(json_encode($Response)); +?> \ No newline at end of file