Telnet sur switch Cisco

Telnet sur switch Cisco - PHP - Programmation

Marsh Posté le 19-01-2005 à 19:32:09    

Bonjour à tous   :)  
Suite à ce post
http://forum.hardware.fr/hardwaref [...] 0216-1.htm,
 j'utilise la classe Telnet pour me connecter sur des switchs cisco et
récupérer le résultat d'une commande. Cela marche niquel sur un type de
switch (2948G) mais pas sur un autre  :(  (3550).
Voici le code que j'utilise :

Code :
  1. error_reporting(-1);
  2. class Telnet {
  3.               var $sock = NULL;
  4.               function telnet($host,$port){
  5.                                             $this->sock =
  6. fsockopen($host,$port);
  7.                                           }
  8.               function close(){
  9.                                 if ($this->sock)
  10.                                                 fclose($this->sock);
  11.                                 $this->sock = NULL;
  12.                                }
  13.               function write($buffer) {
  14.                                         $buffer =
  15. str_replace(chr(255),chr(255).chr(255),$buffer);
  16.                                         fwrite($this->sock,$buffer);
  17.                                       }
  18.               function getc() {
  19.                                 return fgetc($this->sock);
  20.                               }
  21.               function read_till($what) {
  22.                                           $buf = '';
  23.                                           while (1) {
  24.                                           $IAC = chr(255);
  25.                                           $DONT = chr(254);
  26.                                           $DO = chr(253);
  27.                                           $WONT = chr(252);
  28.                                           $WILL = chr(251);
  29.                                           $theNULL = chr(0);
  30.                                           $c = $this->getc();
  31.                                           if ($c === false)
  32.                                                             return $buf;
  33.                                           if ($c == $theNULL) {
  34.                                                               continue;
  35.                                                               }
  36.                                           if ($c == "\021" ) {
  37.                                                               continue;
  38.                                                             }
  39.                                           if ($c != $IAC) {
  40.                                                             $buf .= $c;
  41.                                                             if ($what ==
  42. (substr($buf,strlen($buf)-strlen($what)))) {
  43. return $buf;
  44. } else {
  45. continue;
  46. }
  47.                                                           }
  48.                                           $c = $this->getc();
  49.                                           if ($c == $IAC) {
  50.                                                             $buf .= $c;
  51.                  } else if (($c == $DO) || ($c == $DONT)) {
  52.                                                             $opt =
  53. $this->getc();
  54.                                 fwrite($this->sock,$IAC.$WONT.$opt);
  55.                         } elseif (($c == $WILL) || ($c == $WONT)) {
  56.                                 $opt = $this->getc();
  57.                                 fwrite($this->sock,$IAC.$DONT.$opt);
  58.                         } else {
  59.                                }
  60.                     }
  61.         }
  62. }
  63. echo "Telnet :";
  64.                   //Connnexion telnet et stockage des données reçues :
  65.                   $tn = new telnet("mon_switch",23);
  66.                   sleep(1);
  67.                   echo $tn->read_till("d: " );
  68.                   sleep(1);
  69.                   //Mot de passe :
  70.                   $tn->write("mdp\r\n" );
  71.                   sleep(1);
  72.                   echo $tn->read_till("> " );
  73.                   sleep(1);
  74.                   $tn->write("sh port status\r\n" );
  75.                   $variable = $tn->read_till("> " );
  76.                   echo $tn->close();
  77.                   echo $variable;


Donc, sur un type de switch ca marche, j'ai tout ce qu'il faut dans
$variable, par contre sur d'autres type, le script reste bloqué ici :

Code :
  1. //Mot de passe :
  2. $tn->write("mdp\r\n" );


Il n'arrive pas à écrire le mot de passe, ou à valider.
Je précise qu'en telnet simple, sans passer par php, cela marche
parfaitement.
Si une bonne âme pouvait m'aider, car là je m'arrache les cheveux depuis 3
jours  :sleep:  :fou:

Reply

Marsh Posté le 19-01-2005 à 19:32:09   

Reply

Marsh Posté le 19-01-2005 à 23:01:50    

Reply

Marsh Posté le 19-01-2005 à 23:34:00    

jaywax a écrit :

Bonjour à tous   :)  
Suite à ce post
http://forum.hardware.fr/hardwaref [...] 0216-1.htm,
 j'utilise la classe Telnet pour me connecter sur des switchs cisco et
