summaryrefslogtreecommitdiffstats
path: root/libssh
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2009-11-16 22:36:31 +0100
committerAris Adamantiadis <aris@0xbadc0de.be>2009-11-16 22:36:31 +0100
commit02aecc1278d52fa1c2266e0a16fd3551e922f560 (patch)
treeb1629eb06f9c90593b8facfe99fc8e8c7362b1bb /libssh
parent3e90a11599d3427662ed6edb6d20b7660aba4ad8 (diff)
downloadlibssh-02aecc1278d52fa1c2266e0a16fd3551e922f560.tar.gz
libssh-02aecc1278d52fa1c2266e0a16fd3551e922f560.tar.xz
libssh-02aecc1278d52fa1c2266e0a16fd3551e922f560.zip
Improved pcap dumping support
Diffstat (limited to 'libssh')
-rw-r--r--libssh/client.c11
-rw-r--r--libssh/packet.c17
-rw-r--r--libssh/pcap.c100
3 files changed, 112 insertions, 16 deletions
diff --git a/libssh/client.c b/libssh/client.c
index 5ca79bed..80816b25 100644
--- a/libssh/client.c
+++ b/libssh/client.c
@@ -66,7 +66,11 @@ char *ssh_get_banner(ssh_session session) {
leave_function();
return NULL;
}
-
+#ifdef WITH_PCAP
+ if(session->pcap_ctx && buffer[i] == '\n'){
+ ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_IN,buffer,i+1,i+1);
+ }
+#endif
if (buffer[i] == '\r') {
buffer[i] = '\0';
}
@@ -197,7 +201,10 @@ int ssh_send_banner(ssh_session session, int server) {
leave_function();
return -1;
}
-
+#ifdef WITH_PCAP
+ if(session->pcap_ctx)
+ ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,buffer,strlen(buffer),strlen(buffer));
+#endif
leave_function();
return 0;
}
diff --git a/libssh/packet.c b/libssh/packet.c
index 00b09ffe..717b30fd 100644
--- a/libssh/packet.c
+++ b/libssh/packet.c
@@ -42,6 +42,7 @@
#include "libssh/channels.h"
#include "libssh/session.h"
#include "libssh/messages.h"
+#include "libssh/pcap.h"
/* XXX include selected mac size */
static int macsize=SHA_DIGEST_LEN;
@@ -159,6 +160,14 @@ static int packet_read2(ssh_session session) {
ssh_set_error(session, SSH_FATAL, "Decrypt error");
goto error;
}
+#ifdef WITH_PCAP
+ if(session->pcap_ctx){
+ ssh_pcap_context_write(session->pcap_ctx,
+ SSH_PCAP_DIR_IN, buffer_get(session->in_buffer),
+ buffer_get_len(session->in_buffer),
+ buffer_get_len(session->in_buffer));
+ }
+#endif
ssh_socket_read(session->socket, mac, macsize);
if (packet_hmac_verify(session, session->in_buffer, mac) < 0) {
@@ -488,7 +497,13 @@ static int packet_send2(ssh_session session) {
if (buffer_add_data(session->out_buffer, padstring, padding) < 0) {
goto error;
}
-
+#ifdef WITH_PCAP
+ if(session->pcap_ctx){
+ ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,
+ buffer_get(session->out_buffer),buffer_get_len(session->out_buffer)
+ ,buffer_get_len(session->out_buffer));
+ }
+#endif
hmac = packet_encrypt(session, buffer_get(session->out_buffer),
buffer_get_len(session->out_buffer));
if (hmac) {
diff --git a/libssh/pcap.c b/libssh/pcap.c
index 3c45c1e7..2ff2e4d5 100644
--- a/libssh/pcap.c
+++ b/libssh/pcap.c
@@ -26,16 +26,21 @@
* \addtogroup ssh_pcap
* @{ */
+#include "config.h"
+#ifdef WITH_PCAP
+
#include <stdio.h>
#include <sys/time.h>
+#include <sys/socket.h>
+#include <errno.h>
+
-#include "config.h"
#include "libssh/libssh.h"
#include "libssh/pcap.h"
#include "libssh/session.h"
#include "libssh/buffer.h"
+#include "libssh/socket.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.
@@ -83,6 +88,7 @@ struct pcaprec_hdr_s {
struct ssh_pcap_context_struct {
ssh_session session;
ssh_pcap_file file;
+ int connected;
/* All of these informations are useful to generate
* the dummy IP and TCP packets
*/
@@ -100,6 +106,7 @@ struct ssh_pcap_context_struct {
*/
struct ssh_pcap_file_struct {
FILE *output;
+ u_int16_t ipsequence;
};
/**
@@ -192,7 +199,7 @@ int ssh_pcap_file_close(ssh_pcap_file pcap){
return SSH_OK;
}
-void ssh_pcap_free(ssh_pcap_file pcap){
+void ssh_pcap_file_free(ssh_pcap_file pcap){
ssh_pcap_file_close(pcap);
SAFE_FREE(pcap);
}
@@ -217,10 +224,69 @@ void ssh_pcap_context_set_file(ssh_pcap_context ctx, ssh_pcap_file pcap){
ctx->file=pcap;
}
+/** @internal
+ * @brief sets the IP and port parameters in the connection
+ */
+static int ssh_pcap_context_connect(ssh_pcap_context ctx){
+ ssh_session session=ctx->session;
+ struct sockaddr_in local, remote;
+ socket_t fd;
+ socklen_t len;
+ if(session==NULL)
+ return SSH_ERROR;
+ if(session->socket==NULL)
+ return SSH_ERROR;
+ fd=ssh_socket_get_fd(session->socket);
+ /* TODO: adapt for windows */
+ if(fd<0)
+ return SSH_ERROR;
+ len=sizeof(local);
+ if(getsockname(fd,(struct sockaddr *)&local,&len)<0){
+ ssh_set_error(session,SSH_REQUEST_DENIED,"Getting local IP address: %s",strerror(errno));
+ return SSH_ERROR;
+ }
+ len=sizeof(remote);
+ if(getpeername(fd,(struct sockaddr *)&remote,&len)<0){
+ ssh_set_error(session,SSH_REQUEST_DENIED,"Getting remote IP address: %s",strerror(errno));
+ return SSH_ERROR;
+ }
+ if(local.sin_family != AF_INET){
+ ssh_set_error(session,SSH_REQUEST_DENIED,"Only IPv4 supported for pcap logging");
+ return SSH_ERROR;
+ }
+ memcpy(&ctx->ipsource,&local.sin_addr,sizeof(ctx->ipsource));
+ memcpy(&ctx->ipdest,&remote.sin_addr,sizeof(ctx->ipdest));
+ memcpy(&ctx->portsource,&local.sin_port,sizeof(ctx->portsource));
+ memcpy(&ctx->portdest,&remote.sin_port,sizeof(ctx->portdest));
+
+ ctx->connected=1;
+ return SSH_OK;
+}
+
+#define IPHDR_LEN 20
+#define TCPHDR_LEN 20
+#define TCPIPHDR_LEN (IPHDR_LEN + TCPHDR_LEN)
+/** @internal
+ * @brief write a SSH packet as a TCP over IP in a pcap file
+ * @param ctx open pcap context
+ * @param direction SSH_PCAP_DIRECTION_IN if the packet has been received
+ * @param direction SSH_PCAP_DIRECTION_OUT if the packet has been emitted
+ * @param data pointer to the data to write
+ * @param len data to write in the pcap file. May be smaller than origlen.
+ * @param origlen number of bytes of complete data.
+ * @returns SSH_OK write is successful
+ * @returns SSH_ERROR an error happened.
+ */
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();
+ ssh_buffer ip;
int err;
+ if(ctx==NULL || ctx->file ==NULL)
+ return SSH_ERROR;
+ if(ctx->connected==0)
+ if(ssh_pcap_context_connect(ctx)==SSH_ERROR)
+ return SSH_ERROR;
+ ip=buffer_new();
if(ip==NULL){
ssh_set_error_oom(ctx->session);
return SSH_ERROR;
@@ -231,9 +297,10 @@ int ssh_pcap_context_write(ssh_pcap_context ctx,enum ssh_pcap_direction directio
/* tos */
buffer_add_u8(ip,0);
/* total len */
- buffer_add_u16(ip,htons(origlen + 40));
- /* id */
- buffer_add_u16(ip,htons(1));
+ buffer_add_u16(ip,htons(origlen + TCPIPHDR_LEN));
+ /* IP id number */
+ buffer_add_u16(ip,htons(ctx->file->ipsequence));
+ ctx->file->ipsequence++;
/* fragment offset */
buffer_add_u16(ip,htons(0));
/* TTL */
@@ -251,17 +318,19 @@ int ssh_pcap_context_write(ssh_pcap_context ctx,enum ssh_pcap_direction directio
}
/* TCP */
if(direction==SSH_PCAP_DIR_OUT){
- buffer_add_u16(ip,ntohs(ctx->portsource));
- buffer_add_u16(ip,ntohs(ctx->portdest));
+ buffer_add_u16(ip,ctx->portsource);
+ buffer_add_u16(ip,ctx->portdest);
} else {
- buffer_add_u16(ip,ntohs(ctx->portdest));
- buffer_add_u16(ip,ntohs(ctx->portsource));
+ buffer_add_u16(ip,ctx->portdest);
+ buffer_add_u16(ip,ctx->portsource);
}
/* sequence number */
if(direction==SSH_PCAP_DIR_OUT){
buffer_add_u32(ip,ntohl(ctx->outsequence));
+ ctx->outsequence+=origlen;
} else {
buffer_add_u32(ip,ntohl(ctx->insequence));
+ ctx->insequence+=origlen;
}
/* ack number */
if(direction==SSH_PCAP_DIR_OUT){
@@ -269,7 +338,7 @@ int ssh_pcap_context_write(ssh_pcap_context ctx,enum ssh_pcap_direction directio
} else {
buffer_add_u32(ip,ntohl(ctx->outsequence));
}
- /* header len */
+ /* header len = 20 = 5 * 32 bits, at offset 4*/
buffer_add_u8(ip,5 << 4);
/* flags */
buffer_add_u8(ip,TH_PUSH | TH_ACK);
@@ -281,11 +350,16 @@ int ssh_pcap_context_write(ssh_pcap_context ctx,enum ssh_pcap_direction directio
buffer_add_u16(ip,0);
/* actual data */
buffer_add_data(ip,data,len);
- err=ssh_pcap_file_write_packet(ctx->file,ip,origlen + 40);
+ err=ssh_pcap_file_write_packet(ctx->file,ip,origlen + TCPIPHDR_LEN);
buffer_free(ip);
return err;
}
+void ssh_set_pcap_context(ssh_session session, ssh_pcap_context pcap){
+ session->pcap_ctx=pcap;
+}
+
+
#endif /* WITH_PCAP */
/** @} */
/* vim: set ts=2 sw=2 et cindent: */