diff options
author | Aris Adamantiadis <aris@0xbadc0de.be> | 2009-11-16 22:36:31 +0100 |
---|---|---|
committer | Aris Adamantiadis <aris@0xbadc0de.be> | 2009-11-16 22:36:31 +0100 |
commit | 02aecc1278d52fa1c2266e0a16fd3551e922f560 (patch) | |
tree | b1629eb06f9c90593b8facfe99fc8e8c7362b1bb | |
parent | 3e90a11599d3427662ed6edb6d20b7660aba4ad8 (diff) | |
download | libssh-02aecc1278d52fa1c2266e0a16fd3551e922f560.tar.gz libssh-02aecc1278d52fa1c2266e0a16fd3551e922f560.tar.xz libssh-02aecc1278d52fa1c2266e0a16fd3551e922f560.zip |
Improved pcap dumping support
-rw-r--r-- | examples/sample.c | 54 | ||||
-rw-r--r-- | include/libssh/pcap.h | 5 | ||||
-rw-r--r-- | include/libssh/session.h | 4 | ||||
-rw-r--r-- | libssh/client.c | 11 | ||||
-rw-r--r-- | libssh/packet.c | 17 | ||||
-rw-r--r-- | libssh/pcap.c | 100 |
6 files changed, 170 insertions, 21 deletions
diff --git a/examples/sample.c b/examples/sample.c index 92336629..639605e1 100644 --- a/examples/sample.c +++ b/examples/sample.c @@ -40,6 +40,12 @@ char *user; char *cmds[MAXCMD]; struct termios terminal; +#ifdef WITH_PCAP +/* this header file won't be necessary in the future */ +#include <libssh/pcap.h> +char *pcap_file=NULL; +#endif + static int auth_callback(const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata) { char *answer = NULL; @@ -86,19 +92,27 @@ static void usage(){ " -l user : log in as user\n" " -p port : connect to port\n" " -d : use DSS to verify host public key\n" - " -r : use RSA to verify host public key\n", + " -r : use RSA to verify host public key\n" +#ifdef WITH_PCAP + " -P file : create a pcap debugging file\n" +#endif + , ssh_version(0)); exit(0); } static int opts(int argc, char **argv){ int i; - // for(i=0;i<argc;i++) // printf("%d : %s\n",i,argv[i]); /* insert your own arguments here */ - while((i=getopt(argc,argv,""))!=-1){ + while((i=getopt(argc,argv,"P:"))!=-1){ switch(i){ +#ifdef WITH_PCAP + case 'P': + pcap_file=optarg; + break; +#endif default: fprintf(stderr,"unknown option %c\n",optopt); usage(); @@ -446,6 +460,31 @@ static int client(ssh_session session){ return 0; } +#ifdef WITH_PCAP +ssh_pcap_file pcap; +void set_pcap(ssh_session session); +void set_pcap(ssh_session session){ + ssh_pcap_context ctx; + if(!pcap_file) + return; + pcap=ssh_pcap_file_new(); + if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){ + printf("Error opening pcap file\n"); + ssh_pcap_file_free(pcap); + pcap=NULL; + return; + } + ctx=ssh_pcap_context_new(session); + ssh_pcap_context_set_file(ctx,pcap); + ssh_set_pcap_context(session,ctx); +} +void cleanup_pcap(void); +void cleanup_pcap(){ + ssh_pcap_file_free(pcap); + pcap=NULL; +} +#endif + int main(int argc, char **argv){ ssh_session session; @@ -461,10 +500,17 @@ int main(int argc, char **argv){ } opts(argc,argv); signal(SIGTERM, do_exit); - +#ifdef WITH_PCAP + set_pcap(session); +#endif client(session); + ssh_disconnect(session); ssh_free(session); +#ifdef WITH_PCAP + cleanup_pcap(); +#endif + ssh_finalize(); return 0; diff --git a/include/libssh/pcap.h b/include/libssh/pcap.h index c0ef73fe..558ce563 100644 --- a/include/libssh/pcap.h +++ b/include/libssh/pcap.h @@ -2,6 +2,7 @@ #define PCAP_H_ #include "config.h" +#include "libssh/libssh.h" #ifdef WITH_PCAP typedef struct ssh_pcap_context_struct* ssh_pcap_context; @@ -10,7 +11,7 @@ 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); +void ssh_pcap_file_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); @@ -25,6 +26,8 @@ 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); +void ssh_set_pcap_context(ssh_session session, ssh_pcap_context pcap); + #endif /* WITH_PCAP */ #endif /* PCAP_H_ */ /* vim: set ts=2 sw=2 et cindent: */ diff --git a/include/libssh/session.h b/include/libssh/session.h index c59ba5fb..f490b1e4 100644 --- a/include/libssh/session.h +++ b/include/libssh/session.h @@ -23,6 +23,7 @@ #define SESSION_H_ #include "libssh/priv.h" #include "libssh/packet.h" +#include "libssh/pcap.h" typedef struct ssh_kbdint_struct* ssh_kbdint; @@ -96,6 +97,9 @@ struct ssh_session_struct { ssh_callbacks callbacks; /* Callbacks to user functions */ /* options */ +#ifdef WITH_PCAP + ssh_pcap_context pcap_ctx; /* pcap debugging context */ +#endif char *username; char *host; char *bindaddr; /* TODO: check if needed */ 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: */ |