Logo Search packages:      
Sourcecode: paketto version File versions  Download package

minewt.c

#include "paketto.h"

void minewt_usage();  

int main(int argc, char **argv)
{
      int             opt;
      extern char    *optarg;
      extern int      opterr;

      pcap_t         *internal_pcap, *external_pcap;  /* PCAP descriptor */
      u_char         *internal_packet, *external_packet;    /* Our newly captured packet */
      struct pcap_pkthdr *internal_pkthdr = malloc(sizeof(struct pcap_pkthdr));     /* PCAP packet information structure */
      struct pcap_pkthdr *external_pkthdr = malloc(sizeof(struct pcap_pkthdr));     /* PCAP packet information structure */

      struct bpf_program internal_fp, external_fp;    /* Structure to hold the compiled prog */
      char            internal_pfprogram[8192], external_pfprogram[8192];
      char            internal_dev[255], external_dev[255];
      char        internal_ufilter[4096], external_ufilter[4096];
      int             immediate, promisc = 1;
      int         i, j, verbose = 0;
      int         same_dev=0;
      int         stateless_ipt = 0;
      int         fragment_hack = 0; 
      int         internal_grat = 1;
      int         external_grat = 1;
      int         subnet_listener = 0;
      int         force_gateway_mac = 0; 
      int         webserv;
      char        buf[255], buf2[255], web[1024];
      char *error = malloc(4096);

      char bcast_mac[ETHER_ADDR_LEN] = "\xFF\xFF\xFF\xFF\xFF\xFF";
      char null_mac[ETHER_ADDR_LEN] = "\x00\x00\x00\x00\x00\x00";


      struct timeval now;
      uid_t user;

      struct frame x, ic;
 
      struct libnet_link_int *internal_link, *external_link;

      struct in_addr *internal_ip = NULL,
                     *external_ip = NULL,
                     *gateway_ip = NULL,
                     *incoming_ip = NULL;

      u_char internal_mac[ETHER_ADDR_LEN+1], internal_mac_arp[ETHER_ADDR_LEN+1]; 
      u_char external_mac[ETHER_ADDR_LEN+1], external_mac_arp[ETHER_ADDR_LEN+1]; 
      u_char gateway_mac[ETHER_ADDR_LEN+1];
      u_char incoming_mac[ETHER_ADDR_LEN+1];
      struct in_addr *temp_ip = malloc(sizeof(struct in_addr));
      u_char temp_mac[ETHER_ADDR_LEN+1];  

      struct conn_key   *packet_key;
      struct conn_state *packet_state;
      struct conn_state *temp_state;
 
      /* Set defaults */ 
      bzero(gateway_mac, sizeof(gateway_mac));
      snprintf(internal_dev, sizeof(internal_dev), "%s", pcap_lookupdev(error));
      snprintf(external_dev, sizeof(external_dev), "%s", pcap_lookupdev(error));
      
      memcpy(&internal_mac, "\x00\xAB\xBA\x5A\xAB\xBA", ETHER_ADDR_LEN); 
      memcpy(&external_mac, "\x00\x01\x56\x78\x9a\xbc", ETHER_ADDR_LEN); 
      memcpy(&incoming_mac, "\x00\x01\x56\x78\x9a\xbc", ETHER_ADDR_LEN); 
 
      memcpy(&internal_mac_arp, &internal_mac, ETHER_ADDR_LEN); 
      memcpy(&external_mac_arp, &external_mac, ETHER_ADDR_LEN); 

      while ((opt = getopt(argc, argv, "d:D:m:M:a:A:i:I:r:R:Fst:l:L:vWgG")) != EOF) {
            switch (opt) {
            case 'd':   /* Internal Device */
                  snprintf(internal_dev, sizeof(internal_dev), "%s", optarg);
                  break;
            case 'D':   /* External Device */
                  snprintf(external_dev, sizeof(external_dev), "%s", optarg);
                  break; 
            case 'm':   /* Internal MAC Address */ 
                  if(ether_aton(internal_mac, optarg) != ETHER_ADDR_LEN)
                            minewt_usage(); 
                  memcpy(&internal_mac_arp, &internal_mac, ETHER_ADDR_LEN);         
                  break;
            case 'M':   /* External MAC Address */ 
                  if(ether_aton(external_mac, optarg) != ETHER_ADDR_LEN)
                            minewt_usage(); 
                  memcpy(&external_mac_arp, &external_mac, ETHER_ADDR_LEN); 
                  break; 
            case 'a':   /* Internal MAC Address (ARP Only)*/ 
                  if(ether_aton(internal_mac_arp, optarg) != ETHER_ADDR_LEN)
                            minewt_usage(); 
                  break;
            case 'A':   /* External MAC Address (ARP Only)*/ 
                  if(ether_aton(external_mac_arp, optarg) != ETHER_ADDR_LEN)
                            minewt_usage(); 
                  break; 
            case 'g':
                  internal_grat = 0;
                  break;
            case 'G':
                  external_grat = 0;
                  break;
            case 'i':   /* Internal IP */
                  internal_ip = malloc(sizeof(struct in_addr));
                  if(!inet_aton(optarg, internal_ip)) 
                     minewt_usage();
                  break;
            case 'I':   /* External IP */
                  external_ip = malloc(sizeof(struct in_addr));
                  if(!inet_aton(optarg, external_ip)) 
                     minewt_usage();
                  break;
            case 'r':   /* Router IP */
                  gateway_ip = malloc(sizeof(struct in_addr));
                  if(!inet_aton(optarg, gateway_ip)) 
                     minewt_usage();
                  break;
            case 'R':   /* Router MAC Address */ 
                  if(ether_aton(gateway_mac, optarg) != ETHER_ADDR_LEN)
                            minewt_usage(); 
                  force_gateway_mac=1;
                  break; 
            case 'p':
                  snprintf(internal_ufilter, sizeof(internal_ufilter), "(%s) or", optarg);
                  break;
            case 'P':
                  snprintf(external_ufilter, sizeof(external_ufilter), "(%s) or", optarg);
                  break;                  
            case 'F': 
                  fragment_hack=0; 
                  break; 
            case 's': 
                  if(stateless_ipt)minewt_usage(); 
                  stateless_ipt=3; 
                  break; 
            case 'S': 
                  if(stateless_ipt)minewt_usage(); 
                  stateless_ipt=4;   /* completely invalid mode :-) */
                  break; 
            case 't': 
                  timeout = atoi(optarg); 
                  break; 
            case 'l':
                  incoming_ip = malloc(sizeof(struct in_addr));
                  if(!inet_aton(optarg, incoming_ip))
                    minewt_usage();
                  break; 
            case 'L':
                  incoming_ip = malloc(sizeof(struct in_addr));
                  if(!inet_aton(optarg, incoming_ip))
                     minewt_usage();
                  ether_aton(incoming_mac, "FF:FF:FF:FF:FF:FF");
                  subnet_listener = 1;
            case 'v':
                  verbose = 1;
                  break;
            default:
                  minewt_usage();
            }
      }

      if(!internal_ip) fprintf(stderr, "You must specify an internal IP(-i) to accept packets for translation.\n");
      if(!external_ip) fprintf(stderr, "You must specify an external IP(-I) to send translated packets from.\n");
      if(!gateway_ip && !force_gateway_mac) fprintf(stderr,  "You must specify the gateway IP(-r) or MAC[-R] to send translated packets to.\n\n");
      if(!internal_ip || !external_ip || (!gateway_ip && !force_gateway_mac)) minewt_usage();

      if(geteuid() != 0)
      {
            perror("PK requires root to access the network directly.\n");
            exit(EXIT_FAILURE);
      }
      init_buffer();
 
      internal_link = libnet_open_link_interface(internal_dev, error);
      if(!internal_link){
            fprintf(stderr, "Libnet failure opening link interface: %s", error);
            exit(1);
      }

      /* Begin sniffing on INTERNAL interface*/

      internal_pcap = pcap_open_live(internal_dev, 65535, promisc, 5, error);
      if (internal_pcap == NULL) {
            perror("pcap_open_live");
            exit(EXIT_FAILURE);
      }
      if (ioctl(pcap_fileno(internal_pcap), BIOCIMMEDIATE, &immediate)) {
            /*perror("Couldn't set BPF to Immediate Mode.");*/
      }

      if(!strncmp(internal_dev, external_dev, sizeof(internal_dev)))
      {
            //strncpy(external_dev, internal_dev, sizeof(internal_dev));
            external_link   =  internal_link;
            external_pcap   =  internal_pcap;
            external_pkthdr =  internal_pkthdr;
            same_dev=1;
      }  

      snprintf(external_pfprogram, sizeof(external_pfprogram), 
              "%s arp or ether dst %hX:%hX:%hX:%hX:%hX:%hX "
                           "or dst host %s", 
              external_ufilter,
            external_mac[0], external_mac[1], external_mac[2],
            external_mac[3], external_mac[4], external_mac[5],
              inet_ntoa(*external_ip));
      
      snprintf(internal_pfprogram, sizeof(internal_pfprogram),
            "%s arp or ether dst %hX:%hX:%hX:%hX:%hX:%hX",
            internal_ufilter,
            internal_mac[0], internal_mac[1], internal_mac[2],
            internal_mac[3], internal_mac[4], internal_mac[5]); 
      if(same_dev){ 
            strncpy(buf, internal_pfprogram, sizeof(buf)); 
            snprintf(internal_pfprogram, sizeof(internal_pfprogram), 
            "(%s) or (%s)",
            external_pfprogram, buf);
      } 

      /* Compile and set the filter program */
      if (pcap_compile(internal_pcap, &internal_fp, internal_pfprogram, 1, 0x0) == -1) {
            pcap_perror(internal_pcap, "pcap_compile");
            exit(EXIT_FAILURE);
      }
      if (pcap_setfilter(internal_pcap, &internal_fp) == -1) {
            pcap_perror(internal_pcap, "pcap_setfilter");
            exit(EXIT_FAILURE);
      }      
      
      if(!same_dev){
            /* Begin sniffing on EXTERNAL interface*/
            if ((external_link = libnet_open_link_interface(external_dev, error)) == NULL) {
              fprintf(stderr, "Libnet failure opening link interface: %s", error);
              exit(1);
            }
      
            external_pcap = pcap_open_live(external_dev, 65535, promisc, 5, error);
            if (external_pcap == NULL) {
                  perror("pcap_open_live");
                  exit(EXIT_FAILURE);
            }
            if (ioctl(pcap_fileno(external_pcap), BIOCIMMEDIATE, &immediate)) {
            //perror("Couldn't set BPF to Immediate Mode.");
            }
            /* Compile and set the filter program */
            if (pcap_compile(external_pcap, &external_fp, external_pfprogram, 1, 0x0) == -1) {
                  pcap_perror(external_pcap, "pcap_compile");
                  exit(EXIT_FAILURE);
            }
            if (pcap_setfilter(external_pcap, &external_fp) == -1) {
                  pcap_perror(external_pcap, "pcap_setfilter");
                  exit(EXIT_FAILURE);
            }      
      }
      if(internal_grat){
         internal_packet = malloc(LIBNET_ETH_H + LIBNET_ARP_H);

         libnet_build_ethernet(bcast_mac, internal_mac, ETHERTYPE_ARP, NULL, 0, internal_packet);
         libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN, IPV4_ADDR_LEN, ARPOP_REPLY,
              internal_mac_arp, (char *)internal_ip, bcast_mac, (char *)internal_ip, NULL, 0,
              internal_packet + LIBNET_ETH_H);

         i = libnet_write_link_layer(internal_link, internal_dev, internal_packet, LIBNET_ETH_H + LIBNET_ARP_H);
       if (verbose){
         fprintf(stdout, "GRAT ARP (Internal): Wrote %i bytes to %s announcing %s\n" , i, internal_dev, inet_ntoa(*internal_ip));
                  }
         free(internal_packet);
      }

      if(external_grat){
         external_packet = malloc(LIBNET_ETH_H + LIBNET_ARP_H);

         libnet_build_ethernet(bcast_mac, external_mac, ETHERTYPE_ARP, NULL, 0, external_packet);
         libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN, IPV4_ADDR_LEN, ARPOP_REPLY,
              external_mac_arp, (char *)external_ip, bcast_mac, (char *)external_ip, NULL, 0,
              external_packet + LIBNET_ETH_H);

         i = libnet_write_link_layer(external_link, external_dev, external_packet, LIBNET_ETH_H + LIBNET_ARP_H);
       if (verbose){
         fprintf(stdout, "GRAT ARP (External): Wrote %i bytes to %s announcing %s\n" , i, external_dev, inet_ntoa(*external_ip));
                  }
         free(external_packet);
      }

      /* track down the address of the gateway router */
      if(!force_gateway_mac){ 
         external_packet = malloc(LIBNET_ETH_H + LIBNET_ARP_H);
           
         libnet_build_ethernet(bcast_mac,     /*x.eth->ether_dhost*/
                               external_mac,  /*x.eth->ether_shost*/
                               ETHERTYPE_ARP, /*x.eth->ether_type*/
                               NULL,          /*extra crap to tack on*/
                               0,             /*how much crap*/
                               external_packet);
           
         libnet_build_arp(ARPHRD_ETHER,
                          ETHERTYPE_IP,
                          ETHER_ADDR_LEN,
                          IPV4_ADDR_LEN,
                          ARPOP_REQUEST,
                          external_mac_arp,
                          (char *)external_ip,
                          null_mac,
                          (char *)gateway_ip,
                   NULL,
                   0,
                   external_packet + LIBNET_ETH_H);
           
            i = libnet_write_link_layer(external_link, external_dev, external_packet, LIBNET_ETH_H + LIBNET_ARP_H);
            if (verbose){
                  fprintf(stdout, "ROUTER ARP REQUEST: Wrote %i bytes to %s looking for %s\n" , i, external_dev, inet_ntoa(*gateway_ip));
                  }
         free(external_packet);

      }
      if(incoming_ip && !subnet_listener){//){// && !incoming_mac[0]){
         internal_packet = malloc(LIBNET_ETH_H + LIBNET_ARP_H);

         libnet_build_ethernet(bcast_mac, internal_mac, ETHERTYPE_ARP, NULL, 0, internal_packet);
         libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN, IPV4_ADDR_LEN, ARPOP_REQUEST,
              internal_mac_arp, (char *)internal_ip, null_mac, (char *)incoming_ip, NULL, 0,
              internal_packet + LIBNET_ETH_H);

         i = libnet_write_link_layer(internal_link, internal_dev, internal_packet, LIBNET_ETH_H + LIBNET_ARP_H);
       if (verbose){
         fprintf(stdout, "LISTENER ARP REQUEST: Wrote %i bytes to %s looking for %s\n" , i, internal_dev, inet_ntoa(*incoming_ip));
                  }
         free(internal_packet);
      }

      /* Get the next packet from the queue(s) */
      while (1) {
            internal_packet = (u_char *) pcap_next(internal_pcap, internal_pkthdr);
            bzero(&x, sizeof(x));
            if(same_dev)external_packet = internal_packet;  /* XXX des this work here? */
            if (internal_packet &&
                parse_layers(internal_packet, internal_pkthdr->caplen, &x, 2,
                               pcap_datalink(internal_pcap), 0)){
                  /* Respond to an ARP request for the internal IP address */                   
                  if (ntohs(x.eth->ether_type) == ETHERTYPE_ARP &&
                      x.arp->ar_op == htons(ARPOP_REQUEST) &&
                      !memcmp(x.arp->ar_tpa, internal_ip, IPV4_ADDR_LEN)){

                        munge_arp_request(internal_packet, internal_pkthdr, &x, internal_mac_arp);
                        
                        i = libnet_write_link_layer(internal_link, internal_dev, internal_packet, internal_pkthdr->caplen);
                        if (verbose)
                              fprintf(stdout, "ARP: Wrote %i bytes to internal interface\n", i);
                  } else
                  /* Respond to a ICMP Echo (ping) against the internal IP address */
                  if (!memcmp(&(x.eth->ether_dhost), internal_mac, ETHER_ADDR_LEN) &&
                     ntohs(x.eth->ether_type) == ETHERTYPE_IP && 
                     !memcmp(&(x.ip->ip_dst), internal_ip, IPV4_ADDR_LEN) &&
                     !memcmp((u_char *)&x.ip->ip_dst, internal_ip, IPV4_ADDR_LEN) &&
                     x.ip->ip_p == IPPROTO_ICMP &&
                     x.icmp->icmp_type == ICMP_ECHO) {

                        munge_icmp_echo(internal_packet, internal_pkthdr, &x);
                        dump_buffers();                           
                        i = libnet_write_link_layer(internal_link, internal_dev, internal_packet, internal_pkthdr->caplen);
                        if (verbose)
                              fprintf(stdout, "ICMP: Wrote %i bytes\n", i);
                  } else

                  /* Store the MAC address of the host accepting incoming connections */
                  if (incoming_ip                             &&
                           x.eth->ether_type == ntohs(ETHERTYPE_ARP) &&
                         x.arp->ar_op == htons(ARPOP_REPLY) &&
                        !memcmp(&x.arp->ar_spa, incoming_ip, IPV4_ADDR_LEN)){
                
                        memcpy(incoming_mac, x.arp->ar_sha, ETHER_ADDR_LEN);
                        if (verbose)
                          fprintf(stdout, "Listener Found: %s at %X:%X:%X:%X:%X:%X\n",
                           inet_ntoa(*incoming_ip),
                           incoming_mac[0], incoming_mac[1], incoming_mac[2],
                           incoming_mac[3], incoming_mac[4], incoming_mac[5]);
                  } else
                  /* Outgoing Packet */ /* XXX FIX ICMP FIX ICMP FIX ICMP AIGH :-)*/ 
                  if(     !memcmp(&x.eth->ether_dhost, internal_mac, ETHER_ADDR_LEN) && 
                          ntohs(x.eth->ether_type) == ETHERTYPE_IP && 
                          memcmp(&x.ip->ip_src, external_ip, IPV4_ADDR_LEN) &&
                          memcmp(&x.ip->ip_dst, internal_ip, IPV4_ADDR_LEN) &&
                          memcmp(&x.ip->ip_dst, external_ip, IPV4_ADDR_LEN) &&
                        (x.ip->ip_p == IPPROTO_TCP || x.ip->ip_p == IPPROTO_UDP ||
                        (x.ip->ip_p == IPPROTO_ICMP && x.icmp->icmp_type == ICMP_ECHO)) &&
                         !(x.ip->ip_p == IPPROTO_TCP &&  /* don't forward RST|ACKs */
                         x.tcp->th_flags == TH_RST|TH_ACK &&
                         subnet_listener)){ 

                        packet_key   = malloc(sizeof(struct conn_key));
                        packet_state = malloc(sizeof(struct conn_state));
 
                        /* first store the state */
                                                
                        packet_key->ip_dst   =    x.ip->ip_dst; /* this is from internal! */
                        packet_key->ip_p     =    x.ip->ip_p; 

                        switch(x.ip->ip_p){                        
                              case IPPROTO_TCP: 
                                packet_key->l4_dport =   x.tcp->th_dport;
                                packet_key->l4_sport =   x.tcp->th_sport; 
                                break; 
                              case IPPROTO_UDP: 
                                packet_key->l4_dport =   x.udp->uh_dport;
                                packet_key->l4_sport =   x.udp->uh_sport; 
                                break;
                              case IPPROTO_ICMP:
                                packet_key->l4_dport =   x.icmp->hun.echo.seq;
                                packet_key->l4_sport =   x.icmp->hun.echo.seq; 
                        } 
                              
                        packet_state->ip_src = x.ip->ip_src;
                        memcpy(packet_state->ether_dhost, x.eth->ether_dhost, ETHER_ADDR_LEN);
                        memcpy(packet_state->ether_shost, x.eth->ether_shost, ETHER_ADDR_LEN);
                              
                        packet_state->last_packet.tv_sec = internal_pkthdr->ts.tv_sec;
                        packet_state->last_packet.tv_usec = internal_pkthdr->ts.tv_usec; 
                        if(!stateless_ipt && add_entry(packet_key, packet_state) && verbose)
                           fprintf(stdout, "Adding to state\n");
                        /* then rewrite and emit the new packet on the external interface! */
                        
                        x.ip->ip_src = *external_ip;
                        memcpy(x.eth->ether_dhost, gateway_mac, ETHER_ADDR_LEN);
                        memcpy(x.eth->ether_shost, external_mac, ETHER_ADDR_LEN); 
 
 
                        bzero(buf, sizeof(buf)); 
                        
                        /* Use really experimental method of encoding NAT state into IP
                         * timestamp.  We could use a new IP option, but this is more
                         * interesting.  XXX I really should be encrypting the state and
                         * decrypting it on packet reception, but I don't actually think
                         * anyone should use this form of stateless NAT -- it's too wasteful
                         * of bandwidth.
                         */

                        if(stateless_ipt && (x.ip->ip_hl * 4) == LIBNET_IP_H){ 
                             buf[0] = 68 + (128*fragment_hack);  
                           buf[1] = IPV4_ADDR_LEN+ETHER_ADDR_LEN+ETHER_ADDR_LEN; 
                           buf[2] = 21; 
                           buf[3] = stateless_ipt; 
                            
                           memcpy(&buf[4], &packet_state, 
                           IPV4_ADDR_LEN+ETHER_ADDR_LEN+ETHER_ADDR_LEN); 
                                              
                           for(i=internal_pkthdr->caplen; 
                               i>=LIBNET_ETH_H + (x.ip->ip_hl * 4); 
                               i--){ 
                              internal_packet[i+buf[1]] = internal_packet[i]; 
                           } 
                           for(i=LIBNET_ETH_H+(x.ip->ip_hl * 4), j=0; 
                               j<buf[1]; 
                               i++,j++){ 
                              internal_packet[i] = buf[j]; 
                           } 
                                    
                           i=ntohs(x.ip->ip_len)+buf[1]; 
                           x.ip->ip_len = htons(i); 
                            
                           i=(x.ip->ip_hl * 4)+buf[1]; 
                           x.ip->ip_hl = (i / 4); 
                        } 

                        recalc_checksums(&x, x.ip->ip_p);

                        if(stateless_ipt)j=buf[1]+4;
                        else             j=0;
                        i = libnet_write_link_layer(external_link, external_dev, internal_packet, internal_pkthdr->caplen+j);
                        if (verbose)
                              fprintf(stdout, "TCP/UDP Init (Internal -> External): Wrote %i bytes\n", i);
                  }
            }
            if(!same_dev)external_packet = (u_char *) pcap_next(external_pcap, external_pkthdr); 
            if (external_packet){
                  bzero(&x, sizeof(x));
                  i = parse_layers(external_packet, external_pkthdr->caplen, &x, 2,
                               pcap_datalink(external_pcap), 0);
            
                  /* Respond to an ARP request for the external MAC address. */
                  if (ntohs(x.eth->ether_type) == ETHERTYPE_ARP &&
                      x.arp->ar_op == htons(ARPOP_REQUEST) &&
                      !memcmp(x.arp->ar_tpa, external_ip, IPV4_ADDR_LEN)){

                        munge_arp_request(external_packet, external_pkthdr, &x, external_mac_arp);

                        i = libnet_write_link_layer(external_link, external_dev, external_packet, external_pkthdr->caplen);
                        if (verbose)
                              fprintf(stdout, "ARP External(Ext->Ext): Wrote %i bytes\n", i);
                  } else 

                  /* Store the hardware address of the gateway router.  Refuse to accept the address
                   * if we're manually configured to use a specific MAC address.
                   */
                  if (!force_gateway_mac                             &&
                           x.eth->ether_type == ntohs(ETHERTYPE_ARP) &&
                         x.arp->ar_op == htons(ARPOP_REPLY) &&
                        !memcmp(&x.arp->ar_spa, gateway_ip, IPV4_ADDR_LEN)){
                
                        memcpy(gateway_mac, x.arp->ar_sha, ETHER_ADDR_LEN);
                        if (verbose)
                          fprintf(stdout, "Router Found: %s at %X:%X:%X:%X:%X:%X\n",
                           inet_ntoa(*gateway_ip),
                           gateway_mac[0], gateway_mac[1], gateway_mac[2],
                           gateway_mac[3], gateway_mac[4], gateway_mac[5]);
                  } else
                  /* Respond to a ICMP Echo (ping) against the external IP address */
                  if ((!memcmp(x.eth->ether_dhost, external_mac, ETHER_ADDR_LEN) ||
                       !memcmp(x.eth->ether_dhost, external_mac_arp, ETHER_ADDR_LEN))&&
                     ntohs(x.eth->ether_type) == ETHERTYPE_IP && 
                     !memcmp((u_char *) & x.ip->ip_dst, external_ip, IPV4_ADDR_LEN) &&
                     x.ip->ip_p == IPPROTO_ICMP &&
                     x.icmp->icmp_type == ICMP_ECHO) {

                        munge_icmp_echo(external_packet, external_pkthdr, &x);
                        dump_buffers();                                             
                        i = libnet_write_link_layer(external_link, external_dev, external_packet, external_pkthdr->caplen);
                        if (verbose)
                              fprintf(stdout, "ICMP: Wrote %i bytes\n", i);
                  } else
                  /* Incoming packet, presumably connected to some established session in our state table. */
                  if(ntohs(x.eth->ether_type) == ETHERTYPE_IP &&
                        (x.ip->ip_p == IPPROTO_ICMP && (
                           x.icmp->icmp_type == ICMP_UNREACH      ||
                           x.icmp->icmp_type == ICMP_SOURCEQUENCH ||
                           x.icmp->icmp_type == ICMP_TIMXCEED     ||
                           x.icmp->icmp_type == ICMP_PARAMPROB  ))&& 
                         memcmp(&x.ip->ip_src, external_ip, IPV4_ADDR_LEN) &&
                        !memcmp(&x.ip->ip_dst, external_ip, IPV4_ADDR_LEN)){
                              
                        i=parse_layers((char *)&x.icmp->icmp_data,
                             external_pkthdr->caplen-LIBNET_ETH_H-(int)x.ip->ip_hl*4-8, /* XXX slight chance of bug */
                             &ic, 3, DLT_EN10MB, 1);

                        packet_key   = malloc(sizeof(struct conn_key));
                        packet_state = NULL; 
                        
                        packet_key->ip_dst  = ic.ip->ip_dst;
                        packet_key->ip_p    = ic.ip->ip_p;

                        switch(ic.ip->ip_p){                       
                              case IPPROTO_TCP: 
                                packet_key->l4_dport =   ic.tcp->th_dport;
                                packet_key->l4_sport =   ic.tcp->th_sport; 
                                break; 
                              case IPPROTO_UDP: 
                                packet_key->l4_dport =   ic.udp->uh_dport;
                                packet_key->l4_sport =   ic.udp->uh_sport; 
                                break;
                              case IPPROTO_ICMP: /* XXX this is probably wrong */
                                packet_key->l4_dport =   ic.icmp->hun.echo.seq;
                                packet_key->l4_sport =   ic.icmp->hun.echo.seq;
                                break;
                        } 

                        if(packet_state = find_entry(packet_key)) 
                        {
                              x.ip->ip_dst = packet_state->ip_src;
                              memcpy(x.eth->ether_dhost, packet_state->ether_shost, ETHER_ADDR_LEN);
                              memcpy(x.eth->ether_shost, packet_state->ether_dhost, ETHER_ADDR_LEN);
                
                              recalc_checksums(&x, x.ip->ip_p);
                              i = libnet_write_link_layer(internal_link, internal_dev, external_packet, external_pkthdr->caplen);
                              if (verbose)
                                    fprintf(stdout, "ICMP Response(External->Internal): Wrote %i bytes\n", i);                
                        }
                        free(packet_key);
                  }
                              
                  /* Incoming packet, presumably connected to some established session in our state table. */
                  if(ntohs(x.eth->ether_type) == ETHERTYPE_IP &&
                        (x.ip->ip_p == IPPROTO_TCP  || x.ip->ip_p == IPPROTO_UDP ||
                        (x.ip->ip_p == IPPROTO_ICMP && x.icmp->icmp_type == ICMP_ECHOREPLY))&& 
                         memcmp(&x.ip->ip_src, external_ip, IPV4_ADDR_LEN) &&
                        !memcmp(&x.ip->ip_dst, external_ip, IPV4_ADDR_LEN)){

                        packet_key   = malloc(sizeof(struct conn_key));
                        packet_state = NULL; 
                        
                        packet_key->ip_dst  = x.ip->ip_src;   /* flipped */
                        packet_key->ip_p    = x.ip->ip_p;
                        switch(x.ip->ip_p){                        
                              case IPPROTO_TCP: 
                                packet_key->l4_dport =   x.tcp->th_sport;
                                packet_key->l4_sport =   x.tcp->th_dport; 
                                break; 
                              case IPPROTO_UDP: 
                                packet_key->l4_dport =   x.udp->uh_sport;
                                packet_key->l4_sport =   x.udp->uh_dport; 
                                break;
                              case IPPROTO_ICMP:
                                packet_key->l4_dport =   x.icmp->hun.echo.seq;
                                packet_key->l4_sport =   x.icmp->hun.echo.seq;
                                break;
                        } 
                        
                        

                        /* XXX very probable security hole lives here -- we must validate length, at minimum*/                       
                        if(stateless_ipt   && 
                           (x.ip->ip_hl*4) != LIBNET_IP_H){ 
                              (char *)packet_state = (char *)x.ip + LIBNET_IP_H + 4; 
                           } 
                         
                        if(packet_state || (packet_state = find_entry(packet_key))) 
                        {
                              x.ip->ip_dst = packet_state->ip_src;
                              memcpy(x.eth->ether_dhost, packet_state->ether_shost, ETHER_ADDR_LEN);
                              memcpy(x.eth->ether_shost, packet_state->ether_dhost, ETHER_ADDR_LEN);
                
                              recalc_checksums(&x, x.ip->ip_p);
                              i = libnet_write_link_layer(internal_link, internal_dev, external_packet, external_pkthdr->caplen);
                              if (verbose)
                                    fprintf(stdout, "TCP/UDP Incoming(External->Internal): Wrote %i bytes\n", i);             
                              /* we can't use RST or RST|ACK to clear sessions until we
                               * start doing fugly sequence number checking, which gets
                               * very difficult w/ window scaling.  Incidentally, I suspect
                               * window scaling makes it much easier to snipe sessions.
                               */
                        } else if(incoming_ip && /* xxx fix to not be tcp specific */
                                x.ip->ip_p == IPPROTO_TCP && 
                                  x.tcp->th_flags == TH_SYN && 
                                  memcmp(&x.ip->ip_dst, temp_ip, IPV4_ADDR_LEN)){

                              memcpy(&x.ip->ip_dst, incoming_ip, IPV4_ADDR_LEN);           
                              memcpy(x.eth->ether_dhost, incoming_mac, ETHER_ADDR_LEN); 
                              memcpy(x.eth->ether_shost, internal_mac, ETHER_ADDR_LEN); 
 
                              recalc_checksums(&x, x.ip->ip_p);
                              //print_ip(x.ip);
                              //print_tcp(x.tcp,0);
                              i = libnet_write_link_layer(internal_link, internal_dev, external_packet, external_pkthdr->caplen);
                              if (verbose)
                                    fprintf(stdout, "L3F Incoming(External->Internal): Wrote %i bytes\n", i);                 
                        }
                        free(packet_key);               
                  } 
            internal_packet = NULL;
            external_packet = NULL;
            scrub_buffers(verbose);
            } 
      }
} 
 
