ref/Unix / Linux
Piercing Firewalls
민성아빠
2003. 3. 17. 17:23
Piercing Firewalls
소개:
많은 ISP업체들이 해커로부터 위험성을 가지고 있는 그들의 고객들을 보호하기 위해 방
화벽을 통한 네트워크를 운영하고 있다. 방화벽은 고객들을 보호하기도 하지만, 그것은 그
들의 자유를 제한하기도 한다.
대부분의 방화벽은 출발지가 방화벽 외부일 경우에는 자동적으로 여러가지 보안상 취약점
을 제거하기위해 커넥션이 설립되도록 허가하지 않는다. 불행히도 이러한 현상은 다른 많은
것들을 불가능하게 만든다. 예를들면 방화벽 뒤에 있는 서버에 대해 X-display나 그 외 비
슷한 부류의 서비스를 제공할 수 없게 된다.
한가지 해결책은 방화벽 관리자에게 X-connection(혹은 사용하고자 하는 포트)에 관한 설
정을 변경할 것을 요청하는 것이 될 수 있다. 이것은 방화벽을 통과하기 위해서 6000번 포
트에 대한 커낵션을 허용한다는 것을 뜻한다. 그렇지만 종종 시스템관리자는 이러한 것을
원치 않을 경우가 있다. 예를 들면, 그가 너무나 바쁘거나, 방화벽에 관한 설정을 아직 익히
고 있지 않거나, 단지 '노'라고 거절해 버릴경우가 그것이다. 아마도 여러분은 그 관리자
에게 방화벽을 우회해 가려는 여러분의 계획을 말하려고 싶지 않을 것이다.
이러한 목적 때문에 나는 여러분의 시스템을 통과하기 위한 터널로 TCP connection을 전
송하는 두개의 간단한 프로그램을 작성하였다.
터널(The Tunnel):
해결책은 여러분의 컴퓨터에서 돌고있는 두개의 프로그램이거나 혹은 방화벽 뒤에서 돌고
있는 다른 기계 그리고, 인터넷에서 작동하는 또하나의 UNIX-box이다. 방화벽 뒤에 있는
프로그램은 Internet에 있는 기계의 프로그램( portal이라고 불린다)에 접속한다. 외부로 빠
져나가는 이 접속은 아마도 방화벽에 의해 방해받지 않는 접속이 될 것이다( 물론 그 네트
웍의 보안 정책에 의존하겠지만). Tunnel에서 portal로의 커낵션이 성립하게 되면, portal
은 TCP traffic을 받기 위한 포트를 열게 되고, 이제 우리는 목표에 달할 준비가 된다. 그
기계가 portal에게 접속을 할 때마다. 기계는 방화벽을 통과해서 성립되어있는 접속을 통해
tunnel에게 요청(request) 신호를 되돌리게 된다.그리고 tunnel은 당신의 컴퓨터로 접속을
전달(forwarding)시키게 된다.
이것이 의미하는 것은 당신의 컴퓨터에 있는 어떠한 포트도 방화벽 외부에 있는 어떠한 컴
퓨터로 옮길수 있다는 것을 뜻하고, 결국 어떠한 사람도 그 사이트(site)의 방화벽 정책에
관계없이 방화벽 내부로 접속할 수 있음을 뜻한다.
Example:
방화벽
tunnel ^ portal
######### ^ #########
# Foo #=================# Bar #
######### ^ #########
| ^ |
| ^ |
| ^ |
######### ^ #########
# Goof # ^ # Boof #
######### ^ #########
방화벽
Goof: 당신의 컴퓨터
Foo: tunnel이 실행되고있고 Goof와 같이 방화벽뒤의 기계
Bar: portal이 실행되고 있는 방화벽 외부의 컴퓨터
Boof: Goof로의 접속을 기다리고 있는 방화벽 외부의 컴퓨터
당신은 지금 Goof앞에 앉아 있고 X-windows를 사용하는 프로그램이 돌고 있는 기계인
Boof에서 어떠한 프로그램을 수행하고있다. 그래서 당신은 Goof로 display를 되돌리기를
원할 것이다. X-windows는 방화벽을 통해서 TCP 접속을 시도하게 될 것이다. ( 하지만 그
시도는 방화벽에 의해서 거부될 것이다. )
그래서 이제 당신은 Foo에서 tunnel을 돌리기 시작하고 그것을 Bar의 7000번 포트
(portal이 돌고있다.)로 접속하도록 설정을 해놓고, 또한 당신은 tunnel로 하여금 portal로
부터 되돌아오는 모든 TCP 접속을 Goof의 6000번 포트로 전달(forwarding)시키도록 설
정을 해놓는다. 그리고 bar에서 portal을 돌리고 7000번 포트에서 tunnel이 보내오는 정
보를 받도록 설정을 한다. Tunnel이 접속하게 되면, portal은 X로 오는 정보들은 6001번
포트로 받아들이게 된다. 어떠한 X-application이 portal에 접속할 때 마다, 그 접속은
tunnel로 넘겨지게 되고, 그것은 Goof의 6000번 포트로 넘겨지게 된다.
마침네 Boof에서 당신은 Bar기계로 display를 맞출 수 있게 되었다. 이것은 응용프로그램
으로 하여금 6001번 포트를 사용할 수 있게 한것이다.( 우리는 기계가 그것 자체에서 X-
server가 돌고있다면 6000번을 사용할 수 없다. ). 자 이제 Xeyes를 실행시켜 보아라. 그
것들이 당신들의 앞에 나타나 질 것이다.
결론:
만약 당신이 ISP의 보안 정책에 위배되는 즉, 방화벽을 가로지르는 프로그램을 사용한다면
ISP측에서 그 사실을 알게될 때, 그런 애매모호한 보안상태에 대해서 달갑게 여기지 않을
것이다. 그리고 제발 엄마한테 이르지 말자 -_-
이 프로그램의 장점은 어떠한 기계에서도 root 권한을 필요로 하지 않는 다는 것이다.
이것은 우리들의 작업을 한층 쉽게 만들어준다.
이 코드를 실행하기 위해서는 단지 make라고 치면 된다. 이것은 다음의 버전에서 테스트
되었다.
Solaris 2.5.x, 2.6
IRIX 6.[2,3,4]
FreeBSD 2.1.5
HPUX 10.x
Linux 2.0.x
----[ THE CODE
tunnel/Makefile
CC = gcc
OSFLAGS =
MYFLAGS = -Wall -O2 -g -pedantic
CFLAGS = $(MYFLAGS) $(PROFILE) $(OSFLAGS)
#If you compile on Solaris 2.x, uncomment the following line
#LOCAL_LIBRARIES = -lsocket
TUNNEL_OBJFILES = tunnel.o share.o
PORTAL_OBJFILES = portal.o share.o
all: tunnel portal
tunnel : $(TUNNEL_OBJFILES) share.h
$(CC) $(TUNNEL_OBJFILES) $(LOCAL_LIBRARIES) -o tunnel
tunnel.o : tunnel.c share.h
$(CC) -c $(CFLAGS) $(COMMFLAGS) tunnel.c
portal : $(PORTAL_OBJFILES) share.h
$(CC) $(PORTAL_OBJFILES) $(LOCAL_LIBRARIES) -o portal
portal.o : portal.c share.h
$(CC) -c $(CFLAGS) $(COMMFLAGS) portal.c
share.o : share.c share.h
$(CC) -c $(CFLAGS) $(COMMFLAGS) share.c
clean:
rm -f *.o tunnel portal core
<-->
tunnel/tunnel.c
/*
-TUNNEL-
This is the tunnel part of my firewall piercer. This code is supposed
to be running on the inside of the firewall. The tunnel should then
connect to the portal running on the outside.
start it like:
>% tunnel localhost 23 protal.machine.com 3001
if the portal is running at port 3001 at portal.machine.com, incoming
connections to the portal will get rerouted to this machines telnet
port.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "share.h"
extern char tunnel_buf[MAXLEN*2];
char buf[MAXLEN*2];
extern int tunnel_des; /* The socket destination of a tunnel packet*/
extern int tunnel_src; /* The socket source of a tunel packet*/
extern int tunnel_size; /* Size of tunnel packet*/
extern struct connections connections; /*Linked list of connections*/
char *remote_machine; /*remote machine name to tunnel to*/
extern int tunnel_port; /*tunnel port*/
extern int tunnel_sock; /*tunnel socket*/
char *login_machine=""; /*machine to forward connections to*/
int login_port; /*port to forward connections to*/
int oldtime=0,ping_time=0;
struct connection *descriptors[DESC_MAX];
extern struct connection *descriptors[DESC_MAX];
extern int errno;
FILE *log=stdout; /*logfile = stdout by default*/
void open_tunnel(){
tunnel_sock=remote_connect(remote_machine,tunnel_port);
}
extern int optind;
extern char *optarg;
void usage(){
printf("Usage: tunnel [-l logfile] " \\
" \\n");
printf("where:\\n");
printf("forward_machine is the machine to which the traffic is forwarded\\n");
printf("forward_port is the port to which the traffic is forwarded\\n");
printf("portal_machine is the machine we want to route the trafic from\\n");
printf("portal_port is the port we want to route the trafic from\\n");
printf("Coded by %s\\n",AUTHOR);
}
/********************** Get the options ***********************/
void get_options(int argc,char *argv[]){
int c;
while((c=getopt(argc,argv, "l:")) !=-1)
switch(c){
case 'l':
if(!(log=fopen(optarg,"w"))){
log=stdout;
fprintf(log,"Unable to open logfile '%s':%s\\n",
optarg,strerror(errno));
}
break;
case '?':
default:
usage();
exit(-1);
}
/* the two next options*/
if(argc-optind!=4){
printf("Wrong number of options!\\n");
usage();
exit(-1);
}
login_machine=get_ip(argv[optind++]);
login_port=atoi(argv[optind++]);
remote_machine=get_ip(argv[optind++]);
tunnel_port=atoi(argv[optind++]);
if(login_port65535||tunnel_port65535){
printf("Ports below 1 and above 65535 don't give any sense\\n");
usage();
exit(-1);
}
}
void alive(){
/* To check wether the line is still alive, we Myping it every
ALIVE_TIME seconds. If we don't get a ping from the tunnel
every ALIVE_TIME*2 we disconnect the connection to the
portal, and wait for a new. If the portal has not died, all
the connections through the tunnel will continue as normal once
the connection has been established again.
The reason why I do this is because some firewalls tend to
disable connections if there hasn't been any traffic for some time,
or if the connection had been up too long time.
*/
/*Transmit a Myping packet, we receive the
answer in check_tunnel_connection()*/
if(time(NULL)-oldtime>=ALIVE_TIME){
oldtime=time(NULL);
transmit_tunnel(buf,0,0,0);
}
if(time(NULL)-ping_time>ALIVE_TIME*2){
printf("Connection to portal probably lost, hanging up.\\n");
shutdown(tunnel_sock,2);
close(tunnel_sock);
tunnel_sock=-1;
}
}
int reset_selector(fd_set *selector,fd_set *errsel,struct connection *con)
{
/* We tell the selector to look on the tunnel socket aswell
as our live connections.*/
int maxsock,i;
FD_ZERO(selector);
FD_SET(tunnel_sock,selector);
FD_SET(tunnel_sock,errsel);
con=connections.head;
maxsock=tunnel_sock;
for(i=0;inext){
FD_SET(con->local_sock,selector);
FD_SET(con->local_sock,errsel);
maxsock=max(maxsock,con->local_sock);
}
return(maxsock); /*We return the maximum socket number*/
}
void check_tunnel_connection(fd_set *selector,fd_set *errsel,struct connection *con){
/*Here we check the tunnel for incoming data*/
if(FD_ISSET(tunnel_sock,errsel)){
fprintf(log,"Tunnel connection terminated!\\n");
shutdown(tunnel_sock,2);
close(tunnel_sock);
tunnel_sock=-1;
return;
}
if(FD_ISSET(tunnel_sock,selector)){
if(receive_tunnel()!=-1){
if(tunnel_src==0&&tunnel_des==0){ /*We have a Myping packet*/
ping_time=time(NULL); /*reset the alive_timer*/
}
else if(tunnel_src==0){/*We have a 'hangup' signal for a connection*/
if((con=descriptors[tunnel_des])){
fprintf(log,"Removing connection to %s %d\\n",con->host,con->port);
removeconnection(con);
}
}
else if(tunnel_des==0){ /*We have a new connection*/
int newsock;
if((newsock=remote_connect(login_machine,login_port))!=-1){
connections.num++;
con=(struct connection *)malloc(sizeof(struct connection));
con->host=(char *)malloc(MAX_HOSTNAME_SIZE);
strncpy(con->host,&tunnel_buf[4],MAX_HOSTNAME_SIZE);
con->port=ntohl((((int *)tunnel_buf)[0]));
con->local_sock=newsock;
con->remote_sock=tunnel_src;
con->time=time(NULL);
con->next=connections.head;
connections.head=con;
descriptors[newsock]=con;
fprintf(log,"Connected the incoming call from %s %d to %s %d\\n",con-
>host,con->port,login_machine,login_port);
/*Acknowledge the new connection to the portal*/
transmit_tunnel(buf,0,con->local_sock,con->remote_sock);
}
}
else if(descriptors[tunnel_des]){
/*Send the data to the right descriptor*/
writen(descriptors[tunnel_des]->local_sock,tunnel_buf,tunnel_size);
}
else{
fprintf(log,"Connection to unallocated channel, hangup signal sent\\n");
/*Send a hangup signal to the portal, to disable the connection*/
transmit_tunnel(buf,0,0,tunnel_src);
}
}
}
}
void main(int argc,char **argv)
{
get_options(argc,argv);
fprintf(log,"Opening tunnel to %s port %d\\n",remote_machine,tunnel_port);
fprintf(log,"Tunnelconnections will be forwarded to host %s"\\
" port %d\\n",login_machine,login_port);
connections.num=0;
connections.head=NULL;
signal(SIGINT,ctrlC);
while(1){ /*The tunnel runs infinitely*/
struct connection *con=connections.head;
open_tunnel();
ping_time=time(NULL);
while(tunnel_sock!=-1){
fd_set selector,errsel;
struct timeval alive_time;
alive_time.tv_sec=ALIVE_TIME;
alive_time.tv_usec=0;
alive(); /*Check wether the tunnelconnection is alive*/
/* We have to listen to the tunnel and all the current connections.
we do that with a select call*/
if(select(reset_selector(&selector,&errsel,con)+1,
&selector,NULL,&errsel,&alive_time)){
/*Check for each of the local connections*/
check_local_connections(&selector,&errsel,con);
/*Check for the tunnel*/
check_tunnel_connection(&selector,&errsel,con);
}
}
sleep(RETRY_TIME); /*We sleep a while*/
/* fprintf(log,"Trying to connect to portal.\\n"); */
}
}
<-->
tunnel/portal.c
/*
-PORTAL-
This is the portal part of my firewall piercer. This code is supposed
to be running on the outside of the firewall. The tunnel part should
then connect trough the firewall to this program.
start it like:
>% portal 3000 3001
for tunnel connection on port 3001 and incoming calls on 3000.
when you connect to the portal at port 3000 your connection will be
forwarded to the tunnel.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "share.h"
/***************/
/* Global data */
/***************/
extern char tunnel_buf[MAXLEN*2];
extern int tunnel_des;
extern int tunnel_src;
extern int tunnel_size;
extern struct connections connections;
extern struct connection *descriptors[DESC_MAX];
extern int errno;
extern int tunnel_port; /*tunnel port*/
extern int tunnel_sock; /*tunnel new accepted socket*/
char buf[MAXLEN*2];
char *remote_machine; /*remote machine name*/
int tunnel_basesock; /*tunnel base socket*/
int local_sock; /* local port socket*/
int local_port; /*local machine port*/
FILE *log=stdout; /*logfile = stdout by default*/
int ping_time=0;
/********************** Usage ***********************/
void usage(){
fprintf(stderr,"Usage: portal [-l logfile] \\n");
fprintf(stderr,"where:\\n");
fprintf(stderr,"local_port is the port where we accept incoming" \\
" connections\\n");
fprintf(stderr,"remote_port is the port where we accept the tunnel" \\
" to connect\\n");
fprintf(stderr,"Coded by %s\\n",AUTHOR);
}
/********************** Get the options ***********************/
extern int optind;
extern char *optarg;
void get_options(int argc,char *argv[]){
int c;
while((c=getopt(argc,argv, "l:")) !=-1)
switch(c){
case 'l':
if(!(log=fopen(optarg,"w"))){
log=stdout;
fprintf(log,"Unable to open logfile '%s':%s\\n",
optarg,strerror(errno));
}
break;
case '?':
default:
usage();
exit(-1);
}
/* the two next options*/
if(argc-optind!=2){
printf("Wrong number of options!\\n");
usage();
exit(-1);
}
local_port=atoi(argv[optind++]);
tunnel_port=atoi(argv[optind++]);
if(local_port65535||tunnel_port65535){
printf("Ports below 1 and above 65535 dont give any sense\\n");
usage();
exit(-1);
}
}
/*********************************************************/
/*************** Portal *****************/
/*********************************************************/
void open_local_port(){
/*Open the local port for incoming connections*/
struct sockaddr_in ser;
int opt=1;
local_sock=socket(AF_INET,SOCK_STREAM,0);
if(local_sock==-1){fprintf(log,"Error opening socket\\n");exit(0);}
if(setsockopt(local_sock,SOL_SOCKET,SO_REUSEADDR,
(char *)&opt,sizeof(opt))h_name,cli.sin_port);
return(newsock);
}
void close_portal(){
shutdown(tunnel_sock,1);
close(tunnel_sock);
}
struct connection *receive_local(){
struct sockaddr_in cli;
int newsock,clilen;
struct hostent *from;
struct connection *con;
clilen=sizeof(cli);
/*Accept incoming calls*/
newsock=accept(local_sock,(struct sockaddr *)&cli,&clilen);
if(newsock==-1)
{fprintf(log,"Server Accept Error:%s\\n",strerror(errno));exit(-1);}
/*We want to know know our remote host better*/
from=gethostbyaddr((char *)(&cli.sin_addr),sizeof(cli.sin_addr), PF_INET);
fprintf(log,"New connection from:%s %d\\n",from->h_name,cli.sin_port);
/*Add our new friend to our list of connections*/
connections.num++;
con=(struct connection *)malloc(sizeof(struct connection));
con->host=strdup(from->h_name);
con->port=cli.sin_port;
con->local_sock=newsock;
con->remote_sock=0;
con->time=time(NULL);
con->next=connections.head;
connections.head=con;
descriptors[newsock]=con;
return(con);
}
void alive(){
/* If we don't get a ping from the tunnel
every ALIVE_TIME*2 we disconnect the connection to the
tunnel, and wait for a new. If the tunnel has not died, all
the connections from the tunnel will continue as normal once
the connection has been established again*/
if(time(NULL)-ping_time>ALIVE_TIME*2){
printf("Connection to tunnel probably lost, hanging up.\\n");
shutdown(tunnel_sock,2);
close(tunnel_sock);
tunnel_sock=-1;
}
}
int reset_selector(fd_set *selector,fd_set *errsel,struct connection *con){
/* We tell the selector to look on the tunnel socket aswell
as our live connections, and the connection socket.*/
int maxsock,i;
FD_ZERO(selector);
FD_SET(local_sock,selector);
FD_SET(tunnel_sock,selector);
FD_SET(local_sock,errsel);
FD_SET(tunnel_sock,errsel);
con=connections.head;
maxsock=max(local_sock,tunnel_sock);
for(i=0;inext){
FD_SET(con->local_sock,selector);
FD_SET(con->local_sock,errsel);
maxsock=max(maxsock,con->local_sock);
}
return(maxsock);
}
void check_tunnel_connection(fd_set *selector,fd_set *errsel,struct connection *con){
/*Here we check the tunnel for incoming data*/
if(FD_ISSET(tunnel_sock,errsel)){
fprintf(log,"Tunnel connection terminated!\\n");
shutdown(tunnel_sock,2);
close(tunnel_sock);
tunnel_sock=-1;
return;
}
if(FD_ISSET(tunnel_sock,selector)){
if(receive_tunnel()!=-1){
if(tunnel_src==0&&tunnel_des==0){ /*We got a Myping*/
ping_time=time(NULL);
/* Ping the tunnel back!*/
transmit_tunnel(buf,0,0,0); /*Send a Myping back*/
}
else if(tunnel_des){
if(descriptors[tunnel_des]){
con=descriptors[tunnel_des];
if(tunnel_src!=0){
con->remote_sock=tunnel_src;
writen(descriptors[tunnel_des]->local_sock,tunnel_buf,tunnel_size);
}
else{
printf("Hangup signal received. Removing connection to %s %d\\n",con-
>host,con->port);
removeconnection(con);
}
}
}
}
}
}
void check_connection_port(fd_set *selector,fd_set *errsel,struct connection *con){
/*Here we check the connection port for new connections*/
if(FD_ISSET(local_sock,selector)){
con=receive_local();
if(con){
printf("Transmitting the new connection\\n");
*((int *)(&buf[4]))=htonl(con->port);
strncpy(&buf[8],con->host,MAX_HOSTNAME_SIZE);
*(&buf[8]+strlen(con->host))=0;
transmit_tunnel(buf,4+min(strlen(con->host)+1,MAX_HOSTNAME_SIZE),con-
>local_sock,0);
}
}
}
void main(int argc,char **argv){
get_options(argc,argv);
init_descriptors();
connections.num=0;
connections.head=NULL;
remote_machine=get_ip(argv[2]);
fprintf(log,"Tunneling incoming calls on port %d to port %d \\n"
,local_port,tunnel_port);
connections.num=0;
connections.head=NULL;
fprintf(log,"Opening portal\\n");
open_portal();
signal(SIGINT,ctrlC);
fprintf(log,"Opening localport\\n");
open_local_port();
while(1){
fprintf(log,"Waiting for tunnel connection on port %d\\n",tunnel_port);
while((tunnel_sock=accept_portal())==-1) sleep(4);
ping_time=time(NULL);
while(tunnel_sock!=-1){
fd_set selector,errsel;
struct connection *con=NULL;
struct timeval alive_time;
alive_time.tv_sec=ALIVE_TIME;
alive_time.tv_usec=0;
alive();
/* We have to listen to the tunnel, the local port, and alle the
current connections. */
if(select(reset_selector(&selector,&errsel,con)+1,
&selector,NULL,&errsel,&alive_time)){
check_tunnel_connection(&selector,&errsel,con);
check_connection_port(&selector,&errsel,con);
check_local_connections(&selector,&errsel,con);
}
}
sleep(2);
}
}
<-->
tunnel/share.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "share.h"
char tunnel_buf[MAXLEN*2]; /*Buffer to store the tunnel data in*/
int tunnel_des; /*Destination socket */
int tunnel_src; /*Source socket*/
int tunnel_size; /*Size of the data currently in the buffer*/
int tunnel_sock; /*The socket of the portal*/
int tunnel_port; /*The port we wan't to run on*/
extern FILE *log; /* Our log file*/
extern int errno;
struct connection *descriptors[DESC_MAX];
struct connections connections; /*A linked list of our connections*/
/*
Packet header:
####################################/
# Dest # Source# Data size # / data comes here
###################################\\
1 byte 1 byte 2 bytes
If the sestination field is zero, we are initiating a new connection
If the source field we are dropping a connection
If both the destination and the source is zero, it is a Myping packet.
*/
void ctrlC(int sig)
{
fprintf(log,"Shutting down the hard way\\n");
shutdown(tunnel_sock,2);
close(tunnel_sock);
exit(-1);
}
char *get_ip(char *host){
struct hostent *remote;
struct in_addr *in;
remote=gethostbyname(host);
if(remote==NULL){
fprintf(log,"Hostinformation of remote machine '%s' not resolved,"\\
" reason:%s",host,strerror(errno));
exit(-1);
}
in=(struct in_addr *)remote->h_addr_list[0];
return(strdup(inet_ntoa(*in)));
}
int transmit_tunnel(char *data,int size,int source,int destination){
int nleft=size+4,nwritten;
fd_set selector,errsel;
data[0]=(unsigned char)destination; /*Destination into header*/
data[1]=(unsigned char)source; /*Source into header*/
*((u_short *)&data[2])=htons(size); /*Size into header*/
while(nleft>0){
FD_ZERO(&errsel);
FD_ZERO(&selector);
FD_SET(tunnel_sock,&errsel);
FD_SET(tunnel_sock,&selector);
select(tunnel_sock+1,NULL,&selector,&errsel,NULL);
if(FD_ISSET(tunnel_sock,&errsel)){
printf("Big bug\\n");
}
nwritten=write(tunnel_sock,data,nleft);
if(nwritten==-1){
fprintf(log,"Error writing to tunnel:%s\\n",strerror(errno));
tunnel_sock=-1;
return(nwritten);
}
else if(nwritten==0){
fprintf(log,"Error: Wrote zero bytes in transmit_tunnel\\n");
return(nwritten);
}
nleft-=nwritten;
data+=nwritten;
}
return(size - nleft);
}
int receive_tunnel(){
static int received=0;
int n,left,got=0,quit=0,sofar=0;
received++;
while(sofar0){quit=1;sofar+=n;}
if(n<connections.num&&con;i++,con=con->next){
if(FD_ISSET(con->local_sock,errsel)){
fprintf(log,"LLocal connection terminated\\n");
fprintf(log,"Removing connection to %s %d\\n",con->host,con->port);
if(con->remote_sock) transmit_tunnel(buf,0,0,con->remote_sock);
removeconnection(con);
break;
}
if(FD_ISSET(con->local_sock,selector)&&con->remote_sock){
n=read(con->local_sock,&buf[4],MAXLEN);
if(nhost,con->port);
transmit_tunnel(buf,0,0,con->remote_sock);
removeconnection(con);
break;
}
/*forward the data to the tunnel*/
transmit_tunnel(buf,n,con->local_sock,con->remote_sock);
}
}
}
void ZERO(char * buf,int size){int i=0;while(i0){
nwritten=write(fd,ptr,nleft);
if(nwritten<=0) return(nwritten);
nleft-=nwritten;
ptr+=nwritten;
}
return(nbytes - nleft);
}
int remote_connect(char *machine,int port)
{
int sock;
struct sockaddr_in ser;
ZERO((char *) &ser,sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_addr.s_addr = inet_addr(machine);
ser.sin_port = htons(port);
sock=socket(AF_INET,SOCK_STREAM,0);
if(sock==-1){perror("Error opening socket\\n");return(-1);}
if(connect(sock,(struct sockaddr *) &ser,sizeof(ser))==-1){
fprintf(log,"Can't connect to server:%s\\n",strerror(errno));
return(-1);
}
return(sock);
}
void disconnect(struct connection *con,int sock1,int sock2){
fprintf(log,"Closing link to: %s %d\\n",con->host,con->port);
shutdown(sock1,2);
shutdown(sock2,2);
close(sock1);
close(sock2);
close(con->local_sock);
}
void init_descriptors(){
int i;
for(i=0;inext;
descriptors[c->local_sock]=NULL;
free(c->host);
shutdown(c->local_sock,2);
close(c->local_sock);
free(c);
connections.num--;
return;
}
c2=c;
c=c->next;
while(c){
if(c==con){
/* connections.head=c2; */
c2->next=c->next;
descriptors[c->local_sock]=NULL;
free(c->host);
shutdown(c->local_sock,2);
close(c->local_sock);
free(c);
connections.num--;
return;
}
c2=c;
c=c->next;
}
}
<-->
tunnel/share.h
/*********************/
/* Structs & Defines */
/*********************/
#define MAX_HOSTNAME_SIZE 128
#define MAXLEN 32768 /*Maximum length of our data*/
#define ALIVE_TIME 60 /*Time to wait before sending a Myping*/
#define DESC_MAX 128 /*Maximum number of descriptors used*/
#define RETRY_TIME 60 /* Time to wait before we reconnect to portal*/
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<-->
----[ EOF
소개:
많은 ISP업체들이 해커로부터 위험성을 가지고 있는 그들의 고객들을 보호하기 위해 방
화벽을 통한 네트워크를 운영하고 있다. 방화벽은 고객들을 보호하기도 하지만, 그것은 그
들의 자유를 제한하기도 한다.
대부분의 방화벽은 출발지가 방화벽 외부일 경우에는 자동적으로 여러가지 보안상 취약점
을 제거하기위해 커넥션이 설립되도록 허가하지 않는다. 불행히도 이러한 현상은 다른 많은
것들을 불가능하게 만든다. 예를들면 방화벽 뒤에 있는 서버에 대해 X-display나 그 외 비
슷한 부류의 서비스를 제공할 수 없게 된다.
한가지 해결책은 방화벽 관리자에게 X-connection(혹은 사용하고자 하는 포트)에 관한 설
정을 변경할 것을 요청하는 것이 될 수 있다. 이것은 방화벽을 통과하기 위해서 6000번 포
트에 대한 커낵션을 허용한다는 것을 뜻한다. 그렇지만 종종 시스템관리자는 이러한 것을
원치 않을 경우가 있다. 예를 들면, 그가 너무나 바쁘거나, 방화벽에 관한 설정을 아직 익히
고 있지 않거나, 단지 '노'라고 거절해 버릴경우가 그것이다. 아마도 여러분은 그 관리자
에게 방화벽을 우회해 가려는 여러분의 계획을 말하려고 싶지 않을 것이다.
이러한 목적 때문에 나는 여러분의 시스템을 통과하기 위한 터널로 TCP connection을 전
송하는 두개의 간단한 프로그램을 작성하였다.
터널(The Tunnel):
해결책은 여러분의 컴퓨터에서 돌고있는 두개의 프로그램이거나 혹은 방화벽 뒤에서 돌고
있는 다른 기계 그리고, 인터넷에서 작동하는 또하나의 UNIX-box이다. 방화벽 뒤에 있는
프로그램은 Internet에 있는 기계의 프로그램( portal이라고 불린다)에 접속한다. 외부로 빠
져나가는 이 접속은 아마도 방화벽에 의해 방해받지 않는 접속이 될 것이다( 물론 그 네트
웍의 보안 정책에 의존하겠지만). Tunnel에서 portal로의 커낵션이 성립하게 되면, portal
은 TCP traffic을 받기 위한 포트를 열게 되고, 이제 우리는 목표에 달할 준비가 된다. 그
기계가 portal에게 접속을 할 때마다. 기계는 방화벽을 통과해서 성립되어있는 접속을 통해
tunnel에게 요청(request) 신호를 되돌리게 된다.그리고 tunnel은 당신의 컴퓨터로 접속을
전달(forwarding)시키게 된다.
이것이 의미하는 것은 당신의 컴퓨터에 있는 어떠한 포트도 방화벽 외부에 있는 어떠한 컴
퓨터로 옮길수 있다는 것을 뜻하고, 결국 어떠한 사람도 그 사이트(site)의 방화벽 정책에
관계없이 방화벽 내부로 접속할 수 있음을 뜻한다.
Example:
방화벽
tunnel ^ portal
######### ^ #########
# Foo #=================# Bar #
######### ^ #########
| ^ |
| ^ |
| ^ |
######### ^ #########
# Goof # ^ # Boof #
######### ^ #########
방화벽
Goof: 당신의 컴퓨터
Foo: tunnel이 실행되고있고 Goof와 같이 방화벽뒤의 기계
Bar: portal이 실행되고 있는 방화벽 외부의 컴퓨터
Boof: Goof로의 접속을 기다리고 있는 방화벽 외부의 컴퓨터
당신은 지금 Goof앞에 앉아 있고 X-windows를 사용하는 프로그램이 돌고 있는 기계인
Boof에서 어떠한 프로그램을 수행하고있다. 그래서 당신은 Goof로 display를 되돌리기를
원할 것이다. X-windows는 방화벽을 통해서 TCP 접속을 시도하게 될 것이다. ( 하지만 그
시도는 방화벽에 의해서 거부될 것이다. )
그래서 이제 당신은 Foo에서 tunnel을 돌리기 시작하고 그것을 Bar의 7000번 포트
(portal이 돌고있다.)로 접속하도록 설정을 해놓고, 또한 당신은 tunnel로 하여금 portal로
부터 되돌아오는 모든 TCP 접속을 Goof의 6000번 포트로 전달(forwarding)시키도록 설
정을 해놓는다. 그리고 bar에서 portal을 돌리고 7000번 포트에서 tunnel이 보내오는 정
보를 받도록 설정을 한다. Tunnel이 접속하게 되면, portal은 X로 오는 정보들은 6001번
포트로 받아들이게 된다. 어떠한 X-application이 portal에 접속할 때 마다, 그 접속은
tunnel로 넘겨지게 되고, 그것은 Goof의 6000번 포트로 넘겨지게 된다.
마침네 Boof에서 당신은 Bar기계로 display를 맞출 수 있게 되었다. 이것은 응용프로그램
으로 하여금 6001번 포트를 사용할 수 있게 한것이다.( 우리는 기계가 그것 자체에서 X-
server가 돌고있다면 6000번을 사용할 수 없다. ). 자 이제 Xeyes를 실행시켜 보아라. 그
것들이 당신들의 앞에 나타나 질 것이다.
결론:
만약 당신이 ISP의 보안 정책에 위배되는 즉, 방화벽을 가로지르는 프로그램을 사용한다면
ISP측에서 그 사실을 알게될 때, 그런 애매모호한 보안상태에 대해서 달갑게 여기지 않을
것이다. 그리고 제발 엄마한테 이르지 말자 -_-
이 프로그램의 장점은 어떠한 기계에서도 root 권한을 필요로 하지 않는 다는 것이다.
이것은 우리들의 작업을 한층 쉽게 만들어준다.
이 코드를 실행하기 위해서는 단지 make라고 치면 된다. 이것은 다음의 버전에서 테스트
되었다.
Solaris 2.5.x, 2.6
IRIX 6.[2,3,4]
FreeBSD 2.1.5
HPUX 10.x
Linux 2.0.x
----[ THE CODE
tunnel/Makefile
CC = gcc
OSFLAGS =
MYFLAGS = -Wall -O2 -g -pedantic
CFLAGS = $(MYFLAGS) $(PROFILE) $(OSFLAGS)
#If you compile on Solaris 2.x, uncomment the following line
#LOCAL_LIBRARIES = -lsocket
TUNNEL_OBJFILES = tunnel.o share.o
PORTAL_OBJFILES = portal.o share.o
all: tunnel portal
tunnel : $(TUNNEL_OBJFILES) share.h
$(CC) $(TUNNEL_OBJFILES) $(LOCAL_LIBRARIES) -o tunnel
tunnel.o : tunnel.c share.h
$(CC) -c $(CFLAGS) $(COMMFLAGS) tunnel.c
portal : $(PORTAL_OBJFILES) share.h
$(CC) $(PORTAL_OBJFILES) $(LOCAL_LIBRARIES) -o portal
portal.o : portal.c share.h
$(CC) -c $(CFLAGS) $(COMMFLAGS) portal.c
share.o : share.c share.h
$(CC) -c $(CFLAGS) $(COMMFLAGS) share.c
clean:
rm -f *.o tunnel portal core
<-->
tunnel/tunnel.c
/*
-TUNNEL-
This is the tunnel part of my firewall piercer. This code is supposed
to be running on the inside of the firewall. The tunnel should then
connect to the portal running on the outside.
start it like:
>% tunnel localhost 23 protal.machine.com 3001
if the portal is running at port 3001 at portal.machine.com, incoming
connections to the portal will get rerouted to this machines telnet
port.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "share.h"
extern char tunnel_buf[MAXLEN*2];
char buf[MAXLEN*2];
extern int tunnel_des; /* The socket destination of a tunnel packet*/
extern int tunnel_src; /* The socket source of a tunel packet*/
extern int tunnel_size; /* Size of tunnel packet*/
extern struct connections connections; /*Linked list of connections*/
char *remote_machine; /*remote machine name to tunnel to*/
extern int tunnel_port; /*tunnel port*/
extern int tunnel_sock; /*tunnel socket*/
char *login_machine=""; /*machine to forward connections to*/
int login_port; /*port to forward connections to*/
int oldtime=0,ping_time=0;
struct connection *descriptors[DESC_MAX];
extern struct connection *descriptors[DESC_MAX];
extern int errno;
FILE *log=stdout; /*logfile = stdout by default*/
void open_tunnel(){
tunnel_sock=remote_connect(remote_machine,tunnel_port);
}
extern int optind;
extern char *optarg;
void usage(){
printf("Usage: tunnel [-l logfile] " \\
" \\n");
printf("where:\\n");
printf("forward_machine is the machine to which the traffic is forwarded\\n");
printf("forward_port is the port to which the traffic is forwarded\\n");
printf("portal_machine is the machine we want to route the trafic from\\n");
printf("portal_port is the port we want to route the trafic from\\n");
printf("Coded by %s\\n",AUTHOR);
}
/********************** Get the options ***********************/
void get_options(int argc,char *argv[]){
int c;
while((c=getopt(argc,argv, "l:")) !=-1)
switch(c){
case 'l':
if(!(log=fopen(optarg,"w"))){
log=stdout;
fprintf(log,"Unable to open logfile '%s':%s\\n",
optarg,strerror(errno));
}
break;
case '?':
default:
usage();
exit(-1);
}
/* the two next options*/
if(argc-optind!=4){
printf("Wrong number of options!\\n");
usage();
exit(-1);
}
login_machine=get_ip(argv[optind++]);
login_port=atoi(argv[optind++]);
remote_machine=get_ip(argv[optind++]);
tunnel_port=atoi(argv[optind++]);
if(login_port65535||tunnel_port65535){
printf("Ports below 1 and above 65535 don't give any sense\\n");
usage();
exit(-1);
}
}
void alive(){
/* To check wether the line is still alive, we Myping it every
ALIVE_TIME seconds. If we don't get a ping from the tunnel
every ALIVE_TIME*2 we disconnect the connection to the
portal, and wait for a new. If the portal has not died, all
the connections through the tunnel will continue as normal once
the connection has been established again.
The reason why I do this is because some firewalls tend to
disable connections if there hasn't been any traffic for some time,
or if the connection had been up too long time.
*/
/*Transmit a Myping packet, we receive the
answer in check_tunnel_connection()*/
if(time(NULL)-oldtime>=ALIVE_TIME){
oldtime=time(NULL);
transmit_tunnel(buf,0,0,0);
}
if(time(NULL)-ping_time>ALIVE_TIME*2){
printf("Connection to portal probably lost, hanging up.\\n");
shutdown(tunnel_sock,2);
close(tunnel_sock);
tunnel_sock=-1;
}
}
int reset_selector(fd_set *selector,fd_set *errsel,struct connection *con)
{
/* We tell the selector to look on the tunnel socket aswell
as our live connections.*/
int maxsock,i;
FD_ZERO(selector);
FD_SET(tunnel_sock,selector);
FD_SET(tunnel_sock,errsel);
con=connections.head;
maxsock=tunnel_sock;
for(i=0;inext){
FD_SET(con->local_sock,selector);
FD_SET(con->local_sock,errsel);
maxsock=max(maxsock,con->local_sock);
}
return(maxsock); /*We return the maximum socket number*/
}
void check_tunnel_connection(fd_set *selector,fd_set *errsel,struct connection *con){
/*Here we check the tunnel for incoming data*/
if(FD_ISSET(tunnel_sock,errsel)){
fprintf(log,"Tunnel connection terminated!\\n");
shutdown(tunnel_sock,2);
close(tunnel_sock);
tunnel_sock=-1;
return;
}
if(FD_ISSET(tunnel_sock,selector)){
if(receive_tunnel()!=-1){
if(tunnel_src==0&&tunnel_des==0){ /*We have a Myping packet*/
ping_time=time(NULL); /*reset the alive_timer*/
}
else if(tunnel_src==0){/*We have a 'hangup' signal for a connection*/
if((con=descriptors[tunnel_des])){
fprintf(log,"Removing connection to %s %d\\n",con->host,con->port);
removeconnection(con);
}
}
else if(tunnel_des==0){ /*We have a new connection*/
int newsock;
if((newsock=remote_connect(login_machine,login_port))!=-1){
connections.num++;
con=(struct connection *)malloc(sizeof(struct connection));
con->host=(char *)malloc(MAX_HOSTNAME_SIZE);
strncpy(con->host,&tunnel_buf[4],MAX_HOSTNAME_SIZE);
con->port=ntohl((((int *)tunnel_buf)[0]));
con->local_sock=newsock;
con->remote_sock=tunnel_src;
con->time=time(NULL);
con->next=connections.head;
connections.head=con;
descriptors[newsock]=con;
fprintf(log,"Connected the incoming call from %s %d to %s %d\\n",con-
>host,con->port,login_machine,login_port);
/*Acknowledge the new connection to the portal*/
transmit_tunnel(buf,0,con->local_sock,con->remote_sock);
}
}
else if(descriptors[tunnel_des]){
/*Send the data to the right descriptor*/
writen(descriptors[tunnel_des]->local_sock,tunnel_buf,tunnel_size);
}
else{
fprintf(log,"Connection to unallocated channel, hangup signal sent\\n");
/*Send a hangup signal to the portal, to disable the connection*/
transmit_tunnel(buf,0,0,tunnel_src);
}
}
}
}
void main(int argc,char **argv)
{
get_options(argc,argv);
fprintf(log,"Opening tunnel to %s port %d\\n",remote_machine,tunnel_port);
fprintf(log,"Tunnelconnections will be forwarded to host %s"\\
" port %d\\n",login_machine,login_port);
connections.num=0;
connections.head=NULL;
signal(SIGINT,ctrlC);
while(1){ /*The tunnel runs infinitely*/
struct connection *con=connections.head;
open_tunnel();
ping_time=time(NULL);
while(tunnel_sock!=-1){
fd_set selector,errsel;
struct timeval alive_time;
alive_time.tv_sec=ALIVE_TIME;
alive_time.tv_usec=0;
alive(); /*Check wether the tunnelconnection is alive*/
/* We have to listen to the tunnel and all the current connections.
we do that with a select call*/
if(select(reset_selector(&selector,&errsel,con)+1,
&selector,NULL,&errsel,&alive_time)){
/*Check for each of the local connections*/
check_local_connections(&selector,&errsel,con);
/*Check for the tunnel*/
check_tunnel_connection(&selector,&errsel,con);
}
}
sleep(RETRY_TIME); /*We sleep a while*/
/* fprintf(log,"Trying to connect to portal.\\n"); */
}
}
<-->
tunnel/portal.c
/*
-PORTAL-
This is the portal part of my firewall piercer. This code is supposed
to be running on the outside of the firewall. The tunnel part should
then connect trough the firewall to this program.
start it like:
>% portal 3000 3001
for tunnel connection on port 3001 and incoming calls on 3000.
when you connect to the portal at port 3000 your connection will be
forwarded to the tunnel.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "share.h"
/***************/
/* Global data */
/***************/
extern char tunnel_buf[MAXLEN*2];
extern int tunnel_des;
extern int tunnel_src;
extern int tunnel_size;
extern struct connections connections;
extern struct connection *descriptors[DESC_MAX];
extern int errno;
extern int tunnel_port; /*tunnel port*/
extern int tunnel_sock; /*tunnel new accepted socket*/
char buf[MAXLEN*2];
char *remote_machine; /*remote machine name*/
int tunnel_basesock; /*tunnel base socket*/
int local_sock; /* local port socket*/
int local_port; /*local machine port*/
FILE *log=stdout; /*logfile = stdout by default*/
int ping_time=0;
/********************** Usage ***********************/
void usage(){
fprintf(stderr,"Usage: portal [-l logfile] \\n");
fprintf(stderr,"where:\\n");
fprintf(stderr,"local_port is the port where we accept incoming" \\
" connections\\n");
fprintf(stderr,"remote_port is the port where we accept the tunnel" \\
" to connect\\n");
fprintf(stderr,"Coded by %s\\n",AUTHOR);
}
/********************** Get the options ***********************/
extern int optind;
extern char *optarg;
void get_options(int argc,char *argv[]){
int c;
while((c=getopt(argc,argv, "l:")) !=-1)
switch(c){
case 'l':
if(!(log=fopen(optarg,"w"))){
log=stdout;
fprintf(log,"Unable to open logfile '%s':%s\\n",
optarg,strerror(errno));
}
break;
case '?':
default:
usage();
exit(-1);
}
/* the two next options*/
if(argc-optind!=2){
printf("Wrong number of options!\\n");
usage();
exit(-1);
}
local_port=atoi(argv[optind++]);
tunnel_port=atoi(argv[optind++]);
if(local_port65535||tunnel_port65535){
printf("Ports below 1 and above 65535 dont give any sense\\n");
usage();
exit(-1);
}
}
/*********************************************************/
/*************** Portal *****************/
/*********************************************************/
void open_local_port(){
/*Open the local port for incoming connections*/
struct sockaddr_in ser;
int opt=1;
local_sock=socket(AF_INET,SOCK_STREAM,0);
if(local_sock==-1){fprintf(log,"Error opening socket\\n");exit(0);}
if(setsockopt(local_sock,SOL_SOCKET,SO_REUSEADDR,
(char *)&opt,sizeof(opt))h_name,cli.sin_port);
return(newsock);
}
void close_portal(){
shutdown(tunnel_sock,1);
close(tunnel_sock);
}
struct connection *receive_local(){
struct sockaddr_in cli;
int newsock,clilen;
struct hostent *from;
struct connection *con;
clilen=sizeof(cli);
/*Accept incoming calls*/
newsock=accept(local_sock,(struct sockaddr *)&cli,&clilen);
if(newsock==-1)
{fprintf(log,"Server Accept Error:%s\\n",strerror(errno));exit(-1);}
/*We want to know know our remote host better*/
from=gethostbyaddr((char *)(&cli.sin_addr),sizeof(cli.sin_addr), PF_INET);
fprintf(log,"New connection from:%s %d\\n",from->h_name,cli.sin_port);
/*Add our new friend to our list of connections*/
connections.num++;
con=(struct connection *)malloc(sizeof(struct connection));
con->host=strdup(from->h_name);
con->port=cli.sin_port;
con->local_sock=newsock;
con->remote_sock=0;
con->time=time(NULL);
con->next=connections.head;
connections.head=con;
descriptors[newsock]=con;
return(con);
}
void alive(){
/* If we don't get a ping from the tunnel
every ALIVE_TIME*2 we disconnect the connection to the
tunnel, and wait for a new. If the tunnel has not died, all
the connections from the tunnel will continue as normal once
the connection has been established again*/
if(time(NULL)-ping_time>ALIVE_TIME*2){
printf("Connection to tunnel probably lost, hanging up.\\n");
shutdown(tunnel_sock,2);
close(tunnel_sock);
tunnel_sock=-1;
}
}
int reset_selector(fd_set *selector,fd_set *errsel,struct connection *con){
/* We tell the selector to look on the tunnel socket aswell
as our live connections, and the connection socket.*/
int maxsock,i;
FD_ZERO(selector);
FD_SET(local_sock,selector);
FD_SET(tunnel_sock,selector);
FD_SET(local_sock,errsel);
FD_SET(tunnel_sock,errsel);
con=connections.head;
maxsock=max(local_sock,tunnel_sock);
for(i=0;inext){
FD_SET(con->local_sock,selector);
FD_SET(con->local_sock,errsel);
maxsock=max(maxsock,con->local_sock);
}
return(maxsock);
}
void check_tunnel_connection(fd_set *selector,fd_set *errsel,struct connection *con){
/*Here we check the tunnel for incoming data*/
if(FD_ISSET(tunnel_sock,errsel)){
fprintf(log,"Tunnel connection terminated!\\n");
shutdown(tunnel_sock,2);
close(tunnel_sock);
tunnel_sock=-1;
return;
}
if(FD_ISSET(tunnel_sock,selector)){
if(receive_tunnel()!=-1){
if(tunnel_src==0&&tunnel_des==0){ /*We got a Myping*/
ping_time=time(NULL);
/* Ping the tunnel back!*/
transmit_tunnel(buf,0,0,0); /*Send a Myping back*/
}
else if(tunnel_des){
if(descriptors[tunnel_des]){
con=descriptors[tunnel_des];
if(tunnel_src!=0){
con->remote_sock=tunnel_src;
writen(descriptors[tunnel_des]->local_sock,tunnel_buf,tunnel_size);
}
else{
printf("Hangup signal received. Removing connection to %s %d\\n",con-
>host,con->port);
removeconnection(con);
}
}
}
}
}
}
void check_connection_port(fd_set *selector,fd_set *errsel,struct connection *con){
/*Here we check the connection port for new connections*/
if(FD_ISSET(local_sock,selector)){
con=receive_local();
if(con){
printf("Transmitting the new connection\\n");
*((int *)(&buf[4]))=htonl(con->port);
strncpy(&buf[8],con->host,MAX_HOSTNAME_SIZE);
*(&buf[8]+strlen(con->host))=0;
transmit_tunnel(buf,4+min(strlen(con->host)+1,MAX_HOSTNAME_SIZE),con-
>local_sock,0);
}
}
}
void main(int argc,char **argv){
get_options(argc,argv);
init_descriptors();
connections.num=0;
connections.head=NULL;
remote_machine=get_ip(argv[2]);
fprintf(log,"Tunneling incoming calls on port %d to port %d \\n"
,local_port,tunnel_port);
connections.num=0;
connections.head=NULL;
fprintf(log,"Opening portal\\n");
open_portal();
signal(SIGINT,ctrlC);
fprintf(log,"Opening localport\\n");
open_local_port();
while(1){
fprintf(log,"Waiting for tunnel connection on port %d\\n",tunnel_port);
while((tunnel_sock=accept_portal())==-1) sleep(4);
ping_time=time(NULL);
while(tunnel_sock!=-1){
fd_set selector,errsel;
struct connection *con=NULL;
struct timeval alive_time;
alive_time.tv_sec=ALIVE_TIME;
alive_time.tv_usec=0;
alive();
/* We have to listen to the tunnel, the local port, and alle the
current connections. */
if(select(reset_selector(&selector,&errsel,con)+1,
&selector,NULL,&errsel,&alive_time)){
check_tunnel_connection(&selector,&errsel,con);
check_connection_port(&selector,&errsel,con);
check_local_connections(&selector,&errsel,con);
}
}
sleep(2);
}
}
<-->
tunnel/share.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "share.h"
char tunnel_buf[MAXLEN*2]; /*Buffer to store the tunnel data in*/
int tunnel_des; /*Destination socket */
int tunnel_src; /*Source socket*/
int tunnel_size; /*Size of the data currently in the buffer*/
int tunnel_sock; /*The socket of the portal*/
int tunnel_port; /*The port we wan't to run on*/
extern FILE *log; /* Our log file*/
extern int errno;
struct connection *descriptors[DESC_MAX];
struct connections connections; /*A linked list of our connections*/
/*
Packet header:
####################################/
# Dest # Source# Data size # / data comes here
###################################\\
1 byte 1 byte 2 bytes
If the sestination field is zero, we are initiating a new connection
If the source field we are dropping a connection
If both the destination and the source is zero, it is a Myping packet.
*/
void ctrlC(int sig)
{
fprintf(log,"Shutting down the hard way\\n");
shutdown(tunnel_sock,2);
close(tunnel_sock);
exit(-1);
}
char *get_ip(char *host){
struct hostent *remote;
struct in_addr *in;
remote=gethostbyname(host);
if(remote==NULL){
fprintf(log,"Hostinformation of remote machine '%s' not resolved,"\\
" reason:%s",host,strerror(errno));
exit(-1);
}
in=(struct in_addr *)remote->h_addr_list[0];
return(strdup(inet_ntoa(*in)));
}
int transmit_tunnel(char *data,int size,int source,int destination){
int nleft=size+4,nwritten;
fd_set selector,errsel;
data[0]=(unsigned char)destination; /*Destination into header*/
data[1]=(unsigned char)source; /*Source into header*/
*((u_short *)&data[2])=htons(size); /*Size into header*/
while(nleft>0){
FD_ZERO(&errsel);
FD_ZERO(&selector);
FD_SET(tunnel_sock,&errsel);
FD_SET(tunnel_sock,&selector);
select(tunnel_sock+1,NULL,&selector,&errsel,NULL);
if(FD_ISSET(tunnel_sock,&errsel)){
printf("Big bug\\n");
}
nwritten=write(tunnel_sock,data,nleft);
if(nwritten==-1){
fprintf(log,"Error writing to tunnel:%s\\n",strerror(errno));
tunnel_sock=-1;
return(nwritten);
}
else if(nwritten==0){
fprintf(log,"Error: Wrote zero bytes in transmit_tunnel\\n");
return(nwritten);
}
nleft-=nwritten;
data+=nwritten;
}
return(size - nleft);
}
int receive_tunnel(){
static int received=0;
int n,left,got=0,quit=0,sofar=0;
received++;
while(sofar0){quit=1;sofar+=n;}
if(n<connections.num&&con;i++,con=con->next){
if(FD_ISSET(con->local_sock,errsel)){
fprintf(log,"LLocal connection terminated\\n");
fprintf(log,"Removing connection to %s %d\\n",con->host,con->port);
if(con->remote_sock) transmit_tunnel(buf,0,0,con->remote_sock);
removeconnection(con);
break;
}
if(FD_ISSET(con->local_sock,selector)&&con->remote_sock){
n=read(con->local_sock,&buf[4],MAXLEN);
if(nhost,con->port);
transmit_tunnel(buf,0,0,con->remote_sock);
removeconnection(con);
break;
}
/*forward the data to the tunnel*/
transmit_tunnel(buf,n,con->local_sock,con->remote_sock);
}
}
}
void ZERO(char * buf,int size){int i=0;while(i0){
nwritten=write(fd,ptr,nleft);
if(nwritten<=0) return(nwritten);
nleft-=nwritten;
ptr+=nwritten;
}
return(nbytes - nleft);
}
int remote_connect(char *machine,int port)
{
int sock;
struct sockaddr_in ser;
ZERO((char *) &ser,sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_addr.s_addr = inet_addr(machine);
ser.sin_port = htons(port);
sock=socket(AF_INET,SOCK_STREAM,0);
if(sock==-1){perror("Error opening socket\\n");return(-1);}
if(connect(sock,(struct sockaddr *) &ser,sizeof(ser))==-1){
fprintf(log,"Can't connect to server:%s\\n",strerror(errno));
return(-1);
}
return(sock);
}
void disconnect(struct connection *con,int sock1,int sock2){
fprintf(log,"Closing link to: %s %d\\n",con->host,con->port);
shutdown(sock1,2);
shutdown(sock2,2);
close(sock1);
close(sock2);
close(con->local_sock);
}
void init_descriptors(){
int i;
for(i=0;inext;
descriptors[c->local_sock]=NULL;
free(c->host);
shutdown(c->local_sock,2);
close(c->local_sock);
free(c);
connections.num--;
return;
}
c2=c;
c=c->next;
while(c){
if(c==con){
/* connections.head=c2; */
c2->next=c->next;
descriptors[c->local_sock]=NULL;
free(c->host);
shutdown(c->local_sock,2);
close(c->local_sock);
free(c);
connections.num--;
return;
}
c2=c;
c=c->next;
}
}
<-->
tunnel/share.h
/*********************/
/* Structs & Defines */
/*********************/
#define MAX_HOSTNAME_SIZE 128
#define MAXLEN 32768 /*Maximum length of our data*/
#define ALIVE_TIME 60 /*Time to wait before sending a Myping*/
#define DESC_MAX 128 /*Maximum number of descriptors used*/
#define RETRY_TIME 60 /* Time to wait before we reconnect to portal*/
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<-->
----[ EOF