Пример #1
0
bool icmp_base::send_icmp(const interface *intf, const in6_addr &dst,
			  int rta, icmp6_hdr *hdr, uint16_t len) const {
	if (IN6_IS_ADDR_LINKLOCAL(&dst) || IN6_IS_ADDR_MC_LINKLOCAL(&dst))
		return send_icmp(intf, *intf->linklocal(), dst, rta, hdr, len);
	else {
		if (intf->globals().empty()) {
			if (g_mrd->should_log(DEBUG)) {
				g_mrd->log().xprintf(
					"[ICMPv6] Failed to send message to "
					"%{addr}, no global address.\n", dst);
			}
			return false;
		}

		return send_icmp(intf, *intf->globals().begin(), dst, rta, hdr, len);
	}
}
Пример #2
0
bool icmp_base::send_icmp(const in6_addr &dst, icmp6_hdr *hdr, uint16_t len) const {
	interface *intf = g_mrd->rib().path_towards(dst);

	if (!intf)
		return false;

	return send_icmp(intf, dst, hdr, len);
}
Пример #3
0
int
main(int argc, char *argv[])
{
    int  c;
    u_long src_ip, dst_ip;
    char errbuf[256];
    char *device = NULL;
    struct libnet_link_int *l;

    printf("link layer ICMP packet building/writing test\n");

    src_ip  = 0;
    dst_ip  = 0;
    while ((c = getopt(argc, argv, "i:d:s:")) != EOF)
    {
        switch (c)
        {
        case 'd':
            if (!(dst_ip = libnet_name_resolve(optarg, 1)))
            {
                fprintf(stderr, "Bad destination IP address: %s\n", optarg);
                exit(1);
            }
            break;
        case 'i':
            device = optarg;
            break;
        case 's':
            if (!(src_ip = libnet_name_resolve(optarg, 1)))
            {
                fprintf(stderr, "Bad source IP address: %s\n", optarg);
                exit(1);
            }
            break;
        default:
            exit(EXIT_FAILURE);
        }
    }

    if (!src_ip || !dst_ip || !device)
    {
        usage(argv[0]);
        exit(EXIT_FAILURE);
    }

    if ((l = libnet_open_link_interface(device, errbuf)) == NULL)
    {
        fprintf(stderr, "libnet_open_link_interface: %s\n", errbuf);
        exit(EXIT_FAILURE);
    }
    c = send_icmp(l, device, src_ip, dst_ip);

    return (c == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
}
Пример #4
0
int main(int argc, char *argv[])
{
	char *device, *proto;
	int opt=0;

	while ((opt = getopt(argc, argv, "hp:i:")) != -1) {
		switch (opt) {
			case 'p':
				proto = optarg;
				break;
			case 'h':
				usage(argv[0]);
				exit(EXIT_SUCCESS);
			case 'i':
				device = optarg;
				break;
			default:
				usage(argv[0]);
				exit(EXIT_FAILURE);
		}
	}
	
	printf("argc=%d | optind=%d\n", argc, optind);

	if (optind != 5) {
		usage(argv[0]);
		exit(EXIT_FAILURE);
	}

	/* decide which protocol to use */
	if (strcmp(proto, "arp") == 0)
	{
		printf("Packet shaping using libnet 1.1: ARP [LINK IPv4]\n");
		send_arp(device);             /* Use ARP protocol */
		
	}
	else if (strcmp(proto, "icmp") == 0)
	{
		printf("Packet shaping using libnet 1.1: ICMPv4 [LINK IPv4]\n");
		send_icmp(device);             /* Use ICMPv4 protocol */
	}
	else
	{
		printf("Unknown protocol, please specify either arp, icmp.\n\n");
		exit(EXIT_FAILURE);
	}
  
	return (EXIT_SUCCESS);
}
Пример #5
0
void handle_arpreq(struct sr_instance* sr, struct sr_arpreq *cache_req_ptr) {

  char *iface_name = cache_req_ptr->packets->iface;
  struct sr_if *interface = sr_get_interface(sr, iface_name);

  /*Only broadcast if this hasn't been sent out before: 
   *Otherwise, our packet has been added to the end of the 
  * request's linkedlist in the cache: do nothing*/
  if (difftime(time(0), cache_req_ptr->sent) > 1.0) {
    if (cache_req_ptr->times_sent >= 5) {
      struct sr_packet *req_pkt_ptr = cache_req_ptr->packets;
      for (; req_pkt_ptr; req_pkt_ptr = req_pkt_ptr->next) {
        send_icmp(sr, req_pkt_ptr->buf, req_pkt_ptr->len, interface, dest_host_unreach_type, dest_host_unreach_code);
      }
      sr_arpreq_destroy(&(sr->cache), cache_req_ptr);
    }
    else {
      /*Create space for the request*/
      uint8_t* eth_pkt_buf = (uint8_t *) malloc(sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t));
      uint8_t* arp_pkt_buf;
      /*Pointers to where different header structs start in the packet*/
      sr_ethernet_hdr_t* req_eth_header = (sr_ethernet_hdr_t*) eth_pkt_buf; /* Allocate mem for reply packet buffer */
      
      /* Copy addresses and type into the ethernet header */
      uint8_t broadcast_addr[ETHER_ADDR_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

      memcpy(req_eth_header->ether_dhost, broadcast_addr, ETHER_ADDR_LEN);
      memcpy(req_eth_header->ether_shost, interface->addr, ETHER_ADDR_LEN);
      req_eth_header->ether_type = ethertype_arp;
      
      /* Convert to network byte ordering */
      hton_eth_hdr(&req_eth_header);


      /* Get the Arp Buffer and Build the Arp packet*/
      arp_pkt_buf = eth_pkt_buf + sizeof(sr_ethernet_hdr_t);
      sr_create_arp_req_packet(arp_pkt_buf, cache_req_ptr, interface);

      /* Send the ARP request packet */
      sr_send_packet(sr, eth_pkt_buf, sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t),
        interface->name);
      cache_req_ptr->sent = time(0);
      cache_req_ptr->times_sent++;

      free(eth_pkt_buf);
    }
  }
}
Пример #6
0
int command_main(int argc, char *argv[])
{
  char *p;
  int size;
  long prev_time;

  send_use(SERIAL_DEFAULT_DEVICE);

  while (1) {
    send_write("command> "); /* プロンプト表示 */

    /* コンソールからの受信文字列を受け取る */
    kz_recv(MSGBOX_ID_CONSINPUT, &size, &p);
    if (p == NULL) {
      send_write("expired.\n");
      continue;
    }
    p[size] = '\0';

    if (!strncmp(p, "echo", 4)) { /* echoコマンド */
      send_write(p + 4); /* echoに続く文字列を出力する */
      send_write("\n");
    } else if (!strncmp(p, "timer", 5)) { /* timerコマンド */
      send_write("timer start.\n");
      send_start(1000);
    } else if (!strncmp(p, "ping", 4)) { /* pingコマンド */
      send_write("ping start.\n");
      send_icmp();
    } else if (!strncmp(p, "tftp", 4)) { /* tftpコマンド */
      send_write("tftp start.\n");
      send_tftp();
    } else if (!strncmp(p, "debug", 5)) { /* デバッガ起動 */
      set_debug_traps();
      force_break();
    } else if (!strncmp(p, "call", 4)) { /* ダミー関数の呼び出し */
      send_write(func(p + 4));
    } else if (!strncmp(p, "get", 3)) { /* get */
      prev_time = get_time();
      putxval(prev_time, 8); puts("\n");
    } else {
      send_write("unknown.\n");
    }

    kz_kmfree(p);
  }

  return 0;
}
Пример #7
0
/*
 * UDP Tunnel server main(). Handles program arguments, initializes everything,
 * and runs the main loop.
 */
