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