mirror of
https://github.com/adulau/ssldump.git
synced 2024-11-25 02:47:06 +00:00
322 lines
8.3 KiB
C
322 lines
8.3 KiB
C
/**
|
|
network.c
|
|
|
|
|
|
Copyright (C) 1999-2000 RTFM, Inc.
|
|
All Rights Reserved
|
|
|
|
This package is a SSLv3/TLS protocol analyzer written by Eric Rescorla
|
|
<ekr@rtfm.com> and licensed by RTFM, Inc.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
3. All advertising materials mentioning features or use of this software
|
|
must display the following acknowledgement:
|
|
|
|
This product includes software developed by Eric Rescorla for
|
|
RTFM, Inc.
|
|
|
|
4. Neither the name of RTFM, Inc. nor the name of Eric Rescorla may be
|
|
used to endorse or promote products derived from this
|
|
software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY ERIC RESCORLA AND RTFM, INC. ``AS IS'' AND
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY SUCH DAMAGE.
|
|
|
|
$Id: network.c,v 1.10 2002/09/09 21:02:58 ekr Exp $
|
|
|
|
|
|
ekr@rtfm.com Tue Dec 29 09:52:54 1998
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
#include <r_common.h>
|
|
#include "network.h"
|
|
#ifndef _WIN32
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#endif
|
|
|
|
#include "tcppack.h"
|
|
|
|
#ifdef STDC_HEADERS
|
|
#include <string.h>
|
|
#endif
|
|
|
|
UINT4 NET_print_flags;
|
|
|
|
struct network_handler_ {
|
|
proto_mod *mod;
|
|
proto_ctx *ctx;
|
|
};
|
|
|
|
int network_handler_create(mod,handlerp)
|
|
proto_mod *mod;
|
|
n_handler **handlerp;
|
|
{
|
|
int r,_status;
|
|
n_handler *handler=0;
|
|
|
|
if(!(handler=(n_handler *)malloc(sizeof(n_handler))))
|
|
ABORT(R_NO_MEMORY);
|
|
if(mod->vtbl->create_ctx){
|
|
if((r=mod->vtbl->create_ctx(mod->handle,&handler->ctx)))
|
|
ABORT(r);
|
|
}
|
|
handler->mod=mod;
|
|
*handlerp=handler;
|
|
_status=0;
|
|
abort:
|
|
if(_status){
|
|
network_handler_destroy(mod, &handler);
|
|
}
|
|
return(_status);
|
|
}
|
|
|
|
int network_handler_destroy(mod,handlerp)
|
|
proto_mod *mod;
|
|
n_handler **handlerp;
|
|
{
|
|
n_handler *handler=0;
|
|
if(!handlerp || !*handlerp)
|
|
return(0);
|
|
|
|
handler = *handlerp;
|
|
|
|
mod->vtbl->destroy_ctx(mod->handle,&handler->ctx);
|
|
free(*handlerp);
|
|
*handlerp=0;
|
|
return(0);
|
|
}
|
|
|
|
int network_process_packet(handler,timestamp,data,length,af)
|
|
n_handler *handler;
|
|
struct timeval *timestamp;
|
|
UCHAR *data;
|
|
int length;
|
|
int af;
|
|
{
|
|
int r;
|
|
int hlen;
|
|
packet p;
|
|
u_short off;
|
|
int proto;
|
|
|
|
/*We can pretty much ignore all the options*/
|
|
memcpy(&p.ts,timestamp,sizeof(struct timeval));
|
|
p.base=data;
|
|
p._len=length;
|
|
p.data=data;
|
|
p.len=length;
|
|
p.af=af;
|
|
|
|
if(p.len < 20) {
|
|
if(!(NET_print_flags & NET_PRINT_JSON))
|
|
printf("Malformed packet, packet too small to contain IP header, skipping ...\n");
|
|
return(0);
|
|
}
|
|
|
|
memset(&p.i_addr.so_st, 0x0, sizeof(struct sockaddr_storage));
|
|
memset(&p.r_addr.so_st, 0x0, sizeof(struct sockaddr_storage));
|
|
|
|
if(af == AF_INET) {
|
|
p.l3_hdr.ip=(struct ip *)data;
|
|
memcpy(&p.i_addr.so_in.sin_addr, &p.l3_hdr.ip->ip_src, sizeof(struct in_addr));
|
|
p.i_addr.so_in.sin_family = AF_INET;
|
|
memcpy(&p.r_addr.so_in.sin_addr, &p.l3_hdr.ip->ip_dst, sizeof(struct in_addr));
|
|
p.r_addr.so_in.sin_family = AF_INET;
|
|
|
|
/*Handle, or rather mishandle, fragmentation*/
|
|
off=ntohs(p.l3_hdr.ip->ip_off);
|
|
|
|
if((off & 0x1fff) || /*Later fragment*/
|
|
(off & 0x2000)){ /*More fragments*/
|
|
/* fprintf(stderr,"Fragmented packet! rejecting\n"); */
|
|
return(0);
|
|
}
|
|
|
|
hlen=p.l3_hdr.ip->ip_hl * 4;
|
|
p.data += hlen;
|
|
p.len = ntohs(p.l3_hdr.ip->ip_len);
|
|
|
|
if(p.len > length) {
|
|
if(!(NET_print_flags & NET_PRINT_JSON))
|
|
printf("Malformed packet, size from IP header is larger than size reported by libpcap, skipping ...\n");
|
|
return(0);
|
|
}
|
|
|
|
if (p.len == 0) {
|
|
DBG((0,"ip length reported as 0, presumed to be because of 'TCP segmentation offload' (TSO)\n"));
|
|
p.len = p._len;
|
|
}
|
|
p.len -= hlen;
|
|
|
|
proto = p.l3_hdr.ip->ip_p;
|
|
} else {
|
|
p.l3_hdr.ip6=(struct ip6_hdr *)data;
|
|
memcpy(&p.i_addr.so_in6.sin6_addr, &p.l3_hdr.ip6->ip6_src, sizeof(struct in6_addr));
|
|
p.i_addr.so_in6.sin6_family = AF_INET6;
|
|
memcpy(&p.r_addr.so_in6.sin6_addr, &p.l3_hdr.ip6->ip6_dst, sizeof(struct in6_addr));
|
|
p.r_addr.so_in6.sin6_family = AF_INET6;
|
|
// Skip packets with header extensions
|
|
if(p.l3_hdr.ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_TCP) {
|
|
return 0;
|
|
}
|
|
|
|
hlen=40; // Fixed header size with no extension
|
|
p.data += hlen;
|
|
p.len = ntohs(p.l3_hdr.ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
|
|
if(p.len > length) {
|
|
if(!(NET_print_flags & NET_PRINT_JSON))
|
|
printf("Malformed packet, size from IP header is larger than size reported by libpcap, skipping ...\n");
|
|
return(0);
|
|
}
|
|
|
|
if (p.len == 0) {
|
|
DBG((0,"ip length reported as 0, presumed to be because of 'TCP segmentation offload' (TSO)\n"));
|
|
p.len = p._len;
|
|
}
|
|
|
|
proto = p.l3_hdr.ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt;
|
|
}
|
|
|
|
switch(proto){
|
|
case IPPROTO_TCP:
|
|
if((r=process_tcp_packet(handler->mod,handler->ctx,&p)))
|
|
ERETURN(r);
|
|
break;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
int packet_copy(in,out)
|
|
packet *in;
|
|
packet **out;
|
|
{
|
|
int _status;
|
|
|
|
packet *p=0;
|
|
|
|
if(!(p=(packet *)calloc(1,sizeof(packet))))
|
|
ABORT(R_NO_MEMORY);
|
|
|
|
memcpy(&p->ts,&in->ts,sizeof(struct timeval));
|
|
if(!(p->base=(UCHAR *)malloc(in->_len)))
|
|
ABORT(R_NO_MEMORY);
|
|
memcpy(p->base,in->base,p->_len=in->_len);
|
|
|
|
p->data=p->base + (in->data - in->base);
|
|
p->len=in->len;
|
|
|
|
p->ip=(struct ip *)(p->base + ((UCHAR *)in->ip - in->base));
|
|
p->tcp=(struct tcphdr *)(p->base + ((UCHAR *)in->tcp - in->base));
|
|
|
|
*out=p;
|
|
|
|
_status=0;
|
|
abort:
|
|
if(_status){
|
|
packet_destroy(p);
|
|
}
|
|
return(_status);
|
|
}
|
|
|
|
int packet_destroy(p)
|
|
packet *p;
|
|
{
|
|
if(!p)
|
|
return(0);
|
|
|
|
FREE(p->base);
|
|
FREE(p);
|
|
return(0);
|
|
}
|
|
|
|
int timestamp_diff(t1,t0,diff)
|
|
struct timeval *t1;
|
|
struct timeval *t0;
|
|
struct timeval *diff;
|
|
{
|
|
long d;
|
|
|
|
if(t0->tv_sec > t1->tv_sec)
|
|
ERETURN(R_BAD_ARGS);
|
|
|
|
/*Easy case*/
|
|
if(t0->tv_usec <= t1->tv_usec){
|
|
diff->tv_sec=t1->tv_sec - t0->tv_sec;
|
|
diff->tv_usec=t1->tv_usec - t0->tv_usec;
|
|
return(0);
|
|
}
|
|
|
|
/*Hard case*/
|
|
d=t0->tv_usec - t1->tv_usec;
|
|
if(t1->tv_sec < (t0->tv_sec + 1))
|
|
ERETURN(R_BAD_ARGS);
|
|
diff->tv_sec=t1->tv_sec - (t0->tv_sec + 1);
|
|
diff->tv_usec=1000000 - d;
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
int lookuphostname(so_st,namep)
|
|
struct sockaddr_storage *so_st;
|
|
char **namep;
|
|
{
|
|
int r = 1;
|
|
*namep = calloc(1, NI_MAXHOST);
|
|
void *addr = NULL;
|
|
|
|
if(!(NET_print_flags & NET_PRINT_NO_RESOLVE)) {
|
|
r = getnameinfo((struct sockaddr *) so_st, sizeof(struct sockaddr_storage), *namep, NI_MAXHOST, NULL, 0, 0);
|
|
}
|
|
|
|
if(r) {
|
|
if(so_st->ss_family == AF_INET) {
|
|
addr = &((struct sockaddr_in *) so_st)->sin_addr;
|
|
} else {
|
|
addr = &((struct sockaddr_in6 *) so_st)->sin6_addr;
|
|
}
|
|
inet_ntop(so_st->ss_family, addr, *namep, INET6_ADDRSTRLEN);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
int addrtotext(so_st,namep)
|
|
struct sockaddr_storage *so_st;
|
|
char **namep;
|
|
{
|
|
*namep = calloc(1, NI_MAXHOST);
|
|
void *addr = NULL;
|
|
|
|
if(so_st->ss_family == AF_INET) {
|
|
addr = &((struct sockaddr_in *) so_st)->sin_addr;
|
|
} else {
|
|
addr = &((struct sockaddr_in6 *) so_st)->sin6_addr;
|
|
}
|
|
inet_ntop(so_st->ss_family, addr, *namep, INET6_ADDRSTRLEN);
|
|
|
|
return(0);
|
|
}
|