X-Git-Url: http://git.pk910.de/?p=ircu2.10.12-pk.git;a=blobdiff_plain;f=tools%2FBounce%2FBounce.cpp;fp=tools%2FBounce%2FBounce.cpp;h=df79a1746e10c3ce4c0f9856a6ca0a080c08f17a;hp=0000000000000000000000000000000000000000;hb=0400a5a6479398d82526785c18c0df8bc8b92dce;hpb=d17e10da972ce5776c60b4c317267c6abe0e1ead diff --git a/tools/Bounce/Bounce.cpp b/tools/Bounce/Bounce.cpp new file mode 100755 index 0000000..df79a17 --- /dev/null +++ b/tools/Bounce/Bounce.cpp @@ -0,0 +1,504 @@ +/* + * IRC - Internet Relay Chat, tools/Bounce/Bounce.cpp + * Copyright (C) 1990 Jarkko Oikarinen and + * University of Oulu, Computing Center + * + * See file AUTHORS in IRC package for additional names of + * the programmers. + * + * 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 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Port Bouncer. + * + * This tool is designed to set up a number of local listening ports, and + * then forward any data recived on those ports, to another host/port combo. + * Each listening port can bounce to a different host/port defined in the + * config file. --Gte + * + * $Id: Bounce.cpp,v 1.3 2002-03-07 22:52:57 ghostwolf Exp $ + * + */ + +#include "Bounce.h" + +int main() { + Bounce* application = new Bounce(); + + /* + * Ignore SIGPIPE. + */ + + struct sigaction act; + act.sa_handler = SIG_IGN; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + sigaction(SIGPIPE, &act, 0); + +#ifndef DEBUG + /* + * If we aren't debugging, we might as well + * detach from the console. + */ + + pid_t forkResult = fork() ; + if(forkResult < 0) + { + printf("Unable to fork new process.\n"); + return -1 ; + } + else if(forkResult != 0) + { + printf("Successfully Forked, New process ID is %i.\n", forkResult); + return 0; + } +#endif + + /* + * Create new application object, bind listeners and begin + * polling them. + */ + application->bindListeners(); + + while (1) { + application->checkSockets(); + } +} + +/* + **************************************** + * * + * Bounce class implementation. * + * * + **************************************** + */ + +void Bounce::bindListeners() { +/* + * bindListeners. + * Inputs: Nothing. + * Outputs: Nothing. + * Process: 1. Reads the config file, and.. + * 2. Creates a new listener for each 'P' line found. + * + */ + + FILE* configFd; + char tempBuf[256]; + int localPort = 0; + int remotePort = 0; + char* remoteServer; + char* vHost; + + /* + * Open config File. + */ + + if(!(configFd = fopen("bounce.conf", "r"))) + { + printf("Error, unable to open config file!\n"); + exit(0); + } + + while (fgets(tempBuf, 256, configFd) != NULL) { + if((tempBuf[0] != '#') && (tempBuf[0] != '\r')) { + switch(tempBuf[0]) + { + case 'P': { /* Add new port listener */ + strtok(tempBuf, ":"); + vHost = strtok(NULL, ":"); + localPort = atoi(strtok(NULL, ":")); + remoteServer = strtok(NULL, ":"); + remotePort = atoi(strtok(NULL, ":")); + + Listener* newListener = new Listener(); + strcpy(newListener->myVhost, vHost); + strcpy(newListener->remoteServer, remoteServer); + newListener->remotePort = remotePort; + newListener->localPort = localPort; +#ifdef DEBUG + printf("Adding new Listener: Local: %s:%i, Remote: %s:%i\n", vHost, localPort, remoteServer, remotePort); +#endif + + newListener->beginListening(); + listenerList.insert(listenerList.begin(), newListener); + break; + } + } + } + } +} + +void Bounce::checkSockets() { +/* + * checkSockets. + * Inputs: Nothing. + * Outputs: Nothing. + * Process: 1. Builds up a FD_SET of all sockets we wish to check. + * (Including all listeners & all open connections). + * 2. SELECT(2) the set, and forward/accept as needed. + * + */ + typedef std::list listenerContainer; + typedef listenerContainer::iterator listIter; + + typedef std::list connectionContainer; + typedef connectionContainer::iterator connIter; + + struct timeval tv; + fd_set readfds; + tv.tv_sec = 0; + tv.tv_usec = 1000; + int tempFd = 0; + int tempFd2 = 0; + int highestFd = 0; + int delCheck = 0; + char* tempBuf; + + FD_ZERO(&readfds); + + /* + * Add all Listeners to the set. + */ + + listIter a = listenerList.begin(); + while(a != listenerList.end()) + { + tempFd = (*a)->fd; + FD_SET(tempFd, &readfds); + if (highestFd < tempFd) highestFd = tempFd; + a++; + } + + /* + * Add Local & Remote connections from each + * connection object to the set. + */ + + connIter b = connectionsList.begin(); + while(b != connectionsList.end()) + { + tempFd = (*b)->localSocket->fd; + tempFd2 = (*b)->remoteSocket->fd; + FD_SET(tempFd, &readfds); + if (highestFd < tempFd) highestFd = tempFd; + FD_SET(tempFd2, &readfds); + if (highestFd < tempFd2) highestFd = tempFd2; + b++; + } + + select(highestFd+1, &readfds, NULL, NULL, &tv); + + /* + * Check all connections for readability. + * First check Local FD's. + * If the connection is closed on either side, + * shutdown both sockets, and clean up. + * Otherwise, send the data from local->remote, or + * remote->local. + */ + + b = connectionsList.begin(); + while(b != connectionsList.end()) + { + tempFd = (*b)->localSocket->fd; + + if (FD_ISSET(tempFd, &readfds)) + { + tempBuf = (*b)->localSocket->read(); + if ((tempBuf[0] == 0)) // Connection closed. + { + close((*b)->localSocket->fd); + close((*b)->remoteSocket->fd); +#ifdef DEBUG + printf("Closing FD: %i\n", (*b)->localSocket->fd); + printf("Closing FD: %i\n", (*b)->remoteSocket->fd); +#endif + delete(*b); + delCheck = 1; + b = connectionsList.erase(b); + } else { + (*b)->remoteSocket->write(tempBuf, (*b)->localSocket->lastReadSize); + } + } + + if (!delCheck) b++; + delCheck = 0; + } + + /* + * Now check Remote FD's.. + */ + b = connectionsList.begin(); + while(b != connectionsList.end()) + { + tempFd = (*b)->remoteSocket->fd; + if (FD_ISSET(tempFd, &readfds)) + { + tempBuf = (*b)->remoteSocket->read(); + if ((tempBuf[0] == 0)) // Connection closed. + { + close((*b)->localSocket->fd); + close((*b)->remoteSocket->fd); +#ifdef DEBUG + printf("Closing FD: %i\n", (*b)->localSocket->fd); + printf("Closing FD: %i\n", (*b)->remoteSocket->fd); +#endif + delete(*b); + delCheck = 1; + b = connectionsList.erase(b); + } else { + (*b)->localSocket->write(tempBuf, (*b)->remoteSocket->lastReadSize); + } + } + if (!delCheck) b++; + delCheck = 0; + } + + /* + * Check all listeners for new connections. + */ + + a = listenerList.begin(); + while(a != listenerList.end()) + { + tempFd = (*a)->fd; + if (FD_ISSET(tempFd, &readfds)) + { + recieveNewConnection(*a); + } + a++; + } + +} + +void Bounce::recieveNewConnection(Listener* listener) { +/* + * recieveNewConnection. + * Inputs: A Listener Object. + * Outputs: Nothing. + * Process: 1. Recieves a new connection on a local port, + * and creates a connection object for it. + * 2. Accepts the incomming connection. + * 3. Creates a new Socket object for the remote + * end of the connection. + * 4. Connects up the remote Socket. + * 5. Adds the new Connection object to the + * connections list. + * + */ + + Connection* newConnection = new Connection(); + newConnection->localSocket = listener->handleAccept(); + + Socket* remoteSocket = new Socket(); + newConnection->remoteSocket = remoteSocket; + if(remoteSocket->connectTo(listener->remoteServer, listener->remotePort)) { + connectionsList.insert(connectionsList.begin(), newConnection); + } else { +#ifdef DEBUG + newConnection->localSocket->write("Unable to connect to remote host.\n"); +#endif + close(newConnection->localSocket->fd); + delete(newConnection); + delete(remoteSocket); + } +} + + +/* + **************************************** + * * + * Listener class implementation. * + * * + **************************************** + */ + + +Socket* Listener::handleAccept() { +/* + * handleAccept. + * Inputs: Nothing. + * Outputs: A Socket Object. + * Process: 1. Accept's an incomming connection, + * and returns a new socket object. + */ + + int new_fd = 0; + int sin_size = sizeof(struct sockaddr_in); + + Socket* newSocket = new Socket(); + new_fd = accept(fd, (struct sockaddr*)&newSocket->address, (socklen_t*)&sin_size); + newSocket->fd = new_fd; + return newSocket; +} + +void Listener::beginListening() { +/* + * beginListening. + * Inputs: Nothing. + * Outputs: Nothing. + * Process: 1. Binds the local ports for all the + * Listener objects. + * + */ + + struct sockaddr_in my_addr; + int bindRes; + int optval; + optval = 1; + + fd = socket(AF_INET, SOCK_STREAM, 0); /* Check for no FD's left?! */ + + my_addr.sin_family = AF_INET; + my_addr.sin_port = htons(localPort); + my_addr.sin_addr.s_addr = inet_addr(myVhost); + bzero(&(my_addr.sin_zero), 8); + + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + bindRes = bind(fd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)); + if(bindRes == 0) + { + listen(fd, 10); + } else { + /* + * If we can't bind a listening port, we might aswell drop out. + */ + printf("Unable to bind to %s:%i!\n", myVhost, localPort); + exit(0); + } +} + +/* + **************************************** + * * + * Socket class implementation. * + * * + **************************************** + */ + + +Socket::Socket() { +/* + * Socket Constructor. + * Inputs: Nothing. + * Outputs: Nothing. + * Process: Initialises member variables. + * + */ + + fd = -1; + lastReadSize = 0; +} + +int Socket::write(char *message, int len) { +/* + * write. + * Inputs: Message string, and lenght. + * Outputs: Amount written, or 0 on error. + * Process: 1. Writes out 'len' amount of 'message'. + * to this socket. + * + */ + + if (fd == -1) return 0; + + int amount = ::write(fd, message, len); +#ifdef DEBUG + printf("Wrote %i Bytes.\n", amount); +#endif + return amount; +} + +int Socket::write(char *message) { +/* + * write(2). + * Inputs: Message string. + * Outputs: Amount writte, or 0 on error. + * Process: Writes out the whole of 'message'. + * + */ + + if (fd == -1) return 0; + + int amount = ::write(fd, message, strlen(message)); +#ifdef DEBUG + printf("Wrote %i Bytes.\n", amount); +#endif + return amount; +} + + +int Socket::connectTo(char *hostname, unsigned short portnum) { +/* + * connectTo. + * Inputs: Hostname and port. + * Outputs: +ve on success, 0 on failure. + * Process: 1. Connects this socket to remote 'hostname' on + * port 'port'. + * + */ + + struct hostent *hp; + + if ((hp = gethostbyname(hostname)) == NULL) { + return 0; + } + + memset(&address,0,sizeof(address)); + memcpy((char *)&address.sin_addr,hp->h_addr,hp->h_length); + address.sin_family= hp->h_addrtype; + address.sin_port= htons((u_short)portnum); + + if ((fd = socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) + return 0; + + if (connect(fd, (struct sockaddr*)&address, sizeof(address)) < 0) { + close(fd); + fd = -1; + return 0; + } + return(1); +} + +char* Socket::read() { +/* + * read. + * Inputs: Nothing. + * Outputs: char* to static buffer containing data. + * Process: 1. Reads as much as possible from this socket, up to + * 4k. + * + */ + + int amountRead = 0; + static char buffer[4096]; + + amountRead = ::read(fd, &buffer, 4096); + + if ((amountRead == -1)) buffer[0] = '\0'; + buffer[amountRead] = '\0'; + +#ifdef DEBUG + printf("Read %i Bytes.\n", amountRead); +#endif + + /* + * Record this just incase we're dealing with binary data with 0's in it. + */ + lastReadSize = amountRead; + return (char *)&buffer; +} +