1+ <?php
2+ namespace HackerScripts \Lib ;
3+
4+ /**
5+ * Telnet class
6+ *
7+ * Used to execute remote commands via telnet connection
8+ * Usess sockets functions and fgetc() to process result
9+ *
10+ * All methods throw Exceptions on error
11+ *
12+ * Written by Dalibor Andzakovic <[email protected] > 13+ * Based on the code originally written by Marc Ennaji and extended by
14+ * Matthias Blaser <[email protected] > 15+ *
16+ * Extended by Christian Hammers <[email protected] > 17+ * Modified by Frederik Sauer <[email protected] > 18+ *
19+ */
20+
21+ class Telnet {
22+
23+ private $ host ;
24+ private $ port ;
25+ private $ timeout ;
26+ private $ stream_timeout_sec ;
27+ private $ stream_timeout_usec ;
28+
29+ private $ socket = NULL ;
30+ private $ buffer = NULL ;
31+ private $ prompt ;
32+ private $ errno ;
33+ private $ errstr ;
34+ private $ strip_prompt = TRUE ;
35+
36+ private $ NULL ;
37+ private $ DC1 ;
38+ private $ WILL ;
39+ private $ WONT ;
40+ private $ DO ;
41+ private $ DONT ;
42+ private $ IAC ;
43+
44+ private $ global_buffer = '' ;
45+
46+ const TELNET_ERROR = FALSE ;
47+ const TELNET_OK = TRUE ;
48+
49+ public function __construct ($ host = '127.0.0.1 ' , $ port = '23 ' , $ timeout = 10 , $ prompt = '$ ' , $ stream_timeout = 1 ) {
50+ $ this ->host = $ host ;
51+ $ this ->port = $ port ;
52+ $ this ->timeout = $ timeout ;
53+ $ this ->setPrompt ($ prompt );
54+ $ this ->setStreamTimeout ($ stream_timeout );
55+
56+ // set some telnet special characters
57+ $ this ->NULL = chr (0 );
58+ $ this ->DC1 = chr (17 );
59+ $ this ->WILL = chr (251 );
60+ $ this ->WONT = chr (252 );
61+ $ this ->DO = chr (253 );
62+ $ this ->DONT = chr (254 );
63+ $ this ->IAC = chr (255 );
64+
65+ $ this ->connect ();
66+ }
67+
68+ public function __destruct () {
69+ // clean up resources
70+ $ this ->disconnect ();
71+ $ this ->buffer = NULL ;
72+ $ this ->global_buffer = NULL ;
73+ }
74+
75+ public function connect () {
76+ // check if we need to convert host to IP
77+ if (!preg_match ('/([0-9]{1,3} \\.){3,3}[0-9]{1,3}/ ' , $ this ->host )) {
78+ $ ip = gethostbyname ($ this ->host );
79+
80+ if ($ this ->host == $ ip ) {
81+ throw new Exception ("Cannot resolve $ this ->host " );
82+ } else {
83+ $ this ->host = $ ip ;
84+ }
85+ }
86+
87+ // attempt connection - suppress warnings
88+ $ this ->socket = @fsockopen ($ this ->host , $ this ->port , $ this ->errno , $ this ->errstr , $ this ->timeout );
89+
90+ if (!$ this ->socket ) {
91+ throw new Exception ("Cannot connect to $ this ->host on port $ this ->port " );
92+ }
93+
94+ if (!empty ($ this ->prompt )) {
95+ $ this ->waitPrompt ();
96+ }
97+
98+ return self ::TELNET_OK ;
99+ }
100+
101+ public function disconnect () {
102+ if ($ this ->socket ) {
103+ if (! fclose ($ this ->socket )) {
104+ throw new Exception ("Error while closing telnet socket " );
105+ }
106+ $ this ->socket = NULL ;
107+ }
108+ return self ::TELNET_OK ;
109+ }
110+
111+ public function exec ($ command , $ add_newline = TRUE ) {
112+ $ this ->write ($ command , $ add_newline );
113+ $ this ->waitPrompt ();
114+ return $ this ->getBuffer ();
115+ }
116+
117+ public function login ($ username , $ password ) {
118+ try {
119+ $ this ->setPrompt ('login: ' );
120+ $ this ->waitPrompt ();
121+ $ this ->write ($ username );
122+ $ this ->setPrompt ('Password: ' );
123+ $ this ->waitPrompt ();
124+ $ this ->write ($ password );
125+ $ this ->setPrompt ();
126+ $ this ->waitPrompt ();
127+ } catch (Exception $ e ) {
128+ throw new Exception ("Login failed. " );
129+ }
130+
131+ return self ::TELNET_OK ;
132+ }
133+
134+ public function setPrompt ($ str = '$ ' ) {
135+ return $ this ->setRegexPrompt (preg_quote ($ str , '/ ' ));
136+ }
137+
138+ public function setRegexPrompt ($ str = '\$ ' ) {
139+ $ this ->prompt = $ str ;
140+ return self ::TELNET_OK ;
141+ }
142+
143+ public function setStreamTimeout ($ timeout ) {
144+ $ this ->stream_timeout_usec = (int )(fmod ($ timeout , 1 ) * 1000000 );
145+ $ this ->stream_timeout_sec = (int )$ timeout ;
146+ }
147+
148+ public function stripPromptFromBuffer ($ strip ) {
149+ $ this ->strip_prompt = $ strip ;
150+ } // function stripPromptFromBuffer
151+
152+ protected function getc () {
153+ stream_set_timeout ($ this ->socket , $ this ->stream_timeout_sec , $ this ->stream_timeout_usec );
154+ $ c = fgetc ($ this ->socket );
155+ $ this ->global_buffer .= $ c ;
156+ return $ c ;
157+ }
158+
159+ public function clearBuffer () {
160+ $ this ->buffer = '' ;
161+ }
162+
163+ public function readTo ($ prompt ) {
164+ if (!$ this ->socket ) {
165+ throw new Exception ("Telnet connection closed " );
166+ }
167+
168+ // clear the buffer
169+ $ this ->clearBuffer ();
170+
171+ $ until_t = time () + $ this ->timeout ;
172+ do {
173+ // time's up (loop can be exited at end or through continue!)
174+ if (time () > $ until_t ) {
175+ throw new Exception ("Couldn't find the requested : ' $ prompt' within {$ this ->timeout } seconds " );
176+ }
177+
178+ $ c = $ this ->getc ();
179+
180+ if ($ c === FALSE ) {
181+ if (empty ($ prompt )) {
182+ return self ::TELNET_OK ;
183+ }
184+ throw new Exception ("Couldn't find the requested : ' " . $ prompt . "', it was not in the data returned from server: " . $ this ->buffer );
185+ }
186+
187+ // Interpreted As Command
188+ if ($ c == $ this ->IAC ) {
189+ if ($ this ->negotiateTelnetOptions ()) {
190+ continue ;
191+ }
192+ }
193+
194+ // append current char to global buffer
195+ $ this ->buffer .= $ c ;
196+
197+ // we've encountered the prompt. Break out of the loop
198+ if (!empty ($ prompt ) && preg_match ("/ {$ prompt }$/ " , $ this ->buffer )) {
199+ return self ::TELNET_OK ;
200+ }
201+
202+ } while ($ c != $ this ->NULL || $ c != $ this ->DC1 );
203+ }
204+
205+ public function write ($ buffer , $ add_newline = TRUE ) {
206+ if (!$ this ->socket ) {
207+ throw new Exception ("Telnet connection closed " );
208+ }
209+
210+ // clear buffer from last command
211+ $ this ->clearBuffer ();
212+
213+ if ($ add_newline == TRUE ) {
214+ $ buffer .= "\n" ;
215+ }
216+
217+ $ this ->global_buffer .= $ buffer ;
218+ if (!fwrite ($ this ->socket , $ buffer ) < 0 ) {
219+ throw new Exception ("Error writing to socket " );
220+ }
221+
222+ return self ::TELNET_OK ;
223+ }
224+
225+ protected function getBuffer () {
226+ // Remove all carriage returns from line breaks
227+ $ buf = preg_replace ('/\r\n|\r/ ' , "\n" , $ this ->buffer );
228+ // Cut last line from buffer (almost always prompt)
229+ if ($ this ->strip_prompt ) {
230+ $ buf = explode ("\n" , $ buf );
231+ unset($ buf [count ($ buf ) - 1 ]);
232+ $ buf = implode ("\n" , $ buf );
233+ }
234+ return trim ($ buf );
235+ }
236+
237+ public function getGlobalBuffer () {
238+ return $ this ->global_buffer ;
239+ }
240+
241+ protected function negotiateTelnetOptions () {
242+ $ c = $ this ->getc ();
243+
244+ if ($ c != $ this ->IAC ) {
245+ if (($ c == $ this ->DO ) || ($ c == $ this ->DONT )) {
246+ $ opt = $ this ->getc ();
247+ fwrite ($ this ->socket , $ this ->IAC . $ this ->WONT . $ opt );
248+ } else if (($ c == $ this ->WILL ) || ($ c == $ this ->WONT )) {
249+ $ opt = $ this ->getc ();
250+ fwrite ($ this ->socket , $ this ->IAC . $ this ->DONT . $ opt );
251+ } else {
252+ throw new Exception ('Error: unknown control character ' . ord ($ c ));
253+ }
254+ } else {
255+ throw new Exception ('Error: Something Wicked Happened ' );
256+ }
257+
258+ return self ::TELNET_OK ;
259+ }
260+
261+ protected function waitPrompt () {
262+ return $ this ->readTo ($ this ->prompt );
263+ }
264+ }
0 commit comments