PHP Telnet/SSH动态登录

Cyn*_*kal 6 php ssh login telnet phpseclib

我有一个难以理解的问题.

我正在尝试自动登录到路由器的CLI并运行通过网页获得的一些命令.但是我不知道路由器是否启用了telnet或SSH(可能是一个,另一个或两者),我有一个可能的用户名/密码组合列表,我需要尝试获取访问权限.
哦,我无法更改协议类型或设备上的凭据,因此这不是一个真正的选择.

我能够弄清楚如何使用已知的协议和登录凭据登录到路由器并运行必要的命令(包含在下面),但我不知道是否应该使用if/else块来处理telnet/ssh决定,或者如果switch语句可能更好?在PHP中使用Expect是一种更简单的方法吗?

function tunnelRun($commands,$user,$pass, $yubi){
    $cpeIP = "1.2.3.4";
    $commands_explode = explode("\n", $commands);

    $screenOut = "";

    $ssh = new Net_SSH2('router_jumphost');
    if (!$ssh->login($user, $pass . $yubi)) {
        exit('Login Failed');
    }


    $ssh->setTimeout(2);
    $ssh->write("ssh -l username $cpeIP\n");
    $ssh->read("assword:");
    $ssh->write("password\n");
    $ssh->read("#");
    $ssh->write("\n");
    $cpePrompt = $ssh->read('/.*[#|>]/', NET_SSH2_READ_REGEX);
    $cpePrompt = str_replace("\n", '', trim($cpePrompt));
    $ssh->write("config t\n");


    foreach ($commands_explode as $i) {
        $ssh->write("$i\n"); // note the "\n"
        $ssh->setTimeout(2);
        $screenOut .= $ssh->read();

    }
    $ssh->write("end\n");
    $ssh->read($cpePrompt);
    $ssh->write("exit\n");
    echo "Router Update completed! Results below:<br><br>";

    echo "<div id=\"text_out\"><textarea style=\" border:none; width: 700px;\" rows=\"20\">".$screenOut."</textarea></div>";
Run Code Online (Sandbox Code Playgroud)

更新:

我使用的解决方案是while/switch循环.我想走了Expect路线,但是我一直在讨论如何在我的服务器上将Expect模块集成到PHP中(Windows框.)如果我一直在使用Unix/Linux服务器,那么Expect将是实现这一目标的最简单方法.我现在只是把它变成了一个工作演示,所以案例陈述中仍然有很多变化,而且错误处理仍然需要解决,但基本的想法是存在的.我仍然希望将preg_match语句更多地移动到while循环顶部进行匹配(所以我不会使用不同的preg_match行对整个case部分进行垃圾邮件),但这可能比我更多的工作现在想要.希望这可能会帮助其他人尝试做同样的事情!

    <?php
 include('Net/SSH2.php');
 define('NET_SSH2_LOGGING', NET_SSH2_LOG_COMPLEX);
 ini_set('display_errors', 1);

$conn = new Net_SSH2('somewhere.outthere.com');
if (!$conn->login($user, $pass . $yubi)) {
    exit('Login Failed');
}

$prompt = "Testing#";

$conn->setTimeout(2);
$conn->write("PS1=\"$prompt\"");
$conn->read();
$conn->write("\n");
$screenOut = $conn->read();

//echo "$screenOut is set on the shell<br><br>";
echo $login_db[3][0]. "  ". $login_db[3][1];

$logged_in = false;
$status = "SSH";
$status_prev = "";
$login_counter = 0;
while (!$logged_in && $login_counter <=3) {
    switch ($status) {

        case "Telnet":
            break;
        case "SSH":
            $conn->write("\n");
            $conn->write("ssh -l " . $login_db[$login_counter][0] . " $cpeIP\n");
            $status_prev = $status;
            $status = $conn->read('/\n([.*])$/', NET_SSH2_READ_REGEX);
            break;
        case (preg_match('/Permission denied.*/', $status) ? true : false):
            $conn->write(chr(3)); //Sends Ctrl+C
            $status = $conn->read();
            if (strstr($status, "Testing#")) {
                $status = "SSH";
                $login_counter++;
                break;
            } else {
                break 2;
            }
        case (preg_match('/[pP]assword:/', $status) ? true : false):

            $conn->write($login_db[$login_counter][1] . "\n");
            $status_prev = $status;
            $status = $conn->read('/\n([.*])$/', NET_SSH2_READ_REGEX);
            break;
        case (preg_match('/yes\/no/', $status) ? true : false):
            $conn->write("yes\n");
            $status_prev = $status;
            $status = $conn->read('/\n([.*])$/', NET_SSH2_READ_REGEX);
            break;
        case (preg_match('/(^[a-zA-Z0-9_]+[#]$)|(>)/', $status,$matches) ? true : false):


            $conn->write("show version\n");
            $status = $conn->read(">");
            if(preg_match('/ADTRAN|Adtran|Cisco/', $status)? true:false){
                $logged_in = true;
                break;
            }

        default:
            echo "<br>Something done messed up! Exiting";
            break 2;

    }
    //echo "<pre>" . $conn->getLog() . "</pre>";
}
if ($logged_in === true) {
    echo "<br> Made it out of the While loop cleanly";
} else {
    echo "<br> Made it out of the While loop, but not cleanly";
}
echo "<pre>" . $conn->getLog() . "</pre>";

$conn->disconnect();
echo "disconnected cleanly";
}
?>
Run Code Online (Sandbox Code Playgroud)

Alo*_*gan 3

If 语句可能会使您的代码变得不可读。
在这种情况下,我建议您使用 switch-case 块,
因为 switch-case 可以让您编写更清晰的代码,并且可以让您更有效地捕获异常值。

在 php 中使用 Expect 很简单:

<?php>
ini_set("expect.loguser", "Off");

$stream = fopen("expect://ssh root@remotehost uptime", "r");

$cases = array (
    array (0 => "password:", 1 => PASSWORD)
);

switch (expect_expectl ($stream, $cases)) {
    case PASSWORD:
       fwrite ($stream, "password\n");
       break;
    default:
       die ("Error was occurred while connecting to the remote host!\n");
}

while ($line = fgets($stream)) {
      print $line;
}
fclose ($stream);

?>
Run Code Online (Sandbox Code Playgroud)