AmendHub

Download

jcs

/

subtext

/

telnet.c

 

(View History)

jcs   telnet: Handle (ignore) IAC NOP, don't put unhandled IACs in output Latest amendment: 501 on 2023-05-01

1 /*
2 * Copyright (c) 2021 joshua stein <jcs@jcs.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <stdio.h>
18 #include <string.h>
19
20 #include "logger.h"
21 #include "session.h"
22 #include "subtext.h"
23 #include "telnet.h"
24 #include "tcp.h"
25 #include "util.h"
26
27 #define SE 240 /* end of sub-negotiation options */
28 #define NOP 241 /* no operation */
29 #define SB 250 /* start of sub-negotiation options */
30 #define WILL 251 /* confirm willingness to negotiate */
31 #define WONT 252 /* confirm unwillingness to negotiate */
32 #define DO 253 /* indicate willingness to negotiate */
33 #define DONT 254 /* indicate unwillingness to negotiate */
34 #define IAC 255 /* start of a negotiation sequence */
35
36 #define IS 0 /* sub-negotiation */
37 #define SEND 1 /* sub-negotiation */
38
39 #define IAC_BINARY 0 /* Transmit Binary */
40 #define IAC_ECHO 1 /* Echo Option */
41 #define IAC_SGA 3 /* Suppress Go Ahead Option */
42 #define IAC_STATUS 5 /* Status Option */
43 #define IAC_TM 6 /* Timing Mark Option */
44 #define IAC_NAOCRD 10 /* Output Carriage-Return Disposition Option */
45 #define IAC_NAOHTS 11 /* Output Horizontal Tabstops Option */
46 #define IAC_NAOHTD 12 /* Output Horizontal Tab Disposition Option */
47 #define IAC_NAOFFD 13 /* Output Formfeed Disposition Option */
48 #define IAC_NAOVTS 14 /* Output Vertical Tabstops Option */
49 #define IAC_NAOVTD 15 /* Output Vertical Tab Disposition Option */
50 #define IAC_NAOLFD 16 /* Output Linefeed Disposition */
51 #define IAC_XASCII 17 /* Extended Ascii Option */
52 #define IAC_LOGOUT 18 /* Logout Option */
53 #define IAC_BM 19 /* Byte Macro Option */
54 #define IAC_SUPDUP 22 /* SUPDUP-OUTPUT Option */
55 #define IAC_SENDLOC 23 /* SEND-LOCATION Option */
56 #define IAC_TTYPE 24 /* Terminal Type Option */
57 #define IAC_EOR 25 /* End of Record Option */
58 #define IAC_OUTMRK 27 /* Marking Telnet Option */
59 #define IAC_TTYLOC 28 /* Terminal Location Number Option */
60 #define IAC_DET 20 /* Data Entry Terminal Option DODIIS */
61 #define IAC_X3PAD 30 /* X.3 PAD Option */
62 #define IAC_NAWS 31 /* Window Size Option */
63 #define IAC_TSPEED 32 /* Terminal Speed Option */
64 #define IAC_FLOWCTRL 33 /* Remote Flow Control Option */
65 #define IAC_LINEMODE 34 /* Linemode Option */
66 #define IAC_XDISPLOC 35 /* X Display Location Option */
67 #define IAC_ENVIRON 36 /* Environment Option */
68 #define IAC_AUTH 37 /* Authentication */
69 #define IAC_ENCRYPT 38 /* Encryption Option */
70 #define IAC_NEWENV 39 /* Environment Option */
71 #define IAC_CHARSET 42 /* Charset Option */
72 #define IAC_COMPORT 44 /* Com Port Control Option */
73
74 enum {
75 TELNET_PB_STATE_UNUSED = 0,
76 TELNET_PB_STATE_LISTENING,
77 TELNET_PB_STATE_CONNECTED
78 };
79
80 enum {
81 TELNET_IAC_STATE_IDLE = 0,
82 TELNET_IAC_STATE_IAC,
83 TELNET_IAC_STATE_WILL,
84 TELNET_IAC_STATE_WONT,
85 TELNET_IAC_STATE_DO,
86 TELNET_IAC_STATE_DONT,
87 TELNET_IAC_STATE_SB
88 };
89
90 struct telnet_node {
91 short id;
92 short state;
93 char name[8];
94 ip_addr ip;
95 char ip_s[20];
96 struct session *session;
97 unsigned short obuflen;
98 unsigned char obuf[1024];
99 unsigned char ibuf[64];
100 unsigned short ibuflen;
101 unsigned short ibufoff;
102 unsigned short sending_iac;
103 unsigned short escaped_obuflen;
104 short iac_state;
105 unsigned char iac_sb[128];
106 short sb_len;
107 unsigned short naws_count;
108 /* docs say 4*MTU+1024, but MTU will probably be <1500 */
109 unsigned char tcp_buf[(4 * 1500) + 1024];
110 bool from_trusted_proxy;
111 TCPiopb rcv_pb, send_pb, listen_pb;
112 StreamPtr stream;
113 wdsEntry tcp_wds[2];
114 };
115
116 /* add one to be able to print busy messages */
117 #define MAX_TELNET_NODES (MAX_SESSIONS + 1)
118
119 static struct telnet_node *telnet_nodes[MAX_TELNET_NODES] = { NULL };
120 static struct telnet_node *telnet_listener_node = NULL;
121 static TCPiopb telnet_exit_pb;
122 static TCPStatusPB telnet_status_pb;
123 static bool did_initial_log = false;
124 static UDPiopb udp_ban_pb;
125 static StreamPtr udp_ban_stream;
126 static char *udp_ban_rcv_buf;
127 #define UDP_BAN_RCV_BUF_SIZE 2048
128 static wdsEntry udp_ban_wds[2];
129 static char udp_ban_send_buf[16];
130
131 /* terminals that will have vt100 set by default */
132 static const char * vt100_terms[] = {
133 "ansi",
134 "syncterm",
135 "xterm",
136 "tmux",
137 "screen",
138 "vt100",
139 NULL,
140 };
141
142 void telnet_setup(struct session *session);
143 void telnet_listen_on_node(struct telnet_node *node);
144 void telnet_output_iac(struct session *session, const char *iacs,
145 size_t len);
146 void telnet_print_busy(struct telnet_node *node);
147
148 struct node_funcs telnet_node_funcs = {
149 telnet_setup,
150 telnet_input,
151 telnet_output,
152 telnet_close
153 };
154
155 void
156 telnet_init(void)
157 {
158 short n, error;
159
160 if (!db->config.telnet_port)
161 return;
162
163 logger_printf("[telnet] Initializing MacTCP");
164
165 if (_TCPInit() != noErr)
166 panic("Failed initializing MacTCP");
167
168 /* pre-allocate nodes */
169 for (n = 0; n < MAX_TELNET_NODES; n++) {
170 telnet_nodes[n] = xmalloczero(sizeof(struct telnet_node));
171 if (telnet_nodes[n] == NULL)
172 panic("Failed allocating telnet node %d", n);
173 telnet_nodes[n]->id = n;
174
175 if (n == 0)
176 telnet_listen_on_node(telnet_nodes[n]);
177 }
178
179 if (db->config.trusted_proxy_ip != 0 &&
180 db->config.trusted_proxy_udp_port != 0) {
181 udp_ban_rcv_buf = xmalloc(UDP_BAN_RCV_BUF_SIZE);
182 if (udp_ban_rcv_buf == NULL)
183 panic("Failed allocating UDP ban buf");
184 error = _UDPCreate(&udp_ban_pb, &udp_ban_stream,
185 (Ptr)udp_ban_rcv_buf, UDP_BAN_RCV_BUF_SIZE, NULL, NULL,
186 NULL, false);
187 if (error)
188 panic("UDPCreate failed: %d", error);
189 }
190 }
191
192 void
193 telnet_atexit(void)
194 {
195 struct telnet_node *node;
196 short n;
197
198 for (n = 0; n < MAX_TELNET_NODES; n++) {
199 node = telnet_nodes[n];
200 if (!node)
201 continue;
202
203 if (node->state > TELNET_PB_STATE_UNUSED)
204 _TCPRelease(&telnet_exit_pb, node->stream, nil, nil, false);
205
206 xfree(&node);
207 telnet_nodes[n] = NULL;
208 }
209
210 telnet_listener_node = NULL;
211
212 if (db->config.trusted_proxy_ip != 0 &&
213 db->config.trusted_proxy_udp_port != 0)
214 _UDPRelease(&udp_ban_pb, udp_ban_stream, NULL, NULL, false);
215 }
216
217 void
218 telnet_listen_on_node(struct telnet_node *node)
219 {
220 char ip_s[20];
221 short error, id;
222 ip_addr ip;
223 tcp_port port;
224 long mask;
225
226 id = node->id;
227 memset(node, 0, sizeof(struct telnet_node));
228 node->id = id;
229
230 snprintf(node->name, sizeof(node->name), "ttyt%d", id);
231
232 error = _TCPCreate(&node->listen_pb, &node->stream,
233 (Ptr)&node->tcp_buf, sizeof(node->tcp_buf), nil, nil, nil, false);
234 if (error)
235 panic("TCPCreate[%d] failed: %d", node->id, error);
236
237 error = _TCPGetOurIP(&ip, &mask);
238 if (error)
239 panic("TCPGetOurIP failed: %d", error);
240
241 port = db->config.telnet_port;
242
243 if (!did_initial_log) {
244 long2ip(ip, ip_s);
245 logger_printf("[telnet] Listening on %s:%d", ip_s, port);
246 did_initial_log = true;
247 }
248
249 error = _TCPPassiveOpen(&node->listen_pb, node->stream, nil, nil, &ip,
250 &port, nil, nil, true);
251 if (error)
252 panic("TCPPassiveOpen[%d] on port %d failed: %d",
253 node->id, db->config.telnet_port, error);
254
255 node->state = TELNET_PB_STATE_LISTENING;
256 telnet_listener_node = node;
257 }
258
259 void
260 telnet_idle(void)
261 {
262 struct telnet_node *node;
263 short n, error;
264
265 if (!db->config.telnet_port)
266 return;
267
268 for (n = 0; n < MAX_TELNET_NODES; n++) {
269 node = telnet_nodes[n];
270
271 switch (node->state) {
272 case TELNET_PB_STATE_UNUSED:
273 if (telnet_listener_node == NULL)
274 telnet_listen_on_node(node);
275 break;
276 case TELNET_PB_STATE_LISTENING:
277 error = _TCPStatus(&node->send_pb, node->stream,
278 &telnet_status_pb, nil, nil, false);
279 if (error == connectionDoesntExist) {
280 /*
281 * The connection closed before it could be handled, but
282 * telnet_status_pb.connectionState will still be
283 * listening, so force it into a bogus state to recycle it.
284 */
285 telnet_status_pb.connectionState = -1;
286 }
287
288 switch (telnet_status_pb.connectionState) {
289 case ConnectionStateListening:
290 goto next_node;
291 case ConnectionStateSYNReceived:
292 case ConnectionStateSYNSent:
293 /* TODO: enforce our own timeout on these? */
294 break;
295 case ConnectionStateEstablished:
296 /* start up a new socket for listening */
297 telnet_listener_node = NULL;
298
299 node->ip = telnet_status_pb.remoteHost;
300 long2ip(telnet_status_pb.remoteHost, node->ip_s);
301
302 if (db->config.trusted_proxy_ip != 0 &&
303 db->config.trusted_proxy_ip == node->ip) {
304 node->from_trusted_proxy = true;
305 snprintf(node->name, sizeof(node->name), "ttyw%d",
306 node->id);
307 }
308
309 logger_printf("[%s] New telnet connection from %s%s",
310 node->name, node->ip_s,
311 node->from_trusted_proxy ? " (via trusted proxy)" : "");
312
313 node->state = TELNET_PB_STATE_CONNECTED;
314 node->session = session_create(node->name,
315 node->from_trusted_proxy ? "web" : "telnet",
316 &telnet_node_funcs);
317 if (node->session == NULL) {
318 logger_printf("[%s] No free nodes, disconnecting",
319 node->name);
320 telnet_print_busy(node);
321 _TCPRelease(&node->listen_pb, node->stream, nil,
322 nil, false);
323 node->state = TELNET_PB_STATE_UNUSED;
324 goto next_node;
325 }
326 node->session->cookie = (void *)node;
327 node->session->tspeed = 19200;
328 node->session->is_telnet = true;
329 node->session->log.ip_address = telnet_status_pb.remoteHost;
330 if (node->from_trusted_proxy)
331 node->session->can_nomodem = true;
332 break;
333 default:
334 if (telnet_status_pb.remoteHost == 0)
335 long2ip(node->listen_pb.csParam.open.remoteHost,
336 node->ip_s);
337 else
338 long2ip(telnet_status_pb.remoteHost, node->ip_s);
339
340 logger_printf("[%s] Telnet connection from "
341 "%s in state %d, aborting", node->name, node->ip_s,
342 telnet_status_pb.connectionState);
343
344 if (node->session)
345 node->session->ending = 1;
346 else {
347 _TCPRelease(&node->listen_pb, node->stream, nil, nil,
348 false);
349 node->state = TELNET_PB_STATE_UNUSED;
350 telnet_listener_node = NULL;
351 }
352 goto next_node;
353 }
354 break;
355 case TELNET_PB_STATE_CONNECTED:
356 if (!node->session) {
357 node->state = TELNET_PB_STATE_UNUSED;
358 break;
359 }
360
361 /*
362 * Send buffered data any time we can, the user might not be
363 * in an explicit session_flush() like during chat
364 */
365 telnet_output(node->session);
366 break;
367 }
368
369 next_node:
370 continue;
371 }
372 }
373
374 void
375 telnet_setup(struct session *session)
376 {
377 const char iacs[] = {
378 IAC, WILL, IAC_SGA, /* we will supress go-ahead */
379 IAC, WILL, IAC_ECHO, /* and we will echo for you */
380 IAC, WILL, IAC_BINARY, /* don't mess with binary data we send */
381 IAC, DO, IAC_BINARY, /* and you can send us binary */
382 IAC, DO, IAC_TSPEED, /* send your TSPEED */
383 IAC, DO, IAC_NAWS, /* send your NAWS */
384 IAC, DO, IAC_TTYPE, /* send your TTYPE */
385 IAC, DO, IAC_NEWENV, /* send your NEWENV vars */
386
387 /* IAC, DO, IAC_LINEMODE, */
388 };
389
390 telnet_output_iac(session, iacs, sizeof(iacs));
391 }
392
393 short
394 telnet_input(struct session *session)
395 {
396 struct telnet_node *node = (struct telnet_node *)session->cookie;
397 unsigned short rlen;
398 short error, n, j, used;
399 unsigned char c;
400 char iac_out[8] = { IAC, 0 };
401
402 error = _TCPStatus(&node->rcv_pb, node->stream, &telnet_status_pb, nil,
403 nil, false);
404 if (error ||
405 telnet_status_pb.connectionState != ConnectionStateEstablished) {
406 session->ending = 1;
407 return 0;
408 }
409
410 if (telnet_status_pb.amtUnreadData == 0)
411 return 0;
412
413 rlen = telnet_status_pb.amtUnreadData;
414
415 if (session->direct_output) {
416 if (session->ibuflen + session->ibufoff + rlen >
417 sizeof(session->ibuf)) {
418 /* if we're already halfway through the buffer, reset */
419 if (session->ibufoff >= (sizeof(session->ibuf) / 2)) {
420 memmove(session->ibuf, session->ibuf + session->ibufoff,
421 session->ibuflen);
422 session->ibufoff = 0;
423 }
424 rlen = sizeof(session->ibuf) - session->ibuflen -
425 session->ibufoff;
426 if (rlen == 0)
427 return 0;
428 }
429
430 error = _TCPRcv(&node->rcv_pb, node->stream,
431 (Ptr)(session->ibuf + session->ibufoff + session->ibuflen), &rlen,
432 nil, nil, false);
433 if (error) {
434 session_logf(session, "TCP read failed (%d), closing connection",
435 error);
436 session->ending = 1;
437 return 0;
438 }
439 if (rlen == 0)
440 return 0;
441 session->last_input_at = Time;
442 session->ibuflen += rlen;
443 return rlen;
444 }
445
446 if (node->ibuflen + rlen > sizeof(node->ibuf))
447 rlen = sizeof(node->ibuf) - node->ibuflen;
448
449 error = _TCPRcv(&node->rcv_pb, node->stream,
450 (Ptr)(node->ibuf + node->ibuflen), &rlen, nil, nil, false);
451 if (error) {
452 session_logf(session, "TCP read failed (%d), closing connection",
453 error);
454 session->ending = 1;
455 return 0;
456 }
457
458 if (rlen == 0)
459 return 0;
460
461 session->last_input_at = Time;
462 node->ibuflen += rlen;
463
464 used = 0;
465 for (n = 0; n < node->ibuflen; n++) {
466 if (session->ibuflen >= sizeof(session->ibuf))
467 break;
468
469 c = node->ibuf[n];
470 used++;
471
472 switch (node->iac_state) {
473 case TELNET_IAC_STATE_IDLE:
474 if (c == IAC)
475 node->iac_state = TELNET_IAC_STATE_IAC;
476 else
477 session->ibuf[session->ibuflen++] = c;
478 break;
479 case TELNET_IAC_STATE_IAC:
480 switch (c) {
481 case IAC:
482 /* escaped iac */
483 session->ibuf[session->ibuflen++] = c;
484 node->iac_state = TELNET_IAC_STATE_IDLE;
485 break;
486 case NOP:
487 node->iac_state = TELNET_IAC_STATE_IDLE;
488 break;
489 case WILL:
490 /* client will do something */
491 node->iac_state = TELNET_IAC_STATE_WILL;
492 break;
493 case WONT:
494 /* client will not do something */
495 node->iac_state = TELNET_IAC_STATE_WONT;
496 break;
497 case DO:
498 /* client wants us to do something */
499 node->iac_state = TELNET_IAC_STATE_DO;
500 break;
501 case DONT:
502 /* client wants us not to do something */
503 node->iac_state = TELNET_IAC_STATE_DONT;
504 break;
505 case SB:
506 /* sub-negotiate */
507 node->iac_state = TELNET_IAC_STATE_SB;
508 node->sb_len = 0;
509 break;
510 default:
511 /* unsupported command, ignore it */
512 node->iac_state = TELNET_IAC_STATE_IDLE;
513 break;
514 }
515 break;
516 case TELNET_IAC_STATE_SB: {
517 unsigned short sboff;
518
519 /* keep reading until we see [^IAC] IAC SE */
520 if (c == SE && node->sb_len > 0 &&
521 node->iac_sb[node->sb_len - 1] == IAC) {
522 switch (node->iac_sb[0]) {
523 case IAC_NAWS:
524 /* IAC SB NAWS 0 80 0 24 (80x24) */
525 /* IAC SB NAWS 1 255 255 1 123 (256x378) */
526 /* if either value is 255, it will be 255,255 */
527 sboff = 1;
528
529 if (node->iac_sb[sboff] == 255)
530 sboff++;
531 session->terminal_columns = (node->iac_sb[sboff++] << 8);
532 if (node->iac_sb[sboff] == 255)
533 sboff++;
534 session->terminal_columns |= node->iac_sb[sboff++];
535
536 if (node->iac_sb[sboff] == 255)
537 sboff++;
538 session->terminal_lines = (node->iac_sb[sboff++] << 8);
539 if (node->iac_sb[sboff] == 255)
540 sboff++;
541 session->terminal_lines |= node->iac_sb[sboff++];
542 if (node->naws_count++ < 20)
543 session_logf_buffered(session, "IAC NAWS %d, %d",
544 session->terminal_columns,
545 session->terminal_lines);
546 break;
547 case IAC_TTYPE:
548 /* IAC SB TTYPE IS XTERM IAC SE */
549 node->iac_sb[node->sb_len - 1] = '\0';
550 strlcpy(session->terminal_type,
551 (char *)&node->iac_sb + 2,
552 sizeof(session->terminal_type));
553 session_logf_buffered(session, "IAC TTYPE IS %s",
554 session->terminal_type);
555
556 for (j = 0; vt100_terms[j] != NULL; j++) {
557 if (strncasecmp(session->terminal_type,
558 vt100_terms[j], strlen(vt100_terms[j])) == 0) {
559 session_logf_buffered(session,
560 "Activating vt100 ANSI support for "
561 "matching %s", vt100_terms[j]);
562 session->vt100 = true;
563 break;
564 }
565 }
566
567 break;
568 case IAC_NEWENV: {
569 char k[sizeof(node->iac_sb)], v[sizeof(node->iac_sb)];
570 unsigned char l = 0;
571 bool inv = false;
572
573 k[0] = v[0] = '\0';
574
575 /* \40\0\0USER\1blah\0DISPLAY\1... */
576 for (j = 3; j < node->sb_len; j++) {
577 if (j == node->sb_len - 1 ||
578 node->iac_sb[j] == 0 || node->iac_sb[j] == 3) {
579 v[l] = '\0';
580 if (l) {
581 session_logf_buffered(session,
582 "NEWENV \"%s\" = \"%s\"", k, v);
583
584 if (node->from_trusted_proxy &&
585 strcmp(k, "REMOTE_ADDR") == 0) {
586 node->ip = ip2long(v);
587 strlcpy(node->ip_s, v,
588 sizeof(node->ip_s));
589 node->session->log.ip_address =
590 node->ip;
591 }
592 }
593 l = 0;
594 inv = false;
595 } else if (node->iac_sb[j] == 1) {
596 k[l] = '\0';
597 l = 0;
598 inv = true;
599 } else {
600 if (inv)
601 v[l++] = node->iac_sb[j];
602 else
603 k[l++] = node->iac_sb[j];
604 }
605 }
606 break;
607 }
608 case IAC_TSPEED: {
609 unsigned long tspeed;
610
611 /* IAC SB TSPEED IS 38400,19200 SE */
612 node->iac_sb[node->sb_len - 1] = '\0';
613
614 session_logf_buffered(session, "IAC TSPEED IS %s",
615 node->iac_sb + 2);
616
617 for (j = 2; j < node->sb_len; j++) {
618 if (node->iac_sb[j] == ',') {
619 node->iac_sb[j] = '\0';
620 break;
621 }
622 }
623
624 tspeed = atol((const char *)(node->iac_sb + 2));
625 if (tspeed > 0) {
626 if (tspeed > 57600)
627 tspeed = 57600;
628 node->session->tspeed =
629 node->session->log.tspeed =
630 (unsigned short)tspeed;
631 }
632 break;
633 }
634 }
635 node->iac_state = TELNET_IAC_STATE_IDLE;
636 } else {
637 /* accumulate bytes into iac_sb buffer */
638 if (node->sb_len < sizeof(node->iac_sb))
639 node->iac_sb[node->sb_len++] = c;
640 else {
641 /* IAC overflow */
642 node->iac_state = TELNET_IAC_STATE_IDLE;
643 node->sb_len = 0;
644 session_logf(session, "IAC SB overflow");
645 }
646 }
647 break;
648 }
649 case TELNET_IAC_STATE_WILL:
650 switch (c) {
651 case IAC_ECHO:
652 case IAC_SGA:
653 iac_out[1] = DO;
654 iac_out[2] = IAC_ECHO;
655 telnet_output_iac(session, iac_out, 3);
656 break;
657 case IAC_NEWENV:
658 case IAC_TTYPE:
659 case IAC_TSPEED:
660 iac_out[1] = SB;
661 iac_out[2] = c;
662 iac_out[3] = SEND;
663 iac_out[4] = IAC;
664 iac_out[5] = SE;
665 telnet_output_iac(session, iac_out, 6);
666 break;
667 case IAC_LINEMODE:
668 #if 0
669 iac_out[1] = SB;
670 iac_out[2] = IAC_LINEMODE;
671 iac_out[3] = 1;
672 iac_out[4] = 0;
673 iac_out[5] = IAC;
674 iac_out[6] = SE;
675 telnet_output_iac(session, iac_out, 7);
676 #endif
677 break;
678 case IAC_ENCRYPT:
679 iac_out[1] = DONT;
680 iac_out[2] = IAC_ENCRYPT;
681 telnet_output_iac(session, iac_out, 3);
682 break;
683 }
684 node->iac_state = TELNET_IAC_STATE_IDLE;
685 break;
686 case TELNET_IAC_STATE_WONT:
687 /* we don't care about any of these yet */
688 node->iac_state = TELNET_IAC_STATE_IDLE;
689 break;
690 case TELNET_IAC_STATE_DO:
691 switch (c) {
692 case IAC_BINARY:
693 iac_out[1] = WILL;
694 iac_out[2] = IAC_BINARY;
695 telnet_output_iac(session, iac_out, 3);
696 break;
697 case IAC_ECHO:
698 case IAC_NAWS:
699 case IAC_TSPEED:
700 case IAC_FLOWCTRL:
701 case IAC_SGA:
702 case IAC_LINEMODE:
703 /* we already sent WILLs for these at the beginning */
704 break;
705 default:
706 iac_out[1] = WONT;
707 iac_out[2] = c;
708 telnet_output_iac(session, iac_out, 3);
709 break;
710 }
711 node->iac_state = TELNET_IAC_STATE_IDLE;
712 break;
713 case TELNET_IAC_STATE_DONT:
714 node->iac_state = TELNET_IAC_STATE_IDLE;
715 break;
716 default:
717 warn("telnet_input in bogus IAC state %d", node->iac_state);
718 break;
719 }
720 }
721
722 if (used == node->ibuflen)
723 node->ibuflen = 0;
724 else {
725 memmove(node->ibuf, node->ibuf + used, node->ibuflen - used);
726 node->ibuflen -= used;
727 }
728
729 return rlen;
730 }
731
732 short
733 telnet_output(struct session *session)
734 {
735 struct telnet_node *node = (struct telnet_node *)session->cookie;
736 short error;
737 unsigned char c;
738 unsigned long now;
739
740 if (session->obuflen == 0 || session->ending)
741 return 0;
742
743 if (node->send_pb.ioResult > 0)
744 /* previous _TCPSend has not completed yet */
745 return 0;
746
747 process_result:
748 if (node->tcp_wds[0].length) {
749 if (node->tcp_wds[0].length != node->escaped_obuflen &&
750 node->escaped_obuflen != node->obuflen)
751 warn("bug: tried to send %d (escaped from %d) but TCP says "
752 "we sent %d, how much to shift out?", node->escaped_obuflen,
753 node->obuflen, node->tcp_wds[0].length);
754
755 /* previous _TCPSend completed, shift out those bytes */
756 if (session->obuflen < node->obuflen) {
757 warn("bogus obuflen %d", session->obuflen);
758 session->obuflen = 0;
759 } else
760 session->obuflen -= node->obuflen;
761 if (session->obuflen > 0)
762 memmove(session->obuf, session->obuf + node->obuflen,
763 session->obuflen);
764
765 node->tcp_wds[0].length = 0;
766
767 if (session->obuflen == 0)
768 return node->obuflen;
769 }
770
771 if (session->obuflen == 1 && session->obuf[0] != IAC) {
772 node->obuf[0] = session->obuf[0];
773 node->escaped_obuflen = node->obuflen = 1;
774 } else if (session->direct_output) {
775 memcpy(node->obuf, session->obuf, session->obuflen);
776 node->escaped_obuflen = node->obuflen = session->obuflen;
777 } else {
778 /* copy obuf to node buffer, escaping IACs */
779 for (node->escaped_obuflen = 0, node->obuflen = 0;
780 node->obuflen < session->obuflen &&
781 node->escaped_obuflen < sizeof(node->obuf) - 1;
782 node->obuflen++) {
783 c = session->obuf[node->obuflen];
784
785 if (!node->sending_iac && c == IAC) {
786 node->obuf[node->escaped_obuflen++] = IAC;
787 node->obuf[node->escaped_obuflen++] = IAC;
788 } else
789 node->obuf[node->escaped_obuflen++] = c;
790 }
791 }
792
793 if (node->escaped_obuflen > sizeof(node->obuf)) {
794 warn("bogus obuflen %d > %ld", node->escaped_obuflen,
795 sizeof(node->obuf));
796 session->ending = true;
797 session_close(session);
798 return 0;
799 }
800
801 /*
802 * _TCPSend only knows how many wds pointers were passed in when it
803 * reads the next one and its pointer is zero (or size is zero?)
804 */
805 node->tcp_wds[0].ptr = (Ptr)&node->obuf;
806 node->tcp_wds[0].length = node->escaped_obuflen;
807 node->tcp_wds[1].ptr = 0;
808 node->tcp_wds[1].length = 0;
809
810 now = Ticks;
811 error = _TCPSend(&node->send_pb, node->stream, node->tcp_wds, nil, nil,
812 true);
813 if (error) {
814 warn("TCPSend[%d] failed: %d", node->id, error);
815 session->ending = true;
816 }
817
818 /* if we can send in less than 500ms, avoid a uthread switch */
819 while (Ticks - now <= 30) {
820 if (node->send_pb.ioResult <= 0)
821 goto process_result;
822 }
823
824 return 0;
825 }
826
827 void
828 telnet_output_iac(struct session *session, const char *iacs, size_t len)
829 {
830 struct telnet_node *node = (struct telnet_node *)session->cookie;
831
832 session_flush(session);
833 if (session->ending)
834 return;
835
836 node->sending_iac = 1;
837 session_output(session, iacs, len);
838 session_flush(session);
839 node->sending_iac = 0;
840 }
841
842 void
843 telnet_close(struct session *session)
844 {
845 struct telnet_node *node = (struct telnet_node *)session->cookie;
846 size_t len;
847 short error;
848 unsigned char *tmp;
849
850 if (node->from_trusted_proxy)
851 session->ban_node_source = false;
852
853 if (session->ban_node_source && !node->from_trusted_proxy &&
854 db->config.trusted_proxy_ip != 0 &&
855 db->config.trusted_proxy_udp_port != 0) {
856 session_logf(session, "Closing telnet connection from %s and "
857 "banning IP", node->ip_s);
858
859 tmp = (unsigned char *)&node->ip;
860 len = snprintf(udp_ban_send_buf, sizeof(udp_ban_send_buf),
861 "%d.%d.%d.%d", tmp[0], tmp[1], tmp[2], tmp[3]);
862 udp_ban_wds[0].ptr = (Ptr)&udp_ban_send_buf;
863 udp_ban_wds[0].length = len;
864 udp_ban_wds[1].ptr = 0;
865 udp_ban_wds[1].length = 0;
866
867 error = _UDPSend(&udp_ban_pb, udp_ban_stream, udp_ban_wds,
868 db->config.trusted_proxy_ip,
869 db->config.trusted_proxy_udp_port, NULL, NULL, false);
870 if (error)
871 session_logf(session, "Failed sending IP ban UDP packet: %d",
872 error);
873 } else {
874 session_logf(session, "Closing telnet connection from %s",
875 node->ip_s);
876
877 _TCPClose(&telnet_exit_pb, node->stream, nil, nil, false);
878 /* TODO: allow some time to fully close? */
879 }
880
881 error = _TCPRelease(&telnet_exit_pb, node->stream, nil, nil, false);
882 if (error) {
883 warn("error shutting down telnet session: %d", error);
884 return;
885 }
886
887 session->cookie = NULL;
888 node->state = TELNET_PB_STATE_UNUSED;
889 }
890
891 void
892 telnet_print_busy(struct telnet_node *node)
893 {
894 size_t len, n, olen;
895 unsigned long now;
896 short error;
897 char *data = NULL;
898
899 if ((len = bile_read_alloc(db->bile, DB_TEXT_TYPE,
900 DB_TEXT_NO_FREE_NODES_ID, &data)) == 0) {
901 len = snprintf((char *)&node->obuf, sizeof(node->obuf),
902 "No free nodes, please call back later.\r\n");
903 } else {
904 for (n = 0, olen = 0; n < len && olen < sizeof(node->obuf) - 1;
905 n++) {
906 node->obuf[olen++] = data[n];
907 if (data[n] == '\r' && data[n + 1] != '\n')
908 node->obuf[olen++] = '\n';
909 }
910 xfree(&data);
911 }
912
913 node->tcp_wds[0].ptr = (Ptr)&node->obuf;
914 node->tcp_wds[0].length = len;
915 node->tcp_wds[1].ptr = 0;
916 node->tcp_wds[1].length = 0;
917
918 now = Ticks;
919 error = _TCPSend(&node->send_pb, node->stream, node->tcp_wds, nil, nil,
920 true);
921 if (error)
922 return;
923
924 for (;;) {
925 /* spin for 500ms to let the send finish */
926 if (Ticks - now > 30 || node->send_pb.ioResult <= 0)
927 return;
928 }
929 }