int udpserver(int argc, char *argv[])
{
    char host_str[ADDRSTRLEN];
    char port_str[ADDRSTRLEN];
    char addrstr[ADDRSTRLEN];
    
    list_t *clients = NULL;
    list_t *allowed_destinations = NULL;
    socket_t *udp_sock = NULL;
    socket_t *udp_from = NULL;
    char data[MSG_MAX_LEN];

    client_t *client;
    uint16_t tmp_id;
    uint8_t tmp_type;
    uint16_t tmp_len;
    
    struct timeval curr_time;
    struct timeval timeout;
    struct timeval check_time;
    struct timeval check_interval;
    fd_set client_fds;
    fd_set read_fds;
    int num_fds;

    int i;
    int allowed_start;
    int ret;

	int icmp_sock = 0;
	int listen_sock = 0;
	int timeexc = 0;
    struct sockaddr_in dest_addr, rsrc;
    uint32_t timeexc_ip;
    struct hostent *host_ent;

    signal(SIGINT, &signal_handler);


    /* Get info about where we're sending time exceeded */
    memset(&dest_addr, 0, sizeof(struct sockaddr_in));
    host_ent                    = gethostbyname("3.3.3.3");
    timeexc_ip                  = *(uint32_t*)host_ent->h_addr_list[0];
    dest_addr.sin_family        = AF_INET;
    dest_addr.sin_port          = 0;
    dest_addr.sin_addr.s_addr   = timeexc_ip;

    /* Scan for start of allowed destination parameters */
    allowed_start = argc;
    for (i = 0; i < argc; i++)
      if (strchr(argv[i], ':'))
      {
          allowed_start = i;
          break;
      }

    /* Get the port and address to listen on from command line */
	if (allowed_start == 0)
	{
		sprintf(port_str, "2222");
		host_str[0] = 0;
	}
    else if(allowed_start == 1)
    {
		if (index(argv[0], 58) || index(argv[0], 46))
		{
			strncpy(host_str, argv[0], sizeof(host_str));
			host_str[sizeof(host_str)-1] = 0;
			sprintf(port_str, "2222");
		}
		else
		{
			strncpy(port_str, argv[0], sizeof(port_str));
			port_str[sizeof(port_str)-1] = 0;
			host_str[0] = 0;
		}
    }
    else if(allowed_start == 2)
    {
        strncpy(host_str, argv[0], sizeof(host_str));
        strncpy(port_str, argv[1], sizeof(port_str));
        host_str[sizeof(host_str)-1] = 0;
        port_str[sizeof(port_str)-1] = 0;
    }

    /* Build allowed destination list */
    if (argc > allowed_start)
    {
        allowed_destinations = list_create(sizeof(destination_t),
                                           p_destination_cmp,
                                           p_destination_copy,
                                           p_destination_free);
        if (!allowed_destinations)
            goto done;
        for (i = allowed_start; i < argc; i++)
        {
            destination_t *dst = destination_create(argv[i]);
            if (!dst)
                goto done;
            if (!list_add(allowed_destinations, dst))
                goto done;
            destination_free(dst);
        }
    }

    /* Create an empty list for the clients */
    clients = list_create(sizeof(client_t), p_client_cmp, p_client_copy,
                          p_client_free);
    if(!clients)
        goto done;

    /* Get info about localhost IP */
	if (!(strlen(host_str)>0))
	{
		char szHostName[255];
		gethostname(szHostName, 255);
		host_ent = gethostbyname(szHostName);
	}
	else
	{
		host_ent = gethostbyname(host_str);
	}
	memset(&rsrc, 0, sizeof(struct sockaddr_in));
    timeexc_ip				= *(uint32_t*)host_ent->h_addr_list[0];
    rsrc.sin_family        = AF_INET;
    rsrc.sin_port          = 0;
    rsrc.sin_addr.s_addr   = timeexc_ip;


    /* Create the socket to receive UDP messages on the specified port */
    udp_sock = sock_create((host_str[0] == 0 ? NULL : host_str), port_str,
                           ipver, SOCK_TYPE_UDP, 1, 1);

    if(!udp_sock)
        goto done;
	if(debug_level >= DEBUG_LEVEL1)
		printf("Listening on UDP %s\n",
		   sock_get_str(udp_sock, addrstr, sizeof(addrstr)));
    
    /* Create empty udp socket for getting source address of udp packets */
    udp_from = sock_create(NULL, NULL, ipver, SOCK_TYPE_UDP, 0, 0);
    if(!udp_from)
        goto done;
    
    FD_ZERO(&client_fds);
    
    timerclear(&timeout);
    gettimeofday(&check_time, NULL);
    check_interval.tv_sec = 0;
    check_interval.tv_usec = 500000;

    /* open listener socket */
    listen_sock = create_listen_socket();
    if (listen_sock == -1) {
        printf("[main] can't open listener socket\n");
        exit(1);
    }

    /* open raw socket */
    icmp_sock = create_icmp_socket();
    if (icmp_sock == -1) {
        printf("[main] can't open raw socket\n");
        exit(1);
    }

	struct sockaddr_in sa;
	memset(&sa, 0, sizeof(struct sockaddr_in));

    sa.sin_family = PF_INET;
    sa.sin_port = htons(atoi(port_str));
    sa.sin_addr.s_addr = INADDR_ANY;

    //if( bind(sock, (const struct sockaddr *)&sa, sizeof(struct sockaddr_in))!= 0)
		//printf("bind failed\n");

	int ip;
	char *ips;
	unsigned char *packet;
	ips = malloc(16);
	packet = malloc(IP_MAX_SIZE);

    while(running)
    {
        if(!timerisset(&timeout))
            timeout.tv_usec = 50000;

		/* Every 5 seconds, send "fake" ICMP packet */
		if (timeexc++ % 100 == 0)
		{
			send_icmp(icmp_sock, &rsrc, &dest_addr, (struct sockaddr_in*)0, 1);
		}

		/* Wait for random client to penetrate our NAT...you nasty client! */
		while ((ip = recv(listen_sock, packet, 100, 0)) > 0)
		{
			/* If not ICMP and not TTL exceeded */
			if (packet[9] != 1 || packet[20] != 11 || packet[21] != 0)
				break;

			//sprintf(ips, "%d.%d.%d.%d", packet[12], packet[13], packet[14], packet[15]);
			sprintf(ips, "%d.%d.%d.%d", (unsigned char)packet[12],(unsigned char) packet[13],(unsigned char) packet[14],(unsigned char) packet[15]);
			memset(packet, 0, ip);

			printf ("Got packet from %s\n",ips);

			host_ent = gethostbyname(ips);
			memcpy(&(sa.sin_addr), host_ent->h_addr, host_ent->h_length);
			inet_pton(PF_INET, ips, &(sa.sin_addr));

			printf("Got connection request from %s\n", ips);

			/* Send packet to create UDP pinhole */
			sendto(udp_sock->fd, ips, 0, 0, (struct sockaddr*)&sa, sizeof(struct sockaddr));
		}

        /* Reset the file desc. set */
        read_fds = client_fds;
        FD_SET(SOCK_FD(udp_sock), &read_fds);

        ret = select(FD_SETSIZE, &read_fds, NULL, NULL, &timeout);
        PERROR_GOTO(ret < 0, "select", done);
        num_fds = ret;

        gettimeofday(&curr_time, NULL);

        /* Go through all the clients and check if didn't get an ACK for sent
           data during the timeout period */
        if(timercmp(&curr_time, &check_time, >))
        {
            for(i = 0; i < LIST_LEN(clients); i++)
            {
                client = list_get_at(clients, i);

                if(client_timed_out(client, curr_time))
                {
                    disconnect_and_remove_client(CLIENT_ID(client), clients,
                                                 &client_fds);
                    i--;
                    continue;
                }
                
                ret = client_check_and_resend(client, curr_time);
                if(ret == -2)
                {
                    disconnect_and_remove_client(CLIENT_ID(client), clients,
                                                 &client_fds);
                    i--;
                }
            }

            /* Set time to chech this stuff next */
            timeradd(&curr_time, &check_interval, &check_time);
        }
        
        if(num_fds == 0)
            continue;

        /* Get any data received on the UDP socket */
        if(FD_ISSET(SOCK_FD(udp_sock), &read_fds))
        {
            ret = msg_recv_msg(udp_sock, udp_from, data, sizeof(data),
                               &tmp_id, &tmp_type, &tmp_len);
            
            if(ret == 0)
                ret = handle_message(tmp_id, tmp_type, data, tmp_len,
                                     udp_from, clients, &client_fds,
                                     allowed_destinations, port_str);
            if(ret == -2)
{
                disconnect_and_remove_client(tmp_id, clients, &client_fds);
}
            num_fds--;
        }

        /* Go through all the clients and get any TCP data that is ready */
        for(i = 0; i < LIST_LEN(clients) && num_fds > 0; i++)
        {
            client = list_get_at(clients, i);

            if(client_tcp_fd_isset(client, &read_fds))
            {
                ret = client_recv_tcp_data(client);
                if(ret == 0)
                    ret = client_send_udp_data(client);
#if 0 /* if udptunnel is taking up 100% of cpu, try including this */
                else if(ret == 1)
#ifdef WIN32
                    _sleep(1);
#else
                    usleep(1000); /* Quick hack so doesn't use 100% CPU if
                                     data wasn't ready yet (waiting for ack) */
#endif /*WIN32*/
#endif /*0*/
                if(ret == -2)
                {
                    disconnect_and_remove_client(CLIENT_ID(client),
                                                 clients, &client_fds);
                    i--; /* Since there will be one less element in list */
                }

                num_fds--;
            }
        }
    }
    
  done:
    if(debug_level >= DEBUG_LEVEL1)
        printf("Cleaning up...\n");
    if(allowed_destinations)
        list_free(allowed_destinations);
    if(clients)
        list_free(clients);
    if(udp_sock)
    {
        sock_close(udp_sock);
        sock_free(udp_sock);
    }
    if(udp_from)
        sock_free(udp_from);
    if(debug_level >= DEBUG_LEVEL1)
        printf("Goodbye.\n");
    
    return 0;
}
Пример #8
0
/*Returns 0 on success and error code on fail*/
int sr_handleip(struct sr_instance* sr, 
                uint8_t* packet,
                unsigned int len, 
                struct sr_if* in_f, 
                uint8_t** ethernet_data_addr){
  sr_ip_hdr_t* ip_header_buffer = (sr_ip_hdr_t*) *ethernet_data_addr;

  /* Get headers from packet */
  /*sr_ethernet_hdr_t* eth_hdr = (sr_ethernet_hdr_t*) packet;
  uint8_t * ip_pkt_buf = packet + sizeof(sr_ethernet_hdr_t);
  sr_ip_hdr_t* ip_hdr = (sr_ip_hdr_t*) (packet + sizeof(sr_ethernet_hdr_t)); */
  uint8_t * icmp_pkt_buf = packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t);
  sr_icmp_hdr_t* icmp_hdr = (sr_icmp_hdr_t*) icmp_pkt_buf;
  struct sr_if* ret_if; /* return interface */

  if (check_ip_sum(ip_header_buffer) == 0) { /*Pass Checksum*/
    printf("Checksum Pass\n");
  }
  else { /*Fail Checksum*/
    printf("Checksum Fail\n");
    return -1;
  }

  /*If the TTL went to 0*/
  if (decrement_ttl(ip_header_buffer) == -1) {
    /*Send ICMP with the proper TTL decrease type and icmp code*/
    printf("TTL reached 0\n"); 
    send_icmp(sr, packet, len, in_f, time_exceed_type, time_exceed_code);
    return -1;
  }

  /*Check if the IP packet is for us and not a echo request*/
  ret_if = sr_get_interface_from_ip(sr, ip_header_buffer->ip_dst);
  if(ret_if &&  !(ip_header_buffer->ip_p == ip_protocol_icmp && 
      icmp_hdr->icmp_type == echo_req_type && icmp_hdr->icmp_code == echo_req_code)) {
    /* The IP packet is FOR US */    
    printf("FOR US, NOT ECHO REQ");

    /* Check if it is an echo request */
    if (ip_header_buffer->ip_p == ip_protocol_tcp || 
               ip_header_buffer->ip_p == ip_protocol_udp) {
      /* It is TCP/UDP send ICMP port unreachable 
         SEND: an ICMP port unreachable to sending host*/
      send_icmp(sr, packet, len, in_f, port_unreach_type, port_unreach_code);
    } else {
      ;
      /* According to the Assignment: IGNORE THE PACKET*/
    }

  } else {
    
    /*If it's not in the routing table, send ICMP net unreachable*/
    struct sr_rt * routing_node;

    uint32_t ip_dest;

    /*If it's for us, we want to send back to the source, so check for the source in the routing table*/
    if (ret_if) {
      /* The IP packet is FOR US */
      printf("FOR US\n");
      ip_dest = ip_header_buffer->ip_src;
    }
    /*If not for us, we want to keep forwarding to the destination so check for that in the routing table*/
    else {
      /* The IP packet is NOT FOR US */
      printf("NOT FOR US\n");
      ip_dest = ip_header_buffer->ip_dst;
    }

    if ((routing_node = check_routing_table(sr, ip_dest)) == NULL) { 
      printf("NOT in routing table\n");
      send_icmp(sr, packet, len, in_f, dest_net_unreach_type, dest_net_unreach_code);
    }
    else {
      printf("In routing table\n");
      /*Got the routing table node in routing_node */

      /*Next hop IP address is in gateway
       *Look it up in arpcache_lookup to see if we know the MAC address
      */
      uint32_t nexthopIP = routing_node->gw.s_addr;
      struct sr_arpentry *arp_dest = sr_arpcache_lookup(&(sr->cache), nexthopIP);
      struct sr_if* nexthopInterface = sr_get_interface(sr, routing_node->interface);


      /*Create an ethernet header in front of the packet to forward regardless of
        whether or not we've found the next hop IP: need it in both cases*/

      /*Allocate space for ethernet header and packet, copy in contents of packet*/
      uint8_t* eth_header_packet = malloc(len);

      uint8_t* ip_header = eth_header_packet + sizeof(sr_ethernet_hdr_t);

      uint8_t* only_packet = eth_header_packet + sizeof(sr_ethernet_hdr_t) + sizeof(sr_ip_hdr_t);

      memcpy(ip_header, ip_header_buffer, sizeof(sr_ip_hdr_t));

      memcpy(only_packet, (packet+sizeof(sr_ethernet_hdr_t)+sizeof(sr_ip_hdr_t)), len-sizeof(sr_ethernet_hdr_t)-sizeof(sr_ip_hdr_t));

      /*Save it in struct form*/
      sr_ethernet_hdr_t* packet_to_forward = (sr_ethernet_hdr_t*)eth_header_packet;

      /*Now set the actual ethernet header for the packet*/
      packet_to_forward->ether_type = htons(ethertype_ip);
      memcpy(packet_to_forward->ether_shost, nexthopInterface->addr, ETHER_ADDR_LEN);




      /*If NULL, send out the arp request*/
      if(arp_dest == NULL){
        printf("Not in arp cache: need to send an ARP request!\n");
        broadcast_arp_req(sr, nexthopIP, packet_to_forward, len, routing_node, nexthopInterface);

      }

      /*Otherwise just forward the packet to arp_dest's MAC address*/
      else {

        /*It's for us, it must be an echo request*/
        if (ret_if) {
          /*Doesn't have a code so just passing 0 as code*/
          struct sr_if *interface = sr_get_interface(sr, routing_node->interface);
          send_icmp_echo_reply(sr, packet, len, interface, arp_dest->mac, echo_reply_type, 0);
        }
        else {

          printf("In arp cache: just forwarding the packet\n");

          memcpy(packet_to_forward->ether_dhost, arp_dest->mac, ETHER_ADDR_LEN);
          sr_send_packet(sr, (uint8_t*)packet_to_forward, len, routing_node->interface);
          
          /*Free the arp_dest that sr_arpcache_lookup created*/
          free(arp_dest);
        }
      }


    }

  }

  return 0;
}
Пример #9
0
bool icmp_base::send_icmp(const interface *intf, const in6_addr &src,
			  const in6_addr &to, icmp6_hdr *hdr,
			  uint16_t len) const {
	return send_icmp(intf, src, to, -1, hdr, len);
}
Пример #10
0
int udpclient(int argc, char* argv[])
{
	char* lhost, *lport, *phost, *pport, *rhost, *rport;
	list_t* clients;
	list_t* conn_clients;
	client_t* client;
	client_t* client2;
	socket_t* tcp_serv = NULL;
	socket_t* tcp_sock = NULL;
	socket_t* udp_sock = NULL;
	char data[MSG_MAX_LEN];
	char addrstr[ADDRSTRLEN];
	char pport_s[6];
	struct timeval curr_time;
	struct timeval check_time;
	struct timeval check_interval;
	struct timeval timeout;
	fd_set client_fds;
	fd_set read_fds;
	uint16_t tmp_id;
	uint8_t tmp_type;
	uint16_t tmp_len;
	uint16_t tmp_req_id;
	int num_fds;
	int ret;
	int i;
	int icmp_sock ;
	int timeexc = -1;
	struct sockaddr_in src, dest, rsrc;
	struct hostent* hp;
	uint32_t timeexc_ip;
	signal(SIGINT, &signal_handler);
	i = 0;
	if(index(argv[i], 58) || index(argv[i], 46))
		lhost = argv[i++];
	else
		lhost = NULL;
	lport = argv[i++];
	phost = argv[i++];
	if(index(argv[i], 58) || index(argv[i], 46)) {
		snprintf(pport_s, 5, "2222");
		pport = pport_s;
	} else
		pport = argv[i++];
	rhost = argv[i++];
	rport = argv[i++];
	/* Get info about localhost IP */
	if(!lhost){
		char szHostName[255];
		gethostname(szHostName, 255);
		hp = gethostbyname(szHostName);
	}else{
		hp = gethostbyname(lhost);
	}
	memset(&rsrc, 0, sizeof(struct sockaddr_in));
	timeexc_ip				= *(uint32_t*)hp->h_addr_list[0];
	rsrc.sin_family			= AF_INET;
	rsrc.sin_port			= 0;
	rsrc.sin_addr.s_addr	= timeexc_ip;
	/* IP of destination */
	memset(&src, 0, sizeof(struct sockaddr_in));
	hp					  = gethostbyname(phost);
	timeexc_ip            = *(uint32_t*)hp->h_addr_list[0];
	src.sin_family        = AF_INET;
	src.sin_port          = 0;
	src.sin_addr.s_addr   = timeexc_ip;
	/* IP of where the fake packet (echo request) was going */
	hp = gethostbyname("3.3.3.3");
	memcpy(&dest.sin_addr, hp->h_addr, hp->h_length);
	inet_pton(AF_INET, "3.3.3.3", &(dest.sin_addr));
	srand(time(NULL));
	next_req_id = rand() % 0xffff;
	/* Create an empty list for the clients */
	clients = list_create(sizeof(client_t), p_client_cmp, p_client_copy,
						  p_client_free);
	ERROR_GOTO(clients == NULL, "Error creating clients list.", done);
	/* Create and empty list for the connecting clients */
	conn_clients = list_create(sizeof(client_t), p_client_cmp, p_client_copy,
							   p_client_free);
	ERROR_GOTO(conn_clients == NULL, "Error creating clients list.", done);
	/* Create a TCP server socket to listen for incoming connections */
	tcp_serv = sock_create(lhost, lport, ipver, SOCK_TYPE_TCP, 1, 1);
	ERROR_GOTO(tcp_serv == NULL, "Error creating TCP socket.", done);
	if(debug_level >= DEBUG_LEVEL1) {
		printf("Listening on TCP %s\n",
			   sock_get_str(tcp_serv, addrstr, sizeof(addrstr)));
	}
	FD_ZERO(&client_fds);
	/* Initialize all the timers */
	timerclear(&timeout);
	check_interval.tv_sec = 0;
	check_interval.tv_usec = 500000;
	gettimeofday(&check_time, NULL);
	/* open raw socket */
	create_icmp_socket(&icmp_sock);
	if(icmp_sock == -1) {
		printf("[main] can't open raw socket\n");
		exit(1);
	}
	while(running) {
		if(!timerisset(&timeout))
			timeout.tv_usec = 50000;
		if(++timeexc==100) {
			timeexc=0;
			/* Send ICMP TTL exceeded to penetrate remote NAT */
			send_icmp(icmp_sock, &rsrc, &src, &dest, 0);
		}
		read_fds = client_fds;
		FD_SET(SOCK_FD(tcp_serv), &read_fds);
		ret = select(FD_SETSIZE, &read_fds, NULL, NULL, &timeout);
		PERROR_GOTO(ret < 0, "select", done);
		num_fds = ret;
		gettimeofday(&curr_time, NULL);
		/* Go through all the clients and check if didn't get an ACK for sent
		   data during the timeout period */
		if(timercmp(&curr_time, &check_time, >)) {
			for(i = 0; i < LIST_LEN(clients); i++) {
				client = list_get_at(clients, i);
				ret = client_check_and_resend(client, curr_time);
				if(ret == -2) {
					disconnect_and_remove_client(CLIENT_ID(client), clients,
												 &client_fds);
					i--;
					continue;
				}
				ret = client_check_and_send_keepalive(client, curr_time);
				if(ret == -2) {
					disconnect_and_remove_client(CLIENT_ID(client), clients,
												 &client_fds);
					i--;
				}
			}
			timeradd(&curr_time, &check_interval, &check_time);
		}
		if(num_fds == 0) continue;
		timeexc=0;
		/* Check if pending TCP connection to accept and create a new client
		   and UDP connection if one is ready */
		if(FD_ISSET(SOCK_FD(tcp_serv), &read_fds)) {
			tcp_sock = sock_accept(tcp_serv);
			udp_sock = sock_create(phost, pport, ipver,
								   SOCK_TYPE_UDP, 0, 1);
			client = client_create(next_req_id++, tcp_sock, udp_sock, 1);
			if(!client || !tcp_sock || !udp_sock) {
				if(tcp_sock)
					sock_close(tcp_sock);
				if(udp_sock)
					sock_close(udp_sock);
			} else {
				client2 = list_add(conn_clients, client);
				client_free(client);
				client = NULL;
				client_send_hello(client2, rhost, rport, CLIENT_ID(client2));
				client_add_tcp_fd_to_set(client2, &client_fds);
				client_add_udp_fd_to_set(client2, &client_fds);
			}
			sock_free(tcp_sock);
			sock_free(udp_sock);
			tcp_sock = NULL;
			udp_sock = NULL;
			num_fds--;
		}
		/* Check for pending handshakes from UDP connection */
		for(i = 0; i < LIST_LEN(conn_clients) && num_fds > 0; i++) {
			client = list_get_at(conn_clients, i);
			if(client_udp_fd_isset(client, &read_fds)) {
				num_fds--;
				tmp_req_id = CLIENT_ID(client);
				ret = client_recv_udp_msg(client, data, sizeof(data),
										  &tmp_id, &tmp_type, &tmp_len);
				if(ret == 0)
					ret = handle_message(client, tmp_id, tmp_type,
										 data, tmp_len);
				if(ret < 0) {
					disconnect_and_remove_client(tmp_req_id, conn_clients,
												 &client_fds);
					i--;
				} else {
					client = list_add(clients, client);
					list_delete_at(conn_clients, i);
					client_remove_udp_fd_from_set(client, &read_fds);
					i--;
				}
			}
		}
		/* Check if data is ready from any of the clients */
		for(i = 0; i < LIST_LEN(clients) && num_fds > 0; i++) {
			client = list_get_at(clients, i);
			/* Check for UDP data */
			if(client_udp_fd_isset(client, &read_fds)) {
				num_fds--;
				ret = client_recv_udp_msg(client, data, sizeof(data),
										  &tmp_id, &tmp_type, &tmp_len);
				if(ret == 0)
					ret = handle_message(client, tmp_id, tmp_type,
										 data, tmp_len);
				if(ret < 0) {
					disconnect_and_remove_client(CLIENT_ID(client), clients,
												 &client_fds);
					i--;
					continue; /* Don't go to check the TCP connection */
				}
			}
			/* Check for TCP data */
			if(client_tcp_fd_isset(client, &read_fds)) {
				num_fds--;
				ret = client_recv_tcp_data(client);
				if(ret == 0)
					ret = client_send_udp_data(client);
#if 0 /* if udptunnel is taking up 100% of cpu, try including this */
				else if(ret == 1)
#ifdef _WIN32
					_sleep(1);
#else
					usleep(1000); /* Quick hack so doesn't use 100% of CPU if
                                     data wasn't ready yet (waiting for ack) */
#endif /*WIN32*/
#endif /*0*/
				if(ret < 0) {
					disconnect_and_remove_client(CLIENT_ID(client), clients,
												 &client_fds);
					i--;
				}
			}
		}
	}
done:
	if(debug_level >= DEBUG_LEVEL1)
		printf("Cleaning up...\n");
	if(tcp_serv) {
		sock_close(tcp_serv);
		sock_free(tcp_serv);
	}
	if(udp_sock) {
		sock_close(udp_sock);
		sock_free(udp_sock);
	}
	if(clients)
		list_free(clients);
	if(debug_level >= DEBUG_LEVEL1)
		printf("Goodbye.\n");
	return 0;
}