view cli-tcpfwd.c @ 64:efb5e0b335cf

TCP forwarding works.
author Matt Johnston <matt@ucc.asn.au>
date Thu, 12 Aug 2004 13:48:42 +0000
parents dcc43965928f
children 38c3146aa23d
line wrap: on
line source
#include "includes.h"
#include "options.h"
#include "dbutil.h"
#include "tcpfwd.h"
#include "channel.h"
#include "runopts.h"
#include "session.h"
#include "ssh.h"

static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
		unsigned int remoteport);
static int newtcpforwarded(struct Channel * channel);

const struct ChanType cli_chan_tcpremote = {
	1, /* sepfds */
	"forwarded-tcpip",
	newtcpforwarded,
	NULL,
	NULL,
	NULL
};
static const struct ChanType cli_chan_tcplocal = {
	1, /* sepfds */
	"direct-tcpip",
	NULL,
	NULL,
	NULL,
	NULL
};

void setup_localtcp() {

	int ret;

	if (cli_opts.localfwds == NULL) {
		TRACE(("cli_opts.localfwds == NULL"));
	}

	while (cli_opts.localfwds != NULL) {
		ret = cli_localtcp(cli_opts.localfwds->listenport,
				cli_opts.localfwds->connectaddr,
				cli_opts.localfwds->connectport);
		if (ret == DROPBEAR_FAILURE) {
			dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d",
					cli_opts.localfwds->listenport,
					cli_opts.localfwds->connectaddr,
					cli_opts.localfwds->connectport);
		}

		cli_opts.localfwds = cli_opts.localfwds->next;
	}

}

static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
		unsigned int remoteport) {

	struct TCPListener* tcpinfo = NULL;
	int ret;

	TRACE(("enter cli_localtcp: %d %s %d", listenport, remoteaddr,
				remoteport));

	tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*));
	tcpinfo->sendaddr = remoteaddr;
	tcpinfo->sendport = remoteport;
	tcpinfo->listenport = listenport;
	tcpinfo->chantype = &cli_chan_tcplocal;

	ret = listen_tcpfwd(tcpinfo);

	if (ret == DROPBEAR_FAILURE) {
		m_free(tcpinfo);
	}
	TRACE(("leave cli_localtcp: %d", ret));
	return ret;
}

static void send_msg_global_request_remotetcp(int port) {

	TRACE(("enter send_msg_global_request_remotetcp"));

	CHECKCLEARTOWRITE();
	buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
	buf_putstring(ses.writepayload, "tcpip-forward", 13);
	buf_putbyte(ses.writepayload, 0);
	buf_putstring(ses.writepayload, "0.0.0.0", 7); /* TODO: IPv6? */
	buf_putint(ses.writepayload, port);

	encrypt_packet();

	TRACE(("leave send_msg_global_request_remotetcp"));
}

void setup_remotetcp() {

	struct TCPFwdList * iter = NULL;

	if (cli_opts.remotefwds == NULL) {
		TRACE(("cli_opts.remotefwds == NULL"));
	}

	iter = cli_opts.remotefwds;

	while (iter != NULL) {
		send_msg_global_request_remotetcp(iter->listenport);
		iter = iter->next;
	}
}

static int newtcpforwarded(struct Channel * channel) {

	unsigned int origport;
	struct TCPFwdList * iter = NULL;
	char portstring[NI_MAXSERV];
	int sock;
	int ret = DROPBEAR_FAILURE;

	/* We don't care what address they connected to */
	buf_eatstring(ses.payload);

	origport = buf_getint(ses.payload);

	/* Find which port corresponds */
	iter = cli_opts.remotefwds;

	while (iter != NULL) {
		if (origport == iter->listenport) {
			break;
		}
		iter = iter->next;
	}

	if (iter == NULL) {
		/* We didn't request forwarding on that port */
		dropbear_log(LOG_INFO, "Server send unrequested port, from port %d", 
										origport);
		goto out;
	}
	
	snprintf(portstring, sizeof(portstring), "%d", iter->connectport);
	sock = connect_remote(iter->connectaddr, portstring, 1, NULL);
	if (sock < 0) {
		TRACE(("leave newtcpdirect: sock failed"));
		goto out;
	}

	ses.maxfd = MAX(ses.maxfd, sock);

	/* Note that infd is actually the "outgoing" direction on the
	 * tcp connection, vice versa for outfd.
	 * We don't set outfd, that will get set after the connection's
	 * progress succeeds */
	channel->infd = sock;
	channel->initconn = 1;
	
	ret = DROPBEAR_SUCCESS;

out:
	TRACE(("leave newtcpdirect: ret %d", ret));
	return ret;
}