tunnel


Ce programme permet de transférer toutes les informations qui arrivent sur un port local d'une machine vers une autre machine sur un port donné. Si vous avez jeté un oeil au proxy smtp ou http, vous avez remarqué qu'ils étaient très ( trop ) spécialisé avec cet exemple tous les protocoles sont supportés et peuvent être analysés. Pour avoir la liste des options tapez : tunnel -?

#include <arpa/telnet.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <getopt.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define DEBUG 1
#define TRACKING 0

#define PACKET_SIZE  1024
#define MAX(a,b) (a<b?b:a)
#define FSET(a,b,c)  (FD_ISSET(a,c)?a:b)
#define NFSET(a,b,c) (FD_ISSET(a,c)?b:a)


int writen(int fd, char *ptr, int n);
int readn(int fd, char *ptr, int n);
int forward(int fin, int fout);

unsigned short server_port = 12345;

char *target_name = "target";
unsigned short target_port = 80;
struct sockaddr_in serverSock, clientSock, targetSock;
int fserver, ftarget, fcurrent;

void usage ( void ) {

  printf ( "Usage: tunnel [OPTION]\n"
           "open a tunnel \n\n"
           "  -?     \t this help\n"
           "  -l port\t local port to listen ( default 12345 )\n"
           "  -t host\t target hostname ( default target )\n"
           "  -p port\t target port ( default 80 )\n");
}


int main(int argc, char *argv[])
{
  int ret, len, c;
  struct hostent *targetHostEnt;        /* description du host serveur */
  unsigned long hostAddr;                       /* addr du serveur */
  fd_set fdsr;
  long flags;

  while ( ( c = getopt(argc,argv,"?l:p:t:") ) != -1 ) {
    switch ( c ) {
      case 'l' : server_port = atoi(optarg);   break;
      case 'p' : target_port = atoi(optarg);   break;
      case 't' : target_name = strdup(optarg); break;
      case '?' :
      default  :
        usage();
        return 0;
    }
  }

  if (DEBUG) printf("%s:%d\n",target_name,target_port);

  fserver = socket(AF_INET, SOCK_STREAM, 0);
  if (fserver < 0) {
    perror("socket");
    return -1;
  } else if ( DEBUG ) {
    if (DEBUG) printf("server : %d\n",fserver);
  }
  serverSock.sin_family = AF_INET;
  serverSock.sin_addr.s_addr = INADDR_ANY;
  serverSock.sin_port = htons(server_port);
  if (bind(fserver, (struct sockaddr *) &serverSock, sizeof(struct sockaddr_in))
      < 0) {
    perror("bind");
    return -1;
  }
  if (listen(fserver, 0) < 0) {
    perror("listen");
    return -1;
  }

  for (;;) {
    FD_ZERO(&fdsr);
    FD_SET(fserver, &fdsr);

    ret = select(fserver + 1, &fdsr, 0, 0, 0);
    if (ret <= 0) {
      close(fserver);
    }
    fcurrent = accept(fserver, (struct sockaddr *) &clientSock, &len);
    fcntl(fcurrent, F_GETFL, &flags);
    flags |= O_NONBLOCK;
    fcntl(fcurrent, F_SETFL, &flags);

    if (DEBUG) {
      if (DEBUG) printf("current : %d\n", fcurrent);
    }

    bzero(&targetSock, sizeof(targetSock));
    hostAddr = inet_addr(target_name);
    if ((long) hostAddr != (long) -1)
      bcopy(&hostAddr, &targetSock.sin_addr, sizeof(hostAddr));
    else {      /* si on a donne un nom  */

      targetHostEnt = gethostbyname(target_name);
      if (targetHostEnt == NULL) {
        if (DEBUG) printf("ca chie gethost\n");
        exit(0);
      }
      bcopy(targetHostEnt->h_addr, &targetSock.sin_addr,targetHostEnt->h_length);
    }
    targetSock.sin_port = htons(target_port); /* host to network port */
    targetSock.sin_family = AF_INET;  /* AF_*** : INET=internet */
    if ((ftarget = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
      if (DEBUG) printf("ca chie creation socket client\n");
      exit(0);
    }
    if (connect (ftarget, (struct sockaddr *) &targetSock,sizeof(targetSock))<0) {
      if (DEBUG) printf("ca chie demande de connection %s\n", target_name);
      exit(0);
    }
    if (DEBUG) {
      if (DEBUG) printf("target : %d\n", ftarget);
    }
    fcntl(ftarget, F_GETFL, &flags);
    flags |= O_NONBLOCK;
    fcntl(ftarget, F_SETFL, &flags);

    do {
      FD_ZERO(&fdsr);
      FD_SET(fcurrent, &fdsr);
      FD_SET(ftarget, &fdsr);
      if (DEBUG) printf("?");
      ret = select(MAX(fcurrent, ftarget) + 1, &fdsr, 0, 0, 0);
      if (ret <= 0) {
        if (DEBUG) printf("on ferme\n");
        close(ftarget);
        close(fcurrent);
        break;
      }
      len = 0;
      if ( FD_ISSET(fcurrent,&fdsr) )
        len = forward(fcurrent, ftarget);
      if ( FD_ISSET(ftarget,&fdsr) )
        len = forward(ftarget, fcurrent);
    } while (len);
    if (DEBUG) printf("on ferme\n");
    close(fcurrent);
    close(ftarget);
  }



  return 0;
}

int writen(int fd, char *ptr, int n)
{

int nl, nw;
        nl = n;
        while ( nl > 0 ) {
                nw = write(fd, ptr, nl);
                if ( nw <= 0 )
                        return nw;     /*error*/
                nl -= nw;
                ptr += nw;
        }
        return (n-nl);
}


int readn(int fd, char *ptr, int n){

int nl, nr;
        nl = n;
        while ( nl > 0 ) {
                nr = read(fd,ptr,nl);
                if (nr < 0 ) {
                  if ( nr == -1 )  {
                    *ptr = 0x00;
                    return (n-nl);
                  }
                        return nr;     /*error*/
                } else {
                        if ( nr == 0 )
                                break;
                }
                nl -= nr;
                ptr += nr;
        }
        *ptr = 0x00;
        return (n-nl);
}


int forward(int fin, int fout)
{
  int len;
  char buffer[PACKET_SIZE + 1];

  if (DEBUG) printf ( "%d -> %d\n",fin,fout);

  do {
    len = readn(fin, buffer, PACKET_SIZE);
    buffer[len] = 0x00;
    if (TRACKING) printf("-%d->%s<--\n",len,buffer);
    writen(fout, buffer, len);
  } while (len == PACKET_SIZE);
  return len;
}