
/* http://www.anticode.com  for the latest exploits, tools and documents! */

/* crackpipe.c -- uses the ethertap stuff to try to tunnel an IP,
   without using ipip, to break through firewalls.  May the world's
   fascist admins rot in hell for their port-blocking policies. */

/* usage information is in comments at the very end of this file */

#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>


/* define TCP or UDP here so we can decide how we'd like to
   connect. */
#define UDP
#undef TCP

/* maximum size to use for the copy buffer */
/* setting the MTU of the tap device to something bigger than this
   would probably be a bad idea, methinks */

#define BUFSIZE 4096

/* also, the mtu for the tap device must be smaller than the
   mtu of your connection to the net...  if it's not, packets will be
   chopped up in transit..  looking at this, I'd say you've gotta have
   16 bytes difference, at least, but what's the point in pushing your
   luck.  go for a couple hundered or so, so if your ethernet uses an
   MTU of 1500, do something like 1200 for safety when you ifconfig
   tap0 */

void selectloop(int netfd, int tapfd);
void usage(void);

char buffer[BUFSIZE];


main(int ac, char *av[]) {

     int destport;
     struct sockaddr_in destaddr;
     struct hostent *ht;
     int sock;
     int daemon;
     int netfd;
     int tapfd;

     /* check for a sane number of parameters */
     if(ac != 3) 
	  usage();
     
     /* get port number, bail if atoi gives us 0 */
     if((destport = atoi(av[2])) == 0) 
	  usage();

     /* check if we're a daemon or if we will connect. */
     if(av[1][0] == '-') 
	  daemon = 1;
     else
	  daemon = 0;

     if(!daemon) {
	  /* resolve DNS */
	  if((ht = gethostbyname(av[1])) == NULL) {
	       switch(h_errno) {
	       case HOST_NOT_FOUND:
		    printf("%s: Unknown host\n", av[2]);
		    break;
	       case NO_ADDRESS:
		    printf("%s: No IP address for hostname\n", av[2]);
		    break;
	       case NO_RECOVERY:
		    printf("%s: DNS Error\n", av[2]);
		    break;
	       case TRY_AGAIN:
		    printf("%s: Try again (DNS Fuckup)\n", av[2]);
		    break;
	       default:
		    printf("%s: Unknown DNS error\n", av[2]);
	       }
	       exit(0);
	  }
	  
	  /* set up the destaddr struct */
	  
	  destaddr.sin_port = htons(destport);
	  destaddr.sin_family = AF_INET;
	  memcpy(&destaddr.sin_addr, ht->h_addr, ht->h_length);

     }

#ifdef TCP
     sock = socket(AF_INET, SOCK_STREAM, 0);
#endif

#ifdef UDP
     sock = socket(AF_INET, SOCK_DGRAM, 0);
#endif

     if(sock == -1) {
	  perror("socket");
	  exit(0);
     }

     printf("Opening network socket.\n");
     
     if(!daemon) {
	  if(connect(sock, &destaddr, sizeof(struct sockaddr_in)) ==
	     -1) {
	       perror("connect");
	       exit(0);
	  }
	  netfd = sock;
     } 
     else {
	  struct sockaddr_in listenaddr;
#ifdef UDP
	  struct sockaddr_in remote;
#endif
	  int socklen;
	  
	  listenaddr.sin_port = htons(destport);
	  listenaddr.sin_family = AF_INET;
	  listenaddr.sin_addr.s_addr = inet_addr("0.0.0.0");
	  
	  if(bind(sock, &listenaddr, sizeof(struct sockaddr_in)) ==
	     -1) {
	       perror("bind");
	       exit(0);
	  }

	  socklen = sizeof(struct sockaddr_in);

#ifdef TCP
  
	  if(listen(sock, 1) == -1) {
	       perror("listen");
	       exit(0);
	  }

	  printf("Waiting for TCP connection...\n");


	  if((netfd = accept(sock, &listenaddr, &socklen)) == -1) {
	       perror("accept");
	       exit(0);
	  }

	  

#else /* TCP */
	  netfd = sock;

	  recvfrom(netfd, buffer, BUFSIZE, MSG_PEEK, &remote,
		   &socklen);

	  connect(netfd, &remote, socklen);

#endif
     }     
     /* right.  now, we've got netfd set to something which we're
	going to be able to use to chat with the network. */
     
     printf("Opening /dev/tap0\n");

     tapfd = open("/dev/tap0", O_RDWR);
     if(tapfd == -1) {
	  perror("tapfd");
	  exit(0);
     }

     selectloop(netfd, tapfd);
     
     return 0;
}
  
