Beispiel #1
0
static void dissect_tftp_message(tftp_conv_info_t *tftp_info,
                                 tvbuff_t *tvb, packet_info *pinfo,
                                 proto_tree *tree)
{
  proto_tree *tftp_tree;
  proto_item *ti;
  gint        offset    = 0;
  guint16     opcode;
  guint16     bytes;
  guint16     blocknum;
  guint       i1;
  guint16     error;
  tvbuff_t    *data_tvb = NULL;

  col_set_str(pinfo->cinfo, COL_PROTOCOL, "TFTP");

  /* Protocol root */
  ti = proto_tree_add_item(tree, proto_tftp, tvb, offset, -1, ENC_NA);
  tftp_tree = proto_item_add_subtree(ti, ett_tftp);

  /* Opcode */
  opcode = tvb_get_ntohs(tvb, offset);
  proto_tree_add_uint(tftp_tree, hf_tftp_opcode, tvb, offset, 2, opcode);
  col_add_str(pinfo->cinfo, COL_INFO,
              val_to_str(opcode, tftp_opcode_vals, "Unknown (0x%04x)"));
  offset += 2;

  /* read and write requests contain file names
     for other messages, we add the filenames from the conversation */
  if (opcode!=TFTP_RRQ && opcode!=TFTP_WRQ) {
    if (tftp_info->source_file) {
      ti = proto_tree_add_string(tftp_tree, hf_tftp_source_file, tvb,
          0, 0, tftp_info->source_file);
      PROTO_ITEM_SET_GENERATED(ti);
    }

    if (tftp_info->destination_file) {
      ti = proto_tree_add_string(tftp_tree, hf_tftp_destination_file, tvb,
          0, 0, tftp_info->destination_file);
      PROTO_ITEM_SET_GENERATED(ti);
    }
  }

  switch (opcode) {

  case TFTP_RRQ:
    i1 = tvb_strsize(tvb, offset);
    proto_tree_add_item(tftp_tree, hf_tftp_source_file,
                        tvb, offset, i1, ENC_ASCII|ENC_NA);

    tftp_info->source_file = tvb_get_string_enc(wmem_file_scope(), tvb, offset, i1, ENC_ASCII);
    /* we either have a source file name (for read requests) or a
       destination file name (for write requests) 
       when we set one of the names, we clear the other */
    tftp_info->destination_file = NULL;

    col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
                    tvb_format_stringzpad(tvb, offset, i1));

    offset += i1;

    i1 = tvb_strsize(tvb, offset);
    proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
                        tvb, offset, i1, ENC_ASCII|ENC_NA);

    col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
                    tvb_format_stringzpad(tvb, offset, i1));

    offset += i1;

    tftp_dissect_options(tvb, pinfo,  offset, tftp_tree,
                         opcode, tftp_info);
    break;

  case TFTP_WRQ:
    i1 = tvb_strsize(tvb, offset);
    proto_tree_add_item(tftp_tree, hf_tftp_destination_file,
                        tvb, offset, i1, ENC_ASCII|ENC_NA);

    tftp_info->destination_file =
      tvb_get_string_enc(wmem_file_scope(), tvb, offset, i1, ENC_ASCII);
    tftp_info->source_file = NULL; /* see above */

    col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
                    tvb_format_stringzpad(tvb, offset, i1));

    offset += i1;

    i1 = tvb_strsize(tvb, offset);
    proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
                        tvb, offset, i1, ENC_ASCII|ENC_NA);

    col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
                    tvb_format_stringzpad(tvb, offset, i1));

    offset += i1;

    tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
                         opcode,  tftp_info);
    break;

  case TFTP_INFO:
    tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
                         opcode,  tftp_info);
    break;

  case TFTP_DATA:
    blocknum = tvb_get_ntohs(tvb, offset);
    proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
                        blocknum);

    /* Sequence analysis on blocknums (first pass only) */
    if (!pinfo->fd->flags.visited) {
      if (blocknum > tftp_info->next_block_num) {
        /* There is a gap.  Don't try to recover from this. */
        tftp_info->next_block_num = blocknum + 1;
        tftp_info->blocks_missing = TRUE;
        /* TODO: add info to a result table for showing expert info in later passes */
      }
      else if (blocknum == tftp_info->next_block_num) {
        /* OK, inc what we expect next */
        tftp_info->next_block_num++;
      }
    }
    offset += 2;

    /* Show number of bytes in this block, and whether it is the end of the file */
    bytes = tvb_reported_length_remaining(tvb, offset);
    col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i%s",
                    blocknum,
                    (bytes < tftp_info->blocksize)?" (last)":"" );

    /* Show data in tree */
    if (bytes > 0) {
      data_tvb = tvb_new_subset(tvb, offset, -1, bytes);
      call_dissector(data_handle, data_tvb, pinfo, tree);
    }

    /* If Export Object tap is listening, need to accumulate blocks info list
       to send to tap. But if already know there are blocks missing, there is no
       point in trying. */
    if (have_tap_listener(tftp_eo_tap) && !tftp_info->blocks_missing) {
      file_block_t *block;

      if (blocknum == 1) {
        /* Reset data for this conversation, freeing any accumulated blocks! */
        cleanup_tftp_blocks(tftp_info);
        tftp_info->next_tap_block_num = 1;
      }

      if (blocknum != tftp_info->next_tap_block_num) {
        /* Ignore.  Could be missing frames, or just clicking previous frame */
        return;
      }

      if (bytes > 0) {
        /* Create a block for this block */
        block = (file_block_t*)g_malloc(sizeof(file_block_t));
        block->length = bytes;
        block->data = tvb_memdup(NULL, data_tvb, 0, bytes);

        /* Add to the end of the list (does involve traversing whole list..) */
        tftp_info->block_list = g_slist_append(tftp_info->block_list, block);
        tftp_info->file_length += bytes;

        /* Look for next blocknum next time */
        tftp_info->next_tap_block_num++;
      }

      /* Tap export object only when reach end of file */
      if (bytes < tftp_info->blocksize) {
        tftp_eo_t        *eo_info;

        /* If don't have a filename, won't tap file info */
        if ((tftp_info->source_file == NULL) && (tftp_info->destination_file == NULL)) {
            cleanup_tftp_blocks(tftp_info);
            return;
        }

        /* Create the eo_info to pass to the listener */
        eo_info = wmem_new(wmem_packet_scope(), tftp_eo_t);

        /* Set filename */
        if (tftp_info->source_file) {
          eo_info->filename = g_strdup(tftp_info->source_file);
        }
        else if (tftp_info->destination_file) {
          eo_info->filename = g_strdup(tftp_info->destination_file);
        }

        /* Send block list, which will be combined and freed at tap. */
        eo_info->payload_len = tftp_info->file_length;
        eo_info->pkt_num = blocknum;
        eo_info->block_list = tftp_info->block_list;

        /* Send to tap */
        tap_queue_packet(tftp_eo_tap, pinfo, eo_info);

        /* Have sent, so forget list of blocks, and only pay attention if we
           get back to the first block again. */
        tftp_info->block_list = NULL;
        tftp_info->next_tap_block_num = 1;
      }
    }
    break;

  case TFTP_ACK:
    blocknum = tvb_get_ntohs(tvb, offset);
    proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
                        blocknum);

    col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i",
                    blocknum);
    break;

  case TFTP_ERROR:
    error = tvb_get_ntohs(tvb, offset);
    proto_tree_add_uint(tftp_tree, hf_tftp_error_code, tvb, offset, 2,
                        error);

    col_append_fstr(pinfo->cinfo, COL_INFO, ", Code: %s",
                    val_to_str(error, tftp_error_code_vals, "Unknown (%u)"));

    offset += 2;

    i1 = tvb_strsize(tvb, offset);
    proto_tree_add_item(tftp_tree, hf_tftp_error_string, tvb, offset,
                        i1, ENC_ASCII|ENC_NA);

    col_append_fstr(pinfo->cinfo, COL_INFO, ", Message: %s",
                    tvb_format_stringzpad(tvb, offset, i1));

    expert_add_info(pinfo, NULL, &ei_tftp_blocksize_range);
    break;

  case TFTP_OACK:
    tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
                         opcode, tftp_info);
    break;

  default:
    proto_tree_add_item(tftp_tree, hf_tftp_data, tvb, offset, -1, ENC_NA);
    break;

  }
}
Beispiel #2
0
static void dissect_tftp_message(tftp_conv_info_t *tftp_info,
				 tvbuff_t *tvb, packet_info *pinfo,
				 proto_tree *tree)
{
	proto_tree	 *tftp_tree = NULL;
	proto_item	 *ti;
	gint		 offset = 0;
	guint16		 opcode;
	guint16		 bytes;
	guint16		 blocknum;
	guint		 i1;
	guint16	         error;

	col_set_str(pinfo->cinfo, COL_PROTOCOL, "TFTP");

	opcode = tvb_get_ntohs(tvb, offset);

	col_add_str(pinfo->cinfo, COL_INFO,
		    val_to_str(opcode, tftp_opcode_vals, "Unknown (0x%04x)"));

	if (tree) {
	  ti = proto_tree_add_item(tree, proto_tftp, tvb, offset, -1, ENC_NA);
	  tftp_tree = proto_item_add_subtree(ti, ett_tftp);

	  if (tftp_info->source_file) {
	    ti = proto_tree_add_string(tftp_tree, hf_tftp_source_file, tvb,
				       0, 0, tftp_info->source_file);
	    PROTO_ITEM_SET_GENERATED(ti);
	  }

	  if (tftp_info->destination_file) {
	    ti = proto_tree_add_string(tftp_tree, hf_tftp_destination_file, tvb,
				       0, 0, tftp_info->destination_file);
	    PROTO_ITEM_SET_GENERATED(ti);
	  }

	  proto_tree_add_uint(tftp_tree, hf_tftp_opcode, tvb,
			      offset, 2, opcode);
	}
	offset += 2;

	switch (opcode) {

	case TFTP_RRQ:
	  i1 = tvb_strsize(tvb, offset);
	  proto_tree_add_item(tftp_tree, hf_tftp_source_file,
			      tvb, offset, i1, ENC_ASCII|ENC_NA);

	  tftp_info->source_file = tvb_get_string(wmem_file_scope(), tvb, offset, i1);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
			  tvb_format_stringzpad(tvb, offset, i1));

	  offset += i1;

	  i1 = tvb_strsize(tvb, offset);
	  proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
			      tvb, offset, i1, ENC_ASCII|ENC_NA);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
			  tvb_format_stringzpad(tvb, offset, i1));

	  offset += i1;

	  tftp_dissect_options(tvb, pinfo,  offset, tftp_tree,
			       opcode, tftp_info);
	  break;

	case TFTP_WRQ:
	  i1 = tvb_strsize(tvb, offset);
	  proto_tree_add_item(tftp_tree, hf_tftp_destination_file,
			      tvb, offset, i1, ENC_ASCII|ENC_NA);

	  tftp_info->destination_file =
	    tvb_get_string(wmem_file_scope(), tvb, offset, i1);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
			  tvb_format_stringzpad(tvb, offset, i1));

	  offset += i1;

	  i1 = tvb_strsize(tvb, offset);
	  proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
			           tvb, offset, i1, ENC_ASCII|ENC_NA);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
			  tvb_format_stringzpad(tvb, offset, i1));

	  offset += i1;

	  tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
			       opcode,  tftp_info);
	  break;

	case TFTP_INFO:
	  tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
			       opcode,  tftp_info);
	  break;

	case TFTP_DATA:
	  blocknum = tvb_get_ntohs(tvb, offset);
	  proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
			      blocknum);

	  offset += 2;

	  bytes = tvb_reported_length_remaining(tvb, offset);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i%s",
			  blocknum,
			  (bytes < tftp_info->blocksize)?" (last)":"" );

	  if (bytes != 0) {
	    tvbuff_t *data_tvb = tvb_new_subset(tvb, offset, -1, bytes);
	    call_dissector(data_handle, data_tvb, pinfo, tree);
	  }
	  break;

	case TFTP_ACK:
	  blocknum = tvb_get_ntohs(tvb, offset);
	  proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
			      blocknum);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i",
			  blocknum);
	  break;

	case TFTP_ERROR:
	  error = tvb_get_ntohs(tvb, offset);
	  proto_tree_add_uint(tftp_tree, hf_tftp_error_code, tvb, offset, 2,
			      error);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", Code: %s",
			  val_to_str(error, tftp_error_code_vals, "Unknown (%u)"));

	  offset += 2;

	  i1 = tvb_strsize(tvb, offset);
	  proto_tree_add_item(tftp_tree, hf_tftp_error_string, tvb, offset,
			      i1, ENC_ASCII|ENC_NA);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", Message: %s",
			  tvb_format_stringzpad(tvb, offset, i1));

	  expert_add_info(pinfo, NULL, &ei_tftp_blocksize_range);
	  break;

	case TFTP_OACK:
	  tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
			       opcode, tftp_info);
	  break;

	default:
	  proto_tree_add_text(tftp_tree, tvb, offset, -1,
			      "Data (%d bytes)", tvb_reported_length_remaining(tvb, offset));
	  break;

	}

  return;
}