void minewt_usage() 
{ 
   fprintf(stderr, "  minewt %s:  Userspace NAT/MAT Gateway\n", VERSION); 
   fprintf(stderr, "Component of:   Paketto Keiretsu %s;    Dan Kaminsky  (dan@doxpara.com)\n\n", VERSION);
   fprintf(stderr, "  Min. Usage:   minewt -i internal_ip -I external_ip -r gateway_ip\n");
   fprintf(stderr, "     Options:   -d/-D [device]: Internal/External Device\n");
   fprintf(stderr, "                -m/-M [MAC]   : Internal/External MAC Address\n");
   fprintf(stderr, "                -a/-A [MAC]   : Internal/External MAC Address (ARP Packets Only)\n"); 
   fprintf(stderr, "                -i/-I [IP]    : Internal/External IP Address\n"); 
   fprintf(stderr, "                -r/-R [IP/MAC]: Upstream Router's IP / MAC Address\n"); 
   fprintf(stderr, "                -t   [timeout]: Maximum silence before connection state dropped\n"); 
   fprintf(stderr, "                -v            : Increase Verbosity\n");
   fprintf(stderr, "                -l            : Forward incoming connections to this IP\n");
   fprintf(stderr, "                -g/-G         : Disable Internal/External Gratuitous ARP\n");
 /*fprintf(stderr, "                -L            : Forward incoming connections to this Subnet\n");*/ /*doesn't work, I don't think */
 /*fprintf(stderr, "                                (Use bcast IP for subnet, a la 10.0.1.255)\n");*/
   fprintf(stderr, "  Experiments:  -s/-S         : Embed state in IP Timestamps(Mode 3/Mode 4)\n"); 
   fprintf(stderr, "                -F            : Set split-on-fragment for IP Timestamps\n"); 
   fprintf(stderr, "                [MAC] = R     : Set MAC to Random    (00:??:??:??:??:??)\n"); 
   fprintf(stderr, "                [MAC] = B     : Set MAC to Broadcast (FF:FF:FF:FF:FF:FF)\n"); 
   fprintf(stderr, "                [MAC] = M     : Set MAC to Multicast (01:00:5E:11:22:33)\n"); 
   fprintf(stderr, "                [MAC] = MR    : Set Random Multicast (01:00:5E:??:??:??)\n"); 
   fprintf(stderr, "        Notes:   nCast MACs attached to External and/or External ARP using\n");
   fprintf(stderr, "                 -MMR/-AMR/-MB *may* spawn basic Guerilla Multicast traffic.\n");
   fprintf(stderr, "                 Simply ARPing with an otherwise silent MAC address may\n");
   fprintf(stderr, "                 also work.\n");
   exit(1); 
} 


Generated by  Doxygen 1.6.0   Back to index