/* 

Just library with connect(2) replacement... 

Configuration and running notes: 
a) make
b) make install
c) export CONN_ADDR=ip.ad.dre.ss
d) export LD_PRELOAD=/usr/lib/libconnect.so.M.N
e) enjoy... all programs, which calls connect(2) now will connect
from address, which exported as CONN_ADDR..

                dedicated to inty and irc.lucky.net.

 * $Id: connect.c,v 1.2 2000/05/22 17:29:23 snar Exp $
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <dlfcn.h>

static int conn_initialised=0;
static int (*real_connect)(int, struct sockaddr*, int)=NULL;

static struct sockaddr_in tobi;

int
connect __P((int s, const struct sockaddr *re, socklen_t namelen))
{ 
	struct sockaddr_in nm,*remo=(struct sockaddr_in*)re;
	int nml;
	char* name;

repete:

	switch(conn_initialised) { 
		case -1: 
			return ENOENT;
		case 0:
			name=getenv("CONN_ADDR");	
			bzero(&tobi,sizeof(struct sockaddr_in));
			real_connect=dlsym(RTLD_NEXT,"_connect");
			if(!real_connect) { 
				printf("Can't locate symbol _connect in RTLD_NEXT: %s\n",
					dlerror());
				conn_initialised=-1;
				return errno;
			};		
			if(name) { 
				tobi.sin_addr.s_addr=inet_addr(name);
				tobi.sin_family=PF_INET;
				tobi.sin_port=0;
				conn_initialised=1;
#ifdef CONN_DEBUG
				printf("oki, all connect(2)'s wil be from %s\n",
					inet_ntoa(tobi.sin_addr));
#endif
			} else { 
				conn_initialised=2;
#ifdef CONN_DEBUG
				printf("will connect(2)'s from INADDR_ANY..\n");
#endif
			};
			goto repete;
		case 1:
			nml=sizeof(nm);
			if(getsockname(s,(struct sockaddr*)&nm,&nml)==-1) { 
				return errno;
			};
			if(bcmp(&nm.sin_addr.s_addr,&tobi.sin_addr.s_addr,
				sizeof(nm.sin_addr.s_addr))) { 
#ifdef CONN_DEBUG
				printf("attempt to connect %s:%u from wrong",
					inet_ntoa(remo->sin_addr),
					ntohs(remo->sin_port));
				printf(" address (%s:%u)\n",
					inet_ntoa(nm.sin_addr),
					ntohs(nm.sin_port));
#endif
				if(bind(s,(struct sockaddr*)&tobi,
					sizeof(struct sockaddr_in))==-1) { 
#ifdef CONN_DEBUG
					printf("bind() failed: %s\n",strerror(errno));
#endif
					return errno;
				};
			};
			break;
			case 2:
				break;
			default:
				printf("conn_initialised: unknown state %i\n",conn_initialised);
				return 0;
		};
		return real_connect(s,(struct sockaddr*)remo,namelen);
};


syntax highlighted by Code2HTML, v. 0.9.1