Improved pcap dumping support
Этот коммит содержится в:
родитель
3e90a11599
Коммит
02aecc1278
@ -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;
|
||||
|
@ -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: */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
100
libssh/pcap.c
100
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: */
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user