Exemplo n.º 1
0
int       
__bro_openssl_read(BroConn *bc, uchar *buf, uint buf_size)
{
  int n;

  D_ENTER;
  
  /* It's important here to use <= for comparison, since, as the
   * invaluable O'Reilly OpenSSL book reports, "for each of the four
   * reading and writing functions, a 0 or -1 return value may or may
   * not necessarily indicate that an error has occurred." This may or
   * may not necessarily be indicative of the incredible PITA that
   * OpenSSL is. --cpk
   */
  if ( (n = BIO_read(bc->bio, buf, buf_size)) <= 0)
    {
      if (BIO_should_retry(bc->bio))
	D_RETURN_(0);
      
      __bro_openssl_shutdown(bc);
      D(("Connection closed, BIO_read() returned %i.\n", n));      
      print_errors();
      D_RETURN_(-1);
    }
    
  D_RETURN_(n);
}
Exemplo n.º 2
0
void
__bro_io_loop(BroConn *bc)
{
  D_ENTER;
  
  for ( ; ; )
    {
      D(("I/O loop iteration\n"));
      
      switch (bc->state->io_msg)
	{
	case BRO_IOMSG_STOP:
	  D(("I/O process %u exiting by request.\n", getpid()));
	  __bro_openssl_shutdown(bc);
	  exit(0);
	  
	case BRO_IOMSG_WRITE:
	  if (bc->state->tx_dead)
	    break;

	  if (! io_msg_empty_tx(bc))
	    {	      
	      D(("I/O handler %u encountered write error.\n", getpid()));
	      __bro_openssl_shutdown(bc);
	    }
	  break;

	case BRO_IOMSG_READ:
	  if (bc->state->rx_dead)
	    break;

	  if (io_msg_fill_rx(bc) < 0)
	    {
	      D(("I/O handler %u encountered read error.\n", getpid()));
	      __bro_openssl_shutdown(bc);
	    }
	  break;
	}
            
      bc->state->io_msg = BRO_IOMSG_NONE;
    }  
}
Exemplo n.º 3
0
int
__bro_io_process_input(BroConn *bc)
{
  uint32          buf_off, chunk_size;
  BroMsgHeader    msg_hdr;
  int             result = FALSE;
  
  D_ENTER;
  
  /* Read all available data into receive buffer. Our socket is
   * nonblocking so if nothing's available we'll be back right
   * away. If nothing was read, the subsequent for loop will exit
   * right away, so the io_msg_fill_rx() return code need not be
   * checked here.
   */
  io_msg_fill_rx(bc);

  /* Try to process as much in the input buffer as we can */
  for ( ; ; )
    {  
      D(("----- Attempting to extract a message\n"));

      /* Get the current offset of the buffer pointer to make
       * sure we can reset to it if things go wrong.
       */
      buf_off = __bro_buf_ptr_tell(bc->rx_buf);
      
      /* Now check the buffer contents and see if there's enough
       * for us to analyze it. Start with a uint32 for the size
       * of the first chunk, and then the chunk itself.
       */
      if (! io_read_chunk_size(bc, &chunk_size))
	goto reset_return;
      
      if (chunk_size != sizeof(BroMsgHeader))
	{
	  D(("Received chunk should be %i bytes, but is %i\n",
	     sizeof(BroMsgHeader), chunk_size));
	  io_skip_chunk(bc->rx_buf, buf_off, chunk_size);
	  result = TRUE;
	  continue;
	}
      
      if (! io_read_msg_hdr(bc, &msg_hdr))
	goto reset_return;
      
      switch (msg_hdr.hdr_type)
	{
	case BRO_MSG_REQUEST:
	  {
	    char *tmp = NULL, *tmp2 = NULL;
	        
	    D(("Received MSQ_REQUEST\n"));
	        
	    /* We need to read another chunk, whose data will contain
	     * a sequence of 0-terminated strings, each one being the
	     * name of an event that the peering Bro is interested in.
	     */
	    if (! io_read_chunk_size(bc, &chunk_size))
	      goto reset_return;
	        
	    if (! (tmp = (char *) malloc(chunk_size * sizeof(char))))
	      goto reset_return;
	        
	    if (! __bro_buf_read_data(bc->rx_buf, tmp, chunk_size))
	      {
		free(tmp);
		goto reset_return;
	      }
	        
	    for (tmp2 = tmp; tmp2 < tmp + chunk_size; tmp2 = tmp2 + strlen(tmp2) + 1)
	      {
		char *key;

		if (__bro_ht_get(bc->ev_mask, tmp2))
		  continue;
		
		key = strdup(tmp2);
		__bro_ht_add(bc->ev_mask, key, key);
		D(("Will report event '%s'\n", tmp2));
	      }

	    D(("Now reporting %i event(s).\n", __bro_ht_get_size(bc->ev_mask)));
	    free(tmp);
	  }
	  break;
	    
	case BRO_MSG_VERSION:
	  {
	    uchar *data;
	    uint32 proto_version;
	    uint32 cache_size;
	    uint32 data_version;
	    uint32 runtime; /* unused */

	    D(("Received MSG_VERSION\n"));

	    /* We need to read another chunk for the raw data.
	     */
	    if (! io_read_chunk_size(bc, &chunk_size))
	      goto reset_return;

	    if (! (data = malloc(sizeof(uchar) * chunk_size)))
	      goto reset_return;

	    if (! __bro_buf_read_data(bc->rx_buf, data, chunk_size))
	      {
		free(data);
		goto reset_return;
	      }
	        
	    proto_version = ntohl(((uint32 *) data)[0]);
	    cache_size    = ntohl(((uint32 *) data)[1]);
	    data_version  = ntohl(((uint32 *) data)[2]);
	    runtime       = ntohl(((uint32 *) data)[3]);

	    /* If there are more bytes than required for the 4 uint32s
	     * used above, it means that the peer has sent a connection class
	     * identifier. Extract and register in the handle.
	     */
	    if (chunk_size > 4 * sizeof(uint32))
	      {
		if (bc->peer_class)
		  free(bc->peer_class);
		
		bc->peer_class = strdup((char *) (data + 4 * sizeof(uint32)));
	      }

	    if (proto_version != BRO_PROTOCOL_VERSION)
	      {
		D(("EEEK -- we speak protocol version %i, peer speeks %i. Aborting.\n",
		   BRO_PROTOCOL_VERSION, proto_version));		
		__bro_openssl_shutdown(bc);
		free(data);
		goto reset_return;
	      } else {
		D(("Protocols compatible, we speak version %i\n", BRO_PROTOCOL_VERSION));
	      }
	    
	    if (data_version != 0 && data_version != BRO_DATA_FORMAT_VERSION)
	      {
		D(("EEEK -- we speak data format version %i, peer speeks %i. Aborting.\n",
		   BRO_DATA_FORMAT_VERSION, data_version));		
		__bro_openssl_shutdown(bc);
		free(data);
		goto reset_return;
	      } else {
		D(("Data formats compatible, we speak version %i\n", BRO_DATA_FORMAT_VERSION));
	      }
	    
	    bc->io_cache_maxsize = cache_size;
	    D(("Receiver cache size set to %i entries.\n", cache_size));
	    free(data);

	    bc->state->conn_state_peer = BRO_CONNSTATE_HANDSHAKE;
	    D(("VERSION received, on %p, peer now in HANDSHAKE stage.\n"));
	  }
	  break;
	    
	case BRO_MSG_SERIAL:
	  {
	    uint32 pre_serial;
	        
	    D(("Received MSQ_SERIAL\n"));
	    pre_serial = __bro_buf_ptr_tell(bc->rx_buf);

	    if (! io_read_chunk_size(bc, &chunk_size))
	      goto reset_return;
	        
	    if (! io_process_serialization(bc))
	      io_skip_chunk(bc->rx_buf, pre_serial, chunk_size);
	  }
	  break;
	    
	case BRO_MSG_CAPTURE_FILTER:
	  {
	    uint32 pre_capture;

	    D(("Received MSQ_CAPTURE_FILTER\n"));
	    pre_capture = __bro_buf_ptr_tell(bc->rx_buf);
	        
	    if (! io_read_chunk_size(bc, &chunk_size))
	      goto reset_return;
	        
	    io_skip_chunk(bc->rx_buf, pre_capture, chunk_size);
	  }
	  break;

	case BRO_MSG_PHASE_DONE:
	  /* No additional content for this one. */
	  switch (bc->state->conn_state_peer)
	    {
	    case BRO_CONNSTATE_HANDSHAKE:
	      /* When we complete the handshake phase, it depends
	       * on whether or not the peer has requested synced
	       * state. If so, enter the sync phase, otherwise
	       * we're up and running.
	       */
	      if (bc->state->sync_state_requested)
		{
		  bc->state->conn_state_peer = BRO_CONNSTATE_SYNC;
		  D(("Phase done from peer on %p, sync requested, peer now in SYNC stage.\n", bc));
		}
	      else
		{
		  bc->state->conn_state_peer = BRO_CONNSTATE_RUNNING;
		  D(("Phase done from peer on %p, no sync requested, peer now in RUNNING stage.\n", bc));
		}
	      break;

	    case BRO_CONNSTATE_SYNC:
	      bc->state->conn_state_peer = BRO_CONNSTATE_RUNNING;
	      D(("Phase done from peer on %p, peer now in RUNNING stage.\n", bc));
	      break;
	      
	    default:
	      D(("Ignoring PHASE_DONE in conn state %i/%i on conn %p\n",
		 bc->state->conn_state_self, bc->state->conn_state_peer, bc));
	    }
	  break;
	  
	case BRO_MSG_REQUEST_SYNC:
		{   	  
	    uchar *data;
		
	    D(("Received MSQ_REQUEST_SYNC, peer now in SYNC stage.\n"));
		
	    bc->state->sync_state_requested = 1;
	    bc->state->conn_state_peer = BRO_CONNSTATE_SYNC;

	    /* We need to read another chunk for the raw data.
	     */
	    if (! io_read_chunk_size(bc, &chunk_size))
	      goto reset_return;

	    if (! (data = malloc(sizeof(uchar) * chunk_size)))
	      goto reset_return;

	    if (! __bro_buf_read_data(bc->rx_buf, data, chunk_size))
	      {
		free(data);
		goto reset_return;
	      }
	    D(("Skipping sync interpretation\n"));
	    free(data);
	    break;
	  }
	
	
	case BRO_MSG_CAPS:
	  {
	    uchar *data;

	    D(("Received MSG_CAPS\n"));

	    /* We need to read another chunk for the raw data.
	     */
	    if (! io_read_chunk_size(bc, &chunk_size))
	      goto reset_return;

	    if (! (data = malloc(sizeof(uchar) * chunk_size)))
	      goto reset_return;

	    if (! __bro_buf_read_data(bc->rx_buf, data, chunk_size))
	      {
		free(data);
		goto reset_return;
	      }
	    D(("Skipping capabilities interpretation\n"));
	    free(data);
	    break;
	  }

	default:
	  D(("Skipping unknown message type %i\n", msg_hdr.hdr_type));
	  break;
	}
      
      __bro_buf_consume(bc->rx_buf);
      result = TRUE;

      if ((bc->conn_flags & BRO_CFLAG_YIELD) &&
	  bc->state->conn_state_self == BRO_CONNSTATE_RUNNING &&
	  bc->state->conn_state_peer == BRO_CONNSTATE_RUNNING)	  
	break;
    }
  
 reset_return:
  __bro_buf_ptr_seek(bc->rx_buf, buf_off, SEEK_SET);
  D_RETURN_(result);
}
Exemplo n.º 4
0
int
__bro_openssl_write(BroConn *bc, uchar *buf, uint buf_size)
{
  int n;
  void *old_sig;
  
  D_ENTER;
  
#ifdef BRO_DEBUG
  if (bro_debug_messages)
    {
      unsigned int i = 0;
      int last_hex = 0;

      D(("Sending %u bytes: ", buf_size));
 
      for (i = 0; i < buf_size; i++)
	{
	  if (buf[i] >= 32 && buf[i] <= 126)
	    {
	      printf("%s%c", last_hex ? " " : "", buf[i]);
	      last_hex = 0;
	    }
	  else
	    {
	      printf(" 0x%.2x", buf[i]);
	      last_hex = 1;
	    }
	}
      printf("\n");
    }
#endif

  /* We may get a SIGPIPE if we write to a connection whose peer
   * died. Since we don't know the application context in which
   * we're running, we temporarily set the SIGPIPE handler to our
   * own and then set it back to the old one after we wrote.
   */
  old_sig = signal(SIGPIPE, SIG_IGN);
  
  n = BIO_write(bc->bio, buf, buf_size);
  
  if (n <= 0)
    {
      if (BIO_should_retry(bc->bio))
	{
	  n = 0;
	  goto error_return;
	}

      print_errors();
      __bro_openssl_shutdown(bc);
      D(("Connection closed.\n"));
      n = -1;
    }
  
  BIO_flush(bc->bio);

 error_return:
  
  if (old_sig != SIG_ERR)
    signal(SIGPIPE, old_sig);
  
  D_RETURN_(n);
}