Example #1
0
/*
 * RFC2428 states ....
 *
 *   The first two fields contained in the parenthesis MUST be blank. The
 *   third field MUST be the string representation of the TCP port number
 *   on which the server is listening for a data connection.
 *
 *   The network protocol used by the data connection will be the same network
 *   protocol used by the control connection. In addition, the network
 *   address used to establish the data connection will be the same
 *   network address used for the control connection.
 *
 *   An example response    string follows:
 *
 *       Entering Extended Passive Mode (|||6446|)
 *
 * ... which in fact means that again both address families IPv4 and IPv6
 * are supported. But gladly it's not necessary to parse because it doesn't
 * occur in EPSV responses. We can leverage ftp_ip_address which is
 * protocol independent and already set.
 *
 */
static gboolean
parse_extended_pasv_response(const guchar *line, gint linelen, guint16 *ftp_port,
        guint *pasv_offset, guint *ftp_port_len)
{
    gint       n;
    gchar     *args;
    gchar     *p;
    gchar     *e;
    guchar     c;
    gboolean   ret             = FALSE;
    gboolean   delimiters_seen = FALSE;

    /*
     * Copy the rest of the line into a null-terminated buffer.
     */
    args = wmem_strndup(wmem_packet_scope(), line, linelen);
    p = args;

    /*
     * Look for ( <d> <d> <d>
       (Try to cope with '(' in description)
     */
    for (; !delimiters_seen;) {
        guchar delimiter = '\0';
        while ((c = *p) != '\0' && (c != '('))
            p++;

        if (*p == '\0') {
            return FALSE;
        }

        /* Skip '(' */
        p++;

        /* Make sure same delimiter is used 3 times */
        for (n=0; n<3; n++) {
            if ((c = *p) != '\0') {
                if (delimiter == '\0' && isvalid_rfc2428_delimiter(c)) {
                    delimiter = c;
                }
                if (c != delimiter) {
                    break;
                }
            p++;
            }
            else {
                break;
            }
        }
        delimiters_seen = TRUE;
    }

    /*
     * Should now be at digits.
     */
    if (*p != '\0') {
        const gchar* endptr;
        gboolean port_valid;
        /*
         * We didn't run out of text without finding anything.
         */
        port_valid = ws_strtou16(p, &endptr, ftp_port);
        /* the conversion returned false, but the converted value could
           be valid instead, check it out */
        if (!port_valid && *endptr == '|')
            port_valid = TRUE;
        if (port_valid) {
            *pasv_offset = (guint32)(p - args);

            ret = TRUE;

            /* get port string length */
            if ((e=strchr(p,')')) == NULL) {
                ret = FALSE;
            }
            else {
                *ftp_port_len = (guint)(--e - p);
            }
        }
    }

    return ret;
}
Example #2
0
/*
 * RFC2428 states...
 *
 *     AF Number   Protocol
 *     ---------   --------
 *     1           Internet Protocol, Version 4
 *     2           Internet Protocol, Version 6
 *
 *     AF Number   Address Format      Example
 *     ---------   --------------      -------
 *     1           dotted decimal      132.235.1.2
 *     2           IPv6 string         1080::8:800:200C:417A
 *                 representations
 *                 defined in
 *
 *     The following are sample EPRT commands:
 *          EPRT |1|132.235.1.2|6275|
 *          EPRT |2|1080::8:800:200C:417A|5282|
 *
 *     The first command specifies that the server should use IPv4 to open a
 *     data connection to the host "132.235.1.2" on TCP port 6275.  The
 *     second command specifies that the server should use the IPv6 network
 *     protocol and the network address "1080::8:800:200C:417A" to open a
 *     TCP data connection on port 5282.
 *
 * ... which means in fact that RFC2428 is capable to handle both,
 * IPv4 and IPv6 so we have to care about the address family and properly
 * act depending on it.
 *
 */
