static gint xdmcp_add_authorization_names(proto_tree *tree,
				    tvbuff_t *tvb, gint offset)
{
  proto_tree *anames_tree;
  proto_item *anames_ti;
  gint anames_len, anames_start_offset;

  anames_start_offset = offset;
  anames_len = tvb_get_guint8(tvb, offset);
  anames_ti = proto_tree_add_text(tree, tvb,
				  anames_start_offset, -1,
				  "Authorization names (%d)",
				  anames_len);
  anames_tree = proto_item_add_subtree(anames_ti,
				       ett_xdmcp_authorization_names);

  anames_len = tvb_get_guint8(tvb, offset);
  offset++;
  while (anames_len > 0) {
    offset += xdmcp_add_string(anames_tree, hf_xdmcp_authorization_name,
			       tvb, offset);
    anames_len--;
  }
  proto_item_set_len(anames_ti, offset - anames_start_offset);
  return offset - anames_start_offset;
}
static void dissect_xdmcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
  gint version = -1, opcode = -1;
  gint offset = 0;
  proto_item *ti;
  proto_tree *xdmcp_tree = 0;

  version = tvb_get_ntohs(tvb, offset);
  if (version != XDMCP_PROTOCOL_VERSION) {
    /* Only version 1 exists, so this probably is not XDMCP at all... */
    return;
  }

  col_set_str(pinfo->cinfo, COL_PROTOCOL, "XDMCP");
  col_clear(pinfo->cinfo, COL_INFO);

  if (tree) {
    ti = proto_tree_add_item(tree, proto_xdmcp, tvb, offset, -1, FALSE);
    xdmcp_tree = proto_item_add_subtree(ti, ett_xdmcp);

    proto_tree_add_uint(xdmcp_tree, hf_xdmcp_version, tvb,
			offset, 2, version);
  }
  offset += 2;

  opcode = tvb_get_ntohs(tvb, offset);
  if (tree) {
    proto_tree_add_uint(xdmcp_tree, hf_xdmcp_opcode, tvb,
			offset, 2, opcode);
  }
  offset += 2;
  if (check_col(pinfo->cinfo, COL_INFO)) {
    col_add_str(pinfo->cinfo, COL_INFO, 
                 val_to_str(opcode, opcode_vals, "Unknown (0x%04x)"));

  }

  if (tree) {
    proto_tree_add_item(xdmcp_tree, hf_xdmcp_length, tvb,
			offset, 2, FALSE);
    offset += 2;

    switch (opcode) {
      case XDMCP_FORWARD_QUERY:
      {
	gint alen, plen;
	alen = tvb_get_ntohs(tvb, offset);
	/* I have never seen anything except IPv4 addresses here,
	 * but in theory the protocol should support other address
	 * families. */
	if (alen == 4) {
	  proto_tree_add_text(xdmcp_tree, tvb, offset, alen+2,
			      "Client address: %s",
			      ip_to_str(tvb_get_ptr(tvb, offset+2, 4)));
	  offset += 6;
	} else if (alen == 16) {
	  proto_tree_add_text(xdmcp_tree, tvb, offset, alen+2,
			      "Client address: %s",
			      ip6_to_str((const struct e_in6_addr *)tvb_get_ptr(tvb, offset+2, 16)));
	  offset += 18;
	} else {
	  offset += xdmcp_add_bytes(xdmcp_tree, "Client address", tvb, offset);
	}

	plen = tvb_get_ntohs(tvb, offset);
	if (plen == 2) {
	  proto_tree_add_text(xdmcp_tree, tvb, offset, plen+2,
			      "Client port: %u",
			      tvb_get_ntohs(tvb, offset+2));
	  offset += 4;
	} else {
	  offset += xdmcp_add_bytes(xdmcp_tree, "Client port", tvb, offset);
	}
      }
      /* fall-through */

      case XDMCP_BROADCAST_QUERY:
      case XDMCP_QUERY:
      case XDMCP_INDIRECT_QUERY:
	offset += xdmcp_add_authentication_names(xdmcp_tree, tvb, offset);
	break;

      case XDMCP_WILLING:
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_authentication_name,
				   tvb, offset);
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_hostname,
				   tvb, offset);
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_status,
				   tvb, offset);
	break;

      case XDMCP_UNWILLING:
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_hostname,
				   tvb, offset);
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_status,
				   tvb, offset);
	break;

      case XDMCP_REQUEST:
      {
	proto_tree *clist_tree;
	proto_item *clist_ti;
	gint ctypes_len, caddrs_len, n;
	gint ctypes_start_offset, caddrs_offset;

	proto_tree_add_item(xdmcp_tree, hf_xdmcp_display_number, tvb,
			    offset, 2, FALSE);
	offset += 2;

	ctypes_len = tvb_get_guint8(tvb, offset);
	ctypes_start_offset = offset;
	caddrs_offset = offset + 1 + 2*ctypes_len;
	caddrs_len = tvb_get_guint8(tvb, caddrs_offset);
	if (ctypes_len != caddrs_len) {
	  proto_tree_add_text(xdmcp_tree, NULL, 0, 0,
			      "Error: Connection type/address arrays don't match");
	  return;
	}

	clist_ti = proto_tree_add_text(xdmcp_tree,
				       tvb, ctypes_start_offset, -1,
				       "Connections (%d)",
				       ctypes_len);
	clist_tree = proto_item_add_subtree(clist_ti, ett_xdmcp_connections);

	offset++;
	caddrs_offset++;

	n = 1;
	while (ctypes_len > 0) {
	  proto_item *connection_ti;
	  proto_tree *connection_tree;
	  const char *ip_string;

	  gint alen;
	  gint ctype = tvb_get_ntohs(tvb, offset);
	  offset += 2;
	  alen = tvb_get_ntohs(tvb, caddrs_offset);
	  caddrs_offset += 2;

	  if ((ctype == 0) && (alen == 4)) {
	    ip_string = ip_to_str(tvb_get_ptr(tvb, caddrs_offset, 4));
	  } else if ((ctype == 6) && (alen == 16)) {
	    ip_string = ip6_to_str((const struct e_in6_addr *)tvb_get_ptr(tvb, caddrs_offset, 16));
	  } else {
	    ip_string = NULL;
	  }

	  connection_ti = proto_tree_add_text(clist_tree, NULL, 0, 0,
					      "Connection %d%s%s", n,
					      (ip_string ? ": " : ""),
					      (ip_string ? ip_string : ""));
	  connection_tree = proto_item_add_subtree(connection_ti,
						   ett_xdmcp_connection);

	  proto_tree_add_text(connection_tree, tvb, offset-2, 2,
			      "Type: %s",
			      val_to_str(ctype, family_vals,
					 "Unknown (0x%04x)"));
	  if (ip_string) {
	    proto_tree_add_text(connection_tree, tvb, caddrs_offset-2, alen+2,
				"Address: %s", ip_string);
	  } else {
	    proto_tree_add_text(connection_tree, tvb, caddrs_offset-2, alen+2,
				"Address: (%u byte%s)", alen,
				plurality(alen, "", "s"));
	  }
	  caddrs_offset += alen;
	  ctypes_len--;
	  n++;
	}
	offset = caddrs_offset;
	proto_item_set_len(clist_ti, offset - ctypes_start_offset);

	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_authentication_name,
				   tvb, offset);
	offset += xdmcp_add_bytes(xdmcp_tree, "Authentication data",
				  tvb, offset);

	offset += xdmcp_add_authorization_names(xdmcp_tree, tvb, offset);

	offset += xdmcp_add_text(xdmcp_tree, "Manufacturer display ID",
				 tvb, offset);
	break;
      }

      case XDMCP_ACCEPT:
	proto_tree_add_item(xdmcp_tree, hf_xdmcp_session_id, tvb,
			    offset, 4, FALSE);
	offset += 4;
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_authentication_name,
				   tvb, offset);
	offset += xdmcp_add_bytes(xdmcp_tree, "Authentication data",
				  tvb, offset);
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_authorization_name,
				   tvb, offset);
	offset += xdmcp_add_bytes(xdmcp_tree, "Authorization data",
				  tvb, offset);
	break;

      case XDMCP_DECLINE:
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_status,
				   tvb, offset);
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_authentication_name,
				   tvb, offset);
	offset += xdmcp_add_bytes(xdmcp_tree, "Authentication data",
				  tvb, offset);
	break;

      case XDMCP_MANAGE:
	proto_tree_add_item(xdmcp_tree, hf_xdmcp_session_id, tvb,
			    offset, 4, FALSE);
	offset += 4;

	proto_tree_add_item(xdmcp_tree, hf_xdmcp_display_number, tvb,
			    offset, 2, FALSE);
	offset += 2;

	offset += xdmcp_add_text(xdmcp_tree, "Display class",
				 tvb, offset);
	break;

      case XDMCP_REFUSE:
	proto_tree_add_item(xdmcp_tree, hf_xdmcp_session_id, tvb,
			    offset, 4, FALSE);
	offset += 4;
	break;

      case XDMCP_FAILED:
	proto_tree_add_item(xdmcp_tree, hf_xdmcp_session_id, tvb,
			    offset, 4, FALSE);
	offset += 4;

	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_status,
				   tvb, offset);
	break;

      case XDMCP_KEEPALIVE:
	proto_tree_add_item(xdmcp_tree, hf_xdmcp_display_number, tvb,
			    offset, 2, FALSE);
	offset += 2;

	proto_tree_add_item(xdmcp_tree, hf_xdmcp_session_id, tvb,
			    offset, 4, FALSE);
	offset += 4;
	break;

      case XDMCP_ALIVE:
	proto_tree_add_text(xdmcp_tree, tvb, offset, 1,
			    "Session running: %s",
			    (tvb_get_guint8(tvb, offset) ? "Yes" : "No"));
	offset++;

	proto_tree_add_item(xdmcp_tree, hf_xdmcp_session_id, tvb,
			    offset, 4, FALSE);
	offset += 4;
	break;
    }
  }
}
示例#3
0
static void dissect_xdmcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
  gint version = -1, opcode = -1;
  gint offset = 0;
  proto_item *ti;
  proto_tree *xdmcp_tree = 0;

  version = tvb_get_ntohs(tvb, offset);
  if (version != XDMCP_PROTOCOL_VERSION) {
    /* Only version 1 exists, so this probably is not XDMCP at all... */
    return;
  }

  col_set_str(pinfo->cinfo, COL_PROTOCOL, "XDMCP");
  col_clear(pinfo->cinfo, COL_INFO);

  ti = proto_tree_add_item(tree, proto_xdmcp, tvb, offset, -1, ENC_NA);
  xdmcp_tree = proto_item_add_subtree(ti, ett_xdmcp);

  proto_tree_add_uint(xdmcp_tree, hf_xdmcp_version, tvb,
			offset, 2, version);

  offset += 2;

  opcode = tvb_get_ntohs(tvb, offset);
  if (tree) {
    proto_tree_add_uint(xdmcp_tree, hf_xdmcp_opcode, tvb,
			offset, 2, opcode);
  }
  offset += 2;
  if (check_col(pinfo->cinfo, COL_INFO)) {
    col_add_str(pinfo->cinfo, COL_INFO,
                 val_to_str(opcode, opcode_vals, "Unknown (0x%04x)"));

  }

  if (tree) {
    proto_tree_add_item(xdmcp_tree, hf_xdmcp_length, tvb,
			offset, 2, ENC_BIG_ENDIAN);
    offset += 2;

    switch (opcode) {
      case XDMCP_FORWARD_QUERY:
      {
	gint alen, plen;
	alen = tvb_get_ntohs(tvb, offset);
	/* I have never seen anything except IPv4 addresses here,
	 * but in theory the protocol should support other address
	 * families. */
	if (alen == 4) {
      proto_tree_add_item(xdmcp_tree, hf_xdmcp_client_address_ipv4, tvb, offset+2, alen, ENC_BIG_ENDIAN);
	  offset += 6;
	} else if (alen == 16) {
      proto_tree_add_item(xdmcp_tree, hf_xdmcp_client_address_ipv6, tvb, offset+2, alen, ENC_BIG_ENDIAN);
	  offset += 18;
	} else {
	  offset += xdmcp_add_bytes(xdmcp_tree, hf_xdmcp_client_address_bytes, hf_xdmcp_client_address_bytes_len,
                                tvb, offset);
	}

	plen = tvb_get_ntohs(tvb, offset);
	if (plen == 2) {
      proto_tree_add_item(xdmcp_tree, hf_xdmcp_client_port_u16, tvb, offset+2, plen, ENC_BIG_ENDIAN);
	  offset += 4;
	} else {
	  offset += xdmcp_add_bytes(xdmcp_tree, hf_xdmcp_client_port_bytes, hf_xdmcp_client_port_len,
                    tvb, offset);
	}
      }
      /* fall-through */

      case XDMCP_BROADCAST_QUERY:
      case XDMCP_QUERY:
      case XDMCP_INDIRECT_QUERY:
	offset += xdmcp_add_authentication_names(xdmcp_tree, tvb, offset);
	break;

      case XDMCP_WILLING:
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_authentication_name,
				   tvb, offset);
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_hostname,
				   tvb, offset);
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_status,
				   tvb, offset);
	break;

      case XDMCP_UNWILLING:
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_hostname,
				   tvb, offset);
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_status,
				   tvb, offset);
	break;

      case XDMCP_REQUEST:
      {
	proto_tree *clist_tree;
	proto_item *clist_ti;
	gint ctypes_len, caddrs_len, n;
	gint ctypes_start_offset, caddrs_offset;

	ti = proto_tree_add_item(xdmcp_tree, hf_xdmcp_display_number, tvb,
			    offset, 2, ENC_BIG_ENDIAN);
	offset += 2;

	ctypes_len = tvb_get_guint8(tvb, offset);
	ctypes_start_offset = offset;
	caddrs_offset = offset + 1 + 2*ctypes_len;
	caddrs_len = tvb_get_guint8(tvb, caddrs_offset);
	if (ctypes_len != caddrs_len) {
        expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN, "Error: Connection type/address arrays don't match");
	  return;
	}

	clist_ti = proto_tree_add_text(xdmcp_tree,
				       tvb, ctypes_start_offset, -1,
				       "Connections (%d)",
				       ctypes_len);
	clist_tree = proto_item_add_subtree(clist_ti, ett_xdmcp_connections);

	offset++;
	caddrs_offset++;

	n = 1;
	while (ctypes_len > 0) {
	  proto_item *connection_ti;
	  proto_tree *connection_tree;

	  gint alen;
	  gint ctype = tvb_get_ntohs(tvb, offset);
	  offset += 2;
	  alen = tvb_get_ntohs(tvb, caddrs_offset);
	  caddrs_offset += 2;

	  connection_ti = proto_tree_add_text(clist_tree, NULL, 0, 0,
					      "Connection %d", n);
	  connection_tree = proto_item_add_subtree(connection_ti,
						   ett_xdmcp_connection);

      proto_tree_add_item(connection_tree, hf_xdmcp_connection_type, tvb, offset-2, 2, ENC_BIG_ENDIAN);

	  if ((ctype == 0) && (alen == 4)) {
          proto_tree_add_item(connection_tree, hf_xdmcp_connection_address_ipv4, tvb, caddrs_offset, alen, ENC_BIG_ENDIAN);
          proto_item_append_text(connection_ti, ": %s", tvb_ip_to_str(tvb, caddrs_offset));
      } else if ((ctype == 6) && (alen == 16)) {
          proto_tree_add_item(connection_tree, hf_xdmcp_connection_address_ipv6, tvb, caddrs_offset, alen, ENC_BIG_ENDIAN);
          proto_item_append_text(connection_ti, ": %s", tvb_ip6_to_str(tvb, caddrs_offset));
      } else {
          proto_tree_add_item(connection_tree, hf_xdmcp_connection_address_bytes, tvb, caddrs_offset, alen, ENC_NA);
      }

      caddrs_offset += alen;
	  ctypes_len--;
	  n++;
	}
	offset = caddrs_offset;
	proto_item_set_len(clist_ti, offset - ctypes_start_offset);

	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_authentication_name,
				   tvb, offset);
	offset += xdmcp_add_bytes(xdmcp_tree, hf_xdmcp_authentication_data, hf_xdmcp_authentication_data_len, 
				   tvb, offset);

	offset += xdmcp_add_authorization_names(xdmcp_tree, tvb, offset);

	offset += xdmcp_add_bytes(xdmcp_tree, hf_xdmcp_manufacturer_display_id, hf_xdmcp_manufacturer_display_id_len,
				 tvb, offset);
	break;
      }

      case XDMCP_ACCEPT:
	proto_tree_add_item(xdmcp_tree, hf_xdmcp_session_id, tvb,
			    offset, 4, ENC_BIG_ENDIAN);
	offset += 4;
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_authentication_name,
				   tvb, offset);
	offset += xdmcp_add_bytes(xdmcp_tree, hf_xdmcp_authentication_data, hf_xdmcp_authentication_data_len, 
				   tvb, offset);
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_authorization_name,
				   tvb, offset);
	offset += xdmcp_add_bytes(xdmcp_tree, hf_xdmcp_authorization_data, hf_xdmcp_authorization_data_len, 
				   tvb, offset);
	break;

      case XDMCP_DECLINE:
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_status,
				   tvb, offset);
	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_authentication_name,
				   tvb, offset);
	offset += xdmcp_add_bytes(xdmcp_tree, hf_xdmcp_authentication_data, hf_xdmcp_authentication_data_len, 
				   tvb, offset);
	break;

      case XDMCP_MANAGE:
	proto_tree_add_item(xdmcp_tree, hf_xdmcp_session_id, tvb,
			    offset, 4, ENC_BIG_ENDIAN);
	offset += 4;

	proto_tree_add_item(xdmcp_tree, hf_xdmcp_display_number, tvb,
			    offset, 2, ENC_BIG_ENDIAN);
	offset += 2;

	offset += xdmcp_add_bytes(xdmcp_tree, hf_xdmcp_display_class, hf_xdmcp_display_class_len,
				 tvb, offset);
	break;

      case XDMCP_REFUSE:
	proto_tree_add_item(xdmcp_tree, hf_xdmcp_session_id, tvb,
			    offset, 4, ENC_BIG_ENDIAN);
	offset += 4;
	break;

      case XDMCP_FAILED:
	proto_tree_add_item(xdmcp_tree, hf_xdmcp_session_id, tvb,
			    offset, 4, ENC_BIG_ENDIAN);
	offset += 4;

	offset += xdmcp_add_string(xdmcp_tree, hf_xdmcp_status,
				   tvb, offset);
	break;

      case XDMCP_KEEPALIVE:
	proto_tree_add_item(xdmcp_tree, hf_xdmcp_display_number, tvb,
			    offset, 2, ENC_BIG_ENDIAN);
	offset += 2;

	proto_tree_add_item(xdmcp_tree, hf_xdmcp_session_id, tvb,
			    offset, 4, ENC_BIG_ENDIAN);
	offset += 4;
	break;

      case XDMCP_ALIVE:
      {
    guint8 session_running = tvb_get_guint8(tvb, offset);
	proto_tree_add_uint_format(xdmcp_tree, hf_xdmcp_session_running, tvb,
			    offset, 1, session_running, "Session running: %s", session_running ? "Yes" : "No");
	offset++;

	proto_tree_add_item(xdmcp_tree, hf_xdmcp_session_id, tvb,
			    offset, 4, ENC_BIG_ENDIAN);
	offset += 4;
      }
	break;
    }
  }
}