2015-06-22 14 views
6

Beni güldüren bir sorunum var.PHP Telnet/SSH dinamik giriş

Bir yönlendiriciye CLI girişini otomatikleştirmeye çalışıyorum ve bir web sayfası aracılığıyla elde edilen bazı komutları çalıştırıyorum. Ancak yönlendiricinin telnet veya SSH'nin etkin olup olmadığını bilmiyorum (biri, diğeri veya her ikisi de olabilir) ve erişim elde etmeye çalışmam gereken olası kullanıcı adı/şifre kombinasyonlarım var.
Oh, ve aygıttaki protokol türünü veya kimlik bilgilerini değiştiremiyorum, bu gerçekten bir seçenek değil.

Bilinen bir protokol ve giriş kimlik bilgisine sahip bir yönlendiriciye nasıl giriş yapılabileceğini ve gerekli komutları (aşağıda yer alan) nasıl çalıştıracağımı anlayabiliyorum, ancak eğer çalışmak için bir if/else bloğu kullanmalıyım bilmiyorum telnet/ssh kararları aracılığıyla veya bir anahtar ifadesi daha iyi olabilir mi? PHP içinde Expect kullanmak daha kolay bir yol olabilir mi?

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>"; 

Güncelleme:

Bir süre/switch döngüsü oldu gitti çözüm. Ben Expect rotası gitmişti, ama sunucumda PHP'ye entegre Expect modülünü alma konusunda sorun yaşamaya devam ettim (Windows kutusu.) Eğer bir Unix/Linux sunucusu kullanıyor olsaydım, bunu başarmanın en kolay yolu olurdu. . Şimdilik bir çalışma demosuna girdim, bu yüzden hala durum ifadelerinden eksik olan birçok hata var ve hataların hala çözülmesi gerekiyor, ama temel fikir var. Hala while döngüsünün üstündeki eşleşmeyi yapmak için preg_match ifadelerini biraz daha fazla hareket ettirmek istiyorum (bu yüzden farklı preg_match satırları ile tüm vaka bölümünü spam yapmıyorum), ancak bu benden daha fazla iş olabilir şimdi istiyorum. Umarım bu aynı şeyi yapmaya çalışan başkalarına yardımcı olabilir!

<?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"; 
} 
?> 
+0

'if' '' '' '' '' '' '' '' '' '' '' '' '' '' 'blokları' '' '' '' 'blokları hemen hemen aynıdır. –

cevap

3

Açıklamalar kodunuzun okunamaz hale gelmesini sağlayabilir.
Bu durumda, anahtar kutusu daha net kod yazmanıza olanak tanıyacağından ve istisnai değerleri daha verimli şekilde yakalayabilmenizi sağlayacağından, anahtar kutusu bloklarını
kullanmanızı öneririm. php Expect kullanarak

basittir:

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

$stream = fopen("expect://ssh [email protected] 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); 

?> 
+0

Yukarıdaki kod çok şık görünüyor, ancak okuduğunuz gibi açtığınız bir akış yazıyorsunuz. Okumak ve yazmak için proc_open çalışma süresini mutlaka çağırmak ister? – symcbean

+0

Gerçekten. proc_open - Bir komutu yürütün ve giriş/çıkış için dosya tanıtıcılarını açın (http://php.net/manual/en/function.proc-open.php adresinden) –

0

bekliyoruz file_wrapper kullanarak bazı komplikasyon vardır. Eğer ben olsaydım, telnet için basit bir soket bağlantısı ve ssh bağlantısı başarısız olursa komutlar için (zaman aşımı ile) yoksaydım.

Rahat bir denetimde, telnet client here hassas bir şekilde yazılmış gibi görünüyor - ve biraz yeniden adlandırma ile ssh2 istemci uzantısı (bağlantı bitinden ayrı olarak) ile aynı arabirimi sağlayabilir.