static gboolean
parse_eprt_request(const guchar* line, gint linelen, guint32 *eprt_af,
        guint32 *eprt_ip, guint16 *eprt_ipv6, guint16 *ftp_port,
        guint32 *eprt_ip_len, guint32 *ftp_port_len)
{
    gint      delimiters_seen = 0;
    gchar     delimiter;
    gint      fieldlen;
    gchar    *field;
    gint      n;
    gint      lastn;
    char     *args, *p;
    gboolean  ret = TRUE;


    /* line contains the EPRT parameters, we need at least the 4 delimiters */
    if (!line || linelen<4)
        return FALSE;

    /* Copy the rest of the line into a null-terminated buffer. */
    args = wmem_strndup(wmem_packet_scope(), line, linelen);
    p = args;
    /*
     * Handle a NUL being in the line; if there's a NUL in the line,
     * strlen(args) will terminate at the NUL and will thus return
     * a value less than linelen.
     */
    if ((gint)strlen(args) < linelen)
        linelen = (gint)strlen(args);

    /*
     * RFC2428 sect. 2 states ...
     *
     *     The EPRT command keyword MUST be followed by a single space (ASCII
     *     32). Following the space, a delimiter character (<d>) MUST be
     *     specified.
     *
     * ... the preceding <space> is already stripped so we know that the first
     * character must be the delimiter and has just to be checked to be valid.
     */
    if (!isvalid_rfc2428_delimiter(*p))
        return FALSE;  /* EPRT command does not follow a vaild delimiter;
                        * malformed EPRT command - immediate escape */

    delimiter = *p;
    /* Validate that the delimiter occurs 4 times in the string */
    for (n = 0; n < linelen; n++) {
        if (*(p+n) == delimiter)
            delimiters_seen++;
    }
    if (delimiters_seen != 4)
        return FALSE; /* delimiter doesn't occur 4 times
                       * probably no EPRT request - immediate escape */

    /* we know that the first character is a delimiter... */
    delimiters_seen = 1;
    lastn = 0;
    /* ... so we can start searching from the 2nd onwards */
    for (n=1; n < linelen; n++) {

        if (*(p+n) != delimiter)
            continue;

        /* we found a delimiter */
        delimiters_seen++;

        fieldlen = n - lastn - 1;
        if (fieldlen<=0)
            return FALSE; /* all fields must have data in them */
        field =  p + lastn + 1;

        if (delimiters_seen == 2) {     /* end of address family field */
            gchar *af_str;
            af_str = wmem_strndup(wmem_packet_scope(), field, fieldlen);
            if (!ws_strtou32(af_str, NULL, eprt_af))
                return FALSE;
        }
        else if (delimiters_seen == 3) {/* end of IP address field */
            gchar *ip_str;
            ip_str = wmem_strndup(wmem_packet_scope(), field, fieldlen);

            if (*eprt_af == EPRT_AF_IPv4) {
                if (str_to_ip(ip_str, eprt_ip))
                   ret = TRUE;
                else
                   ret = FALSE;
            }
            else if (*eprt_af == EPRT_AF_IPv6) {
                if (str_to_ip6(ip_str, eprt_ipv6))
                   ret = TRUE;
                else
                   ret = FALSE;
            }
            else
                return FALSE; /* invalid/unknown address family */

            *eprt_ip_len = fieldlen;
        }
        else if (delimiters_seen == 4) {/* end of port field */
            gchar *pt_str;
            pt_str = wmem_strndup(wmem_packet_scope(), field, fieldlen);

            if (!ws_strtou16(pt_str, NULL, ftp_port))
                return FALSE;
            *ftp_port_len = fieldlen;
        }

        lastn = n;
    }

    return ret;
}
Example #3
0
int main(int argc, char **argv)
{
	int result;
	int option_idx = 0;
	char* remote_host = NULL;
	guint16 remote_port = 22;
	char* remote_username = NULL;
	char* remote_password = NULL;
	char* remote_interface = NULL;
	char* sshkey = NULL;
	char* sshkey_passphrase = NULL;
	char* remote_filter = NULL;
	guint32 count = 0;
	int ret = EXIT_FAILURE;
	extcap_parameters * extcap_conf = g_new0(extcap_parameters, 1);
	char* help_url;
	char* help_header = NULL;

#ifdef _WIN32
	WSADATA wsaData;

	attach_parent_console();
#endif  /* _WIN32 */

	help_url = data_file_url("ciscodump.html");
	extcap_base_set_util_info(extcap_conf, argv[0], CISCODUMP_VERSION_MAJOR, CISCODUMP_VERSION_MINOR,
		CISCODUMP_VERSION_RELEASE, help_url);
	g_free(help_url);
	extcap_base_register_interface(extcap_conf, CISCODUMP_EXTCAP_INTERFACE, "Cisco remote capture", 147, "Remote capture dependent DLT");

	help_header = g_strdup_printf(
		" %s --extcap-interfaces\n"
		" %s --extcap-interface=%s --extcap-dlts\n"
		" %s --extcap-interface=%s --extcap-config\n"
		" %s --extcap-interface=%s --remote-host myhost --remote-port 22222 "
		"--remote-username myuser --remote-interface gigabit0/0 "
		"--fifo=FILENAME --capture\n", argv[0], argv[0], CISCODUMP_EXTCAP_INTERFACE, argv[0],
		CISCODUMP_EXTCAP_INTERFACE, argv[0], CISCODUMP_EXTCAP_INTERFACE);
	extcap_help_add_header(extcap_conf, help_header);
	g_free(help_header);

	extcap_help_add_option(extcap_conf, "--help", "print this help");
	extcap_help_add_option(extcap_conf, "--version", "print the version");
	extcap_help_add_option(extcap_conf, "--remote-host <host>", "the remote SSH host");
	extcap_help_add_option(extcap_conf, "--remote-port <port>", "the remote SSH port (default: 22)");
	extcap_help_add_option(extcap_conf, "--remote-username <username>", "the remote SSH username (default: the current user)");
	extcap_help_add_option(extcap_conf, "--remote-password <password>", "the remote SSH password. "
		"If not specified, ssh-agent and ssh-key are used");
	extcap_help_add_option(extcap_conf, "--sshkey <public key path>", "the path of the ssh key");
	extcap_help_add_option(extcap_conf, "--sshkey-passphrase <public key passphrase>", "the passphrase to unlock public ssh");
	extcap_help_add_option(extcap_conf, "--remote-interface <iface>", "the remote capture interface");
	extcap_help_add_option(extcap_conf, "--remote-filter <filter>", "a filter for remote capture "
		"(default: don't capture data for lal interfaces IPs)");

	opterr = 0;
	optind = 0;

	if (argc == 1) {
		extcap_help_print(extcap_conf);
		goto end;
	}

	while ((result = getopt_long(argc, argv, ":", longopts, &option_idx)) != -1) {

		switch (result) {

		case OPT_HELP:
			extcap_help_print(extcap_conf);
			ret = EXIT_SUCCESS;
			goto end;

		case OPT_VERSION:
			printf("%s\n", extcap_conf->version);
			goto end;

		case OPT_REMOTE_HOST:
			g_free(remote_host);
			remote_host = g_strdup(optarg);
			break;

		case OPT_REMOTE_PORT:
			if (!ws_strtou16(optarg, NULL, &remote_port) || remote_port == 0) {
				g_warning("Invalid port: %s", optarg);
				goto end;
			}
			break;

		case OPT_REMOTE_USERNAME:
			g_free(remote_username);
			remote_username = g_strdup(optarg);
			break;

		case OPT_REMOTE_PASSWORD:
			g_free(remote_password);
			remote_password = g_strdup(optarg);
			memset(optarg, 'X', strlen(optarg));
			break;

		case OPT_SSHKEY:
			g_free(sshkey);
			sshkey = g_strdup(optarg);
			break;

		case OPT_SSHKEY_PASSPHRASE:
			g_free(sshkey_passphrase);
			sshkey_passphrase = g_strdup(optarg);
			memset(optarg, 'X', strlen(optarg));
			break;

		case OPT_REMOTE_INTERFACE:
			g_free(remote_interface);
			remote_interface = g_strdup(optarg);
			break;

		case OPT_REMOTE_FILTER:
			g_free(remote_filter);
			remote_filter = g_strdup(optarg);
			break;

		case OPT_REMOTE_COUNT:
			if (!ws_strtou32(optarg, NULL, &count)) {
				g_warning("Invalid packet count: %s", optarg);
				goto end;
			}
			break;

		case ':':
			/* missing option argument */
			g_warning("Option '%s' requires an argument", argv[optind - 1]);
			break;

		default:
			if (!extcap_base_parse_options(extcap_conf, result - EXTCAP_OPT_LIST_INTERFACES, optarg)) {
				g_warning("Invalid option: %s", argv[optind - 1]);
				goto end;
			}
		}
	}

	extcap_cmdline_debug(argv, argc);

	if (optind != argc) {
		g_warning("Unexpected extra option: %s", argv[optind]);
		goto end;
	}

	if (extcap_base_handle_interface(extcap_conf)) {
		ret = EXIT_SUCCESS;
		goto end;
	}

	if (extcap_conf->show_config) {
		ret = list_config(extcap_conf->interface, remote_port);
		goto end;
	}

#ifdef _WIN32
	result = WSAStartup(MAKEWORD(1,1), &wsaData);
	if (result != 0) {
		g_warning("ERROR: WSAStartup failed with error: %d", result);
		goto end;
	}
#endif  /* _WIN32 */

	if (extcap_conf->capture) {
		if (!remote_host) {
			g_warning("Missing parameter: --remote-host");
			goto end;
		}

		if (!remote_interface) {
			g_warning("ERROR: No interface specified (--remote-interface)");
			goto end;
		}
		if (count == 0) {
			g_warning("ERROR: count of packets must be specified (--remote-count)");
			goto end;
		}

		ret = ssh_open_remote_connection(remote_host, remote_port, remote_username,
			remote_password, sshkey, sshkey_passphrase, remote_interface,
			remote_filter, count, extcap_conf->fifo);
	} else {
		g_debug("You should not come here... maybe some parameter missing?");
		ret = EXIT_FAILURE;
	}

end:
	g_free(remote_host);
	g_free(remote_username);
	g_free(remote_password);
	g_free(remote_interface);
	g_free(sshkey);
	g_free(sshkey_passphrase);
	g_free(remote_filter);
	extcap_base_cleanup(&extcap_conf);
	return ret;
}
Example #4
0
int main(int argc, char *argv[])
{
	int option_idx = 0;
	int result;
	guint16 port = 0;
	int ret = EXIT_FAILURE;
	extcap_parameters* extcap_conf = g_new0(extcap_parameters, 1);
	char* help_url;
	char* help_header = NULL;
	char* payload = NULL;
	char* port_msg = NULL;
#ifdef _WIN32
	WSADATA wsaData;
	attach_parent_console();
#endif  /* _WIN32 */

	help_url = data_file_url("udpdump.html");
	extcap_base_set_util_info(extcap_conf, argv[0], UDPDUMP_VERSION_MAJOR, UDPDUMP_VERSION_MINOR, UDPDUMP_VERSION_RELEASE,
		help_url);
	g_free(help_url);
	extcap_base_register_interface(extcap_conf, UDPDUMP_EXTCAP_INTERFACE, "UDP Listener remote capture", 252, "Exported PDUs");

	help_header = g_strdup_printf(
		" %s --extcap-interfaces\n"
		" %s --extcap-interface=%s --extcap-dlts\n"
		" %s --extcap-interface=%s --extcap-config\n"
		" %s --extcap-interface=%s --port 5555 --fifo myfifo --capture",
		argv[0], argv[0], UDPDUMP_EXTCAP_INTERFACE, argv[0], UDPDUMP_EXTCAP_INTERFACE, argv[0], UDPDUMP_EXTCAP_INTERFACE);
	extcap_help_add_header(extcap_conf, help_header);
	g_free(help_header);
	extcap_help_add_option(extcap_conf, "--help", "print this help");
	extcap_help_add_option(extcap_conf, "--version", "print the version");
	port_msg = g_strdup_printf("the port to listens on. Default: %u", UDPDUMP_DEFAULT_PORT);
	extcap_help_add_option(extcap_conf, "--port <port>", port_msg);
	g_free(port_msg);

	opterr = 0;
	optind = 0;

	if (argc == 1) {
		extcap_help_print(extcap_conf);
		goto end;
	}

	while ((result = getopt_long(argc, argv, ":", longopts, &option_idx)) != -1) {
		switch (result) {

		case OPT_HELP:
			extcap_help_print(extcap_conf);
			ret = EXIT_SUCCESS;
			goto end;

		case OPT_VERSION:
			printf("%s\n", extcap_conf->version);
			goto end;

		case OPT_PORT:
			if (!ws_strtou16(optarg, NULL, &port)) {
				g_warning("Invalid port: %s", optarg);
				goto end;
			}
			break;

		case OPT_PAYLOAD:
			g_free(payload);
			payload = g_strdup(optarg);
			break;

		case ':':
			/* missing option argument */
			g_warning("Option '%s' requires an argument", argv[optind - 1]);
			break;

		default:
			if (!extcap_base_parse_options(extcap_conf, result - EXTCAP_OPT_LIST_INTERFACES, optarg)) {
				g_warning("Invalid option: %s", argv[optind - 1]);
				goto end;
			}
		}
	}

	extcap_cmdline_debug(argv, argc);

	if (optind != argc) {
		g_warning("Unexpected extra option: %s", argv[optind]);
		goto end;
	}

	if (extcap_base_handle_interface(extcap_conf)) {
		ret = EXIT_SUCCESS;
		goto end;
	}

	if (extcap_conf->show_config) {
		ret = list_config(extcap_conf->interface);
		goto end;
	}

	if (!payload)
		payload = g_strdup("data");

#ifdef _WIN32
	result = WSAStartup(MAKEWORD(1,1), &wsaData);
	if (result != 0) {
		g_warning("Error: WSAStartup failed with error: %d", result);
		goto end;
	}
#endif  /* _WIN32 */

	if (port == 0)
		port = UDPDUMP_DEFAULT_PORT;

	if (extcap_conf->capture)
		run_listener(extcap_conf->fifo, port, payload);

end:
	/* clean up stuff */
	extcap_base_cleanup(&extcap_conf);
	g_free(payload);
	return ret;
}
Example #5
0
int main(int argc, char *argv[])
{
	char* err_msg;
	int result;
	int option_idx = 0;
	ssh_params_t* ssh_params = ssh_params_new();
	char* remote_interface = NULL;
	char* remote_filter = NULL;
	guint32 count = 0;
	int ret = EXIT_FAILURE;
	extcap_parameters * extcap_conf = g_new0(extcap_parameters, 1);
	char* help_url;
	char* help_header = NULL;

	/*
	 * Get credential information for later use.
	 */
	init_process_policies();

	/*
	 * Attempt to get the pathname of the directory containing the
	 * executable file.
	 */
	err_msg = init_progfile_dir(argv[0]);
	if (err_msg != NULL) {
		g_warning("Can't get pathname of directory containing the captype program: %s.",
			err_msg);
		g_free(err_msg);
	}

	help_url = data_file_url("ciscodump.html");
	extcap_base_set_util_info(extcap_conf, argv[0], CISCODUMP_VERSION_MAJOR, CISCODUMP_VERSION_MINOR,
		CISCODUMP_VERSION_RELEASE, help_url);
	g_free(help_url);
	extcap_base_register_interface(extcap_conf, CISCODUMP_EXTCAP_INTERFACE, "Cisco remote capture", 147, "Remote capture dependent DLT");

	help_header = g_strdup_printf(
		" %s --extcap-interfaces\n"
		" %s --extcap-interface=%s --extcap-dlts\n"
		" %s --extcap-interface=%s --extcap-config\n"
		" %s --extcap-interface=%s --remote-host myhost --remote-port 22222 "
		"--remote-username myuser --remote-interface gigabit0/0 "
		"--fifo=FILENAME --capture\n", argv[0], argv[0], CISCODUMP_EXTCAP_INTERFACE, argv[0],
		CISCODUMP_EXTCAP_INTERFACE, argv[0], CISCODUMP_EXTCAP_INTERFACE);
	extcap_help_add_header(extcap_conf, help_header);
	g_free(help_header);

	extcap_help_add_option(extcap_conf, "--help", "print this help");
	extcap_help_add_option(extcap_conf, "--version", "print the version");
	extcap_help_add_option(extcap_conf, "--remote-host <host>", "the remote SSH host");
	extcap_help_add_option(extcap_conf, "--remote-port <port>", "the remote SSH port (default: 22)");
	extcap_help_add_option(extcap_conf, "--remote-username <username>", "the remote SSH username (default: the current user)");
	extcap_help_add_option(extcap_conf, "--remote-password <password>", "the remote SSH password. "
		"If not specified, ssh-agent and ssh-key are used");
	extcap_help_add_option(extcap_conf, "--sshkey <public key path>", "the path of the ssh key");
	extcap_help_add_option(extcap_conf, "--sshkey-passphrase <public key passphrase>", "the passphrase to unlock public ssh");
	extcap_help_add_option(extcap_conf, "--proxycommand <proxy command>", "the command to use as proxy the the ssh connection");
	extcap_help_add_option(extcap_conf, "--remote-interface <iface>", "the remote capture interface");
	extcap_help_add_option(extcap_conf, "--remote-filter <filter>", "a filter for remote capture "
		"(default: don't capture data for lal interfaces IPs)");

	opterr = 0;
	optind = 0;

	if (argc == 1) {
		extcap_help_print(extcap_conf);
		goto end;
	}

	while ((result = getopt_long(argc, argv, ":", longopts, &option_idx)) != -1) {

		switch (result) {

		case OPT_HELP:
			extcap_help_print(extcap_conf);
			ret = EXIT_SUCCESS;
			goto end;

		case OPT_VERSION:
			printf("%s\n", extcap_conf->version);
			goto end;

		case OPT_REMOTE_HOST:
			g_free(ssh_params->host);
			ssh_params->host = g_strdup(optarg);
			break;

		case OPT_REMOTE_PORT:
			if (!ws_strtou16(optarg, NULL, &ssh_params->port) || ssh_params->port == 0) {
				g_warning("Invalid port: %s", optarg);
				goto end;
			}
			break;

		case OPT_REMOTE_USERNAME:
			g_free(ssh_params->username);
			ssh_params->username = g_strdup(optarg);
			break;

		case OPT_REMOTE_PASSWORD:
			g_free(ssh_params->password);
			ssh_params->password = g_strdup(optarg);
			memset(optarg, 'X', strlen(optarg));
			break;

		case OPT_SSHKEY:
			g_free(ssh_params->sshkey_path);
			ssh_params->sshkey_path = g_strdup(optarg);
			break;

		case OPT_SSHKEY_PASSPHRASE:
			g_free(ssh_params->sshkey_passphrase);
			ssh_params->sshkey_passphrase = g_strdup(optarg);
			memset(optarg, 'X', strlen(optarg));
			break;

		case OPT_PROXYCOMMAND:
			g_free(ssh_params->proxycommand);
			ssh_params->proxycommand = g_strdup(optarg);
			break;

		case OPT_REMOTE_INTERFACE:
			g_free(remote_interface);
			remote_interface = g_strdup(optarg);
			break;

		case OPT_REMOTE_FILTER:
			g_free(remote_filter);
			remote_filter = g_strdup(optarg);
			break;

		case OPT_REMOTE_COUNT:
			if (!ws_strtou32(optarg, NULL, &count)) {
				g_warning("Invalid packet count: %s", optarg);
				goto end;
			}
			break;

		case ':':
			/* missing option argument */
			g_warning("Option '%s' requires an argument", argv[optind - 1]);
			break;

		default:
			if (!extcap_base_parse_options(extcap_conf, result - EXTCAP_OPT_LIST_INTERFACES, optarg)) {
				g_warning("Invalid option: %s", argv[optind - 1]);
				goto end;
			}
		}
	}

	extcap_cmdline_debug(argv, argc);

	if (optind != argc) {
		g_warning("Unexpected extra option: %s", argv[optind]);
		goto end;
	}

	if (extcap_base_handle_interface(extcap_conf)) {
		ret = EXIT_SUCCESS;
		goto end;
	}

	if (extcap_conf->show_config) {
		ret = list_config(extcap_conf->interface, ssh_params->port);
		goto end;
	}

	err_msg = ws_init_sockets();
	if (err_msg != NULL) {
		g_warning("ERROR: %s", err_msg);
                g_free(err_msg);
		g_warning("%s", please_report_bug());
		goto end;
	}

	if (extcap_conf->capture) {
		if (!ssh_params->host) {
			g_warning("Missing parameter: --remote-host");
			goto end;
		}

		if (!remote_interface) {
			g_warning("ERROR: No interface specified (--remote-interface)");
			goto end;
		}
		if (count == 0) {
			g_warning("ERROR: count of packets must be specified (--remote-count)");
			goto end;
		}
		ssh_params->debug = extcap_conf->debug;
		ret = ssh_open_remote_connection(ssh_params, remote_interface,
			remote_filter, count, extcap_conf->fifo);
	} else {
		g_debug("You should not come here... maybe some parameter missing?");
		ret = EXIT_FAILURE;
	}

end:
	ssh_params_free(ssh_params);
	g_free(remote_interface);
	g_free(remote_filter);
	extcap_base_cleanup(&extcap_conf);
	return ret;
}
static void
dissect_quakeworld_ConnectionlessPacket(tvbuff_t *tvb, packet_info *pinfo,
	proto_tree *tree, int direction)
{
	proto_tree	*cl_tree;
	proto_tree	*text_tree = NULL;
	proto_item	*pi = NULL;
	guint8		*text;
	int		len;
	int		offset;
	guint32		marker;
	int		command_len;
	const char	*command = "";
	gboolean	command_finished = FALSE;

	marker = tvb_get_ntohl(tvb, 0);
	cl_tree = proto_tree_add_subtree(tree, tvb, 0, -1, ett_quakeworld_connectionless, NULL, "Connectionless");

	proto_tree_add_uint(cl_tree, hf_quakeworld_connectionless_marker,
				tvb, 0, 4, marker);

	/* all the rest of the packet is just text */
	offset = 4;

	text = tvb_get_stringz_enc(wmem_packet_scope(), tvb, offset, &len, ENC_ASCII|ENC_NA);
	/* actually, we should look for a eol char and stop already there */

	if (cl_tree) {
		proto_item *text_item;
		text_item = proto_tree_add_string(cl_tree, hf_quakeworld_connectionless_text,
						  tvb, offset, len, text);
		text_tree = proto_item_add_subtree(text_item, ett_quakeworld_connectionless_text);
	}

	if (direction == DIR_C2S) {
		/* client to server commands */
		const char *c;

		Cmd_TokenizeString(text, len);
		c = Cmd_Argv(0);

		/* client to sever commands */
		if (strcmp(c,"ping") == 0) {
			command = "Ping";
			command_len = 4;
		} else if (strcmp(c,"status") == 0) {
			command = "Status";
			command_len = 6;
		} else if (strcmp(c,"log") == 0) {
			command = "Log";
			command_len = 3;
		} else if (strcmp(c,"connect") == 0) {
			guint32 version = 0;
			guint16 qport = 0;
			guint32 challenge = 0;
			gboolean version_valid = TRUE;
			gboolean qport_valid = TRUE;
			gboolean challenge_valid = TRUE;
			const char *infostring;
			proto_tree *argument_tree = NULL;
			command = "Connect";
			command_len = Cmd_Argv_length(0);
			if (text_tree) {
				proto_item *argument_item;
				pi = proto_tree_add_string(text_tree, hf_quakeworld_connectionless_command,
					tvb, offset, command_len, command);
				argument_item = proto_tree_add_string(text_tree,
					hf_quakeworld_connectionless_arguments,
					tvb, offset + Cmd_Argv_start(1), len + 1 - Cmd_Argv_start(1),
					text + Cmd_Argv_start(1));
				argument_tree = proto_item_add_subtree(argument_item,
								       ett_quakeworld_connectionless_arguments);
				command_finished=TRUE;
			}
			version_valid = ws_strtou32(Cmd_Argv(1), NULL, &version);
			qport_valid = ws_strtou16(Cmd_Argv(2), NULL, &qport);
			challenge_valid = ws_strtou32(Cmd_Argv(3), NULL, &challenge);
			infostring = Cmd_Argv(4);

			if (text_tree && (!version_valid || !qport_valid || !challenge_valid))
				expert_add_info(pinfo, pi, &ei_quakeworld_connectionless_command_invalid);

			if (argument_tree) {
				proto_item *info_item;
				proto_tree *info_tree;
				proto_tree_add_uint(argument_tree,
					hf_quakeworld_connectionless_connect_version,
					tvb,
					offset + Cmd_Argv_start(1),
					Cmd_Argv_length(1), version);
				proto_tree_add_uint(argument_tree,
					hf_quakeworld_connectionless_connect_qport,
					tvb,
					offset + Cmd_Argv_start(2),
					Cmd_Argv_length(2), qport);
				proto_tree_add_int(argument_tree,
					hf_quakeworld_connectionless_connect_challenge,
					tvb,
					offset + Cmd_Argv_start(3),
					Cmd_Argv_length(3), challenge);
				info_item = proto_tree_add_string(argument_tree,
					hf_quakeworld_connectionless_connect_infostring,
					tvb,
					offset + Cmd_Argv_start(4),
					Cmd_Argv_length(4), infostring);
				info_tree = proto_item_add_subtree(
					info_item, ett_quakeworld_connectionless_connect_infostring);
				dissect_id_infostring(tvb, info_tree, offset + Cmd_Argv_start(4),
					wmem_strdup(wmem_packet_scope(), infostring),
					ett_quakeworld_connectionless_connect_infostring_key_value,
					hf_quakeworld_connectionless_connect_infostring_key_value,
					hf_quakeworld_connectionless_connect_infostring_key,
					hf_quakeworld_connectionless_connect_infostring_value);
			}
		} else if (strcmp(c,"getchallenge") == 0) {
			command = "Get Challenge";
			command_len = Cmd_Argv_length(0);
		} else if (strcmp(c,"rcon") == 0) {
			const char* password;
			int i;
			char remaining[MAX_TEXT_SIZE+1];
			proto_tree *argument_tree = NULL;
			command = "Remote Command";
			command_len = Cmd_Argv_length(0);
			if (text_tree) {
				proto_item *argument_item;
				proto_tree_add_string(text_tree, hf_quakeworld_connectionless_command,
					tvb, offset, command_len, command);
				argument_item = proto_tree_add_string(text_tree,
					hf_quakeworld_connectionless_arguments,
					tvb, offset + Cmd_Argv_start(1), len - Cmd_Argv_start(1),
					text + Cmd_Argv_start(1));
				argument_tree =	proto_item_add_subtree(argument_item,
								       ett_quakeworld_connectionless_arguments);
				command_finished=TRUE;
			}
			password = Cmd_Argv(1);
			if (argument_tree) {
				proto_tree_add_string(argument_tree,
					hf_quakeworld_connectionless_rcon_password,
					tvb,
					offset + Cmd_Argv_start(1),
					Cmd_Argv_length(1), password);
			}
			remaining[0] = '\0';
			for (i=2; i<Cmd_Argc() ; i++) {
				g_strlcat (remaining, Cmd_Argv(i), MAX_TEXT_SIZE+1);
				g_strlcat (remaining, " ", MAX_TEXT_SIZE+1);
			}
			if (text_tree) {
				proto_tree_add_string(argument_tree,
					hf_quakeworld_connectionless_rcon_command,
					tvb, offset + Cmd_Argv_start(2),
					Cmd_Argv_start(Cmd_Argc()-1) + Cmd_Argv_length(Cmd_Argc()-1) -
					Cmd_Argv_start(2),
					remaining);
			}
		} else if (c[0]==A2A_PING && ( c[1]=='\0' || c[1]=='\n')) {
			command = "Ping";
			command_len = 1;
		} else if (c[0]==A2A_ACK && ( c[1]=='\0' || c[1]=='\n')) {
			command = "Ack";
			command_len = 1;
		} else {
			command = "Unknown";
			command_len = len - 1;
		}
	}
	else {
		/* server to client commands */
		if (text[0] == S2C_CONNECTION) {
			command = "Connected";
			command_len = 1;
		} else if (text[0] == A2C_CLIENT_COMMAND) {
			command = "Client Command";
			command_len = 1;
			/* stringz (command), stringz (localid) */
		} else if (text[0] == A2C_PRINT) {
			command = "Print";
			command_len = 1;
			/* string */
		} else if (text[0] == A2A_PING) {
			command = "Ping";
			command_len = 1;
		} else if (text[0] == S2C_CHALLENGE) {
			command = "Challenge";
			command_len = 1;
			/* string, conversion */
		} else {
			command = "Unknown";
			command_len = len - 1;
		}
	}

	col_append_fstr(pinfo->cinfo, COL_INFO, " %s", command);

	if (!command_finished) {
		proto_tree_add_string(text_tree, hf_quakeworld_connectionless_command,
			tvb, offset, command_len, command);
	}
	/*offset += len;*/
}