aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2009-11-08 23:42:41 +0100
committerAris Adamantiadis <aris@0xbadc0de.be>2009-11-08 23:42:41 +0100
commit10b625e18030144f30a68556321a4c3d11fa7e25 (patch)
treebc06f5a5386ace21a90d3ea4dad74be460042afd
parent10f27457d36fd39eee5c317d59e6ecfbc898db58 (diff)
downloadlibssh-10b625e18030144f30a68556321a4c3d11fa7e25.tar.gz
libssh-10b625e18030144f30a68556321a4c3d11fa7e25.tar.xz
libssh-10b625e18030144f30a68556321a4c3d11fa7e25.zip
First lines of experimental pcap output support
This will serve to debug packets right under wireshark !
-rw-r--r--DefineOptions.cmake1
-rw-r--r--config.h.cmake3
-rw-r--r--include/libssh/buffer.h1
-rw-r--r--include/libssh/pcap.h30
-rw-r--r--libssh/CMakeLists.txt1
-rw-r--r--libssh/buffer.c15
-rw-r--r--libssh/pcap.c291
-rw-r--r--tests/Makefile5
-rw-r--r--tests/test_pcap.c50
9 files changed, 396 insertions, 1 deletions
diff --git a/DefineOptions.cmake b/DefineOptions.cmake
index bec65614..f0697960 100644
--- a/DefineOptions.cmake
+++ b/DefineOptions.cmake
@@ -6,3 +6,4 @@ option(WITH_STATIC_LIB "Build with a static library" OFF)
option(WITH_DEBUG_CRYPTO "Build with cryto debug output" OFF)
option(WITH_DEBUG_CALLTRACE "Build with calltrace debug output" ON)
option(WITH_GCRYPT "Compile against libgcrypt" OFF)
+option(WITH_PCAP "Compile with Pcap generation support" OFF)
diff --git a/config.h.cmake b/config.h.cmake
index b483ea1c..8ef29ff2 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -83,6 +83,9 @@
/* Define to 1 if you want to enable debug output for crypto functions */
#cmakedefine DEBUG_CRYPTO 1
+/* Define to 1 if you want to enable pcap output support (experimental) */
+#cmakedefine WITH_PCAP 1
+
/* Define to 1 if you want to enable calltrace debug output */
#cmakedefine DEBUG_CALLTRACE 1
diff --git a/include/libssh/buffer.h b/include/libssh/buffer.h
index d8055fd7..1219cead 100644
--- a/include/libssh/buffer.h
+++ b/include/libssh/buffer.h
@@ -33,6 +33,7 @@ struct ssh_buffer_struct {
int buffer_add_ssh_string(ssh_buffer buffer, ssh_string string);
int buffer_add_u8(ssh_buffer buffer, uint8_t data);
+int buffer_add_u16(ssh_buffer buffer, uint16_t data);
int buffer_add_u32(ssh_buffer buffer, uint32_t data);
int buffer_add_u64(ssh_buffer buffer, uint64_t data);
int buffer_add_data(ssh_buffer buffer, const void *data, uint32_t len);
diff --git a/include/libssh/pcap.h b/include/libssh/pcap.h
new file mode 100644
index 00000000..c0ef73fe
--- /dev/null
+++ b/include/libssh/pcap.h
@@ -0,0 +1,30 @@
+#ifndef PCAP_H_
+#define PCAP_H_
+
+#include "config.h"
+
+#ifdef WITH_PCAP
+typedef struct ssh_pcap_context_struct* ssh_pcap_context;
+typedef struct ssh_pcap_file_struct* ssh_pcap_file;
+
+ssh_pcap_file ssh_pcap_file_new(void);
+int ssh_pcap_file_open(ssh_pcap_file pcap, const char *filename);
+int ssh_pcap_file_close(ssh_pcap_file pcap);
+void ssh_pcap_free(ssh_pcap_file pcap);
+
+/* to be removed from here after tests */
+int ssh_pcap_file_write_packet(ssh_pcap_file pcap, ssh_buffer packet, u_int32_t original_len);
+
+ssh_pcap_context ssh_pcap_context_new(ssh_session session);
+
+enum ssh_pcap_direction{
+ SSH_PCAP_DIR_IN,
+ SSH_PCAP_DIR_OUT
+};
+void ssh_pcap_context_set_file(ssh_pcap_context, ssh_pcap_file);
+int ssh_pcap_context_write(ssh_pcap_context,enum ssh_pcap_direction direction, void *data,
+ u_int32_t len, u_int32_t origlen);
+
+#endif /* WITH_PCAP */
+#endif /* PCAP_H_ */
+/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/CMakeLists.txt b/libssh/CMakeLists.txt
index 7a4093da..11ddcff5 100644
--- a/libssh/CMakeLists.txt
+++ b/libssh/CMakeLists.txt
@@ -93,6 +93,7 @@ set(libssh_SRCS
misc.c
options.c
packet.c
+ pcap.c
poll.c
session.c
scp.c
diff --git a/libssh/buffer.c b/libssh/buffer.c
index a24dc688..761c51b0 100644
--- a/libssh/buffer.c
+++ b/libssh/buffer.c
@@ -174,6 +174,7 @@ int buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
return 0;
}
+
/** \internal
* \brief add a 32 bits unsigned integer to the tail of buffer
* \param buffer buffer
@@ -189,6 +190,20 @@ int buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data){
}
/** \internal
+ * \brief add a 16 bits unsigned integer to the tail of buffer
+ * \param buffer buffer
+ * \param data 16 bits integer
+ * \return 0 on success, -1 on error.
+ */
+int buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data){
+ if (buffer_add_data(buffer, &data, sizeof(data)) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/** \internal
* \brief add a 64 bits unsigned integer to the tail of buffer
* \param buffer buffer
* \param data 64 bits integer
diff --git a/libssh/pcap.c b/libssh/pcap.c
new file mode 100644
index 00000000..3c45c1e7
--- /dev/null
+++ b/libssh/pcap.c
@@ -0,0 +1,291 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2009 by Aris Adamantiadis
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/* pcap.c */
+/** \defgroup ssh_pcap SSH-pcap
+ * \brief libssh pcap file generation
+ *
+ * \addtogroup ssh_pcap
+ * @{ */
+
+#include <stdio.h>
+#include <sys/time.h>
+
+#include "config.h"
+#include "libssh/libssh.h"
+#include "libssh/pcap.h"
+#include "libssh/session.h"
+#include "libssh/buffer.h"
+
+#ifdef WITH_PCAP
+/* The header of a pcap file is the following. We are not going to make it
+ * very complicated.
+ * Just for information.
+ */
+struct pcap_hdr_s {
+ u_int32_t magic_number; /* magic number */
+ u_int16_t version_major; /* major version number */
+ u_int16_t version_minor; /* minor version number */
+ int32_t thiszone; /* GMT to local correction */
+ u_int32_t sigfigs; /* accuracy of timestamps */
+ u_int32_t snaplen; /* max length of captured packets, in octets */
+ u_int32_t network; /* data link type */
+};
+
+#define PCAP_MAGIC 0xa1b2c3d4
+#define PCAP_VERSION_MAJOR 2
+#define PCAP_VERSION_MINOR 4
+
+#define DLT_RAW 12 /* raw IP */
+
+/* TCP flags */
+#define TH_FIN 0x01
+#define TH_SYN 0x02
+#define TH_RST 0x04
+#define TH_PUSH 0x08
+#define TH_ACK 0x10
+#define TH_URG 0x20
+
+/* The header of a pcap packet.
+ * Just for information.
+ */
+struct pcaprec_hdr_s {
+ u_int32_t ts_sec; /* timestamp seconds */
+ u_int32_t ts_usec; /* timestamp microseconds */
+ u_int32_t incl_len; /* number of octets of packet saved in file */
+ u_int32_t orig_len; /* actual length of packet */
+};
+
+/** @private
+ * @brief a pcap context expresses the state of a pcap dump
+ * in a SSH session only. Multiple pcap contexts may be used into
+ * a single pcap file.
+ */
+
+struct ssh_pcap_context_struct {
+ ssh_session session;
+ ssh_pcap_file file;
+ /* All of these informations are useful to generate
+ * the dummy IP and TCP packets
+ */
+ u_int32_t ipsource;
+ u_int32_t ipdest;
+ u_int16_t portsource;
+ u_int16_t portdest;
+ u_int32_t outsequence;
+ u_int32_t insequence;
+};
+
+/** @private
+ * @brief a pcap file expresses the state of a pcap file which may
+ * contain several streams.
+ */
+struct ssh_pcap_file_struct {
+ FILE *output;
+};
+
+/**
+ * @brief create a new ssh_pcap_file object
+ */
+ssh_pcap_file ssh_pcap_file_new(){
+ return malloc(sizeof(struct ssh_pcap_file_struct));
+}
+
+/** @internal
+ * @brief writes a packet on file
+ */
+static int ssh_pcap_file_write(ssh_pcap_file pcap, ssh_buffer packet){
+ int err;
+ uint32_t len;
+ if(pcap == NULL || pcap->output==NULL)
+ return SSH_ERROR;
+ len=buffer_get_len(packet);
+ err=fwrite(buffer_get(packet),len,1,pcap->output);
+ if(err<0)
+ return SSH_ERROR;
+ else
+ return SSH_OK;
+}
+
+/** @internal
+ * @brief prepends a packet with the pcap header and writes packet
+ * on file
+ */
+int ssh_pcap_file_write_packet(ssh_pcap_file pcap, ssh_buffer packet, u_int32_t original_len){
+ ssh_buffer header=buffer_new();
+ struct timeval now;
+ int err;
+ if(header == NULL)
+ return SSH_ERROR;
+ gettimeofday(&now,NULL);
+ buffer_add_u32(header,htonl(now.tv_sec));
+ buffer_add_u32(header,htonl(now.tv_usec));
+ buffer_add_u32(header,htonl(buffer_get_len(packet)));
+ buffer_add_u32(header,htonl(original_len));
+ buffer_add_buffer(header,packet);
+ err=ssh_pcap_file_write(pcap,header);
+ buffer_free(header);
+ return err;
+}
+
+/**
+ * @brief opens a new pcap file and create header
+ */
+int ssh_pcap_file_open(ssh_pcap_file pcap, const char *filename){
+ ssh_buffer header;
+ int err;
+ if(pcap == NULL)
+ return SSH_ERROR;
+ if(pcap->output){
+ fclose(pcap->output);
+ pcap->output=NULL;
+ }
+ pcap->output=fopen(filename,"wb");
+ if(pcap->output==NULL)
+ return SSH_ERROR;
+ header=buffer_new();
+ if(header==NULL)
+ return SSH_ERROR;
+ buffer_add_u32(header,htonl(PCAP_MAGIC));
+ buffer_add_u16(header,htons(PCAP_VERSION_MAJOR));
+ buffer_add_u16(header,htons(PCAP_VERSION_MINOR));
+ /* currently hardcode GMT to 0 */
+ buffer_add_u32(header,htonl(0));
+ /* accuracy */
+ buffer_add_u32(header,htonl(0));
+ /* size of the biggest packet */
+ buffer_add_u32(header,htonl(MAX_PACKET_LEN));
+ /* we will write sort-of IP */
+ buffer_add_u32(header,htonl(DLT_RAW));
+ err=ssh_pcap_file_write(pcap,header);
+ buffer_free(header);
+ return err;
+}
+
+int ssh_pcap_file_close(ssh_pcap_file pcap){
+ int err;
+ if(pcap ==NULL || pcap->output==NULL)
+ return SSH_ERROR;
+ err=fclose(pcap->output);
+ pcap->output=NULL;
+ if(err != 0)
+ return SSH_ERROR;
+ else
+ return SSH_OK;
+}
+
+void ssh_pcap_free(ssh_pcap_file pcap){
+ ssh_pcap_file_close(pcap);
+ SAFE_FREE(pcap);
+}
+
+
+/** @internal
+ * @brief allocates a new ssh_pcap_context object
+ */
+
+ssh_pcap_context ssh_pcap_context_new(ssh_session session){
+ ssh_pcap_context ctx=malloc(sizeof(struct ssh_pcap_context_struct));
+ if(ctx==NULL){
+ ssh_set_error_oom(session);
+ return NULL;
+ }
+ ZERO_STRUCTP(ctx);
+ ctx->session=session;
+ return ctx;
+}
+
+void ssh_pcap_context_set_file(ssh_pcap_context ctx, ssh_pcap_file pcap){
+ ctx->file=pcap;
+}
+
+int ssh_pcap_context_write(ssh_pcap_context ctx,enum ssh_pcap_direction direction
+ , void *data, u_int32_t len, u_int32_t origlen){
+ ssh_buffer ip=buffer_new();
+ int err;
+ if(ip==NULL){
+ ssh_set_error_oom(ctx->session);
+ return SSH_ERROR;
+ }
+ /* build an IP packet */
+ /* V4, 20 bytes */
+ buffer_add_u8(ip,4 << 4 | 5);
+ /* tos */
+ buffer_add_u8(ip,0);
+ /* total len */
+ buffer_add_u16(ip,htons(origlen + 40));
+ /* id */
+ buffer_add_u16(ip,htons(1));
+ /* fragment offset */
+ buffer_add_u16(ip,htons(0));
+ /* TTL */
+ buffer_add_u8(ip,64);
+ /* protocol TCP=6 */
+ buffer_add_u8(ip,6);
+ /* checksum */
+ buffer_add_u16(ip,0);
+ if(direction==SSH_PCAP_DIR_OUT){
+ buffer_add_u32(ip,ctx->ipsource);
+ buffer_add_u32(ip,ctx->ipdest);
+ } else {
+ buffer_add_u32(ip,ctx->ipdest);
+ buffer_add_u32(ip,ctx->ipsource);
+ }
+ /* TCP */
+ if(direction==SSH_PCAP_DIR_OUT){
+ buffer_add_u16(ip,ntohs(ctx->portsource));
+ buffer_add_u16(ip,ntohs(ctx->portdest));
+ } else {
+ buffer_add_u16(ip,ntohs(ctx->portdest));
+ buffer_add_u16(ip,ntohs(ctx->portsource));
+ }
+ /* sequence number */
+ if(direction==SSH_PCAP_DIR_OUT){
+ buffer_add_u32(ip,ntohl(ctx->outsequence));
+ } else {
+ buffer_add_u32(ip,ntohl(ctx->insequence));
+ }
+ /* ack number */
+ if(direction==SSH_PCAP_DIR_OUT){
+ buffer_add_u32(ip,ntohl(ctx->insequence));
+ } else {
+ buffer_add_u32(ip,ntohl(ctx->outsequence));
+ }
+ /* header len */
+ buffer_add_u8(ip,5 << 4);
+ /* flags */
+ buffer_add_u8(ip,TH_PUSH | TH_ACK);
+ /* window */
+ buffer_add_u16(ip,htons(65535));
+ /* checksum */
+ buffer_add_u16(ip,htons(0));
+ /* urgent data ptr */
+ buffer_add_u16(ip,0);
+ /* actual data */
+ buffer_add_data(ip,data,len);
+ err=ssh_pcap_file_write_packet(ctx->file,ip,origlen + 40);
+ buffer_free(ip);
+ return err;
+}
+
+#endif /* WITH_PCAP */
+/** @} */
+/* vim: set ts=2 sw=2 et cindent: */
diff --git a/tests/Makefile b/tests/Makefile
index 8483856e..1ec30d6a 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,4 +1,4 @@
-all: test_tunnel test_exec
+all: test_tunnel test_exec test_pcap
CFLAGS=-I../include/ -g -Wall
LDFLAGS=-lssh -L../build/libssh/
@@ -8,5 +8,8 @@ test_tunnel: test_tunnel.o authentication.o connection.o
test_exec: test_exec.o authentication.o connection.o
gcc -o $@ $^ $(LDFLAGS)
+test_pcap: test_pcap.o
+ gcc -o $@ $^ $(LDFLAGS)
+
clean:
rm -f *.o test_tunnel
diff --git a/tests/test_pcap.c b/tests/test_pcap.c
new file mode 100644
index 00000000..994ae4bf
--- /dev/null
+++ b/tests/test_pcap.c
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2009 by Aris Adamantiadis
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/* Simple test for the pcap functions */
+
+#include <libssh/libssh.h>
+#include <libssh/pcap.h>
+#include <libssh/buffer.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv){
+ ssh_pcap_file pcap;
+ ssh_pcap_context ctx;
+ ssh_buffer buffer=buffer_new();
+ char *str="Hello, this is a test string to test the capabilities of the"
+ "pcap file writer.";
+ printf("Simple pcap tester\n");
+ pcap=ssh_pcap_file_new();
+ if(ssh_pcap_file_open(pcap,"test.cap") != SSH_OK){
+ printf("error happened\n");
+ return EXIT_FAILURE;
+ }
+ buffer_add_data(buffer,str,strlen(str));
+ ctx=ssh_pcap_context_new(NULL);
+ ssh_pcap_context_set_file(ctx,pcap);
+ ssh_pcap_context_write(ctx,SSH_PCAP_DIR_OUT,str,strlen(str),strlen(str));
+
+ return EXIT_SUCCESS;
+}