Esempio n. 1
0
// if the caller attempted to bind to 0.0.0.0 or ::, then change it to
// this node's public IP address
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {

   errno = 0;

   // save the original bind() call
   void *handle = dlopen( LIBC_PATH, RTLD_LAZY );
   if (!handle) {
      handle = dlopen( LIBC_PATH_DEBIAN, RTLD_LAZY );
      if( !handle ) {
         fprintf( stderr, "Error loading libc.so.6\n" );
         fflush( stderr );
         return -1;
      }
   }
   bind_original = dlsym(handle, "bind");
   if( bind_original == NULL ) {
      fprintf( stderr, "Error loading bind symbol\n" );
      fflush( stderr );
      return -1;
   }

   int tried_normal_bind = 0;

   int rc = is_addr_any( addr );

   fprintf( stderr, "bind(%d, %p, %ld)\n", sockfd, addr, addrlen);

   if( rc > 0 ) {

      rc = 0;

      // rewrite this address
      struct sockaddr_storage new_addr;
      memset( &new_addr, 0, sizeof(struct sockaddr_storage));
      memcpy( &new_addr, addr, addrlen );

      rc = get_public_ip( (struct sockaddr*)&new_addr );
      if( rc == -EINVAL ) {
         // this will happen for DHCP, so bind the normal way
         fprintf(stderr, "WARNING: could not get IP address; attempting normal bind.");
         rc = bind_original( sockfd, (struct sockaddr*)&new_addr, addrlen );
         fprintf(stderr, "normal bind rc = %d, errno = %d\n", rc, errno );
         tried_normal_bind = 1;
      }
      else if( rc != 0 ) {
         rc = -1;
      }

      if( rc == 0 && tried_normal_bind == 0 ) {
         debug( addr, (struct sockaddr*)&new_addr );
         rc = bind_original( sockfd, (struct sockaddr*)&new_addr, addrlen );
         fprintf( stderr, "re-addressed bind rc = %d, errno = %d\n", rc, errno);

         // save this result
         if( rc == 0 ) {
            cache_public_ip( (struct sockaddr*)&new_addr);
         }
      }
   }
   else {
      rc = bind_original( sockfd, (struct sockaddr*)addr, addrlen );
      fprintf( stderr, "bind rc = %d, errno = %d\n", rc, errno);
   }
   return rc;
}
Esempio n. 2
0
/// This is main...
int main(int argc,char* argv[]) {
  int ret;
  in_port_t fixedport = 0;
  struct sockaddr_storage fixedhost;
  struct addrinfo hints, *res, *reslist;
  struct tracker_s * conn;

  memset(&fixedhost, '\0', sizeof(fixedhost));
  printf("netsed " VERSION " by Alexey Shumkin <*****@*****.**>\n"
         "      based on 1.2 from Julien VdG <*****@*****.**>\n"
         "      which is based on 0.01c from Michal Zalewski <*****@*****.**>\n");
  setbuffer(stdout,NULL,0);

  parse_params(argc, argv);

  memset(&hints, '\0', sizeof(hints));
  hints.ai_family = family;
  hints.ai_flags = AI_CANONNAME;
  hints.ai_socktype = tcp ? SOCK_STREAM : SOCK_DGRAM;

  if ((ret = getaddrinfo(rhost, rport, &hints, &reslist))) {
    ERR("getaddrinfo(): %s\n", gai_strerror(ret));
    error("Impossible to resolve remote address or port.");
  }
  /* We have candidates for remote host. */
  for (res = reslist; res; res = res->ai_next) {
    int sd = -1;

    if ( (sd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0)
      continue;
    /* Has successfully built a socket for this address family. */
    /* Record the address structure and the port. */
    fixedport = get_port(res->ai_addr);
    if (!is_addr_any(res->ai_addr))
      memcpy(&fixedhost, res->ai_addr, res->ai_addrlen);
    close(sd);
    break;
  }
  freeaddrinfo(reslist);
  if (res == NULL)
    error("Failed in resolving remote host.");

  if (fixedhost.ss_family && fixedport)
    printf("[+] Using fixed forwarding to %s,%s.\n",rhost,rport);
  else if (fixedport)
    printf("[+] Using dynamic (transparent proxy) forwarding with fixed port %s.\n",rport);
  else if (fixedhost.ss_family)
    printf("[+] Using dynamic (transparent proxy) forwarding with fixed addr %s.\n",rhost);
  else
    printf("[+] Using dynamic (transparent proxy) forwarding.\n");
  if (foreground) {
      printf("Run in foreground...\n");
  } else {
    int x = fork();
    if (x == -1) {
      printf("Error creating a fork. Run in foreground...\n");
    } else if (x) {
      printf("Detached: PID=%d\n", x);
      exit(0);
    }
  }

  bind_and_listen(fixedhost.ss_family, tcp, lport);

  printf("[+] Listening on port %s/%s.\n", lport, (tcp)?"tcp":"udp");

  signal(SIGPIPE, SIG_IGN);
  struct sigaction sa;
  sa.sa_flags = 0;
  sigemptyset(&sa.sa_mask);
  sa.sa_handler = sig_int;
  if (sigaction(SIGINT, &sa, NULL) == -1) error("netsed: sigaction() failed");

  while (!stop) {
    struct sockaddr_storage s;
    socklen_t l = sizeof(s);
    struct sockaddr_storage conho;
    in_port_t conpo;
    char ipstr[INET6_ADDRSTRLEN], portstr[12];

    int sel;
    fd_set rd_set;
    struct timeval timeout, *ptimeout;
    int nfds = lsock;
    FD_ZERO(&rd_set);
    FD_SET(lsock,&rd_set);
    timeout.tv_sec = UDP_TIMEOUT+1;
    timeout.tv_usec = 0;
    ptimeout = NULL;

    {
      conn = connections;
      while(conn != NULL) {
        if(tcp) {
          FD_SET(conn->csock, &rd_set);
          if (nfds < conn->csock) nfds = conn->csock;
        } else {
          // adjust timeout to earliest connection end time
          int remain = UDP_TIMEOUT - (now - conn->time);
          if (remain < 0) remain = 0;
          if (timeout.tv_sec > remain) {
            timeout.tv_sec = remain;
            // time updated to need to timeout
            ptimeout = &timeout;
          }
        }
        FD_SET(conn->fsock, &rd_set);
        if (nfds < conn->fsock) nfds = conn->fsock;
        // point on next
        conn = conn->n;
      }
    }

    sel=select(nfds+1, &rd_set, (fd_set*)0, (fd_set*)0, ptimeout);
    time(&now);
    if (stop)
    {
      break;
    }
    if (sel < 0) {
      DBG("[!] select fail! %s\n", strerror(errno));
      break;
    }
    if (sel == 0) {
      DBG("[*] select timeout. now: %d\n", now);
      // Here we still have to go through the list to expire some udp
      // connection if they timed out... But no descriptor will be set.
      // For tcp, select will not timeout.
    }

    if (FD_ISSET(lsock, &rd_set)) {
      int csock=-1;
      ssize_t rd=-1;
      if (tcp) {
        csock = accept(lsock,(struct sockaddr*)&s,&l);
      } else {
        // udp does not handle accept, so track connections manually
        // also set csock if a new connection need to be registered
        // to share the code with tcp ;)
        rd = recvfrom(lsock,buf,sizeof(buf),0,(struct sockaddr*)&s,&l);
        if(rd >= 0) {
          conn = connections;
          while(conn != NULL) {
            // look for existing connections
            if ((conn->csl == l) && (0 == memcmp(&s, conn->csa, l))) {
              // found
              break;
            }
            // point on next
            conn = conn->n;
          }
          // not found
          if(conn == NULL) {
            // udp 'connection' socket is the listening one
            csock = lsock;
          } else {
            DBG("[+] Got incoming datagram from existing connection.\n");
          }
        } else {
          ERR("recvfrom(): %s", strerror(errno));
        }
      }

      // new connection (tcp accept, or udp conn not found)
      if ((csock)>=0) {
        int one=1;
        getnameinfo((struct sockaddr *) &s, l, ipstr, sizeof(ipstr),
                    portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV);
        printf("[+] Got incoming connection from %s,%s", ipstr, portstr);
        conn = malloc(sizeof(struct tracker_s));
        if(NULL == conn) error("netsed: unable to malloc() connection tracker struct");
        // protocol specific init
        if (tcp) {
          setsockopt(csock,SOL_SOCKET,SO_OOBINLINE,&one,sizeof(int));
          conn->csa = NULL;
          conn->csl = 0;
          conn->state = ESTABLISHED;
        } else {
          conn->csa = malloc(l);
          if(NULL == conn->csa) error("netsed: unable to malloc() connection tracker sockaddr struct");
          memcpy(conn->csa, &s, l);
          conn->csl = l;
          conn->state = UNREPLIED;
        }
        conn->csock = csock;
        conn->time = now;

        conn->live = malloc(rules * sizeof(struct rule_item));
        if(NULL == conn->live) error("netsed: unable to malloc() connection tracker sockaddr struct");
        memcpy(conn->live, rule_live, rules * sizeof(struct rule_item));

        l = sizeof(s);
#ifndef LINUX_NETFILTER
        // was OK for linux 2.2 nat
        getsockname(csock,(struct sockaddr*)&s,&l);
#else
        // for linux 2.4 and later
        getsockopt(csock, SOL_IP, SO_ORIGINAL_DST,(struct sockaddr*)&s,&l);
#endif
        getnameinfo((struct sockaddr *) &s, l, ipstr, sizeof(ipstr),
                    portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV);
        printf(" to %s,%s\n", ipstr, portstr);
        conpo = get_port((struct sockaddr *) &s);

        memcpy(&conho, &s, sizeof(conho));

        if (fixedport) conpo=fixedport;
        if (fixedhost.ss_family)
          memcpy(&conho, &fixedhost, sizeof(conho));

        // forward to addr
        memcpy(&s, &conho, sizeof(s));
        set_port((struct sockaddr *) &s, conpo);
        getnameinfo((struct sockaddr *) &s, l, ipstr, sizeof(ipstr),
                    portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV);
        printf("[*] Forwarding connection to %s,%s\n", ipstr, portstr);

        // connect will bind with some dynamic addr/port
        conn->fsock = socket(s.ss_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);

        if (connect(conn->fsock,(struct sockaddr*)&s,l)) {
           printf("[!] Cannot connect to remote server, dropping connection.\n");
           freetracker(conn);
           conn = NULL;
        } else {
          setsockopt(conn->fsock,SOL_SOCKET,SO_OOBINLINE,&one,sizeof(int));
          conn->n = connections;
          connections = conn;
        }
      }
      // udp has data process forwarding
      if((rd >= 0) && (conn != NULL)) {
        b2server_sed(conn, rd);
      }
    } // lsock is set
    // all other sockets
    conn = connections;
    struct tracker_s ** pconn = &connections;
    while(conn != NULL) {
      // incoming data ?
      if(tcp && FD_ISSET(conn->csock, &rd_set)) {
        client2server_sed(conn);
      }
      if(FD_ISSET(conn->fsock, &rd_set)) {
        server2client_sed(conn);
      }
      // timeout ? udp only
      DBG("[!] connection last time: %d, now: %d\n", conn->time, now);
      if(!tcp && ((now - conn->time) >= UDP_TIMEOUT)) {
        DBG("[!] connection timeout.\n");
        conn->state = TIMEOUT;
      }
      if(conn->state >= DISCONNECTED) {
        // remove it
        (*pconn)=conn->n;
        freetracker(conn);
        conn=(*pconn);
      } else {
        // point on next
        pconn = &(conn->n);
        conn = conn->n;
      }
    }
  }

  clean_socks();
  exit(0);
}