telgate.cpp 7.35 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* telgate.cpp */

/* Synchronet telnet gateway routines */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
11
 * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html		*
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"
#include "telnet.h" 

void sbbs_t::telnet_gate(char* destaddr, ulong mode)
{
	char*	p;
	uchar	buf[512];
	int		i;
	int		rd;
47
	uint	attempts;
48
49
	ulong	l;
	bool	gotline;
50
	ushort	port;
51
52
53
54
55
	ulong	ip_addr;
	ulong	save_console;
	SOCKET	remote_socket;
	SOCKADDR_IN	addr;

56
57
58
59
60
	if(mode&TG_RLOGIN)
		port=513;
	else
		port=IPPORT_TELNET;

61
62
63
64
65
66
67
	p=strchr(destaddr,':');
	if(p!=NULL) {
		*p=0;
		port=atoi(p+1);
	}

	ip_addr=resolve_ip(destaddr);
68
	if(ip_addr==INADDR_NONE) {
69
		lprintf(LOG_NOTICE,"!TELGATE Failed to resolve address: %s",destaddr);
rswindell's avatar
rswindell committed
70
		bprintf("!Failed to resolve address: %s\r\n",destaddr);
71
72
73
		return;
	}

74
    if((remote_socket = open_socket(SOCK_STREAM, client.protocol)) == INVALID_SOCKET) {
75
76
77
78
79
		errormsg(WHERE,ERR_OPEN,"socket",0);
		return;
	}

	memset(&addr,0,sizeof(addr));
80
	addr.sin_addr.s_addr = htonl(startup->telnet_interface);
81
82
83
	addr.sin_family = AF_INET;

	if((i=bind(remote_socket, (struct sockaddr *) &addr, sizeof (addr)))!=0) {
84
		lprintf(LOG_NOTICE,"!TELGATE ERROR %d (%d) binding to socket %d",i, ERROR_VALUE, remote_socket);
rswindell's avatar
rswindell committed
85
		bprintf("!ERROR %d (%d) binding to socket\r\n",i, ERROR_VALUE);
rswindell's avatar
rswindell committed
86
		close_socket(remote_socket);
87
88
89
90
		return;
	}

	memset(&addr,0,sizeof(addr));
91
	addr.sin_addr.s_addr = ip_addr;
92
93
94
95
	addr.sin_family = AF_INET;
	addr.sin_port   = htons(port);

	if((i=connect(remote_socket, (struct sockaddr *)&addr, sizeof(addr)))!=0) {
96
		lprintf(LOG_NOTICE,"!TELGATE ERROR %d (%d) connecting to server: %s"
97
			,i,ERROR_VALUE, destaddr);
rswindell's avatar
rswindell committed
98
		bprintf("!ERROR %d (%d) connecting to server: %s\r\n"
99
			,i,ERROR_VALUE, destaddr);
rswindell's avatar
rswindell committed
100
		close_socket(remote_socket);
101
102
103
104
105
106
		return;
	}

	l=1;

	if((i = ioctlsocket(remote_socket, FIONBIO, &l))!=0) {
107
		lprintf(LOG_NOTICE,"!TELGATE ERROR %d (%d) disabling socket blocking"
108
			,i, ERROR_VALUE);
rswindell's avatar
rswindell committed
109
		close_socket(remote_socket);
110
111
112
		return;
	}

rswindell's avatar
rswindell committed
113
	lprintf(LOG_INFO,"Node %d %s gate to %s port %u on socket %d"
114
115
116
		,cfg.node_num
		,mode&TG_RLOGIN ? "RLogin" : "Telnet"
		,destaddr,port,remote_socket);
117
118
119
120

	if(!(mode&TG_CTRLKEYS))
		console|=CON_RAW_IN;

121
122
123
	if(mode&TG_RLOGIN) {
		p=(char*)buf;
		*(p++)=0;
124
125
126
127
128
129
		p+=sprintf(p,"%s",useron.alias);
		p++;	// Add NULL
		p+=sprintf(p,"%s",useron.name);
		p++;	// Add NULL
		p+=sprintf(p,"%s/57600",terminal);
		p++;	// Add NULL
130
		l=p-(char*)buf;
131
		sendsocket(remote_socket,(char*)buf,l);
132
	}
133

134
	/* This is required for gating to Unix telnetd */
135
	if(mode&TG_NOTERMTYPE)
136
		request_telnet_opt(TELNET_DONT,TELNET_TERM_TYPE, 3000);	// Re-negotiation of terminal type
137

138
	/* Text/NVT mode by default */
139
140
141
142
	request_telnet_opt(TELNET_DONT,TELNET_BINARY_TX, 3000);

	if(mode&(TG_PASSTHRU|TG_RLOGIN))
		telnet_mode|=TELNET_MODE_GATE;	// Pass-through telnet commands
143

144
	while(online) {
145
146
		if(!(mode&TG_NOCHKTIME))
			gettimeleft();
147
148
		rd=RingBufRead(&inbuf,buf,sizeof(buf));
		if(rd) {
149
150
151
152
153
154
155
156
157
158
#if 0
			if(memchr(buf,TELNET_IAC,rd)) {
				char dump[2048];
				dump[0];
				p=dump;
				for(int i=0;i<rd;i++)
					p+=sprintf(p,"%u ",buf[i]);
				lprintf(LOG_DEBUG,"Node %d Telnet cmd from client: %s", cfg.node_num, dump);
			}
#endif
159
			if(telnet_remote_option[TELNET_BINARY_TX]!=TELNET_WILL) {
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
				if(*buf==0x1d) { // ^]
					save_console=console;
					console&=~CON_RAW_IN;	// Allow Ctrl-U/Ctrl-P
					CRLF;
					while(online) {
						SYNC;
						mnemonics("\1n\r\n\1h\1bTelnet Gate: \1y~D\1wisconnect, "
							"\1y~E\1wcho toggle, \1y~L\1wist Users, \1y~P\1wrivate message, "
							"\1y~Q\1wuit: ");
						switch(getkeys("DELPQ",0)) {
							case 'D':
								closesocket(remote_socket);
								break;
							case 'E':
								mode^=TG_ECHO;
								bprintf(text[EchoIsNow]
									,mode&TG_ECHO
									? text[ON]:text[OFF]);
								continue;
							case 'L':
								whos_online(true);
								continue;
							case 'P':
								nodemsg();
								continue;
						}
						break;
					}
					attr(LIGHTGRAY);
					console=save_console;
				}
191
192
				else if(*buf<' ' && mode&TG_CTRLKEYS)
					handle_ctrlkey(*buf, K_NONE);
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
				gotline=false;
				if(mode&TG_LINEMODE && buf[0]!='\r') {
					ungetkey(buf[0]);
					l=K_CHAT;
					if(!(mode&TG_ECHO))
						l|=K_NOECHO;
					rd=getstr((char*)buf,sizeof(buf)-1,l);
					if(!rd)
						continue;
					strcat((char*)buf,crlf);
					rd+=2;
					gotline=true;
				}
				if(mode&TG_CRLF && buf[rd-1]=='\r')
					buf[rd++]='\n';
				if(!gotline && mode&TG_ECHO) {
					RingBufWrite(&outbuf,buf,rd);
				}
			}
212
213
214
215
216
217
218
219
220
			for(attempts=0;attempts<60 && online; attempts++) /* added retry loop here, Jan-20-2003 */
			{
				if((i=sendsocket(remote_socket,(char*)buf,rd))>=0)
					break;
				if(ERROR_VALUE!=EWOULDBLOCK)
					break;
				mswait(500);
			} 
			if(i<0) {
221
				lprintf(LOG_NOTICE,"!TELGATE ERROR %d sending on socket %d",ERROR_VALUE,remote_socket);
222
223
224
225
226
				break;
			}
		}
		rd=recv(remote_socket,(char*)buf,sizeof(buf),0);
		if(rd<0) {
227
			if(ERROR_VALUE==EWOULDBLOCK) {
228
229
				if(mode&TG_NODESYNC) {
					SYNC;
230
231
232
233
234
				} else {
					// Check if the node has been interrupted
					getnodedat(cfg.node_num,&thisnode,0);
					if(thisnode.misc&NODE_INTR)
						break;
235
				}
236
				YIELD();
237
238
				continue;
			}
239
			lprintf(LOG_NOTICE,"!TELGATE ERROR %d receiving on socket %d",ERROR_VALUE,remote_socket);
240
241
242
			break;
		}
		if(!rd) {
243
			lprintf(LOG_INFO,"Node %d Telnet gate disconnected",cfg.node_num);
244
245
			break;
		}
246
247
248
249
250
251
252
#if 0
		if(memchr(buf,TELNET_IAC,rd)) {
			char dump[2048];
			dump[0];
			p=dump;
			for(int i=0;i<rd;i++)
				p+=sprintf(p,"%u ",buf[i]);
253
			lprintf(LOG_DEBUG,"Node %d Telnet cmd from server: %s", cfg.node_num, dump);
254
255
		}
#endif
256
257
258
259
260
261
		RingBufWrite(&outbuf,buf,rd);
	}
	console&=~CON_RAW_IN;
	telnet_mode&=~TELNET_MODE_GATE;

	/* Disable Telnet Terminal Echo */
262
	request_telnet_opt(TELNET_WILL,TELNET_ECHO);
263
264
265

	close_socket(remote_socket);

266
	lprintf(LOG_INFO,"Node %d Telnet gate to %s finished",cfg.node_num,destaddr);
267
268
}