]>
jfr.im git - irc/quakenet/snircd.git/blob - tools/Bounce/Bounce.cpp
2 * IRC - Internet Relay Chat, tools/Bounce/Bounce.cpp
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
6 * See file AUTHORS in IRC package for additional names of
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 1, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 * This tool is designed to set up a number of local listening ports, and
26 * then forward any data recived on those ports, to another host/port combo.
27 * Each listening port can bounce to a different host/port defined in the
30 * $Id: Bounce.cpp,v 1.3 2002/03/07 22:52:57 ghostwolf Exp $
37 Bounce
* application
= new Bounce();
44 act
.sa_handler
= SIG_IGN
;
46 sigemptyset(&act
.sa_mask
);
47 sigaction(SIGPIPE
, &act
, 0);
51 * If we aren't debugging, we might as well
52 * detach from the console.
55 pid_t forkResult
= fork() ;
58 printf("Unable to fork new process.\n");
61 else if(forkResult
!= 0)
63 printf("Successfully Forked, New process ID is %i.\n", forkResult
);
69 * Create new application object, bind listeners and begin
72 application
->bindListeners();
75 application
->checkSockets();
80 ****************************************
82 * Bounce class implementation. *
84 ****************************************
87 void Bounce::bindListeners() {
92 * Process: 1. Reads the config file, and..
93 * 2. Creates a new listener for each 'P' line found.
108 if(!(configFd
= fopen("bounce.conf", "r")))
110 printf("Error, unable to open config file!\n");
114 while (fgets(tempBuf
, 256, configFd
) != NULL
) {
115 if((tempBuf
[0] != '#') && (tempBuf
[0] != '\r')) {
118 case 'P': { /* Add new port listener */
119 strtok(tempBuf
, ":");
120 vHost
= strtok(NULL
, ":");
121 localPort
= atoi(strtok(NULL
, ":"));
122 remoteServer
= strtok(NULL
, ":");
123 remotePort
= atoi(strtok(NULL
, ":"));
125 Listener
* newListener
= new Listener();
126 strcpy(newListener
->myVhost
, vHost
);
127 strcpy(newListener
->remoteServer
, remoteServer
);
128 newListener
->remotePort
= remotePort
;
129 newListener
->localPort
= localPort
;
131 printf("Adding new Listener: Local: %s:%i, Remote: %s:%i\n", vHost
, localPort
, remoteServer
, remotePort
);
134 newListener
->beginListening();
135 listenerList
.insert(listenerList
.begin(), newListener
);
143 void Bounce::checkSockets() {
148 * Process: 1. Builds up a FD_SET of all sockets we wish to check.
149 * (Including all listeners & all open connections).
150 * 2. SELECT(2) the set, and forward/accept as needed.
153 typedef std::list
<Listener
*> listenerContainer
;
154 typedef listenerContainer::iterator listIter
;
156 typedef std::list
<Connection
*> connectionContainer
;
157 typedef connectionContainer::iterator connIter
;
172 * Add all Listeners to the set.
175 listIter a
= listenerList
.begin();
176 while(a
!= listenerList
.end())
179 FD_SET(tempFd
, &readfds
);
180 if (highestFd
< tempFd
) highestFd
= tempFd
;
185 * Add Local & Remote connections from each
186 * connection object to the set.
189 connIter b
= connectionsList
.begin();
190 while(b
!= connectionsList
.end())
192 tempFd
= (*b
)->localSocket
->fd
;
193 tempFd2
= (*b
)->remoteSocket
->fd
;
194 FD_SET(tempFd
, &readfds
);
195 if (highestFd
< tempFd
) highestFd
= tempFd
;
196 FD_SET(tempFd2
, &readfds
);
197 if (highestFd
< tempFd2
) highestFd
= tempFd2
;
201 select(highestFd
+1, &readfds
, NULL
, NULL
, &tv
);
204 * Check all connections for readability.
205 * First check Local FD's.
206 * If the connection is closed on either side,
207 * shutdown both sockets, and clean up.
208 * Otherwise, send the data from local->remote, or
212 b
= connectionsList
.begin();
213 while(b
!= connectionsList
.end())
215 tempFd
= (*b
)->localSocket
->fd
;
217 if (FD_ISSET(tempFd
, &readfds
))
219 tempBuf
= (*b
)->localSocket
->read();
220 if ((tempBuf
[0] == 0)) // Connection closed.
222 close((*b
)->localSocket
->fd
);
223 close((*b
)->remoteSocket
->fd
);
225 printf("Closing FD: %i\n", (*b
)->localSocket
->fd
);
226 printf("Closing FD: %i\n", (*b
)->remoteSocket
->fd
);
230 b
= connectionsList
.erase(b
);
232 (*b
)->remoteSocket
->write(tempBuf
, (*b
)->localSocket
->lastReadSize
);
241 * Now check Remote FD's..
243 b
= connectionsList
.begin();
244 while(b
!= connectionsList
.end())
246 tempFd
= (*b
)->remoteSocket
->fd
;
247 if (FD_ISSET(tempFd
, &readfds
))
249 tempBuf
= (*b
)->remoteSocket
->read();
250 if ((tempBuf
[0] == 0)) // Connection closed.
252 close((*b
)->localSocket
->fd
);
253 close((*b
)->remoteSocket
->fd
);
255 printf("Closing FD: %i\n", (*b
)->localSocket
->fd
);
256 printf("Closing FD: %i\n", (*b
)->remoteSocket
->fd
);
260 b
= connectionsList
.erase(b
);
262 (*b
)->localSocket
->write(tempBuf
, (*b
)->remoteSocket
->lastReadSize
);
270 * Check all listeners for new connections.
273 a
= listenerList
.begin();
274 while(a
!= listenerList
.end())
277 if (FD_ISSET(tempFd
, &readfds
))
279 recieveNewConnection(*a
);
286 void Bounce::recieveNewConnection(Listener
* listener
) {
288 * recieveNewConnection.
289 * Inputs: A Listener Object.
291 * Process: 1. Recieves a new connection on a local port,
292 * and creates a connection object for it.
293 * 2. Accepts the incomming connection.
294 * 3. Creates a new Socket object for the remote
295 * end of the connection.
296 * 4. Connects up the remote Socket.
297 * 5. Adds the new Connection object to the
302 Connection
* newConnection
= new Connection();
303 newConnection
->localSocket
= listener
->handleAccept();
305 Socket
* remoteSocket
= new Socket();
306 newConnection
->remoteSocket
= remoteSocket
;
307 if(remoteSocket
->connectTo(listener
->remoteServer
, listener
->remotePort
)) {
308 connectionsList
.insert(connectionsList
.begin(), newConnection
);
311 newConnection
->localSocket
->write("Unable to connect to remote host.\n");
313 close(newConnection
->localSocket
->fd
);
314 delete(newConnection
);
315 delete(remoteSocket
);
321 ****************************************
323 * Listener class implementation. *
325 ****************************************
329 Socket
* Listener::handleAccept() {
333 * Outputs: A Socket Object.
334 * Process: 1. Accept's an incomming connection,
335 * and returns a new socket object.
339 int sin_size
= sizeof(struct sockaddr_in
);
341 Socket
* newSocket
= new Socket();
342 new_fd
= accept(fd
, (struct sockaddr
*)&newSocket
->address
, (socklen_t
*)&sin_size
);
343 newSocket
->fd
= new_fd
;
347 void Listener::beginListening() {
352 * Process: 1. Binds the local ports for all the
357 struct sockaddr_in my_addr
;
362 fd
= socket(AF_INET
, SOCK_STREAM
, 0); /* Check for no FD's left?! */
364 my_addr
.sin_family
= AF_INET
;
365 my_addr
.sin_port
= htons(localPort
);
366 my_addr
.sin_addr
.s_addr
= inet_addr(myVhost
);
367 bzero(&(my_addr
.sin_zero
), 8);
369 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &optval
, sizeof(optval
));
371 bindRes
= bind(fd
, (struct sockaddr
*)&my_addr
, sizeof(struct sockaddr
));
377 * If we can't bind a listening port, we might aswell drop out.
379 printf("Unable to bind to %s:%i!\n", myVhost
, localPort
);
385 ****************************************
387 * Socket class implementation. *
389 ****************************************
395 * Socket Constructor.
398 * Process: Initialises member variables.
406 int Socket::write(char *message
, int len
) {
409 * Inputs: Message string, and lenght.
410 * Outputs: Amount written, or 0 on error.
411 * Process: 1. Writes out 'len' amount of 'message'.
416 if (fd
== -1) return 0;
418 int amount
= ::write(fd
, message
, len
);
420 printf("Wrote %i Bytes.\n", amount
);
425 int Socket::write(char *message
) {
428 * Inputs: Message string.
429 * Outputs: Amount writte, or 0 on error.
430 * Process: Writes out the whole of 'message'.
434 if (fd
== -1) return 0;
436 int amount
= ::write(fd
, message
, strlen(message
));
438 printf("Wrote %i Bytes.\n", amount
);
444 int Socket::connectTo(char *hostname
, unsigned short portnum
) {
447 * Inputs: Hostname and port.
448 * Outputs: +ve on success, 0 on failure.
449 * Process: 1. Connects this socket to remote 'hostname' on
456 if ((hp
= gethostbyname(hostname
)) == NULL
) {
460 memset(&address
,0,sizeof(address
));
461 memcpy((char *)&address
.sin_addr
,hp
->h_addr
,hp
->h_length
);
462 address
.sin_family
= hp
->h_addrtype
;
463 address
.sin_port
= htons((u_short
)portnum
);
465 if ((fd
= socket(hp
->h_addrtype
,SOCK_STREAM
,0)) < 0)
468 if (connect(fd
, (struct sockaddr
*)&address
, sizeof(address
)) < 0) {
476 char* Socket::read() {
480 * Outputs: char* to static buffer containing data.
481 * Process: 1. Reads as much as possible from this socket, up to
487 static char buffer
[4096];
489 amountRead
= ::read(fd
, &buffer
, 4096);
491 if ((amountRead
== -1)) buffer
[0] = '\0';
492 buffer
[amountRead
] = '\0';
495 printf("Read %i Bytes.\n", amountRead
);
499 * Record this just incase we're dealing with binary data with 0's in it.
501 lastReadSize
= amountRead
;
502 return (char *)&buffer
;