Esempio n. 1
0
packet_t *packet_parse(uint8_t *data, size_t length, options_t options)
{
  packet_t *packet = (packet_t*) safe_malloc(sizeof(packet_t));
  buffer_t *buffer = buffer_create_with_data(BO_BIG_ENDIAN, data, length);

  /* Validate the size */
  if(buffer_get_length(buffer) > MAX_PACKET_SIZE)
  {
    LOG_FATAL("Packet is too long: %zu bytes\n", buffer_get_length(buffer));
    exit(1);
  }

  packet->packet_id    = buffer_read_next_int16(buffer);
  packet->packet_type  = (packet_type_t) buffer_read_next_int8(buffer);
  packet->session_id   = buffer_read_next_int16(buffer);

  switch(packet->packet_type)
  {
    case PACKET_TYPE_SYN:
      packet->body.syn.seq     = buffer_read_next_int16(buffer);
      packet->body.syn.options = buffer_read_next_int16(buffer);
      break;

    case PACKET_TYPE_MSG:
      if(options & OPT_CHUNKED_DOWNLOAD)
      {
        packet->body.msg.options.chunked.chunk = buffer_read_next_int32(buffer);
      }
      else
      {
        packet->body.msg.options.normal.seq     = buffer_read_next_int16(buffer);
        packet->body.msg.options.normal.ack     = buffer_read_next_int16(buffer);
      }
      packet->body.msg.data    = buffer_read_remaining_bytes(buffer, &packet->body.msg.data_length, -1, FALSE);
      break;

    case PACKET_TYPE_FIN:
      packet->body.fin.reason = buffer_alloc_next_ntstring(buffer);

      break;

    case PACKET_TYPE_PING:
      packet->body.ping.data = buffer_alloc_next_ntstring(buffer);

      break;

    default:
      LOG_FATAL("Error: unknown message type (0x%02x)\n", packet->packet_type);
      exit(0);
  }

  buffer_destroy(buffer);

  return packet;
}
Esempio n. 2
0
void sessions_print(sessions_t *sessions)
{
	session_t *session = sessions->first_session;

	while(session)
	{
		fprintf(stderr, "%s: %d bytes waiting\n", session->name, buffer_get_length(session->buffer));
		session = (session_t*)session->next_session;
	}
	if(buffer_can_read_int8(sessions->buffer_data))
		fprintf(stderr, "%d bytes buffered\n", buffer_get_length(sessions->buffer_data));
}
Esempio n. 3
0
// Parses body. Returns true iff progress was made.
bool frameparser_parse_body(frameparser *fp, buffer *b)
{
  log_printf(LOG_LEVEL_DEBUG, "frameparser_parse_body\n");

  if (fp->length_left == FP_LENGTH_UNKNOWN)
  {
    // Look for NUL terminator
    int nulpos = buffer_find_byte(b, '\x00');
    if (nulpos < 0)
    {
      // No NUL, so grab everything
      int count = buffer_get_length(b);
      bytestring *body = frame_ensure_body(fp->cur_frame);
      buffer_append_bytestring(b, body, 0, count);
      buffer_consume(b, count);
      return true;
    }
    else if (nulpos == 0)
    {
      // NUL as next character, so the frame is complete
      fp->state = FP_STATE_END;
      return true;
    }
    else
    {
      // NUL after some other bytes, so grab them and the frame is complete
      bytestring *body = frame_ensure_body(fp->cur_frame);
      buffer_append_bytestring(b, body, 0, nulpos);
      buffer_consume(b, nulpos);
      fp->state = FP_STATE_END;
      return true;
    }
  }
  else
  {
    // Remaining length is known. Figure out how many bytes to grab.
    int count = buffer_get_length(b);
    if (fp->length_left < count)
      count = fp->length_left;

    // Grab the bytes
    bytestring *body = frame_ensure_body(fp->cur_frame);
    buffer_append_bytestring(b, body, 0, count);
    buffer_consume(b, count);
    fp->length_left -= count;

    // If we satisfied the expected length then the frame is complete
    if (fp->length_left == 0)
      fp->state = FP_STATE_END;

    return true;
  }
}
Esempio n. 4
0
// Parses a frame's command. Returns true iff progress was made.
bool frameparser_parse_command(frameparser *fp, buffer *b)
{
  log_printf(LOG_LEVEL_DEBUG, "frameparser_parse_command\n");
  // Valid input in this state is a string followed by CR/LF or LF, which matches a known frame command

  // Try to find LF line terminator
  int lfpos = buffer_find_byte(b, '\x0A');
  if (lfpos < 0)  // No LF yet?
  {
    if (buffer_get_length(b) > LIMIT_FRAME_CMD_LINE_LEN)
      frameparser_set_error(fp, "Line length limit exceeded waiting for command");

    return false;  // No progress
  }
  else if (lfpos == 0)
    abort();  // Should never happen in this state

  // Figure out number of bytes in command string
  int len = lfpos;
  if (buffer_get_byte(b, len - 1) == '\x0D')
    len--;

  // Extract the command into a new bytestring
  bytestring *bs = bytestring_new(len);
  buffer_append_bytestring(b, bs, 0, len);
  bytestring_dump(bs);

  // Consume the current line
  buffer_consume(b, lfpos + 1);

  // Find the command code for this command
  frame_command cmd = frame_command_code(bytestring_get_bytes(bs), bytestring_get_length(bs));

  // Clean up the bytestring
  bytestring_free(bs);

  // Make sure command is valid
  if (cmd == CMD_NONE)
  {
    frameparser_set_error(fp, "Unknown command");
    return false;
  }

  // Set up a new frame structure to hold parsed data
  if (!fp->cur_frame)
    fp->cur_frame = frame_new();

  // Store parsed data
  frame_set_command(fp->cur_frame, cmd);

  // Got a valid command, so headers should be next
  fp->state = FP_STATE_HEADER;
  return true;
}
Esempio n. 5
0
frameparser_outcome frameparser_parse(frameparser *fp, buffer *b)
{
  // Parse as much as we can from the buffer
  bool done = false;
  while ((!done) && (buffer_get_length(b) > 0))
  {
    if (!frameparser_parse_internal(fp, b))
      done = true;
  }

  // Can't make any more parsing progress for now. Might as well compact the buffer.
  buffer_compact(b);

  if (fp->state == FP_STATE_ERROR)
    return FP_OUTCOME_ERROR;
  else if (fp->fin_frame)
    return FP_OUTCOME_FRAME;

  return FP_OUTCOME_WAITING;
}
Esempio n. 6
0
// Push waiting output out to the socket.
void connection_pump_output(connection *c)
{
  int writecount = 0;

  // If we have data waiting to go out, try writing it
  size_t outbuflen = buffer_get_length(c->outbuffer);
  if (outbuflen > 0)
  {
    writecount = buffer_output_fd(c->outbuffer, c->fd, outbuflen);
    if (writecount < 0)
    {
      int error = errno;
      if (error == EPIPE)
        connection_close(c);
      else if ((error != EAGAIN) && (error != EWOULDBLOCK))
        connection_abort(c, error);  // Unexpected error
    }
  }

  // Update write timestamp, if needed
  if (writecount > 0)
    gettimeofday(&c->writetime, NULL);

}
Esempio n. 7
0
// Parses keepalive linefeeds. Returns true iff progress was made.
bool frameparser_parse_idle(frameparser *fp, buffer *b)
{
  log_printf(LOG_LEVEL_DEBUG, "frameparser_parse_idle\n");
  // Valid input in this state is a CR/LF pair, or bare LF

  uint8_t byte = buffer_get_byte(b, 0);
  if (byte == '\x0D')
  {
    // Should be CR/LF pair. Make sure we have at least two bytes
    size_t len = buffer_get_length(b);
    if (len < 2)
      return false;  // No progress

    // Make sure second byte is LF
    byte = buffer_get_byte(b, 1);
    if (byte != '\x0A')
    {
      frameparser_set_error(fp, "Expected 0x0A after 0x0D, got 0x%02X", byte);
      return false;  // No progress
    }

    // Eat the CR/LF pair
    buffer_consume(b, 2);
    return true;
  }
  else if (byte == '\x0A')
  {
    // Bare LF
    buffer_consume(b, 1);
    return true;
  }

  // Something else? Must be the start of a frame
  fp->state = FP_STATE_COMMAND;
  return true;
}
Esempio n. 8
0
/* Needs to be freed with safe_free() */
uint8_t *command_packet_to_bytes(command_packet_t *packet, size_t *length)
{
  buffer_t *buffer = buffer_create(BO_BIG_ENDIAN);
  buffer_t *buffer_with_size = buffer_create(BO_BIG_ENDIAN);
  uint16_t packed_id;

  packed_id  = (packet->is_request ? 0x0000 : 0x8000);
  packed_id |= (packet->request_id & 0x7FFF);
  buffer_add_int16(buffer, packed_id);

  buffer_add_int16(buffer, packet->command_id);

  switch(packet->command_id)
  {
    case COMMAND_PING:
      if(packet->is_request)
        buffer_add_ntstring(buffer, packet->r.request.body.ping.data);
      else
        buffer_add_ntstring(buffer, packet->r.response.body.ping.data);

      break;

    case COMMAND_SHELL:
      if(packet->is_request)
        buffer_add_ntstring(buffer, packet->r.request.body.shell.name);
      else
        buffer_add_int16(buffer, packet->r.response.body.shell.session_id);
      break;

    case COMMAND_EXEC:
      if(packet->is_request)
      {
        buffer_add_ntstring(buffer, packet->r.request.body.exec.name);
        buffer_add_ntstring(buffer, packet->r.request.body.exec.command);
      }
      else
      {
        buffer_add_int16(buffer, packet->r.response.body.exec.session_id);
      }
      break;

    case COMMAND_DOWNLOAD:
      if(packet->is_request)
      {
        buffer_add_ntstring(buffer, packet->r.request.body.download.filename);
      }
      else
      {
        buffer_add_bytes(buffer, packet->r.response.body.download.data, packet->r.response.body.download.length);
      }
      break;

    case COMMAND_UPLOAD:
      if(packet->is_request)
      {
        buffer_add_ntstring(buffer, packet->r.request.body.upload.filename);
        buffer_add_bytes(buffer, packet->r.request.body.upload.data, packet->r.request.body.upload.length);
      }
      else
      {
      }
      break;

    case COMMAND_SHUTDOWN:
      break;

    case TUNNEL_CONNECT:
      if(packet->is_request)
      {
        buffer_add_int32(buffer, packet->r.request.body.tunnel_connect.options);
        buffer_add_ntstring(buffer, packet->r.request.body.tunnel_connect.host);
        buffer_add_int16(buffer, packet->r.request.body.tunnel_connect.port);
      }
      else
      {
        buffer_add_int32(buffer, packet->r.response.body.tunnel_connect.tunnel_id);
      }
      break;

    case TUNNEL_DATA:
      if(packet->is_request)
      {
        buffer_add_int32(buffer, packet->r.request.body.tunnel_data.tunnel_id);
        buffer_add_bytes(buffer, packet->r.request.body.tunnel_data.data, packet->r.request.body.tunnel_data.length);
      }
      else
      {
      }
      break;

    case TUNNEL_CLOSE:
      if(packet->is_request)
      {
        buffer_add_int32(buffer, packet->r.request.body.tunnel_close.tunnel_id);
        buffer_add_ntstring(buffer, packet->r.request.body.tunnel_close.reason);
      }
      else
      {
      }
      break;

    case COMMAND_ERROR:
      if(packet->is_request)
      {
        buffer_add_int16(buffer, packet->r.request.body.error.status);
        buffer_add_ntstring(buffer, packet->r.request.body.error.reason);
      }
      else
      {
        buffer_add_int16(buffer, packet->r.response.body.error.status);
        buffer_add_ntstring(buffer, packet->r.response.body.error.reason);
      }
      break;


    default:
      LOG_FATAL("Unknown command_id: 0x%04x", packet->command_id);
      exit(1);
  }

  buffer_add_int32(buffer_with_size, buffer_get_length(buffer));
  buffer_add_buffer(buffer_with_size, buffer);
  buffer_destroy(buffer);

  return buffer_create_string_and_destroy(buffer_with_size, length);
}
Esempio n. 9
0
// Parses a header line. Returns true iff progress was made.
bool frameparser_parse_header(frameparser *fp, buffer *b)
{
  log_printf(LOG_LEVEL_DEBUG, "frameparser_parse_header\n");
  // Valid input in this state is either:
  // 1. CR/LF or LF alone, denoting the end of headers
  // 2. A key name, followed by a colon, followed by a value name, terminated with CR/LF or LF

  // Try to find LF line terminator
  int lfpos = buffer_find_byte(b, '\x0A');
  if (lfpos < 0)  // No LF yet?
  {
    if (buffer_get_length(b) > LIMIT_FRAME_HEADER_LINE_LEN)
      frameparser_set_error(fp, "Line length limit exceeded waiting for header");

    return false;  // No progress
  }
  else if (lfpos == 0)  // LF alone
  {
    buffer_consume(b, 1);
    frameparser_parse_headers_complete(fp);
    return true;
  }
  else if ((lfpos == 1) && (buffer_get_byte(b, 0) == '\x0D'))  // CR/LF alone
  {
    buffer_consume(b, 2);
    frameparser_parse_headers_complete(fp);
    return true;
  }

  // Figure out number of bytes in the line
  int len = lfpos;
  if (buffer_get_byte(b, len - 1) == '\x0D')
    len--;

  // Find the colon delimiter
  int colonpos = buffer_find_byte_within(b, ':', 0, len);
  if (colonpos < 0)  // No colon?
  {
    frameparser_set_error(fp, "Expected colon delimiter on header line");
    return false;
  }
  else if (colonpos == 0)  // Starts with colon?
  {
    frameparser_set_error(fp, "Header name has zero length");
    return false;
  }

  // Extract the key
  bytestring *key = bytestring_new(colonpos);
  buffer_append_bytestring(b, key, 0, colonpos);

  // Extract the value
  bytestring *val = bytestring_new(len - colonpos - 1);
  buffer_append_bytestring(b, val, colonpos + 1, len - colonpos - 1);

  // Consume the current line
  buffer_consume(b, lfpos + 1);

  // Unescape the key and value if needed
  frame_command cmd = frame_get_command(fp->cur_frame);
  if ((cmd != CMD_CONNECT) && (cmd != CMD_CONNECTED))
  {
    key = unescape_header_bytestring(key);
    val = unescape_header_bytestring(val);
  }

  bytestring_dump(key);
  bytestring_dump(val);

  headerbundle *hb = frame_get_headerbundle(fp->cur_frame);
  headerbundle_append_header(hb, key, val);  // The bundle takes ownership of key and val

  return true;
}