récupérer le résultat d'une commande. Cela marche niquel sur un type de
switch (2948G) mais pas sur un autre  :(  (3550).


Le 2900 doit tourner sous IOS 12.0 et le 3550 sous IOS 12.1, ou un truc comme ça. Donc il doit s'attendre à un usage plus rigoureux du protocole telnet (Cisco a fait quelques progrès dessus, bien que IOS ne soit pas parfaitement compliant, en particulier sur l'echo.).
 
Je n'ai pas regardé le lien que te donne T509, mais tu as tout intérêt à utiliser du code qui te fournit un protocole telnet correct...
 

Reply

Marsh Posté le 19-01-2005 à 23:39:42    

La différence avec cette classe est que la fonction que j'indique commence par initier la connexion telnet avec les headers ad-hoc. Je ne les vois nulle part dans cette classe

Reply

Marsh Posté le 19-01-2005 à 23:42:56    

T509 a écrit :

La différence avec cette classe est que la fonction que j'indique commence par initier la connexion telnet avec les headers ad-hoc. Je ne les vois nulle part dans cette classe


exactement, c'est pour ça que je lui disais d'utiliser du code plus rigoureux (le tien a l'air très bien), vu que les switchs et routeurs cisco font gaffe à ça.  
 
Surtout depuis les quelques problèmes de sécu de l'an 2002, et parce qu'il y a eu pas mal de bug reports sur le fait qu'ils géraient mal les en-têtes du protocole telnet).

Reply

Marsh Posté le 20-01-2005 à 08:30:01    

Merci pour vos réponses !
Aprés avoir repris ton code T509 comme suit :

Code :
  1. <?php
  2. //récupération des informations d'une balise Argos par connexion directe au centre de calcul CLS  
  3. //variables du script  
  4. $serveur = "hostname_switch";        //serveur de connexion netdis.cls.fr  
  5. //$login = "EVERYONE";            //login au serveur  
  6. $password = "mdp";            //password  
  7. $commande = "sh port status";        //commande à effectuer  
  8. function telnet($serveur, $mdp, $commande) {
  9.    
  10.     $close = "LOGOUT";
  11.    
  12.     // entetes TELNET  
  13.     $header1=chr(0xFF).chr(0xFB).chr(0x1F).chr(0xFF).chr(0xFB).
  14.     chr(0x20).chr(0xFF).chr(0xFB).chr(0x18).chr(0xFF).chr(0xFB).
  15.     chr(0x27).chr(0xFF).chr(0xFD).chr(0x01).chr(0xFF).chr(0xFB).
  16.     chr(0x03).chr(0xFF).chr(0xFD).chr(0x03).chr(0xFF).chr(0xFC).
  17.     chr(0x23).chr(0xFF).chr(0xFC).chr(0x24).chr(0xFF).chr(0xFA).
  18.     chr(0x1F).chr(0x00).chr(0x50).chr(0x00).chr(0x18).chr(0xFF).
  19.     chr(0xF0).chr(0xFF).chr(0xFA).chr(0x20).chr(0x00).chr(0x33).
  20.     chr(0x38).chr(0x34).chr(0x30).chr(0x30).chr(0x2C).chr(0x33).
  21.     chr(0x38).chr(0x34).chr(0x30).chr(0x30).chr(0xFF).chr(0xF0).
  22.     chr(0xFF).chr(0xFA).chr(0x27).chr(0x00).chr(0xFF).chr(0xF0).
  23.     chr(0xFF).chr(0xFA).chr(0x18).chr(0x00).chr(0x58).chr(0x54).
  24.     chr(0x45).chr(0x52).chr(0x4D).chr(0xFF).chr(0xF0);
  25.    
  26.     $header2=chr(0xFF).chr(0xFC).chr(0x01).chr(0xFF).chr(0xFC).
  27.     chr(0x22).chr(0xFF).chr(0xFE).chr(0x05).chr(0xFF).chr(0xFC).chr(0x21);
  28.    
  29.     // connexion  
  30.     $fp=pfsockopen($serveur,23);
  31.    
  32.     // envoi de l'entete telnet  
  33.     fputs($fp,$header1);
  34.     sleep(1);
  35.     fputs($fp,$header2);
  36.     sleep(1);
  37.    
  38.     //recupération de la réponse  
  39.     $output.=fread($fp,128);
  40.     $stat=socket_get_status($fp);
  41.     $output.=fread($fp, $stat["unread_bytes"]);
  42.    
  43.     /* login  
  44.     fputs($fp,$login."\r" );  
  45.     sleep(1);  
  46.      
  47.     //recupération de la réponse  
  48.     $output.=fread($fp,128);  
  49.     $stat=socket_get_status($fp);  
  50.     $output.=fread($fp, $stat["unread_bytes"]);  
  51.      
  52.     //password*/
  53.     fputs($fp,$mdp."\r" );
  54.     sleep(1);
  55.    
  56.     //recupération de la réponse  
  57.     $output.=fread($fp,128);
  58.     $stat=socket_get_status($fp);
  59.     $output.=fread($fp, $stat["unread_bytes"]);
  60.    
  61.     // envoi de la commande  
  62.     fputs($fp,$commande."\r" );       
  63.     sleep(1);
  64.    
  65.     //lecture de la reponse  
  66.     $output.=fread($fp,128);
  67.     $stat=socket_get_status($fp);
  68.     $output.=fread($fp, $stat["unread_bytes"]);
  69.    
  70.     //logout  
  71.     fputs($fp,$close."\r" );
  72.     fclose($fp);
  73.    
  74.     $result = strpos($output, $commande);
  75.    
  76.     if ($result) {
  77.         return $output;
  78.     }
  79.     else {
  80.         echo $output;
  81.         return FALSE;
  82.     }
  83. }
  84. // Fin de la fonction de connexion TELNET  
  85. ///////////////////////////////////////////////////////  
  86. //appel des resultats par TELNET  
  87. $reponse = telnet($serveur, $password, $commande);
  88. echo $reponse;
  89. //Test sans connexion  
  90. //$reponse = "ARGOS READY /COM/C,10,,ALL PROG  \t  \r   10 10000  43.543N     10.398W  \t\n\t   3      \n\r\t      286/1322Z-286/0926 ( 3) 0.99811E+3               32   0.20000E+2   0.32000E+2 ";  
  91. /*si la réponse n'est pas complete, on recommence (jusque 2 essais)  
  92. if (!$reponse) {  
  93.     sleep(3);  
  94.     $reponse = telnet($serveur, $password, $commande);  
  95. }  
  96. if (!$reponse) {  
  97.     sleep(3);  
  98.     $reponse = telnet($serveur, $password, $commande);  
  99. }  
  100. if ($reponse) {  
  101.     //traitement de la chaine retour  
  102.     if (strpos($reponse, "/".$commande)) {  
  103.          
  104.         //extraction des données  
  105.         ereg("[0-9]{1,3}\.[0-9]{3}(N|S)", $reponse, $lat); //recup latitude  
  106.         ereg("[0-9]{1,3}\.[0-9]{3}(W|E)", $reponse, $long); //recup longitude  
  107.         ereg($long[0]."[ \t\n\r]+([0-9A-Z]{1})", $reponse, $classe); //recup classe de résultat  
  108.         ereg("([0-9]{1,3})/([0-9]{4})Z-([0-9]{1,3})/([0-9]{4})", $reponse, $date); //recup date et heure de dernière localisation  
  109.                  
  110.         //traitement de la date  
  111.         $aujourdhui = strftime("%j" );     //numéro d'aujourd'hui dans le calendrier  
  112.                         //si le numero du jour de > à celui d'aujourd'hui, nous travaillons avec l'annee derniere  
  113.         $annee = ($aujourdhui < $date[3]) ? intval(strftime("%Y" )) - 1 : intval(strftime("%Y" ));       
  114.         $minute = substr($date[4], 2, 2);  
  115.         $heure = substr($date[4], 0, 2);  
  116.          
  117.         $derniere_localisation = date("d/m/Y", mktime (0,0,0,1,$date[3],$annee))." $heure:$minute";  
  118.          
  119.          
  120.         //enregistrement dans un fichier des donnees LAT et LONG  
  121.         $fichier = "gps.html";  
  122.         $fp = fopen($fichier, "wb" );  
  123.         fputs($fp, "LAT : $lat[0] <br />LONG : $long[0]" );  
  124.         fclose($fp);  
  125.          
  126.          
  127.         echo "La derni&egrave;re localisation de la balise : $derniere_localisation GMT <br />LAT : $lat[0] <br />LONG : $long[0] <br />Classe de résultat : $classe[1]";  
  128.          
  129.     }  
  130.     else {  
  131.         echo "Erreur de r&eacute;cup&eacute;ration des donn&eacute;es";  
  132.     }  
  133. }  
  134. else {  
  135.     echo "Erreur de connexion avec le serveur Argos";  
  136. }  
  137. */
  138. ?>


Je l'ai juste un peu adapté car la connexion telnet ne necessite pas de login sur mes switchs.
La réponse du script (sur les deux modèles) :

Code :
  1. Fatal error: Maximum execution time of 30 seconds exceeded in c:\program files\easyphp\www\test.php on line 60


 :sweat:

Reply

Marsh Posté le 20-01-2005 à 13:49:40    

Eh bien il bloque sur la réception de la réponse après le mdp.
c'est à toi de gérer ta connexion ensuite. Moi j'e l'ai utilisé avec un serveur donné. Pour le reste c'est à toi d'adapter ...

Reply

Marsh Posté le 20-01-2005 à 15:11:21    

T509 a écrit :

Eh bien il bloque sur la réception de la réponse après le mdp.
c'est à toi de gérer ta connexion ensuite. Moi j'e l'ai utilisé avec un serveur donné. Pour le reste c'est à toi d'adapter ...


... Quelle perspicacité --> Voir mon 1er post.
Ce qui m'interresse, c'est surtout la fameuse gestion de ma connexion...

Reply

Marsh Posté le 20-01-2005 à 20:54:55    

Serieux ca serait cool si vous pouviez m'aider car je suis arrivé aux max de mes possibilités ...  :heink:

Reply

Marsh Posté le 20-01-2005 à 21:58:42    

j'avais codé il y a longtemps une fonction pour faire ca, elle fonctionnait sur tous les modeles cisco qu'il m'avait eté donné d'essayer (dont les 3550)
elle est loin d'etre au point mais elle fonctionne : http://phpcs.com/code.aspx?ID=20381

Reply

Marsh Posté le 20-01-2005 à 21:58:42   

Reply

Marsh Posté le 24-01-2005 à 09:07:59    

Salut à tous et merci psyjc pour ton code, mais j'ai beaucoup de mal à l'adapter :(. J'ai donc poursuivi mes recherches et suit tombé sur le script de Frame IP que j'ai adapté à ma sauce. Et la surprise, ca marche pour mes deux types de switch mais lors du rendu des résultats, le script tourne en boucle et je me retrouve avec un gros timeout, malgrés le fait que j'ai les résultats escontés... Voici le code :

Code :
  1. <?php
  2. function reception($id_de_la_socket,$chaine_attendue,$affichage){
  3.   // Argument 1 : $id_de_la_socket est de type SOCKET. Il représente l'id de la socket à analyser.
  4.   // Argument 2 : $chaine_attendue est de type char xx[xx]. Il représente la chaine de caractère indiquant la fin de la reception.
  5.   // Argument 3 : $affichage est de type bool. Il indique si l'echo des caractères reçu doit être affiché.
  6. $chaine_recue="";
  7. $tempo="";
  8. $condition_de_sortie=0;
  9. // *****************************
  10. // Boucle de reception
  11. // *****************************
  12. while($condition_de_sortie==0){
  13.  // *****************************
  14.  // Valide si la chaine attendue est réceptionnée ou la fin du tampon
  15.  // *****************************
  16.  if (strpos($chaine_recue,$chaine_attendue)!=false||@feof($id_de_la_socket))
  17.   $condition_de_sortie=1;
  18.  // *****************************
  19.  // Reception des données de 1280 octets, mais peu importe dû au mode non bloquant
  20.  // *****************************
  21.  $tempo=fgets($id_de_la_socket,1024);
  22.  // *****************************
  23.  // Force l'affiche
  24.  // *****************************
  25.  flush();
  26.  // *****************************
  27.  // Remplace le code de retour charriot pour correspondre à la norme html
  28.  // *****************************
  29.  $tempo=str_replace("\n","<br>",$tempo);
  30.  // *****************************
  31.  // Affichage des données recues
  32.  // *****************************
  33.  if ($affichage==true)
  34.   echo $tempo;
  35.  // *****************************
  36.  // Concatenation des donnée recue afin de pourvoir comparer par rapport à la chaine attendue de sortie
  37.  // *****************************
  38.  $chaine_recue.=$tempo;
  39.  }
  40. }
  41. $routeur_ip="mon_switch";
  42. $prompt_cisco="MON_SWITCH>";
  43. $id_de_la_socket=@fsockopen($routeur_ip,23,&$errno,&$errstr,2);
  44. if($id_de_la_socket){
  45.                     //reception($id_de_la_socket,"Password: ",true);
  46.                     fputs ($id_de_la_socket, "mdp\nmdp\n" );
  47.                     //Obligé de taper le mdp deux fois sinon cela ne marche pas sur les deux types de switchs.
  48.                       reception($id_de_la_socket,$prompt_cisco,false);
  49.               $commande_cisco="sh version\n";
  50.                                              fputs ($id_de_la_socket, $commande_cisco);
  51.                                              reception($id_de_la_socket,$commande_cisco,true);
  52.                                                                    fin_du_script();
  53.                   }
  54. else
  55. lookingglass_erreur(2);
  56. // ********************************************
  57. // Fonction d'affichage de l'erreur de saisie
  58. // ********************************************
  59. function lookingglass_erreur($erreur) // $erreur représente le numéro d'erreur.
  60. {
  61. // ********************************************
  62. // Affichage de titre
  63. // ********************************************
  64. echo
  65.  '
  66.  <p align="center">
  67.   <b>
  68.    <font size="5" color="#008000">
  69.     Erreur
  70.    </font>
  71.   </b>
  72.  </p>
  73.  ';
  74. // ********************************************
  75. // Affichage de l'erreur
  76. // ********************************************
  77. echo
  78.  '
  79.  <p>
  80.  ';
  81. // ********************************************
  82. // Message personnalisé
  83. // ********************************************
  84. if ($erreur==1)
  85.  echo 'Désolé, pour des raisons de sécurité, l\'équipe FrameIP ne peut pas vous permettre d\'utiliser les adresses privées.';
  86. elseif ($erreur==2)
  87.  echo 'Désolé, impossible d\'ouvrir la session TCP à destination du routeur.';
  88. // ********************************************
  89. // Fin du script général
  90. // ********************************************
  91. fin_du_script();
  92. }
  93. function fin_du_script()
  94. {
  95. // ********************************************
  96. // Affiche de l'Url
  97. // ********************************************
  98. echo '
  99.  Fin du script
  100.  ';
  101. // ********************************************
  102. // Fin de la page Html
  103. // ********************************************
  104. echo $variable;
  105. // ********************************************
  106. // Fin du script général
  107. // ********************************************
  108. exit(0);
  109. }
  110. ?>


En fait, l'objectif est à travers une boucle et selon le nombre de ports du switch, d'effectuer deux commandes sur chaque port switch :

Code :
  1. sh port status 2/$i --> Voir le status du port sur un 2948G
  2. sh int status Fa0/$i --> La même chose sur un 3550
  3. Et enfin si le port est enabled :
  4. sh cam dyn (2/$i ou Fa0/$i) --> Voir l'adresse mac présente sur le port.


Le problème avec ce code, c'est que l'affichage s'effectue (bien que je n'arrive pas à mettre le tout dans une variable), mais la boucle d'affichage ne se termine pas... Je ne peux donc pas faire ma boucle pour effectuer mon "sh cam dyn $i (ou $i = un port/switch)...
Si vous aviez une idée ou encore un peu de temps à me consacrer  :D

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed