forked from osmocom/wireshark
extcap: add ciscodump.
Ciscodump is a new extcap that allows packet capture on Cisco routers (IOS 12.4 and later) through SSH. Change-Id: Ic9c5be01d3bd0112116f7fc9fa10e26c1552b007 Reviewed-on: https://code.wireshark.org/review/13886 Reviewed-by: Roland Knall <rknall@gmail.com>
This commit is contained in:
parent
2e98866171
commit
a6921c79ab
|
@ -1218,7 +1218,7 @@ endforeach()
|
|||
include(FeatureSummary)
|
||||
#SET_FEATURE_INFO(NAME DESCRIPTION [URL [COMMENT] ])
|
||||
SET_FEATURE_INFO(SBC "SBC Codec for Bluetooth A2DP stream playing" "www: http://git.kernel.org/cgit/bluetooth/sbc.git" )
|
||||
SET_FEATURE_INFO(LIBSSH "libssh is library for ssh connections and it is needed to build sshdump" "www: https://www.libssh.org/get-it/" )
|
||||
SET_FEATURE_INFO(LIBSSH "libssh is library for ssh connections and it is needed to build sshdump/ciscodump" "www: https://www.libssh.org/get-it/" )
|
||||
|
||||
FEATURE_SUMMARY(WHAT ALL)
|
||||
|
||||
|
@ -2374,6 +2374,32 @@ elseif (BUILD_sshdump)
|
|||
#message( WARNING "Cannot find libssh, cannot build sshdump" )
|
||||
endif()
|
||||
|
||||
if(ENABLE_EXTCAP AND BUILD_ciscodump AND LIBSSH_FOUND)
|
||||
set(ciscodump_LIBS
|
||||
wsutil
|
||||
${GLIB2_LIBRARIES}
|
||||
${CMAKE_DL_LIBS}
|
||||
${LIBSSH_LIBRARIES}
|
||||
)
|
||||
if (WIN32)
|
||||
set(ciscodump_LIBS wsutil ${ciscodump_LIBS})
|
||||
endif()
|
||||
set(ciscodump_FILES
|
||||
extcap/ciscodump.c
|
||||
extcap/extcap-base.c
|
||||
extcap/ssh-base.c
|
||||
pcapio.c
|
||||
)
|
||||
|
||||
add_executable(ciscodump WIN32 ${ciscodump_FILES})
|
||||
set_extcap_executable_properties(ciscodump)
|
||||
target_link_libraries(ciscodump ${ciscodump_LIBS})
|
||||
target_include_directories(ciscodump PUBLIC ${LIBSSH_INCLUDE_DIR})
|
||||
install(TARGETS ciscodump RUNTIME DESTINATION ${EXTCAP_DIR})
|
||||
elseif (BUILD_ciscodump)
|
||||
#message( WARNING "Cannot find libssh, cannot build ciscodump" )
|
||||
endif()
|
||||
|
||||
if(ENABLE_EXTCAP AND BUILD_randpktdump)
|
||||
set(randpktdump_LIBS
|
||||
randpkt_core
|
||||
|
@ -2464,6 +2490,7 @@ set(CLEAN_FILES
|
|||
${dumpcap_FILES}
|
||||
${androiddump_FILES}
|
||||
${sshdump_FILES}
|
||||
${ciscodump_FILES}
|
||||
)
|
||||
|
||||
if (WERROR_COMMON_FLAGS)
|
||||
|
|
|
@ -16,6 +16,7 @@ option(BUILD_randpkt "Build randpkt" ON)
|
|||
option(BUILD_dftest "Build dftest" ON)
|
||||
option(BUILD_androiddump "Build androiddump" ON)
|
||||
option(BUILD_sshdump "Build sshdump" ON)
|
||||
option(BUILD_ciscodump "Build ciscodump" ON)
|
||||
option(BUILD_randpktdump "Build randpktdump" ON)
|
||||
option(AUTOGEN_dcerpc "Autogenerate DCE RPC dissectors" OFF)
|
||||
option(AUTOGEN_pidl "Autogenerate pidl dissectors" OFF)
|
||||
|
|
|
@ -416,7 +416,7 @@ GNUTLS_PKG=3.2.15-2.7
|
|||
GPGERROR_DLL=libgpg-error-0.dll
|
||||
GCC_DLL=libgcc_s_sjlj-1.dll
|
||||
|
||||
# Optional: libssh library is required for sshdump support
|
||||
# Optional: libssh library is required for sshdump and ciscodump support
|
||||
#
|
||||
# If you don't have libssh, comment this line out so that LIBSSH_DIR
|
||||
# isn't defined.
|
||||
|
|
57
configure.ac
57
configure.ac
|
@ -3016,13 +3016,16 @@ dnl sshdump check
|
|||
AC_MSG_CHECKING(whether to build sshdump)
|
||||
|
||||
AC_ARG_ENABLE(sshdump,
|
||||
AC_HELP_STRING( [--enable-sshdump],
|
||||
[build sshdump @<:@default=yes@:>@]),
|
||||
sshdump=$enableval,enable_sshdump=yes)
|
||||
AC_HELP_STRING( [--enable-sshdump],
|
||||
[build sshdump @<:@default=yes@:>@]),
|
||||
[],[enable_sshdump=yes])
|
||||
|
||||
if test "x$have_extcap" != xyes; then
|
||||
AC_MSG_RESULT(no, extcap disabled)
|
||||
enable_sshdump=no
|
||||
elif test "x$have_good_libssh" != xyes; then
|
||||
AC_MSG_RESULT(no, libssh not available)
|
||||
enable_sshdump=no
|
||||
elif test "x$enable_sshdump" = "xyes" ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
|
@ -3030,15 +3033,8 @@ else
|
|||
fi
|
||||
|
||||
if test "x$enable_sshdump" = "xyes" ; then
|
||||
if test "x$have_good_libssh" = "xyes" ; then
|
||||
sshdump_bin="sshdump\$(EXEEXT)"
|
||||
sshdump_man="sshdump.1"
|
||||
else
|
||||
echo "Can't find libssh. Disabling sshdump."
|
||||
enable_sshdump=no
|
||||
sshdump_bin=""
|
||||
sshdump_man=""
|
||||
fi
|
||||
sshdump_bin="sshdump\$(EXEEXT)"
|
||||
sshdump_man="sshdump.1"
|
||||
else
|
||||
sshdump_bin=""
|
||||
sshdump_man=""
|
||||
|
@ -3046,13 +3042,43 @@ fi
|
|||
AC_SUBST(sshdump_bin)
|
||||
AC_SUBST(sshdump_man)
|
||||
|
||||
dnl ciscodump check
|
||||
AC_MSG_CHECKING(whether to build ciscodump)
|
||||
|
||||
AC_ARG_ENABLE(ciscodump,
|
||||
AC_HELP_STRING( [--enable-ciscodump],
|
||||
[build ciscodump @<:@default=yes@:>@]),
|
||||
[],[enable_ciscodump=yes])
|
||||
|
||||
if test "x$have_extcap" != xyes; then
|
||||
AC_MSG_RESULT(no, extcap disabled)
|
||||
enable_ciscodump=no
|
||||
elif test "x$have_good_libssh" != xyes; then
|
||||
AC_MSG_RESULT(no, libssh not available)
|
||||
enable_ciscodump=no
|
||||
elif test "x$enable_ciscodump" = "xyes" ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
if test "x$enable_ciscodump" = "xyes" ; then
|
||||
ciscodump_bin="ciscodump\$(EXEEXT)"
|
||||
ciscodump_man="ciscodump.1"
|
||||
else
|
||||
ciscodump_bin=""
|
||||
ciscodump_man=""
|
||||
fi
|
||||
AC_SUBST(ciscodump_bin)
|
||||
AC_SUBST(ciscodump_man)
|
||||
|
||||
dnl randpktdump check
|
||||
AC_MSG_CHECKING(whether to build randpktdump)
|
||||
|
||||
AC_ARG_ENABLE(randpktdump,
|
||||
AC_HELP_STRING( [--enable-randpktdump],
|
||||
[build androiddump @<:@default=yes@:>@]),
|
||||
randpktdump=$enableval,enable_randpktdump=yes)
|
||||
AC_HELP_STRING( [--enable-randpktdump],
|
||||
[build androiddump @<:@default=yes@:>@]),
|
||||
randpktdump=$enableval,enable_randpktdump=yes)
|
||||
|
||||
if test "x$have_extcap" != xyes; then
|
||||
AC_MSG_RESULT(no, extcap disabled)
|
||||
|
@ -3443,6 +3469,7 @@ echo " Build dftest : $enable_dftest"
|
|||
echo " Build rawshark : $enable_rawshark"
|
||||
echo " Build androiddump : $enable_androiddump"
|
||||
echo " Build sshdump : $enable_sshdump"
|
||||
echo " Build ciscodump : $enable_ciscodump"
|
||||
echo " Build randpktdump : $enable_randpktdump"
|
||||
echo " Build echld : $have_echld"
|
||||
echo ""
|
||||
|
|
|
@ -84,6 +84,7 @@ pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/randpktdump 1)
|
|||
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/rawshark 1)
|
||||
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/reordercap 1)
|
||||
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/sshdump 1)
|
||||
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/ciscodump 1)
|
||||
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/text2pcap 1)
|
||||
pod2manhtml(${CMAKE_CURRENT_SOURCE_DIR}/tshark 1)
|
||||
pod2manhtml(${CMAKE_CURRENT_BINARY_DIR}/wireshark 1)
|
||||
|
@ -107,6 +108,7 @@ set(MAN1_INSTALL_FILES
|
|||
${CMAKE_CURRENT_BINARY_DIR}/rawshark.1
|
||||
${CMAKE_CURRENT_BINARY_DIR}/reordercap.1
|
||||
${CMAKE_CURRENT_BINARY_DIR}/sshdump.1
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ciscodump.1
|
||||
${CMAKE_CURRENT_BINARY_DIR}/text2pcap.1
|
||||
${CMAKE_CURRENT_BINARY_DIR}/tshark.1
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wireshark.1
|
||||
|
@ -134,6 +136,7 @@ set(HTML_INSTALL_FILES
|
|||
${CMAKE_CURRENT_BINARY_DIR}/rawshark.html
|
||||
${CMAKE_CURRENT_BINARY_DIR}/reordercap.html
|
||||
${CMAKE_CURRENT_BINARY_DIR}/sshdump.html
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ciscodump.html
|
||||
${CMAKE_CURRENT_BINARY_DIR}/text2pcap.html
|
||||
${CMAKE_CURRENT_BINARY_DIR}/tshark.html
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wireshark.html
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
|
||||
=head1 NAME
|
||||
|
||||
ciscodump - Provide interfaces to capture from a remote Cisco router through SSH.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<ciscodump>
|
||||
S<[ B<--help> ]>
|
||||
S<[ B<--version> ]>
|
||||
S<[ B<--extcap-interfaces> ]>
|
||||
S<[ B<--extcap-dlts> ]>
|
||||
S<[ B<--extcap-interface>=E<lt>interfaceE<gt> ]>
|
||||
S<[ B<--extcap-config> ]>
|
||||
S<[ B<--extcap-capture-filter>=E<lt>capture filterE<gt> ]>
|
||||
S<[ B<--capture> ]>
|
||||
S<[ B<--fifo>=E<lt>path to file or pipeE<gt> ]>
|
||||
S<[ B<--remote-host>=E<lt>IP addressE<gt> ]>
|
||||
S<[ B<--remote-port>=E<lt>TCP portE<gt> ]>
|
||||
S<[ B<--remote-username>=E<lt>usernameE<gt> ]>
|
||||
S<[ B<--remote-password>=E<lt>passwordE<gt> ]>
|
||||
S<[ B<--remote-filter>=E<lt>filter<gt> ]>
|
||||
S<[ B<--sshkey>=E<lt>public key path<gt> ]>
|
||||
S<[ B<--remote-interface>=E<lt>interfaceE<gt> ]>
|
||||
|
||||
|
||||
B<ciscodump>
|
||||
S<B<--extcap-interfaces>>
|
||||
|
||||
B<ciscodump>
|
||||
S<B<--extcap-interface>=E<lt>interfaceE<gt>>
|
||||
S<B<--extcap-dlts>>
|
||||
|
||||
B<ciscodump>
|
||||
S<B<--extcap-interface>=E<lt>interfaceE<gt>>
|
||||
S<B<--extcap-config>>
|
||||
|
||||
B<ciscodump>
|
||||
S<B<--extcap-interface>=E<lt>interfaceE<gt>>
|
||||
S<B<--fifo>=E<lt>path to file or pipeE<gt>>
|
||||
S<B<--capture>>
|
||||
S<B<--remote-host=remoterouter>>
|
||||
S<B<--remote-port=22>>
|
||||
S<B<--remote-username=user>>
|
||||
S<B<--remote-interface>=E<lt>the router interfaceE<gt>>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<ciscodump> is an extcap tool that relys on Cisco EPC to allow a user to run a remote capture
|
||||
on a Cisco router in a SSH connection. The minimum IOS version supporting this feature is 12.4(20)T. More details can be
|
||||
found here:
|
||||
http://www.cisco.com/c/en/us/products/collateral/ios-nx-os-software/ios-embedded-packet-capture/datasheet_c78-502727.html
|
||||
|
||||
Supported interfaces:
|
||||
|
||||
=over 4
|
||||
|
||||
=item 1. cisco
|
||||
|
||||
=back
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item --help
|
||||
|
||||
Print program arguments.
|
||||
|
||||
=item --version
|
||||
|
||||
Print program version.
|
||||
|
||||
=item --extcap-interfaces
|
||||
|
||||
List available interfaces.
|
||||
|
||||
=item --extcap-interface=E<lt>interfaceE<gt>
|
||||
|
||||
Use specified interfaces.
|
||||
|
||||
=item --extcap-dlts
|
||||
|
||||
List DLTs of specified interface.
|
||||
|
||||
=item --extcap-config
|
||||
|
||||
List configuration options of specified interface.
|
||||
|
||||
=item --capture
|
||||
|
||||
Start capturing from specified interface and save it in place specified by --fifo.
|
||||
|
||||
=item --fifo=E<lt>path to file or pipeE<gt>
|
||||
|
||||
Save captured packet to file or send it through pipe.
|
||||
|
||||
=item --remote-host=E<lt>remote hostE<gt>
|
||||
|
||||
The address of the remote host for capture.
|
||||
|
||||
=item --remote-port=E<lt>remote portE<gt>
|
||||
|
||||
The SSH port of the remote host.
|
||||
|
||||
=item --remote-username=E<lt>usernameE<gt>
|
||||
|
||||
The username for ssh authentication.
|
||||
|
||||
=item --remote-password=E<lt>passwordE<gt>
|
||||
|
||||
The password to use (if not ssh-agent and pubkey are used). WARNING: the
|
||||
passwords are stored in plaintext and visible to all users on this system. It is
|
||||
recommended to use keyfiles with a SSH agent.
|
||||
|
||||
=item --remote-filter=E<lt>filterE<gt>
|
||||
|
||||
The remote filter on the router. This is a capture filter that follows the Cisco IOS standards (http://www.cisco.com/c/en/us/support/docs/ip/access-lists/26448-ACLsamples.html). Multiple filters can be specified using a comma between them. BEWARE: when using a filter, the default behavior is to drop all the packets except the ones that fall into the filter.
|
||||
|
||||
Examples:
|
||||
|
||||
permit ip host MYHOST any, permit ip any host MYHOST (capture the traffic for MYHOST)
|
||||
|
||||
deny ip host MYHOST any, deny ip any host MYHOST, permit ip any any (capture all the traffic except MYHOST)
|
||||
|
||||
=item --sshkey=E<lt>SSH private key pathE<gt>
|
||||
|
||||
The path to a private key for authentication.
|
||||
|
||||
=item --remote-interface=E<lt>remote interfaceE<gt>
|
||||
|
||||
The remote network interface to capture from.
|
||||
|
||||
=item --extcap-capture-filter=E<lt>capture filterE<gt>
|
||||
|
||||
Unused (compatibility only).
|
||||
|
||||
=back
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
To see program arguments:
|
||||
|
||||
ciscodump --help
|
||||
|
||||
To see program version:
|
||||
|
||||
ciscodump --version
|
||||
|
||||
To see interfaces:
|
||||
|
||||
ciscodump --extcap-interfaces
|
||||
|
||||
Only one interface (cisco) is supported.
|
||||
|
||||
Output:
|
||||
interface {value=cisco}{display=SSH remote capture}
|
||||
|
||||
To see interface DLTs:
|
||||
|
||||
ciscodump --extcap-interface=cisco --extcap-dlts
|
||||
|
||||
Output:
|
||||
dlt {number=147}{name=cisco}{display=Remote capture dependant DLT}
|
||||
|
||||
To see interface configuration options:
|
||||
|
||||
ciscodump --extcap-interface=cisco --extcap-config
|
||||
|
||||
Output:
|
||||
ciscodump --extcap-interface=cisco --extcap-config
|
||||
arg {number=0}{call=--remote-host}{display=Remote SSH server address}
|
||||
{type=string}{tooltip=The remote SSH host. It can be both an IP address or a hostname}
|
||||
{required=true}
|
||||
arg {number=1}{call=--remote-port}{display=Remote SSH server port}{type=unsigned}
|
||||
{default=22}{tooltip=The remote SSH host port (1-65535)}{range=1,65535}
|
||||
arg {number=2}{call=--remote-username}{display=Remote SSH server username}{type=string}
|
||||
{default=<current user>}{tooltip=The remote SSH username. If not provided, the current
|
||||
user will be used}
|
||||
arg {number=3}{call=--remote-password}{display=Remote SSH server password}{type=string}
|
||||
{tooltip=The SSH password, used when other methods (SSH agent or key files) are unavailable.}
|
||||
arg {number=4}{call=--sshkey}{display=Path to SSH private key}{type=fileselect}
|
||||
{tooltip=The path on the local filesystem of the private ssh key}
|
||||
arg {number=5}{call--sshkey-passphrase}{display=SSH key passphrase}
|
||||
{type=string}{tooltip=Passphrase to unlock the SSH private key}
|
||||
arg {number=6}{call=--remote-interface}{display=Remote interface}{type=string}
|
||||
{required=true}{tooltip=The remote network interface used for capture}
|
||||
arg {number=7}{call=--remote-filter}{display=Remote capture filter}{type=string}
|
||||
{default=(null)}{tooltip=The remote capture filter}
|
||||
arg {number=8}{call=--remote-count}{display=Packets to capture}{type=unsigned}{required=true}
|
||||
{tooltip=The number of remote packets to capture.}
|
||||
|
||||
|
||||
To capture:
|
||||
|
||||
ciscodump --extcap-interface cisco --fifo=/tmp/cisco.pcap --capture --remote-host 192.168.1.10
|
||||
--remote-username user --remote-interface gigabit0/0
|
||||
--remote-filter "permit ip host 192.168.1.1 any, permit ip any host 192.168.1.1"
|
||||
|
||||
NOTE: Packet count is mandatory, hence the capture will start after this number.
|
||||
|
||||
=head1 KNOWN ISSUES
|
||||
|
||||
The configuration of the capture on the routers is a multi-step process. If the SSH connection is interrupted during
|
||||
it, the configuration can be in an inconsistent state. That can happen also if the capture is stopped and ciscodump
|
||||
can't clean the configuration up. In this case it is necessary to log into the router and manually clean the
|
||||
configuration, removing both the capture point (WIRESHARK_CAPTURE_POINT), the capture buffer (WIRESHARK_CAPTURE_BUFFER)
|
||||
and the capture filter (WIRESHARK_CAPTURE_FILTER).
|
||||
|
||||
Another known issues is related to the number of captured packets (--remote-count). Due to the nature of the capture
|
||||
buffer, ciscodump waits for the capture to complete and then issues the command to show it. It means that if the user
|
||||
specifies a number of packets above the currently captured, the show command is never shown. Not only is the count of
|
||||
the maximum number of captured packets, but it is also the _exact_ number of expected packets.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
wireshark(1), tshark(1), dumpcap(1), extcap(4), sshdump(1)
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
B<ciscodump> is part of the B<Wireshark> distribution. The latest version
|
||||
of B<Wireshark> can be found at L<https://www.wireshark.org>.
|
||||
|
||||
HTML versions of the Wireshark project man pages are available at:
|
||||
L<https://www.wireshark.org/docs/man-pages>.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Original Author
|
||||
-------- ------
|
||||
Dario Lombardo <lomato[AT]gmail.com>
|
|
@ -34,9 +34,10 @@ EXTRA_DIST = \
|
|||
extcap_PROGRAMS = \
|
||||
@androiddump_bin@ \
|
||||
@randpktdump_bin@ \
|
||||
@sshdump_bin@
|
||||
@sshdump_bin@ \
|
||||
@ciscodump_bin@
|
||||
|
||||
EXTRA_PROGRAMS = androiddump randpktdump sshdump
|
||||
EXTRA_PROGRAMS = androiddump randpktdump sshdump ciscodump
|
||||
|
||||
if ENABLE_STATIC
|
||||
androiddump_LDFLAGS = -Wl,-static -all-static
|
||||
|
@ -78,3 +79,17 @@ sshdump_LDADD = \
|
|||
@GLIB_LIBS@ \
|
||||
@LIBSSH_LIBS@ \
|
||||
@SOCKET_LIBS@
|
||||
|
||||
if ENABLE_STATIC
|
||||
ciscodump_LDFLAGS = -Wl,-static -all-static
|
||||
else
|
||||
ciscodump_LDFLAGS = -export-dynamic
|
||||
endif
|
||||
|
||||
# Libraries and plugin flags with which to link ciscodump.
|
||||
ciscodump_LDADD = \
|
||||
../wiretap/libwiretap.la \
|
||||
../wsutil/libwsutil.la \
|
||||
@GLIB_LIBS@ \
|
||||
@LIBSSH_LIBS@ \
|
||||
@SOCKET_LIBS@
|
||||
|
|
|
@ -37,6 +37,12 @@ sshdump_SOURCES = \
|
|||
extcap-base.c \
|
||||
ssh-base.c
|
||||
|
||||
# ciscodump specifics
|
||||
ciscodump_SOURCES = \
|
||||
ciscodump.c \
|
||||
extcap-base.c \
|
||||
ssh-base.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
extcap-base.h \
|
||||
extcap-base.h \
|
||||
ssh-base.h
|
||||
|
|
|
@ -61,10 +61,21 @@ sshdump_LIBS = $(sshdump_WSLIBS) \
|
|||
$(LIBSSH_LIBS) \
|
||||
$(GLIB_LIBS)
|
||||
|
||||
ciscodump_OBJECTS = $(ciscodump_SOURCES:.c=.obj)
|
||||
|
||||
ciscodump_WSLIBS = \
|
||||
..\wiretap\wiretap-$(WTAP_VERSION).lib \
|
||||
..\wsutil\libwsutil.lib
|
||||
|
||||
ciscodump_LIBS = $(ciscodump_WSLIBS) \
|
||||
wsock32.lib user32.lib \
|
||||
$(LIBSSH_LIBS) \
|
||||
$(GLIB_LIBS)
|
||||
|
||||
EXECUTABLES=androiddump.exe randpktdump.exe
|
||||
|
||||
!IFDEF LIBSSH_DIR
|
||||
EXECUTABLES += sshdump.exe
|
||||
EXECUTABLES += sshdump.exe ciscodump.exe
|
||||
!ENDIF
|
||||
|
||||
all: $(EXECUTABLES)
|
||||
|
@ -96,11 +107,19 @@ sshdump.exe : $(LIBS_CHECK) ..\config.h sshdump.obj extcap-base.obj ssh-base.obj
|
|||
!IFDEF MANIFEST_INFO_REQUIRED
|
||||
mt.exe -nologo -manifest "sshdump.exe.manifest" -outputresource:sshdump.exe;1
|
||||
!ENDIF
|
||||
ciscodump.exe : $(LIBS_CHECK) ..\config.h ciscodump.obj extcap-base.obj ssh-base.obj $(ciscodump_WSLIBS)
|
||||
@echo Linking $@
|
||||
$(LINK) @<<
|
||||
/OUT:ciscodump.exe $(conflags) $(conlibsdll) $(LDFLAGS) /SUBSYSTEM:WINDOWS ciscodump.obj extcap-base.obj ssh-base.obj $(ciscodump_LIBS)
|
||||
<<
|
||||
!IFDEF MANIFEST_INFO_REQUIRED
|
||||
mt.exe -nologo -manifest "ciscodump.exe.manifest" -outputresource:ciscodump.exe;1
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
clean:
|
||||
rm -f $(androiddump_OBJECTS) $(randpktdump_OBJECTS) $(sshdump_OBJECTS) \
|
||||
$(EXECUTABLES) *.nativecodeanalysis.xml *.pdb *.sbr \
|
||||
${ciscodump_OBJECTS} $(EXECUTABLES) *.nativecodeanalysis.xml *.pdb *.sbr \
|
||||
doxygen.cfg *.exe.manifest
|
||||
|
||||
# "distclean" removes all files not part of the distribution.
|
||||
|
@ -138,8 +157,8 @@ checkapi: checkapi-base checkapi-todo
|
|||
|
||||
checkapi-base:
|
||||
$(PERL) ../tools/checkAPIs.pl -g deprecated-gtk -build \
|
||||
$(androiddump_SOURCES) $(randpktdump_SOURCES) $(sshdump_SOURCES)
|
||||
$(androiddump_SOURCES) $(randpktdump_SOURCES) $(sshdump_SOURCES) ${ciscodump_SOURCES}
|
||||
|
||||
checkapi-todo:
|
||||
$(PERL) ../tools/checkAPIs.pl -M -g deprecated-gtk-todo -build \
|
||||
$(androiddump_SOURCES) $(randpktdump_SOURCES) $(sshdump_SOURCES)
|
||||
$(androiddump_SOURCES) $(randpktdump_SOURCES) $(sshdump_SOURCES) ${ciscodump_SOURCES}
|
||||
|
|
|
@ -0,0 +1,735 @@
|
|||
/* ciscodump.c
|
||||
* ciscodump is extcap tool used to capture data using a ssh on a remote cisco router
|
||||
*
|
||||
* Copyright 2015, Dario Lombardo
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <extcap/extcap-base.h>
|
||||
#include <wsutil/interface.h>
|
||||
#include <extcap/ssh-base.h>
|
||||
#include <pcapio.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef STDERR_FILENO
|
||||
#define STDERR_FILENO 2
|
||||
#endif
|
||||
|
||||
#ifndef STDOUT_FILENO
|
||||
#define STDOUT_FILENO 1
|
||||
#endif
|
||||
|
||||
#define CISCODUMP_VERSION_MAJOR "1"
|
||||
#define CISCODUMP_VERSION_MINOR "0"
|
||||
#define CISCODUMP_VERSION_RELEASE "0"
|
||||
|
||||
/* The read timeout in msec */
|
||||
#define CISCODUMP_READ_TIMEOUT 3000
|
||||
|
||||
#define CISCODUMP_EXTCAP_INTERFACE "cisco"
|
||||
#define SSH_READ_BLOCK_SIZE 1024
|
||||
#define SSH_READ_TIMEOUT 10000
|
||||
|
||||
#define WIRESHARK_CAPTURE_POINT "WIRESHARK_CAPTURE_POINT"
|
||||
#define WIRESHARK_CAPTURE_BUFFER "WIRESHARK_CAPTURE_BUFFER"
|
||||
#define WIRESHARK_CAPTURE_ACCESSLIST "WIRESHARK_CAPTURE_ACCESSLIST"
|
||||
|
||||
#define PCAP_SNAPLEN 0xffff
|
||||
|
||||
#define PACKET_MAX_SIZE 65535
|
||||
|
||||
#define MINIMUM_IOS_MAJOR 12
|
||||
#define MINIMUM_IOS_MINOR 4
|
||||
|
||||
/* Status of the parser */
|
||||
enum {
|
||||
CISCODUMP_PARSER_STARTING,
|
||||
CISCODUMP_PARSER_IN_PACKET,
|
||||
CISCODUMP_PARSER_IN_HEADER,
|
||||
CISCODUMP_PARSER_END_PACKET,
|
||||
CISCODUMP_PARSER_ERROR
|
||||
};
|
||||
|
||||
#define verbose_print(...) { if (verbose) printf(__VA_ARGS__); }
|
||||
|
||||
static gboolean verbose = TRUE;
|
||||
|
||||
enum {
|
||||
EXTCAP_BASE_OPTIONS_ENUM,
|
||||
OPT_HELP,
|
||||
OPT_VERSION,
|
||||
OPT_VERBOSE,
|
||||
OPT_REMOTE_HOST,
|
||||
OPT_REMOTE_PORT,
|
||||
OPT_REMOTE_USERNAME,
|
||||
OPT_REMOTE_PASSWORD,
|
||||
OPT_REMOTE_INTERFACE,
|
||||
OPT_REMOTE_FILTER,
|
||||
OPT_SSHKEY,
|
||||
OPT_SSHKEY_PASSPHRASE,
|
||||
OPT_REMOTE_COUNT
|
||||
};
|
||||
|
||||
static struct option longopts[] = {
|
||||
EXTCAP_BASE_OPTIONS,
|
||||
{ "help", no_argument, NULL, OPT_HELP},
|
||||
{ "version", no_argument, NULL, OPT_VERSION},
|
||||
{ "verbose", optional_argument, NULL, OPT_VERBOSE},
|
||||
SSH_BASE_OPTIONS,
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static char* interfaces_list_to_filter(GSList* interfaces, unsigned int remote_port)
|
||||
{
|
||||
GString* filter = g_string_new(NULL);
|
||||
GSList* cur;
|
||||
|
||||
if (interfaces) {
|
||||
g_string_append_printf(filter, "deny tcp host %s any eq %u, deny tcp any eq %u host %s",
|
||||
(char*)interfaces->data, remote_port, remote_port, (char*)interfaces->data);
|
||||
cur = g_slist_next(interfaces);
|
||||
while (cur->next != NULL) {
|
||||
g_string_append_printf(filter, ", deny tcp host %s any eq %u, deny tcp any eq %u host %s",
|
||||
(char*)cur->data, remote_port, remote_port, (char*)cur->data);
|
||||
cur = cur->next;
|
||||
}
|
||||
g_string_append_printf(filter, ", permit ip any any");
|
||||
}
|
||||
|
||||
return g_string_free(filter, FALSE);
|
||||
}
|
||||
|
||||
static char* local_interfaces_to_filter(const unsigned int remote_port)
|
||||
{
|
||||
GSList* interfaces = local_interfaces_to_list();
|
||||
char* filter = interfaces_list_to_filter(interfaces, remote_port);
|
||||
g_slist_free_full(interfaces, g_free);
|
||||
return filter;
|
||||
}
|
||||
|
||||
/* Read bytes from the channel. If bytes == -1, read all data (until timeout). If outbuf != NULL, data are stored there */
|
||||
static int read_output_bytes(ssh_channel channel, int bytes, char* outbuf)
|
||||
{
|
||||
char chr;
|
||||
int total;
|
||||
int bytes_read;
|
||||
|
||||
total = (bytes > 0 ? bytes : G_MAXINT);
|
||||
bytes_read = 0;
|
||||
|
||||
while(ssh_channel_read_timeout(channel, &chr, 1, 0, 2000) > 0 && bytes_read < total) {
|
||||
verbose_print("%c", chr);
|
||||
if (chr == '^')
|
||||
return EXIT_FAILURE;
|
||||
if (outbuf)
|
||||
outbuf[bytes_read] = chr;
|
||||
bytes_read++;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void ciscodump_cleanup(ssh_session sshs, ssh_channel channel, const char* iface, const char* cfilter)
|
||||
{
|
||||
if (channel) {
|
||||
if (read_output_bytes(channel, -1, NULL) == EXIT_SUCCESS) {
|
||||
ssh_channel_printf(channel, "monitor capture point stop %s\n", WIRESHARK_CAPTURE_POINT);
|
||||
ssh_channel_printf(channel, "no monitor capture point ip cef %s %s\n", WIRESHARK_CAPTURE_POINT, iface);
|
||||
ssh_channel_printf(channel, "no monitor capture buffer %s\n", WIRESHARK_CAPTURE_BUFFER);
|
||||
if (cfilter) {
|
||||
ssh_channel_printf(channel, "configure terminal\n");
|
||||
ssh_channel_printf(channel, "no ip access-list ex %s\n", WIRESHARK_CAPTURE_ACCESSLIST);
|
||||
}
|
||||
read_output_bytes(channel, -1, NULL);
|
||||
}
|
||||
}
|
||||
ssh_cleanup(&sshs, &channel);
|
||||
}
|
||||
|
||||
static int wait_until_data(ssh_channel channel, const long unsigned count)
|
||||
{
|
||||
long unsigned got = 0;
|
||||
char output[SSH_READ_BLOCK_SIZE];
|
||||
char* output_ptr;
|
||||
guint rounds = 100;
|
||||
|
||||
while (got < count && rounds--) {
|
||||
if (ssh_channel_printf(channel, "show monitor capture buffer %s parameters\n", WIRESHARK_CAPTURE_BUFFER) == EXIT_FAILURE) {
|
||||
errmsg_print("Can't write to channel");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (read_output_bytes(channel, SSH_READ_BLOCK_SIZE, output) == EXIT_FAILURE)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
output_ptr = g_strstr_len(output, strlen(output), "Packets");
|
||||
if (!output_ptr) {
|
||||
errmsg_print("Error in sscanf()");
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
sscanf(output_ptr, "Packets : %lu", &got);
|
||||
}
|
||||
}
|
||||
verbose_print("All packets got: dumping\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int parse_line(char* packet _U_, unsigned* offset, char* line, int status)
|
||||
{
|
||||
char** parts;
|
||||
char** part;
|
||||
int value;
|
||||
guint64 size;
|
||||
|
||||
if (strlen(line) <= 1) {
|
||||
if (status == CISCODUMP_PARSER_IN_PACKET)
|
||||
return CISCODUMP_PARSER_END_PACKET;
|
||||
else
|
||||
return status;
|
||||
}
|
||||
|
||||
/* we got the packet header */
|
||||
/* The packet header is a line like: */
|
||||
/* 16:09:37.171 ITA Mar 18 2016 : IPv4 LES CEF : Gi0/1 None */
|
||||
if (g_regex_match_simple("^\\d{2}:\\d{2}:\\d{2}.\\d+ .*", line, G_REGEX_CASELESS, G_REGEX_MATCH_ANCHORED)) {
|
||||
return CISCODUMP_PARSER_IN_HEADER;
|
||||
}
|
||||
|
||||
/* we got a line of the packet */
|
||||
/* A line looks like */
|
||||
/* <address>: <1st group> <2nd group> <3rd group> <4th group> <ascii representation> */
|
||||
/* ABCDEF01: 01020304 05060708 090A0B0C 0D0E0F10 ................ */
|
||||
/* Note that any of the 4 groups are optional and that a group can be 1 to 4 bytes long */
|
||||
parts = g_regex_split_simple(
|
||||
"^[\\dA-Z]{8,8}:\\s+([\\dA-Z]{2,8})\\s+([\\dA-Z]{2,8}){0,1}\\s+([\\dA-Z]{2,8}){0,1}\\s+([\\dA-Z]{2,8}){0,1}.*",
|
||||
line, G_REGEX_CASELESS, G_REGEX_MATCH_ANCHORED);
|
||||
|
||||
part = parts;
|
||||
while(*part) {
|
||||
if (strlen(*part) > 1) {
|
||||
value = htonl(strtoul(*part, NULL, 16));
|
||||
size = strlen(*part) / 2;
|
||||
memcpy(packet + *offset, &value, size);
|
||||
*offset += size;
|
||||
}
|
||||
part++;
|
||||
}
|
||||
return CISCODUMP_PARSER_IN_PACKET;
|
||||
}
|
||||
|
||||
static void ssh_loop_read(ssh_channel channel, FILE* fp, const long unsigned count)
|
||||
{
|
||||
char line[SSH_READ_BLOCK_SIZE];
|
||||
char chr;
|
||||
unsigned offset = 0;
|
||||
unsigned packet_size = 0;
|
||||
char packet[PACKET_MAX_SIZE];
|
||||
time_t curtime = time(NULL);
|
||||
int err;
|
||||
guint64 bytes_written;
|
||||
long unsigned packets = 0;
|
||||
int status = CISCODUMP_PARSER_STARTING;
|
||||
|
||||
do {
|
||||
if (ssh_channel_read_timeout(channel, &chr, 1, FALSE, SSH_READ_TIMEOUT) == SSH_ERROR) {
|
||||
errmsg_print("Error reading from channel");
|
||||
return;
|
||||
}
|
||||
|
||||
if (chr != '\n') {
|
||||
line[offset] = chr;
|
||||
offset++;
|
||||
} else {
|
||||
/* Parse the current line */
|
||||
line[offset] = '\0';
|
||||
status = parse_line(packet, &packet_size, line, status);
|
||||
|
||||
if (status == CISCODUMP_PARSER_END_PACKET) {
|
||||
/* dump the packet to the pcap file */
|
||||
libpcap_write_packet(fp, curtime, (guint32)(curtime / 1000), packet_size, packet_size, packet, &bytes_written, &err);
|
||||
verbose_print("Dumped packet %lu size: %u\n", packets, packet_size);
|
||||
packet_size = 0;
|
||||
status = CISCODUMP_PARSER_STARTING;
|
||||
packets++;
|
||||
}
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
} while(packets < count);
|
||||
}
|
||||
|
||||
static int check_ios_version(ssh_channel channel)
|
||||
{
|
||||
gchar* cmdline = "show version | include Cisco IOS\n";
|
||||
gchar version[255];
|
||||
guint major = 0;
|
||||
guint minor = 0;
|
||||
gchar* cur;
|
||||
|
||||
memset(version, 0x0, 255);
|
||||
|
||||
if (ssh_channel_write(channel, cmdline, (guint32)strlen(cmdline)) == SSH_ERROR)
|
||||
return FALSE;
|
||||
if (read_output_bytes(channel, (int)strlen(cmdline), NULL) == EXIT_FAILURE)
|
||||
return FALSE;
|
||||
if (read_output_bytes(channel, 255, version) == EXIT_FAILURE)
|
||||
return FALSE;
|
||||
|
||||
cur = g_strstr_len(version, strlen(version), "Version");
|
||||
if (cur) {
|
||||
cur += strlen("Version ");
|
||||
sscanf(cur, "%u.%u", &major, &minor);
|
||||
if ((major > MINIMUM_IOS_MAJOR) || (major == MINIMUM_IOS_MAJOR && minor >= MINIMUM_IOS_MINOR)) {
|
||||
verbose_print("Current IOS Version: %u.%u\n", major, minor);
|
||||
if (read_output_bytes(channel, -1, NULL) == EXIT_FAILURE)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
errmsg_print("Invalid IOS version. Minimum version: 12.4, current: %u.%u", major, minor);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static ssh_channel run_capture(ssh_session sshs, const char* iface, const char* cfilter, const unsigned long int count)
|
||||
{
|
||||
char* cmdline = NULL;
|
||||
ssh_channel channel;
|
||||
int ret = 0;
|
||||
|
||||
channel = ssh_channel_new(sshs);
|
||||
if (!channel)
|
||||
return NULL;
|
||||
|
||||
if (ssh_channel_open_session(channel) != SSH_OK)
|
||||
goto error;
|
||||
|
||||
if (ssh_channel_request_pty(channel) != SSH_OK)
|
||||
goto error;
|
||||
|
||||
if (ssh_channel_change_pty_size(channel, 80, 24) != SSH_OK)
|
||||
goto error;
|
||||
|
||||
if (ssh_channel_request_shell(channel) != SSH_OK)
|
||||
goto error;
|
||||
|
||||
if (!check_ios_version(channel))
|
||||
goto error;
|
||||
|
||||
if (ssh_channel_printf(channel, "terminal length 0\n") == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
if (ssh_channel_printf(channel, "monitor capture buffer %s max-size 9500\n", WIRESHARK_CAPTURE_BUFFER) == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
if (ssh_channel_printf(channel, "monitor capture buffer %s limit packet-count %lu\n", WIRESHARK_CAPTURE_BUFFER, count) == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
if (cfilter) {
|
||||
gchar* multiline_filter;
|
||||
gchar* chr;
|
||||
|
||||
if (ssh_channel_printf(channel, "configure terminal\n") == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
if (ssh_channel_printf(channel, "ip access-list ex %s\n", WIRESHARK_CAPTURE_ACCESSLIST) == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
multiline_filter = g_strdup(cfilter);
|
||||
chr = multiline_filter;
|
||||
while((chr = g_strstr_len(chr, strlen(chr), ",")) != NULL) {
|
||||
chr[0] = '\n';
|
||||
verbose_print("Splitting filter into multiline\n");
|
||||
}
|
||||
ret = ssh_channel_write(channel, multiline_filter, (uint32_t)strlen(multiline_filter));
|
||||
g_free(multiline_filter);
|
||||
if (ret == SSH_ERROR)
|
||||
goto error;
|
||||
|
||||
if (ssh_channel_printf(channel, "\nend\n") == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
if (ssh_channel_printf(channel, "monitor capture buffer %s filter access-list %s\n",
|
||||
WIRESHARK_CAPTURE_BUFFER, WIRESHARK_CAPTURE_ACCESSLIST) == EXIT_FAILURE)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ssh_channel_printf(channel, "monitor capture point ip cef %s %s both\n", WIRESHARK_CAPTURE_POINT,
|
||||
iface) == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
if (ssh_channel_printf(channel, "monitor capture point associate %s %s \n", WIRESHARK_CAPTURE_POINT,
|
||||
WIRESHARK_CAPTURE_BUFFER) == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
if (ssh_channel_printf(channel, "monitor capture point start %s\n", WIRESHARK_CAPTURE_POINT) == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
if (read_output_bytes(channel, -1, NULL) == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
if (wait_until_data(channel, count) == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
if (read_output_bytes(channel, -1, NULL) == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
cmdline = g_strdup_printf("show monitor capture buffer %s dump\n", WIRESHARK_CAPTURE_BUFFER);
|
||||
if (ssh_channel_printf(channel, cmdline) == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
if (read_output_bytes(channel, (int)strlen(cmdline), NULL) == EXIT_FAILURE)
|
||||
goto error;
|
||||
|
||||
g_free(cmdline);
|
||||
return channel;
|
||||
error:
|
||||
g_free(cmdline);
|
||||
errmsg_print("Error running ssh remote command");
|
||||
read_output_bytes(channel, -1, NULL);
|
||||
|
||||
ssh_channel_close(channel);
|
||||
ssh_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ssh_open_remote_connection(const char* hostname, const unsigned int port, const char* username, const char* password,
|
||||
const char* sshkey, const char* sshkey_passphrase, const char* iface, const char* cfilter,
|
||||
const unsigned long int count, const char* fifo)
|
||||
{
|
||||
ssh_session sshs;
|
||||
ssh_channel channel;
|
||||
FILE* fp = stdout;
|
||||
guint64 bytes_written = 0;
|
||||
int err;
|
||||
int ret = EXIT_FAILURE;
|
||||
char* err_info = NULL;
|
||||
|
||||
if (g_strcmp0(fifo, "-")) {
|
||||
/* Open or create the output file */
|
||||
fp = fopen(fifo, "w");
|
||||
if (!fp) {
|
||||
errmsg_print("Error creating output file: %s\n", g_strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
sshs = create_ssh_connection(hostname, port, username, password, sshkey, sshkey_passphrase, &err_info);
|
||||
if (!sshs) {
|
||||
errmsg_print("Error creating connection: %s", err_info);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!libpcap_write_file_header(fp, 1, PCAP_SNAPLEN, FALSE, &bytes_written, &err)) {
|
||||
errmsg_print("Can't write pcap file header");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
channel = run_capture(sshs, iface, cfilter, count);
|
||||
if (!channel) {
|
||||
ret = EXIT_FAILURE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
verbose_print("\n");
|
||||
|
||||
/* read from channel and write into fp */
|
||||
ssh_loop_read(channel, fp, count);
|
||||
|
||||
/* clean up and exit */
|
||||
ciscodump_cleanup(sshs, channel, iface, cfilter);
|
||||
|
||||
ret = EXIT_SUCCESS;
|
||||
cleanup:
|
||||
if (fp != stdout)
|
||||
fclose(fp);
|
||||
verbose_print("\n\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void help(const char* binname)
|
||||
{
|
||||
printf("Help\n");
|
||||
printf(" Usage:\n");
|
||||
printf(" %s --extcap-interfaces\n", binname);
|
||||
printf(" %s --extcap-interface=INTERFACE --extcap-dlts\n", binname);
|
||||
printf(" %s --extcap-interface=INTERFACE --extcap-config\n", binname);
|
||||
printf(" %s --extcap-interface=INTERFACE --remote-host myhost --remote-port 22222 "
|
||||
"--remote-username myuser --remote-interface gigabit0/0 "
|
||||
"--fifo=FILENAME --capture\n", binname);
|
||||
printf("\n\n");
|
||||
printf(" --help: print this help\n");
|
||||
printf(" --version: print the version\n");
|
||||
printf(" --verbose: print more messages\n");
|
||||
printf(" --extcap-interfaces: list the interfaces\n");
|
||||
printf(" --extcap-interface <iface>: specify the interface\n");
|
||||
printf(" --extcap-dlts: list the DTLs for an interface\n");
|
||||
printf(" --extcap-config: list the additional configuration for an interface\n");
|
||||
printf(" --extcap-capture-filter <filter>: the capture filter\n");
|
||||
printf(" --capture: run the capture\n");
|
||||
printf(" --fifo <file>: dump data to file or fifo\n");
|
||||
printf(" --remote-host <host>: the remote SSH host\n");
|
||||
printf(" --remote-port <port>: the remote SSH port (default: 22)\n");
|
||||
printf(" --remote-username <username>: the remote SSH username (default: the current user)\n");
|
||||
printf(" --remote-password <password>: the remote SSH password. If not specified, ssh-agent and ssh-key are used\n");
|
||||
printf(" --sshkey <public key path>: the path of the ssh key\n");
|
||||
printf(" --sshkey-passphrase <public key passphrase>: the passphrase to unlock public ssh\n");
|
||||
printf(" --remote-interface <iface>: the remote capture interface\n");
|
||||
printf(" --remote-filter <filter>: a filter for remote capture (default: don't capture data for local interfaces IPs)\n");
|
||||
}
|
||||
|
||||
static int list_config(char *interface, unsigned int remote_port)
|
||||
{
|
||||
unsigned inc = 0;
|
||||
char* ipfilter;
|
||||
|
||||
if (!interface) {
|
||||
g_fprintf(stderr, "ERROR: No interface specified.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (g_strcmp0(interface, CISCODUMP_EXTCAP_INTERFACE)) {
|
||||
errmsg_print("ERROR: interface must be %s\n", CISCODUMP_EXTCAP_INTERFACE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ipfilter = local_interfaces_to_filter(remote_port);
|
||||
|
||||
printf("arg {number=%u}{call=--remote-host}{display=Remote SSH server address}"
|
||||
"{type=string}{tooltip=The remote SSH host. It can be both "
|
||||
"an IP address or a hostname}{required=true}\n", inc++);
|
||||
printf("arg {number=%u}{call=--remote-port}{display=Remote SSH server port}"
|
||||
"{type=unsigned}{default=22}{tooltip=The remote SSH host port (1-65535)}"
|
||||
"{range=1,65535}\n", inc++);
|
||||
printf("arg {number=%u}{call=--remote-username}{display=Remote SSH server username}"
|
||||
"{type=string}{default=%s}{tooltip=The remote SSH username. If not provided, "
|
||||
"the current user will be used}\n", inc++, g_get_user_name());
|
||||
printf("arg {number=%u}{call=--remote-password}{display=Remote SSH server password}"
|
||||
"{type=password}{tooltip=The SSH password, used when other methods (SSH agent "
|
||||
"or key files) are unavailable.}\n", inc++);
|
||||
printf("arg {number=%u}{call=--sshkey}{display=Path to SSH private key}"
|
||||
"{type=fileselect}{tooltip=The path on the local filesystem of the private ssh key}\n",
|
||||
inc++);
|
||||
printf("arg {number=%u}{call--sshkey-passphrase}{display=SSH key passphrase}"
|
||||
"{type=password}{tooltip=Passphrase to unlock the SSH private key}\n",
|
||||
inc++);
|
||||
printf("arg {number=%u}{call=--remote-interface}{display=Remote interface}"
|
||||
"{type=string}{required=true}{tooltip=The remote network interface used for capture"
|
||||
"}\n", inc++);
|
||||
printf("arg {number=%u}{call=--remote-filter}{display=Remote capture filter}"
|
||||
"{type=string}{tooltip=The remote capture filter}", inc++);
|
||||
if (ipfilter)
|
||||
printf("{default=%s}", ipfilter);
|
||||
printf("\n");
|
||||
printf("arg {number=%u}{call=--remote-count}{display=Packets to capture}"
|
||||
"{type=unsigned}{required=true}{tooltip=The number of remote packets to capture.}\n",
|
||||
inc++);
|
||||
|
||||
g_free(ipfilter);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int result;
|
||||
int option_idx = 0;
|
||||
int i;
|
||||
char* remote_host = NULL;
|
||||
unsigned int 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;
|
||||
unsigned long int count = 0;
|
||||
int ret = EXIT_SUCCESS;
|
||||
extcap_parameters * extcap_conf = g_new0(extcap_parameters, 1);
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
|
||||
attach_parent_console();
|
||||
#endif /* _WIN32 */
|
||||
|
||||
extcap_base_set_util_info(extcap_conf, CISCODUMP_VERSION_MAJOR, CISCODUMP_VERSION_MINOR, CISCODUMP_VERSION_RELEASE, NULL);
|
||||
extcap_base_register_interface(extcap_conf, CISCODUMP_EXTCAP_INTERFACE, "Cisco remote capture", 147, "Remote capture dependent DLT");
|
||||
|
||||
opterr = 0;
|
||||
optind = 0;
|
||||
|
||||
if (argc == 1) {
|
||||
help(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
verbose_print("%s ", argv[i]);
|
||||
}
|
||||
verbose_print("\n");
|
||||
|
||||
while ((result = getopt_long(argc, argv, ":", longopts, &option_idx)) != -1) {
|
||||
|
||||
switch (result) {
|
||||
|
||||
case OPT_HELP:
|
||||
help(argv[0]);
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
case OPT_VERBOSE:
|
||||
verbose = TRUE;
|
||||
break;
|
||||
|
||||
case OPT_VERSION:
|
||||
printf("%s.%s.%s\n", CISCODUMP_VERSION_MAJOR, CISCODUMP_VERSION_MINOR, CISCODUMP_VERSION_RELEASE);
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
case OPT_REMOTE_HOST:
|
||||
g_free(remote_host);
|
||||
remote_host = g_strdup(optarg);
|
||||
break;
|
||||
|
||||
case OPT_REMOTE_PORT:
|
||||
remote_port = (unsigned int)strtoul(optarg, NULL, 10);
|
||||
if (remote_port > 65535 || remote_port == 0) {
|
||||
printf("Invalid port: %s\n", optarg);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
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:
|
||||
count = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case ':':
|
||||
/* missing option argument */
|
||||
errmsg_print("Option '%s' requires an argument", argv[optind - 1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!extcap_base_parse_options(extcap_conf, result - EXTCAP_OPT_LIST_INTERFACES, optarg)) {
|
||||
errmsg_print("Invalid option: %s", argv[optind - 1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc) {
|
||||
errmsg_print("Unexpected extra option: %s", argv[optind]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (extcap_base_handle_interface(extcap_conf))
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
if (extcap_conf->show_config)
|
||||
return list_config(extcap_conf->interface, remote_port);
|
||||
|
||||
#ifdef _WIN32
|
||||
result = WSAStartup(MAKEWORD(1,1), &wsaData);
|
||||
if (result != 0) {
|
||||
if (verbose)
|
||||
errmsg_print("ERROR: WSAStartup failed with error: %d", result);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
if (extcap_conf->capture) {
|
||||
if (!remote_host) {
|
||||
errmsg_print("Missing parameter: --remote-host");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!remote_interface) {
|
||||
errmsg_print("ERROR: No interface specified (--remote-interface)");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (count == 0) {
|
||||
errmsg_print("ERROR: count of packets must be specified (--remote-count)");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
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 {
|
||||
verbose_print("You should not come here... maybe some parameter missing?\n");
|
||||
ret = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
extcap_base_cleanup(&extcap_conf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||
LPSTR lpCmdLine, int nCmdShow) {
|
||||
return main(__argc, __argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=4 tabstop=4 noexpandtab:
|
||||
* :indentSize=4:tabSize=4:noTabs=false:
|
||||
*/
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <extcap/extcap-base.h>
|
||||
#include <log.h>
|
||||
#include <string.h>
|
||||
|
||||
#define verbose_print(...) { if (verbose) printf(__VA_ARGS__); }
|
||||
|
||||
|
@ -132,6 +133,22 @@ failure:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int ssh_channel_printf(ssh_channel channel, const char* fmt, ...)
|
||||
{
|
||||
gchar* buf;
|
||||
va_list arg;
|
||||
int ret = EXIT_SUCCESS;
|
||||
|
||||
va_start(arg, fmt);
|
||||
buf = g_strdup_vprintf(fmt, arg);
|
||||
if (ssh_channel_write(channel, buf, (guint32)strlen(buf)) == SSH_ERROR)
|
||||
ret = EXIT_FAILURE;
|
||||
va_end(arg);
|
||||
g_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ssh_cleanup(ssh_session* sshs, ssh_channel* channel)
|
||||
{
|
||||
if (*channel) {
|
||||
|
|
|
@ -27,10 +27,24 @@
|
|||
|
||||
#include <libssh/libssh.h>
|
||||
|
||||
#define SSH_BASE_OPTIONS \
|
||||
{ "remote-host", required_argument, NULL, OPT_REMOTE_HOST}, \
|
||||
{ "remote-port", required_argument, NULL, OPT_REMOTE_PORT}, \
|
||||
{ "remote-username", required_argument, NULL, OPT_REMOTE_USERNAME}, \
|
||||
{ "remote-password", required_argument, NULL, OPT_REMOTE_PASSWORD}, \
|
||||
{ "remote-interface", required_argument, NULL, OPT_REMOTE_INTERFACE}, \
|
||||
{ "remote-filter", required_argument, NULL, OPT_REMOTE_FILTER}, \
|
||||
{ "remote-count", required_argument, NULL, OPT_REMOTE_COUNT}, \
|
||||
{ "sshkey", required_argument, NULL, OPT_SSHKEY}, \
|
||||
{ "sshkey-passphrase", required_argument, NULL, OPT_SSHKEY_PASSPHRASE}
|
||||
|
||||
/* Create a ssh connection using all the possible authentication menthods */
|
||||
ssh_session create_ssh_connection(const char* hostname, const unsigned int port, const char* username,
|
||||
const char* password, const char* sshkey_path, const char* sshkey_passphrase, char** err_info);
|
||||
|
||||
/* Write a formatted message in the channel */
|
||||
int ssh_channel_printf(ssh_channel channel, const char* fmt, ...);
|
||||
|
||||
/* Clean the current ssh session and channel. */
|
||||
void ssh_cleanup(ssh_session* sshs, ssh_channel* channel);
|
||||
|
||||
|
|
Loading…
Reference in New Issue