Source of file NetworkHelper.php
Size: 20,768 Bytes - Last Modified: 2020-10-24T02:46:31+00:00
/home/travis/build/NextDom/nextdom-core/src/Helpers/NetworkHelper.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 | <?php /* This file is part of Jeedom. * * Jeedom is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Jeedom is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jeedom. If not, see <http://www.gnu.org/licenses/>. */ /* This file is part of NextDom Software. * * NextDom is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * NextDom Software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NextDom Software. If not, see <http://www.gnu.org/licenses/>. */ namespace NextDom\Helpers; use NextDom\Enums\LogTarget; use NextDom\Enums\UserLocation; use NextDom\Exceptions\CoreException; use NextDom\Managers\ConfigManager; use NextDom\Managers\EqLogicManager; use NextDom\Managers\PluginManager; use NextDom\Managers\UpdateManager; use NextDom\Model\Entity\Cmd; use NextDom\Model\Entity\Update; /** * Class NetworkHelper * * @TODO: Dépendance avec le plugin OpenVPN * * @package NextDom\Helpers */ class NetworkHelper { /** * Get user source location * @return string * @throws \Exception */ public static function getUserLocation(): string { $clientIp = self::getClientIp(); $nextdomIp = self::getNetworkAccess(UserLocation::INTERNAL, 'ip', '', false); // Check validate IP if (!filter_var($nextdomIp, FILTER_VALIDATE_IP)) { return UserLocation::EXTERNAL; } // Check 4 parts of the IP // @TODO: Pourquoi ? Si l'ip est valide $nextdomIpParts = explode('.', $nextdomIp); if (count($nextdomIpParts) !== 4) { return UserLocation::EXTERNAL; } // Check all local IPs if defined if (ConfigManager::byKey('network::localip') != '') { $localIps = explode(';', ConfigManager::byKey('network::localip')); foreach ($localIps as $localIp) { if (self::netMatch($localIp, $clientIp)) { return UserLocation::INTERNAL; } } } // Check CIDR /24 $match = $nextdomIpParts[0] . '.' . $nextdomIpParts[1] . '.' . $nextdomIpParts[2] . '.*'; return self::netMatch($match, $clientIp) ? UserLocation::INTERNAL : UserLocation::EXTERNAL; } /** * Get server IP from PHP server data * * @return string Server IP */ public static function getClientIp(): string { if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { return $_SERVER['HTTP_X_FORWARDED_FOR']; } elseif (isset($_SERVER['HTTP_X_REAL_IP'])) { return $_SERVER['HTTP_X_REAL_IP']; } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) { return $_SERVER['HTTP_CLIENT_IP']; } elseif (isset($_SERVER['REMOTE_ADDR'])) { return $_SERVER['REMOTE_ADDR']; } return ''; } /** * Get type of network access * * @param string $_mode * @param string $_protocol * @param string $_default * @param bool $_test * @return mixed|string * @throws \Exception */ public static function getNetworkAccess($_mode = 'auto', $_protocol = '', $_default = '', $_test = false) { if ($_mode == 'auto') { $_mode = self::getUserLocation(); } if ($_mode == UserLocation::INTERNAL && ConfigManager::byKey('internalAddr', 'core', '') == '') { self::checkConf($_mode); } if ($_mode == UserLocation::EXTERNAL && ConfigManager::byKey('market::allowDNS') != 1 && ConfigManager::byKey('externalAddr', 'core', '') == '') { self::checkConf($_mode); } if ($_test && !self::test($_mode)) { self::checkConf($_mode); } if ($_mode == UserLocation::INTERNAL) { if (strpos(ConfigManager::byKey('internalAddr', 'core', $_default), 'http://') !== false || strpos(ConfigManager::byKey('internalAddr', 'core', $_default), 'https://') !== false) { ConfigManager::save('internalAddr', str_replace(['http://', 'https://'], '', ConfigManager::byKey('internalAddr', 'core', $_default))); } if ($_protocol == 'ip' || $_protocol == 'dns') { return ConfigManager::byKey('internalAddr', 'core', $_default); } if ($_protocol == 'ip:port' || $_protocol == 'dns:port') { return ConfigManager::byKey('internalAddr') . ':' . ConfigManager::byKey('internalPort', 'core', 80); } if ($_protocol == 'proto:ip' || $_protocol == 'proto:dns') { return ConfigManager::byKey('internalProtocol') . ConfigManager::byKey('internalAddr'); } if ($_protocol == 'proto:ip:port' || $_protocol == 'proto:dns:port') { return ConfigManager::byKey('internalProtocol') . ConfigManager::byKey('internalAddr') . ':' . ConfigManager::byKey('internalPort', 'core', 80); } if ($_protocol == 'proto:127.0.0.1:port:comp') { return trim(ConfigManager::byKey('internalProtocol') . '127.0.0.1:' . ConfigManager::byKey('internalPort', 'core', 80) . '/' . trim(ConfigManager::byKey('internalComplement'), '/'), '/'); } if ($_protocol == 'http:127.0.0.1:port:comp') { return trim('http://127.0.0.1:' . ConfigManager::byKey('internalPort', 'core', 80) . '/' . trim(ConfigManager::byKey('internalComplement'), '/'), '/'); } return trim(ConfigManager::byKey('internalProtocol') . ConfigManager::byKey('internalAddr') . ':' . ConfigManager::byKey('internalPort', 'core', 80) . '/' . trim(ConfigManager::byKey('internalComplement'), '/'), '/'); } if ($_mode == 'dnsnextdom') { return ConfigManager::byKey('nextdom::url'); } if ($_mode == UserLocation::EXTERNAL) { if ($_protocol == 'ip') { if (ConfigManager::byKey('market::allowDNS') == 1 && ConfigManager::byKey('nextdom::url') != '' && ConfigManager::byKey('network::disableMangement') == 0) { return self::getIpFromString(ConfigManager::byKey('nextdom::url')); } return self::getIpFromString(ConfigManager::byKey('externalAddr')); } if ($_protocol == 'ip:port') { if (ConfigManager::byKey('market::allowDNS') == 1 && ConfigManager::byKey('nextdom::url') != '' && ConfigManager::byKey('network::disableMangement') == 0) { $url = parse_url(ConfigManager::byKey('nextdom::url')); if (isset($url['host'])) { if (isset($url['port'])) { return self::getIpFromString($url['host']) . ':' . $url['port']; } else { return self::getIpFromString($url['host']); } } } return ConfigManager::byKey('externalAddr') . ':' . ConfigManager::byKey('externalPort', 'core', 80); } if ($_protocol == 'proto:dns:port' || $_protocol == 'proto:ip:port') { if (ConfigManager::byKey('market::allowDNS') == 1 && ConfigManager::byKey('nextdom::url') != '' && ConfigManager::byKey('network::disableMangement') == 0) { $url = parse_url(ConfigManager::byKey('nextdom::url')); $return = ''; if (isset($url['scheme'])) { $return = $url['scheme'] . '://'; } if (isset($url['host'])) { if (isset($url['port'])) { return $return . $url['host'] . ':' . $url['port']; } else { return $return . $url['host']; } } } return ConfigManager::byKey('externalProtocol') . ConfigManager::byKey('externalAddr') . ':' . ConfigManager::byKey('externalPort', 'core', 80); } if ($_protocol == 'proto:dns' || $_protocol == 'proto:ip') { if (ConfigManager::byKey('market::allowDNS') == 1 && ConfigManager::byKey('nextdom::url') != '' && ConfigManager::byKey('network::disableMangement') == 0) { $url = parse_url(ConfigManager::byKey('nextdom::url')); $return = ''; if (isset($url['scheme'])) { $return = $url['scheme'] . '://'; } if (isset($url['host'])) { if (isset($url['port'])) { return $return . $url['host'] . ':' . $url['port']; } else { return $return . $url['host']; } } } return ConfigManager::byKey('externalProtocol') . ConfigManager::byKey('externalAddr'); } if ($_protocol == 'dns:port') { if (ConfigManager::byKey('market::allowDNS') == 1 && ConfigManager::byKey('nextdom::url') != '' && ConfigManager::byKey('network::disableMangement') == 0) { $url = parse_url(ConfigManager::byKey('nextdom::url')); if (isset($url['host'])) { if (isset($url['port'])) { return $url['host'] . ':' . $url['port']; } else { return $url['host']; } } } return ConfigManager::byKey('externalAddr') . ':' . ConfigManager::byKey('externalPort', 'core', 80); } if ($_protocol == 'proto') { if (ConfigManager::byKey('market::allowDNS') == 1 && ConfigManager::byKey('nextdom::url') != '' && ConfigManager::byKey('network::disableMangement') == 0) { $url = parse_url(ConfigManager::byKey('nextdom::url')); if (isset($url['scheme'])) { return $url['scheme'] . '://'; } } return ConfigManager::byKey('externalProtocol'); } if (ConfigManager::byKey('dns::token') != '' && ConfigManager::byKey('market::allowDNS') == 1 && ConfigManager::byKey('nextdom::url') != '' && ConfigManager::byKey('network::disableMangement') == 0) { return trim(ConfigManager::byKey('nextdom::url') . '/' . trim(ConfigManager::byKey('externalComplement', 'core', ''), '/'), '/'); } return trim(ConfigManager::byKey('externalProtocol') . ConfigManager::byKey('externalAddr') . ':' . ConfigManager::byKey('externalPort', 'core', 80) . '/' . trim(ConfigManager::byKey('externalComplement'), '/'), '/'); } return ''; } /** * @param string $_mode * @throws \Exception */ public static function checkConf($_mode = UserLocation::EXTERNAL) { if (ConfigManager::byKey($_mode . 'Protocol') == '') { ConfigManager::save($_mode . 'Protocol', 'http://'); } if (ConfigManager::byKey($_mode . 'Port') == '') { ConfigManager::save($_mode . 'Port', 80); } if (ConfigManager::byKey($_mode . 'Protocol') == 'https://' && ConfigManager::byKey($_mode . 'Port') == 80) { ConfigManager::save($_mode . 'Port', 443); } if (ConfigManager::byKey($_mode . 'Protocol') == 'http://' && ConfigManager::byKey($_mode . 'Port') == 443) { ConfigManager::save($_mode . 'Port', 80); } if (trim(ConfigManager::byKey($_mode . 'Complement')) == '/') { ConfigManager::save($_mode . 'Complement', ''); } if ($_mode == UserLocation::INTERNAL) { foreach (self::getInterfacesList() as $interface) { if ($interface == 'lo') { continue; } $ip = self::getInterfaceIp($interface); if (!self::netMatch('127.0.*.*', $ip) && $ip != '' && filter_var($ip, FILTER_VALIDATE_IP)) { ConfigManager::save('internalAddr', $ip); break; } } } } /** * @return array * @throws \Exception */ public static function getInterfacesList() { $interfaces = explode("\n", shell_exec(SystemHelper::getCmdSudo() . "ip -o link show | awk -F': ' '{print $2}'")); $result = []; foreach ($interfaces as $interface) { if (trim($interface) == '') { continue; } $result[] = $interface; } return $result; } /* * *********************DNS************************* */ /** * @param $_interface * @return bool|string * @throws \Exception */ public static function getInterfaceIp($_interface) { $ip = trim(shell_exec(SystemHelper::getCmdSudo() . "ip addr show " . $_interface . " 2> /dev/null | grep \"inet .*" . $_interface . "\" | awk '{print $2}' | cut -d '/' -f 1")); if (filter_var($ip, FILTER_VALIDATE_IP)) { return $ip; } return false; } /** * @param string $network * @param string $ip * * @return bool */ public static function netMatch($network, $ip) { $ip = trim($ip); if ($ip === trim($network)) { return true; } $network = str_replace(' ', '', $network); if (strpos($network, '*') !== false) { if (strpos($network, '/') !== false) { $asParts = explode('/', $network); if ($asParts[0]) { $network = $asParts[0]; } else { $network = null; } } $nCount = substr_count($network, '*'); $network = str_replace('*', '0', $network); if ($nCount == 1) { $network .= '/24'; } elseif ($nCount == 2) { $network .= '/16'; } elseif ($nCount == 3) { $network .= '/8'; } elseif ($nCount > 3) { return true; // if *.*.*.*, then all, so matched } } $d = strpos($network, '-'); if ($d === false) { if (strpos($network, '/') === false) { if ($ip == $network) { return true; } return false; } $ip_arr = explode('/', $network); if (!preg_match("@\d*\.\d*\.\d*\.\d*@", $ip_arr[0], $matches)) { $ip_arr[0] .= ".0"; // Alternate form 194.1.4/24 } $network_long = ip2long($ip_arr[0]); $x = ip2long($ip_arr[1]); $mask = long2ip($x) == $ip_arr[1] ? $x : (0xffffffff << (32 - $ip_arr[1])); $ip_long = ip2long($ip); return ($ip_long & $mask) == ($network_long & $mask); } else { $from = trim(ip2long(substr($network, 0, $d))); $to = trim(ip2long(substr($network, $d + 1))); $ip = ip2long($ip); return ($ip >= $from && $ip <= $to); } } /** * @param string $_mode * @param int $_timeout * @return bool * @throws \Exception */ public static function test($_mode = UserLocation::EXTERNAL, $_timeout = 2) { if (ConfigManager::byKey('network::disableMangement') == 1) { return true; } if ($_mode == UserLocation::INTERNAL && self::netMatch('127.0.*.*', self::getNetworkAccess($_mode, 'ip', '', false))) { return false; } $url = trim(self::getNetworkAccess($_mode, '', '', false), '/') . '/public/here.html'; $ch = curl_init(); curl_setopt($ch, CURLOPT_TIMEOUT, $_timeout); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_HEADER, false); if ($_mode == UserLocation::EXTERNAL) { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); } $data = curl_exec($ch); if (curl_errno($ch)) { LogHelper::addDebug(LogTarget::NETWORK, 'Erreur sur ' . $url . ' => ' . curl_errno($ch)); curl_close($ch); return false; } curl_close($ch); if (trim($data) != 'ok') { LogHelper::addDebug(LogTarget::NETWORK, 'Retour NOK sur ' . $url . ' => ' . $data); return false; } return true; } /** * @param $_string * @return bool|mixed|string */ public static function getIpFromString($_string) { $result = parse_url($_string); if (isset($result['host'])) { $_string = $result['host']; } else { $_string = str_replace(['https://', 'http://'], '', $_string); if (strpos($_string, '/') !== false) { $_string = substr($_string, 0, strpos($_string, '/')); } if (strpos($_string, ':') !== false) { $_string = substr($_string, 0, strpos($_string, ':')); } } if (!filter_var($_string, FILTER_VALIDATE_IP)) { $_string = gethostbyname($_string); } return $_string; } /** * @param $_interface * @return bool|string * @throws \Exception */ public static function getInterfaceMac($_interface) { $valid_mac = "([0-9A-F]{2}[:-]){5}([0-9A-F]{2})"; $mac = trim(shell_exec(SystemHelper::getCmdSudo() . "ip addr show " . $_interface . " 2>&1 | grep ether | awk '{print $2}'")); if (preg_match("/" . $valid_mac . "/i", $mac)) { return $mac; } return false; } public static function cron5() { if (ConfigManager::byKey('network::disableMangement') == 1) { return; } if (!self::test(UserLocation::INTERNAL)) { self::checkConf(UserLocation::INTERNAL); } if (!self::test(UserLocation::EXTERNAL)) { self::checkConf(UserLocation::EXTERNAL); } if (!NextDomHelper::isCapable('sudo') || NextDomHelper::getHardwareName() == 'docker') { return; } exec(SystemHelper::getCmdSudo() . 'ping -n -c 1 -t 255 8.8.8.8 2>&1 > /dev/null', $output, $return_val); if ($return_val == 0) { return; } $gw = shell_exec("ip route show default | awk '/default/ {print $3}'"); if ($gw == '') { LogHelper::addError('network', __('Souci réseau détecté, redémarrage du réseau. Aucune gateway de trouvée')); exec(SystemHelper::getCmdSudo() . 'service networking restart'); return; } exec(SystemHelper::getCmdSudo() . 'ping -n -c 1 -t 255 ' . $gw . ' 2>&1 > /dev/null', $output, $return_val); if ($return_val == 0) { return; } exec(SystemHelper::getCmdSudo() . 'ping -n -c 1 -t 255 ' . $gw . ' 2>&1 > /dev/null', $output, $return_val); if ($return_val == 0) { return; } LogHelper::addError('network', __('Souci réseau détecté, redémarrage du réseau. La gateway ne répond pas au ping : ') . $gw); exec(SystemHelper::getCmdSudo() . 'service networking restart'); } public static function checkOpenPort($targetHost, $targetPort) { $fp = @fsockopen($targetHost, $targetPort, $errno, $errstr, 0.1); if (!is_resource($fp)) { return false; } fclose($fp); return true; } } |