void selectloop(int netfd, int tapfd) {

     fd_set rfds;
     int maxfd;
     int len;

     if(netfd > tapfd)
	  maxfd = netfd;
     else
	  maxfd = tapfd;


     while(1) {

	  FD_ZERO(&rfds);
	  FD_SET(netfd, &rfds);
	  FD_SET(tapfd, &rfds);

	  if(select(maxfd+1, &rfds, NULL, NULL, NULL) == -1) {
	       perror("select");
	       exit(0);
	  }

	  if(FD_ISSET(netfd, &rfds)) {
	       FD_CLR(netfd, &rfds);
	       
	       if((len = read(netfd, buffer, BUFSIZE)) < 1) {
		    if(len == -1)
			 perror("read_netfd");
		    printf("netfd died, quitting\n");
		    close(tapfd);
		    exit(0);
	       }
	       
	       printf("%d bytes from network\n", len);
	       write(tapfd, buffer, len);
	       continue;
	  }

	  if(FD_ISSET(tapfd, &rfds)) {
	       FD_CLR(tapfd, &rfds);

	       if((len = read(tapfd, buffer, BUFSIZE)) < 1) {
		    if(len == -1)
			 perror("read_tapfd");
		    printf("tapfd died, quitting\n");
		    shutdown(netfd, 2);
		    close(netfd);
		    exit(0);
	       }

	       printf("%d bytes from interface\n", len);
	       write(netfd, buffer, len);
	       continue;
	  }

     } /* end of looping */

}
     

void usage(void) {

     printf("You fucked up the arguments.\n");
     exit(0);

}

/* songs of firewalls, by the crackpipe author, just for some
   interesting source reading. */

/* firewall song #1, to the tune of "the beverly hillbillies" */

/* ohhhh, lemme tell you a story about a man who's lame 
   this nasty admin oughta hang his head in shame,
   thought one day "this network's kinda loose"
   into his mind poured a bubblin' ooze... */

/* "firewalls," he thought...
   no mail, no dns... */

/* well, the users decided, this shit has gotta go
   we just need the proper sexy hunk of code,
   well, crackpipe came and broke a hole on through,
   and gave the bastards a needed "fuck you"... */

/* hmmmm.  need to finish that eventualy */



/* alright, this should tell you how to use this fucker...  well,
   hopefully...  */

/* alright, the args go something like this:

   crackpipe <host | -> <port>
   
   the first argument is either the hostname to connect to, or, if
   you're the host which will be listening, a -.. obviously, the
   system inside the firewall gives the hostname, and the free system
   gives the -.  

   both sides must specify a port #...  this should, clearly, be the
   same for both ends...

   that should explain it..
*/

/* oh, also, here's what you'll need to turn on in the linux kernel --

   first, you'll need a kernel in the later 2.1 range... I'd say from
   2.1.80 up should be cool, but I'm not positive about that..  if all
   of the config options I mention below aren't present, it's too old.

   in the "Networking Options" section, turn on:
   "Kernel/User netlink socket"
   and, just below,
   "Netlink device emulation"

   also, in the "Network device support" section, turn on:
   "Ethertap network tap"

   if those are compiled in, your kernel is set. */

/* configuring the ethertap device --

   first, the necessary /dev files need to exist, so run:
   mknod /dev/tap0 c 36 16

   to get that to exist.

   next, you have to ifconfig the ethertap device, so pick a subnet
   you're going to use for that.  in this example, we're going to use
   the network 192.168.1.0, with one side as 192.168.1.1, and the
   other as 192.168.1.2...  so, you'll need to do:

   ifconfig tap0 192.168.1.1(or .2) mtu 1200

   (see the notes at the beginning for a good size for the mtu value.
   basically, it's got to be lower than the mtu value listed for eth0
   when you run ifconfig)

   2.1 kernels should create the needed route automatically, so that
   shouldn't be a problem.

*/

/* hopefully, no matter how 14m3 you are, that will give you some idea
   of what you need to do, config-wise.  if not, well, then ask some
   '1337 linux-guru type d00d, and hopefully he can get the routing
   and shit right. */
