aboutsummaryrefslogtreecommitdiff
path: root/libssh/pcap.c
diff options
context:
space:
mode:
Diffstat (limited to 'libssh/pcap.c')
-rw-r--r--libssh/pcap.c434
1 files changed, 0 insertions, 434 deletions
diff --git a/libssh/pcap.c b/libssh/pcap.c
deleted file mode 100644
index 56bf3316..00000000
--- a/libssh/pcap.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * 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 */
-#include "config.h"
-#ifdef WITH_PCAP
-
-#include <stdio.h>
-#ifdef _WIN32
-#include <ws2tcpip.h>
-#else
-#include <sys/time.h>
-#include <sys/socket.h>
-#endif
-#include <errno.h>
-
-#include "libssh/libssh.h"
-#include "libssh/pcap.h"
-#include "libssh/session.h"
-#include "libssh/buffer.h"
-#include "libssh/socket.h"
-
-/**
- * @internal
- *
- * @defgroup libssh_pcap The libssh pcap functions
- * @ingroup libssh
- *
- * The pcap file generation
- *
- *
- * @{
- */
-
-/* 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 {
- uint32_t magic_number; /* magic number */
- uint16_t version_major; /* major version number */
- uint16_t version_minor; /* minor version number */
- int32_t thiszone; /* GMT to local correction */
- uint32_t sigfigs; /* accuracy of timestamps */
- uint32_t snaplen; /* max length of captured packets, in octets */
- uint32_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 {
- uint32_t ts_sec; /* timestamp seconds */
- uint32_t ts_usec; /* timestamp microseconds */
- uint32_t incl_len; /* number of octets of packet saved in file */
- uint32_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;
- int connected;
- /* All of these information are useful to generate
- * the dummy IP and TCP packets
- */
- uint32_t ipsource;
- uint32_t ipdest;
- uint16_t portsource;
- uint16_t portdest;
- uint32_t outsequence;
- uint32_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;
- uint16_t ipsequence;
-};
-
-/**
- * @brief create a new ssh_pcap_file object
- */
-ssh_pcap_file ssh_pcap_file_new(){
- struct ssh_pcap_file_struct *pcap;
-
- pcap = malloc(sizeof(struct ssh_pcap_file_struct));
- if (pcap == NULL) {
- return NULL;
- }
- ZERO_STRUCTP(pcap);
-
- return pcap;
-}
-
-/** @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=ssh_buffer_get_len(packet);
- err=fwrite(ssh_buffer_get_begin(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, uint32_t original_len){
- ssh_buffer header=ssh_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(ssh_buffer_get_len(packet)));
- buffer_add_u32(header,htonl(original_len));
- buffer_add_buffer(header,packet);
- err=ssh_pcap_file_write(pcap,header);
- ssh_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=ssh_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);
- ssh_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_file_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_free(ssh_pcap_context ctx){
- SAFE_FREE(ctx);
-}
-
-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_in(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, uint32_t len, uint32_t origlen){
- 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=ssh_buffer_new();
- 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 + 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 */
- 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,ctx->portsource);
- buffer_add_u16(ip,ctx->portdest);
- } else {
- 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){
- buffer_add_u32(ip,ntohl(ctx->insequence));
- } else {
- buffer_add_u32(ip,ntohl(ctx->outsequence));
- }
- /* header len = 20 = 5 * 32 bits, at offset 4*/
- 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 + TCPIPHDR_LEN);
- ssh_buffer_free(ip);
- return err;
-}
-
-/** @brief sets the pcap file used to trace the session
- * @param current session
- * @param pcap an handler to a pcap file. A pcap file may be used in several
- * sessions.
- * @returns SSH_ERROR in case of error, SSH_OK otherwise.
- */
-int ssh_set_pcap_file(ssh_session session, ssh_pcap_file pcap){
- ssh_pcap_context ctx=ssh_pcap_context_new(session);
- if(ctx==NULL){
- ssh_set_error_oom(session);
- return SSH_ERROR;
- }
- ctx->file=pcap;
- if(session->pcap_ctx)
- ssh_pcap_context_free(session->pcap_ctx);
- session->pcap_ctx=ctx;
- return SSH_OK;
-}
-
-
-#else /* WITH_PCAP */
-
-/* Simple stub returning errors when no pcap compiled in */
-
-#include "libssh/libssh.h"
-#include "libssh/priv.h"
-
-int ssh_pcap_file_close(ssh_pcap_file pcap){
- (void) pcap;
- return SSH_ERROR;
-}
-
-void ssh_pcap_file_free(ssh_pcap_file pcap){
- (void) pcap;
-}
-
-ssh_pcap_file ssh_pcap_file_new(void){
- return NULL;
-}
-int ssh_pcap_file_open(ssh_pcap_file pcap, const char *filename){
- (void) pcap;
- (void) filename;
- return SSH_ERROR;
-}
-
-int ssh_set_pcap_file(ssh_session session, ssh_pcap_file pcapfile){
- (void) pcapfile;
- ssh_set_error(session,SSH_REQUEST_DENIED,"Pcap support not compiled in");
- return SSH_ERROR;
-}
-
-#endif
-
-/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */