Exemplo n.º 1
0
int conn_select_fd(struct conn_t *conn, select_ctx *sctx) {
  int evts = SELECT_READ;
  if (!conn->sock) return -1;
  if (conn->write_buf &&
      conn->write_pos < conn->write_buf->slen) 
    evts |= SELECT_WRITE;
  net_select_modfd(sctx, conn->sock, evts);
  return net_select_fd(sctx, conn->sock, evts);
}
Exemplo n.º 2
0
int main(int argc, char **argv) {
  int status;
  int idx;
  int active_last = 0;
  int active = 0;

  struct redir_t *redir;

  int keep_going = 1;
  int reload_config = 0;

  uint8_t hwaddr[6];
  struct ifreq ifr;

  int selfpipe;
  
  int fd = socket(AF_INET, SOCK_DGRAM, 0);

  options_init();

  chilli_signals(&keep_going, &reload_config);
  
  process_options(argc, argv, 1);
  
  safe_strncpy(ifr.ifr_name, _options.dhcpif, sizeof(ifr.ifr_name));

#ifdef SIOCGIFHWADDR  
  if (ioctl(fd, SIOCGIFHWADDR, (caddr_t)&ifr) == 0) {
    memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, PKT_ETH_ALEN);
  } else {
    log_err(errno, "could not get MAC address");
    return -1;
  }
#endif  

  close(fd);
  
  /* create an instance of redir */
  if (redir_new(&redir, &_options.uamlisten, _options.uamport, 
#ifdef ENABLE_UAMUIPORT
		_options.uamuiport
#else
		0
#endif
		)) {
    log_err(0, "Failed to create redir");
    return -1;
  }
  
  if (redir_listen(redir)) {
    log_err(0, "Failed to create redir listen");
    return -1;
  }

  redir_set(redir, hwaddr, (_options.debug));
  redir_set_cb_getstate(redir, sock_redir_getstate);
  
  redir->cb_handle_url = redir_handle_url;

  if (net_select_init(&sctx))
    log_err(errno, "select init");

  selfpipe = selfpipe_init();

  /* epoll */
  net_select_addfd(&sctx, selfpipe, SELECT_READ);
  net_select_addfd(&sctx, redir->fd[0], SELECT_READ);
  net_select_addfd(&sctx, redir->fd[1], SELECT_READ);

  if (_options.gid && setgid(_options.gid)) {
    log_err(errno, "setgid(%d) failed while running with gid = %d\n", 
	    _options.gid, getgid());
  }
  
  if (_options.uid && setuid(_options.uid)) {
    log_err(errno, "setuid(%d) failed while running with uid = %d\n", 
	    _options.uid, getuid());
  }

  while (keep_going) {

    /* select/poll */
    net_select_zero(&sctx);
    net_select_fd(&sctx, selfpipe, SELECT_READ);
    net_select_fd(&sctx, redir->fd[0], SELECT_READ);
    net_select_fd(&sctx, redir->fd[1], SELECT_READ);
  
    active = 0;

    if (reload_config) {
      reload_options(argc, argv);
      reload_config = 0;

      redir_set(redir, hwaddr, _options.debug);
    }

    for (idx=0; idx < max_requests; idx++) {

      conn_select_fd(&requests[idx].conn, &sctx);

      if (requests[idx].inuse && requests[idx].socket_fd) {
	time_t now = mainclock_tick();
	int fd = requests[idx].socket_fd;
	int timeout = 60;

	if (now - requests[idx].last_active > timeout) {
	  log_dbg("timeout connection %d", idx);
	  redir_conn_finish(&requests[idx].conn, &requests[idx]);
	} else {
	  int evt = SELECT_READ;
	  timeout = 0;
	  if (conn_write_remaining(&requests[idx].conn))
	    evt |= SELECT_WRITE;
	  net_select_fd(&sctx, fd, evt);
	  active++;
	}
	
#if(_debug_ > 1)
	if (_options.debug) {
	  struct sockaddr_in address;
	  socklen_t addrlen = sizeof(address);
	  
	  if (getpeername(fd, (struct sockaddr *)&address, 
			  &addrlen) >= 0) {
	    char line[512];
	    
	    safe_snprintf(line, sizeof(line),
			  "#%d (%d) %d connection from %s %d",
			  timeout ? -1 : active, fd, 
			  (int) requests[idx].last_active,
			  inet_ntoa(address.sin_addr),
			  ntohs(address.sin_port));
	    
	    if (requests[idx].conn.sock) {
	      addrlen = sizeof(address);
	      if (getpeername(requests[idx].conn.sock,
			      (struct sockaddr *)&address,
			      &addrlen) >= 0) {
		safe_snprintf(line+strlen(line),
			      sizeof(line)-strlen(line),
			      " to %s %d",
			      inet_ntoa(address.sin_addr),
			      ntohs(address.sin_port));
	      }
	    }
	    
	    if (timeout) {
	      safe_snprintf(line+strlen(line), 
			    sizeof(line)-strlen(line),
			    " (timeout)");
	    }

	    log_dbg("%s", line);
	  }
	}
#endif
      }
    }

    if (active != active_last) {
      log_dbg("active connections: %d", active);
      active_last = active;
    }
    
    status = net_select(&sctx);
    
#if defined(USING_POLL) && defined(HAVE_SYS_EPOLL_H) && (_debug_ > 1)
    if (_options.debug && status > 0) {
      int i;
      log_dbg("epoll %d", status);
      for (i=0; i < status; i++) {
	log_dbg("epoll fd %d %d", 
		sctx.events[i].data.fd, 
		sctx.events[i].events);
      }
    }
#endif

    switch (status) {
    case -1:
      log_err(errno, "select() returned -1!");
      break;  

    default:
      if (status > 0) {

	if (net_select_read_fd(&sctx, selfpipe)==1) {
	  chilli_handle_signal(0, 0);
	}
	
	if (redir->fd[0])
	  if (net_select_read_fd(&sctx, redir->fd[0])==1 && 
	      redir_accept2(redir, 0) < 0)
	    log_err(0, "redir_accept() failed!");
	
	if (redir->fd[1])
	  if (net_select_read_fd(&sctx, redir->fd[1])==1 && 
	      redir_accept2(redir, 1) < 0)
	    log_err(0, "redir_accept() failed!");
      
	for (idx=0; idx < max_requests; idx++) {

	  /*
	   *  Update remote connections with activity
	   */
	  conn_select_update(&requests[idx].conn, &sctx);

	  /*
	   *  Check client connections with activity
	   */
	  if (requests[idx].inuse && requests[idx].socket_fd) {
	    int fd = requests[idx].socket_fd;
	    
#ifdef HAVE_SSL
	    if (requests[idx].sslcon) {
	      if (openssl_check_accept(requests[idx].sslcon, 0) < 0) {
		log_dbg("ssl error %d", errno);
		redir_conn_finish(&requests[idx].conn, &requests[idx]);
		continue;
	      }
	    }
#endif

	    switch (net_select_write_fd(&sctx, fd)) {
	    case 1:
	      log_dbg("client writeable");
	      redir_cli_rewrite(&requests[idx], &requests[idx].conn);
	      break;
	    }
	    
	    switch (net_select_read_fd(&sctx, fd)) {
	    case -1:
	      log_dbg("EXCEPTION");
	      redir_conn_finish(&requests[idx].conn, 
				&requests[idx]);
	      break;

	    case 1:
	      {
		if (requests[idx].proxy) {
		  char b[PKT_MAX_LEN];
		  int r;
		  
#ifdef HAVE_SSL
		  if (requests[idx].sslcon) {
		    /*
		      log_dbg("proxy_read_ssl");
		    */
		    r = openssl_read(requests[idx].sslcon, 
				     b, sizeof(b)-1, 0);
		  } else
#endif
		    r = safe_read(fd, b, sizeof(b)-1);
		  
		  /*
		    log_dbg("proxy_read: %d %d", fd, r);
		  */
		  
		  if (r <= 0) {

		    log_dbg("recv %d %d %d", r, 
			    requests[idx].conn.read_buf->slen -
			    requests[idx].conn.read_pos,
			    errno);

		    if (!(r == -1 && 
			  (errno == EWOULDBLOCK || errno == EAGAIN))) {
		      if (redir_cli_rewrite(&requests[idx], 
					    &requests[idx].conn) == 0) {
			log_dbg("done reading and writing");
			redir_conn_finish(&requests[idx].conn, 
					  &requests[idx]);
		      }
		    }
		    
		  } else if (r > 0) {

		    int w;
		    requests[idx].last_active = mainclock_tick();
		    w = net_write(requests[idx].conn.sock, b, r);
		    
		    /*
		      log_dbg("proxy_write: %d", w);
		    */
		    if (r != w) {
		      log_err(errno, "problem writing what we read from client");
		      redir_conn_finish(&requests[idx].conn, 
					&requests[idx]);
		    }
		  }
		  
		} else {
#ifdef HAVE_SSL
		go_again:
#endif
		  switch (redir_main(redir, fd, fd, 
				     &requests[idx].conn.peer,
				     &requests[idx].baddr, 
				     requests[idx].uiidx, 
				     &requests[idx])) {
		  case 1:
		    /*log_dbg("redir cont'ed");*/
#ifdef HAVE_SSL
		    if (requests[idx].sslcon && 
			openssl_pending(requests[idx].sslcon) > 0) {
		      log_dbg("ssl_pending, trying again");
		      goto go_again;
		    }
#endif
		  break;
		  case -1: 
		    log_dbg("redir error");
		  default:
		    log_dbg("redir completed");
		    redir_conn_finish(&requests[idx].conn, 
				      &requests[idx]);
		    break;
		  }
		}
	      }
	      break;
	    }
	  }
	}
      }
      
      break;
    }
  }

  redir_free(redir);

  child_killall(SIGKILL);

  selfpipe_finish();
  
  return 0;
}