|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* This file is part of the SSH Library
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* Copyright (c) 2009 by Aris Adamantiadis
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* The SSH Library is free software; you can redistribute it and/or modify
|
|
Packit Service |
31306d |
* it under the terms of the GNU Lesser General Public License as published by
|
|
Packit Service |
31306d |
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
|
Packit Service |
31306d |
* option) any later version.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* The SSH Library is distributed in the hope that it will be useful, but
|
|
Packit Service |
31306d |
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
Packit Service |
31306d |
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
Packit Service |
31306d |
* License for more details.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
31306d |
* along with the SSH Library; see the file COPYING. If not, write to
|
|
Packit Service |
31306d |
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
Packit Service |
31306d |
* MA 02111-1307, USA.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* pcap.c */
|
|
Packit Service |
31306d |
#include "config.h"
|
|
Packit Service |
31306d |
#ifdef WITH_PCAP
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#include <stdio.h>
|
|
Packit Service |
31306d |
#ifdef _WIN32
|
|
Packit Service |
31306d |
#include <winsock2.h>
|
|
Packit Service |
31306d |
#include <ws2tcpip.h>
|
|
Packit Service |
31306d |
#else
|
|
Packit Service |
31306d |
#include <netinet/in.h>
|
|
Packit Service |
31306d |
#include <sys/socket.h>
|
|
Packit Service |
31306d |
#endif
|
|
Packit Service |
31306d |
#ifdef HAVE_SYS_TIME_H
|
|
Packit Service |
31306d |
#include <sys/time.h>
|
|
Packit Service |
31306d |
#endif /* HAVE_SYS_TIME_H */
|
|
Packit Service |
31306d |
#include <errno.h>
|
|
Packit Service |
31306d |
#include <stdlib.h>
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#include "libssh/libssh.h"
|
|
Packit Service |
31306d |
#include "libssh/pcap.h"
|
|
Packit Service |
31306d |
#include "libssh/session.h"
|
|
Packit Service |
31306d |
#include "libssh/buffer.h"
|
|
Packit Service |
31306d |
#include "libssh/socket.h"
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @defgroup libssh_pcap The libssh pcap functions
|
|
Packit Service |
31306d |
* @ingroup libssh
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* The pcap file generation
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @{
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* The header of a pcap file is the following. We are not going to make it
|
|
Packit Service |
31306d |
* very complicated.
|
|
Packit Service |
31306d |
* Just for information.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
struct pcap_hdr_s {
|
|
Packit Service |
31306d |
uint32_t magic_number; /* magic number */
|
|
Packit Service |
31306d |
uint16_t version_major; /* major version number */
|
|
Packit Service |
31306d |
uint16_t version_minor; /* minor version number */
|
|
Packit Service |
31306d |
int32_t thiszone; /* GMT to local correction */
|
|
Packit Service |
31306d |
uint32_t sigfigs; /* accuracy of timestamps */
|
|
Packit Service |
31306d |
uint32_t snaplen; /* max length of captured packets, in octets */
|
|
Packit Service |
31306d |
uint32_t network; /* data link type */
|
|
Packit Service |
31306d |
};
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#define PCAP_MAGIC 0xa1b2c3d4
|
|
Packit Service |
31306d |
#define PCAP_VERSION_MAJOR 2
|
|
Packit Service |
31306d |
#define PCAP_VERSION_MINOR 4
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#define DLT_RAW 12 /* raw IP */
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* TCP flags */
|
|
Packit Service |
31306d |
#define TH_FIN 0x01
|
|
Packit Service |
31306d |
#define TH_SYN 0x02
|
|
Packit Service |
31306d |
#define TH_RST 0x04
|
|
Packit Service |
31306d |
#define TH_PUSH 0x08
|
|
Packit Service |
31306d |
#define TH_ACK 0x10
|
|
Packit Service |
31306d |
#define TH_URG 0x20
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* The header of a pcap packet.
|
|
Packit Service |
31306d |
* Just for information.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
struct pcaprec_hdr_s {
|
|
Packit Service |
31306d |
uint32_t ts_sec; /* timestamp seconds */
|
|
Packit Service |
31306d |
uint32_t ts_usec; /* timestamp microseconds */
|
|
Packit Service |
31306d |
uint32_t incl_len; /* number of octets of packet saved in file */
|
|
Packit Service |
31306d |
uint32_t orig_len; /* actual length of packet */
|
|
Packit Service |
31306d |
};
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @private
|
|
Packit Service |
31306d |
* @brief a pcap context expresses the state of a pcap dump
|
|
Packit Service |
31306d |
* in a SSH session only. Multiple pcap contexts may be used into
|
|
Packit Service |
31306d |
* a single pcap file.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
struct ssh_pcap_context_struct {
|
|
Packit Service |
31306d |
ssh_session session;
|
|
Packit Service |
31306d |
ssh_pcap_file file;
|
|
Packit Service |
31306d |
int connected;
|
|
Packit Service |
31306d |
/* All of these information are useful to generate
|
|
Packit Service |
31306d |
* the dummy IP and TCP packets
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
uint32_t ipsource;
|
|
Packit Service |
31306d |
uint32_t ipdest;
|
|
Packit Service |
31306d |
uint16_t portsource;
|
|
Packit Service |
31306d |
uint16_t portdest;
|
|
Packit Service |
31306d |
uint32_t outsequence;
|
|
Packit Service |
31306d |
uint32_t insequence;
|
|
Packit Service |
31306d |
};
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @private
|
|
Packit Service |
31306d |
* @brief a pcap file expresses the state of a pcap file which may
|
|
Packit Service |
31306d |
* contain several streams.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
struct ssh_pcap_file_struct {
|
|
Packit Service |
31306d |
FILE *output;
|
|
Packit Service |
31306d |
uint16_t ipsequence;
|
|
Packit Service |
31306d |
};
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief create a new ssh_pcap_file object
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
ssh_pcap_file ssh_pcap_file_new(void) {
|
|
Packit Service |
31306d |
struct ssh_pcap_file_struct *pcap;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
pcap = (struct ssh_pcap_file_struct *) malloc(sizeof(struct ssh_pcap_file_struct));
|
|
Packit Service |
31306d |
if (pcap == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ZERO_STRUCTP(pcap);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return pcap;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @internal
|
|
Packit Service |
31306d |
* @brief writes a packet on file
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
static int ssh_pcap_file_write(ssh_pcap_file pcap, ssh_buffer packet){
|
|
Packit Service |
31306d |
int err;
|
|
Packit Service |
31306d |
uint32_t len;
|
|
Packit Service |
31306d |
if(pcap == NULL || pcap->output==NULL)
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
len=ssh_buffer_get_len(packet);
|
|
Packit Service |
31306d |
err=fwrite(ssh_buffer_get(packet),len,1,pcap->output);
|
|
Packit Service |
31306d |
if(err<0)
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
else
|
|
Packit Service |
31306d |
return SSH_OK;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @internal
|
|
Packit Service |
31306d |
* @brief prepends a packet with the pcap header and writes packet
|
|
Packit Service |
31306d |
* on file
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_pcap_file_write_packet(ssh_pcap_file pcap, ssh_buffer packet, uint32_t original_len){
|
|
Packit Service |
31306d |
ssh_buffer header=ssh_buffer_new();
|
|
Packit Service |
31306d |
struct timeval now;
|
|
Packit Service |
31306d |
int err;
|
|
Packit Service |
31306d |
if(header == NULL)
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
gettimeofday(&now,NULL);
|
|
Packit Service |
31306d |
err = ssh_buffer_allocate_size(header,
|
|
Packit Service |
31306d |
sizeof(uint32_t) * 4 +
|
|
Packit Service |
31306d |
ssh_buffer_get_len(packet));
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
err = ssh_buffer_add_u32(header,htonl(now.tv_sec));
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
err = ssh_buffer_add_u32(header,htonl(now.tv_usec));
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
err = ssh_buffer_add_u32(header,htonl(ssh_buffer_get_len(packet)));
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
err = ssh_buffer_add_u32(header,htonl(original_len));
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
err = ssh_buffer_add_buffer(header,packet);
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
err=ssh_pcap_file_write(pcap,header);
|
|
Packit Service |
31306d |
error:
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(header);
|
|
Packit Service |
31306d |
return err;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief opens a new pcap file and create header
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_pcap_file_open(ssh_pcap_file pcap, const char *filename){
|
|
Packit Service |
31306d |
ssh_buffer header;
|
|
Packit Service |
31306d |
int err;
|
|
Packit Service |
31306d |
if(pcap == NULL)
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
if(pcap->output){
|
|
Packit Service |
31306d |
fclose(pcap->output);
|
|
Packit Service |
31306d |
pcap->output=NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
pcap->output=fopen(filename,"wb");
|
|
Packit Service |
31306d |
if(pcap->output==NULL)
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
header=ssh_buffer_new();
|
|
Packit Service |
31306d |
if(header==NULL)
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
err = ssh_buffer_allocate_size(header,
|
|
Packit Service |
31306d |
sizeof(uint32_t) * 5 +
|
|
Packit Service |
31306d |
sizeof(uint16_t) * 2);
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
err = ssh_buffer_add_u32(header,htonl(PCAP_MAGIC));
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
err = ssh_buffer_add_u16(header,htons(PCAP_VERSION_MAJOR));
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
err = ssh_buffer_add_u16(header,htons(PCAP_VERSION_MINOR));
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/* currently hardcode GMT to 0 */
|
|
Packit Service |
31306d |
err = ssh_buffer_add_u32(header,htonl(0));
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/* accuracy */
|
|
Packit Service |
31306d |
err = ssh_buffer_add_u32(header,htonl(0));
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/* size of the biggest packet */
|
|
Packit Service |
31306d |
err = ssh_buffer_add_u32(header,htonl(MAX_PACKET_LEN));
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/* we will write sort-of IP */
|
|
Packit Service |
31306d |
err = ssh_buffer_add_u32(header,htonl(DLT_RAW));
|
|
Packit Service |
31306d |
if (err < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
err=ssh_pcap_file_write(pcap,header);
|
|
Packit Service |
31306d |
error:
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(header);
|
|
Packit Service |
31306d |
return err;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
int ssh_pcap_file_close(ssh_pcap_file pcap){
|
|
Packit Service |
31306d |
int err;
|
|
Packit Service |
31306d |
if(pcap ==NULL || pcap->output==NULL)
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
err=fclose(pcap->output);
|
|
Packit Service |
31306d |
pcap->output=NULL;
|
|
Packit Service |
31306d |
if(err != 0)
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
else
|
|
Packit Service |
31306d |
return SSH_OK;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
void ssh_pcap_file_free(ssh_pcap_file pcap){
|
|
Packit Service |
31306d |
ssh_pcap_file_close(pcap);
|
|
Packit Service |
31306d |
SAFE_FREE(pcap);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @internal
|
|
Packit Service |
31306d |
* @brief allocates a new ssh_pcap_context object
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ssh_pcap_context ssh_pcap_context_new(ssh_session session){
|
|
Packit Service |
31306d |
ssh_pcap_context ctx = (struct ssh_pcap_context_struct *) malloc(sizeof(struct ssh_pcap_context_struct));
|
|
Packit Service |
31306d |
if(ctx==NULL){
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ZERO_STRUCTP(ctx);
|
|
Packit Service |
31306d |
ctx->session=session;
|
|
Packit Service |
31306d |
return ctx;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
void ssh_pcap_context_free(ssh_pcap_context ctx){
|
|
Packit Service |
31306d |
SAFE_FREE(ctx);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
void ssh_pcap_context_set_file(ssh_pcap_context ctx, ssh_pcap_file pcap){
|
|
Packit Service |
31306d |
ctx->file=pcap;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @internal
|
|
Packit Service |
31306d |
* @brief sets the IP and port parameters in the connection
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
static int ssh_pcap_context_connect(ssh_pcap_context ctx)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
ssh_session session=ctx->session;
|
|
Packit Service |
31306d |
struct sockaddr_in local = {
|
|
Packit Service |
31306d |
.sin_family = AF_UNSPEC,
|
|
Packit Service |
31306d |
};
|
|
Packit Service |
31306d |
struct sockaddr_in remote = {
|
|
Packit Service |
31306d |
.sin_family = AF_UNSPEC,
|
|
Packit Service |
31306d |
};
|
|
Packit Service |
31306d |
socket_t fd;
|
|
Packit Service |
31306d |
socklen_t len;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (session == NULL) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (session->socket == NULL) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
fd = ssh_socket_get_fd(session->socket);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* TODO: adapt for windows */
|
|
Packit Service |
31306d |
if (fd < 0) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
len = sizeof(local);
|
|
Packit Service |
31306d |
rc = getsockname(fd, (struct sockaddr *)&local, &len;;
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
ssh_set_error(session,
|
|
Packit Service |
31306d |
SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"Getting local IP address: %s",
|
|
Packit Service |
31306d |
strerror(errno));
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
len = sizeof(remote);
|
|
Packit Service |
31306d |
rc = getpeername(fd, (struct sockaddr *)&remote, &len;;
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
ssh_set_error(session,
|
|
Packit Service |
31306d |
SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"Getting remote IP address: %s",
|
|
Packit Service |
31306d |
strerror(errno));
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (local.sin_family != AF_INET) {
|
|
Packit Service |
31306d |
ssh_set_error(session,
|
|
Packit Service |
31306d |
SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"Only IPv4 supported for pcap logging");
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
memcpy(&ctx->ipsource, &local.sin_addr, sizeof(ctx->ipsource));
|
|
Packit Service |
31306d |
memcpy(&ctx->ipdest, &remote.sin_addr, sizeof(ctx->ipdest));
|
|
Packit Service |
31306d |
memcpy(&ctx->portsource, &local.sin_port, sizeof(ctx->portsource));
|
|
Packit Service |
31306d |
memcpy(&ctx->portdest, &remote.sin_port, sizeof(ctx->portdest));
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ctx->connected = 1;
|
|
Packit Service |
31306d |
return SSH_OK;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#define IPHDR_LEN 20
|
|
Packit Service |
31306d |
#define TCPHDR_LEN 20
|
|
Packit Service |
31306d |
#define TCPIPHDR_LEN (IPHDR_LEN + TCPHDR_LEN)
|
|
Packit Service |
31306d |
/** @internal
|
|
Packit Service |
31306d |
* @brief write a SSH packet as a TCP over IP in a pcap file
|
|
Packit Service |
31306d |
* @param ctx open pcap context
|
|
Packit Service |
31306d |
* @param direction SSH_PCAP_DIRECTION_IN if the packet has been received
|
|
Packit Service |
31306d |
* @param direction SSH_PCAP_DIRECTION_OUT if the packet has been emitted
|
|
Packit Service |
31306d |
* @param data pointer to the data to write
|
|
Packit Service |
31306d |
* @param len data to write in the pcap file. May be smaller than origlen.
|
|
Packit Service |
31306d |
* @param origlen number of bytes of complete data.
|
|
Packit Service |
31306d |
* @returns SSH_OK write is successful
|
|
Packit Service |
31306d |
* @returns SSH_ERROR an error happened.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_pcap_context_write(ssh_pcap_context ctx,
|
|
Packit Service |
31306d |
enum ssh_pcap_direction direction,
|
|
Packit Service |
31306d |
void *data,
|
|
Packit Service |
31306d |
uint32_t len,
|
|
Packit Service |
31306d |
uint32_t origlen)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
ssh_buffer ip;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (ctx == NULL || ctx->file == NULL) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (ctx->connected == 0) {
|
|
Packit Service |
31306d |
if (ssh_pcap_context_connect(ctx) == SSH_ERROR) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ip = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (ip == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(ctx->session);
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* build an IP packet */
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(ip,
|
|
Packit Service |
31306d |
"bbwwwbbw",
|
|
Packit Service |
31306d |
4 << 4 | 5, /* V4, 20 bytes */
|
|
Packit Service |
31306d |
0, /* tos */
|
|
Packit Service |
31306d |
origlen + TCPIPHDR_LEN, /* total len */
|
|
Packit Service |
31306d |
ctx->file->ipsequence, /* IP id number */
|
|
Packit Service |
31306d |
0, /* fragment offset */
|
|
Packit Service |
31306d |
64, /* TTL */
|
|
Packit Service |
31306d |
6, /* protocol TCP=6 */
|
|
Packit Service |
31306d |
0); /* checksum */
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ctx->file->ipsequence++;
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (direction == SSH_PCAP_DIR_OUT) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_u32(ip, ctx->ipsource);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_u32(ip, ctx->ipdest);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_u32(ip, ctx->ipdest);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_u32(ip, ctx->ipsource);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/* TCP */
|
|
Packit Service |
31306d |
if (direction == SSH_PCAP_DIR_OUT) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_u16(ip, ctx->portsource);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_u16(ip, ctx->portdest);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_u16(ip, ctx->portdest);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_u16(ip, ctx->portsource);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/* sequence number */
|
|
Packit Service |
31306d |
if (direction == SSH_PCAP_DIR_OUT) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(ip, "d", ctx->outsequence);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ctx->outsequence += origlen;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(ip, "d", ctx->insequence);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ctx->insequence += origlen;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/* ack number */
|
|
Packit Service |
31306d |
if (direction == SSH_PCAP_DIR_OUT) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(ip, "d", ctx->insequence);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(ip, "d", ctx->outsequence);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(ip,
|
|
Packit Service |
31306d |
"bbwwwP",
|
|
Packit Service |
31306d |
5 << 4, /* header len = 20 = 5 * 32 bits, at offset 4*/
|
|
Packit Service |
31306d |
TH_PUSH | TH_ACK, /* flags */
|
|
Packit Service |
31306d |
65535, /* window */
|
|
Packit Service |
31306d |
0, /* checksum */
|
|
Packit Service |
31306d |
0, /* urgent data ptr */
|
|
Packit Service |
31306d |
(size_t)len, data); /* actual data */
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
rc = ssh_pcap_file_write_packet(ctx->file, ip, origlen + TCPIPHDR_LEN);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
error:
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(ip);
|
|
Packit Service |
31306d |
return rc;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @brief sets the pcap file used to trace the session
|
|
Packit Service |
31306d |
* @param current session
|
|
Packit Service |
31306d |
* @param pcap an handler to a pcap file. A pcap file may be used in several
|
|
Packit Service |
31306d |
* sessions.
|
|
Packit Service |
31306d |
* @returns SSH_ERROR in case of error, SSH_OK otherwise.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_set_pcap_file(ssh_session session, ssh_pcap_file pcap){
|
|
Packit Service |
31306d |
ssh_pcap_context ctx=ssh_pcap_context_new(session);
|
|
Packit Service |
31306d |
if(ctx==NULL){
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ctx->file=pcap;
|
|
Packit Service |
31306d |
if(session->pcap_ctx)
|
|
Packit Service |
31306d |
ssh_pcap_context_free(session->pcap_ctx);
|
|
Packit Service |
31306d |
session->pcap_ctx=ctx;
|
|
Packit Service |
31306d |
return SSH_OK;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#else /* WITH_PCAP */
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Simple stub returning errors when no pcap compiled in */
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#include "libssh/libssh.h"
|
|
Packit Service |
31306d |
#include "libssh/priv.h"
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
int ssh_pcap_file_close(ssh_pcap_file pcap){
|
|
Packit Service |
31306d |
(void) pcap;
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
void ssh_pcap_file_free(ssh_pcap_file pcap){
|
|
Packit Service |
31306d |
(void) pcap;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ssh_pcap_file ssh_pcap_file_new(void){
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
int ssh_pcap_file_open(ssh_pcap_file pcap, const char *filename){
|
|
Packit Service |
31306d |
(void) pcap;
|
|
Packit Service |
31306d |
(void) filename;
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
int ssh_set_pcap_file(ssh_session session, ssh_pcap_file pcapfile){
|
|
Packit Service |
31306d |
(void) pcapfile;
|
|
Packit Service |
31306d |
ssh_set_error(session,SSH_REQUEST_DENIED,"Pcap support not compiled in");
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#endif
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @} */
|