Support for HEP-EEP packet encapsulation.

This changes allow sending and receiving packets using EEP protocol.
EEP (formely HEP) is an encapsulation protocol developed for HOMER
SIPCAPTURE project.

Additional information can be found at hep repository:
 - https://github.com/sipcapture/HEP
This commit is contained in:
Kaian 2015-09-23 15:43:31 +02:00
parent 3ac971b445
commit ccf80781c7
9 changed files with 870 additions and 53 deletions

View File

@ -1,9 +1,10 @@
bin_PROGRAMS=sngrep
sngrep_SOURCES=capture.c capture_reasm.c capture_ws.c sip.c sip_call.c sip_msg.c sip_attr.c main.c option.c
sngrep_SOURCES=capture.c capture_eep.c capture_reasm.c capture_ws.c
if WITH_OPENSSL
sngrep_SOURCES+=capture_tls.c
endif
sngrep_SOURCES+=sip.c sip_call.c sip_msg.c sip_attr.c main.c option.c
sngrep_SOURCES+=group.c filter.c keybinding.c media.c setting.c rtp.c util.c vector.c
sngrep_SOURCES+=ui_manager.c ui_call_list.c ui_call_flow.c ui_call_raw.c
sngrep_SOURCES+=ui_filter.c ui_save.c ui_msg_diff.c ui_column_select.c ui_settings.c
if WITH_OPENSSL
sngrep_SOURCES+=capture_tls.c
endif

View File

@ -35,6 +35,7 @@
#include "capture.h"
#include "capture_ws.h"
#include "capture_reasm.h"
#include "capture_eep.h"
#ifdef WITH_OPENSSL
#include "capture_tls.h"
#endif
@ -56,6 +57,17 @@ capture_init(int limit, int rtp_capture)
capture_cfg.sources = vector_create(1, 1);
capture_cfg.tcp_reasm = vector_create(0, 10);
capture_cfg.ip_reasm = vector_create(0, 10);
// Fixme
if (setting_has_value(SETTING_CAPTURE_STORAGE, "none")) {
capture_cfg.storage = CAPTURE_STORAGE_NONE;
} else if (setting_has_value(SETTING_CAPTURE_STORAGE, "memory")) {
capture_cfg.storage = CAPTURE_STORAGE_MEMORY;
} else if (setting_has_value(SETTING_CAPTURE_STORAGE, "disk")) {
capture_cfg.storage = CAPTURE_STORAGE_DISK;
}
}
void
@ -205,8 +217,6 @@ parse_packet(u_char *info, const struct pcap_pkthdr *header, const u_char *packe
uint32_t size_capture = header->caplen;
// Packet payload size
uint32_t size_payload = size_capture - capinfo->link_hl;
// Media structure for RTP packets
rtp_stream_t *stream;
// Captured packet info
capture_packet_t *pkt;
@ -292,13 +302,30 @@ parse_packet(u_char *info, const struct pcap_pkthdr *header, const u_char *packe
return;
}
// Check if we can handle this packet
if (capture_packet_parse(pkt) == 0) {
// Send this packet through eep
capture_eep_send(pkt);
// Store this packets in output file
dump_packet(capture_cfg.pd, pkt);
return;
}
// Not an interesting packet ...
capture_packet_destroy(pkt);
}
int
capture_packet_parse(capture_packet_t *pkt)
{
// Media structure for RTP packets
rtp_stream_t *stream;
// We're only interested in packets with payload
if (capture_packet_get_payload_len(pkt)) {
// Parse this header and payload
if (sip_load_message(pkt, pkt->ip_src, pkt->sport, pkt->ip_dst, pkt->dport)) {
// Store this packets in output file
dump_packet(capture_cfg.pd, pkt);
return;
return 0;
}
// Check if this packet belongs to a RTP stream
@ -306,18 +333,15 @@ parse_packet(u_char *info, const struct pcap_pkthdr *header, const u_char *packe
if ((stream = rtp_check_stream(pkt, pkt->ip_src, pkt->sport, pkt->ip_dst, pkt->dport))) {
// We have an RTP packet!
capture_packet_set_type(pkt, CAPTURE_PACKET_RTP);
// Store this packets in output file
dump_packet(capture_cfg.pd, pkt);
// Store this pacekt if capture rtp is enabled
if (capture_cfg.rtp_capture) {
call_add_rtp_packet(stream_get_call(stream), pkt);
return;
return 0;
}
}
}
// Not an interesting packet ...
capture_packet_destroy(pkt);
return 1;
}
void
@ -479,11 +503,12 @@ capture_last_error(cap)
}
capture_packet_t *
capture_packet_create(uint8_t proto, const char *ip_src, const char *ip_dst, uint32_t id)
capture_packet_create(uint8_t ip_ver, uint8_t proto, const char *ip_src, const char *ip_dst, uint32_t id)
{
// Create a new packet
capture_packet_t *packet;
packet = sng_malloc(sizeof(capture_packet_t));
packet->ip_version = ip_ver;
packet->proto = proto;
packet->frames = vector_create(1, 1);
packet->ip_id = id;
@ -537,9 +562,12 @@ capture_packet_add_frame(capture_packet_t *pkt, const struct pcap_pkthdr *header
// Add frame to this packet
frame = sng_malloc(sizeof(capture_frame_t));
frame->header = sng_malloc(sizeof(struct pcap_pkthdr));
frame->data = sng_malloc(header->caplen);
memcpy(frame->header, header, sizeof(struct pcap_pkthdr));
memcpy(frame->data, packet, header->caplen);
if (capture_cfg.storage != 0) {
frame->data = sng_malloc(header->caplen);
memcpy(frame->data, packet, header->caplen);
}
vector_append(pkt->frames, frame);
return frame;
}

View File

@ -83,6 +83,12 @@ enum capture_status {
CAPTURE_OFFLINE_LOADING,
};
enum capture_storage {
CAPTURE_STORAGE_NONE = 0,
CAPTURE_STORAGE_MEMORY,
CAPTURE_STORAGE_DISK
};
//! Shorter declaration of capture_config structure
typedef struct capture_config capture_config_t;
//; Shorter declaration of capture_info structure
@ -128,6 +134,8 @@ struct capture_config {
int limit;
//! Also capture RTP packets
int rtp_capture;
//! Where should we store captured packets
int storage;
//! Key file for TLS decrypt
const char *keyfile;
//! The compiled filter expression
@ -180,6 +188,8 @@ struct capture_info
*/
struct capture_packet {
// IP protocol
uint8_t ip_version;
// Transport protocol
uint8_t proto;
// Packet type as defined in capture_packet_type
int type;
@ -258,6 +268,17 @@ capture_offline(const char *infile, const char *outfile);
void
parse_packet(u_char *capinfo, const struct pcap_pkthdr *header, const u_char *packet);
/**
* @brief Check if the given packet structure is SIP/RTP/..
*
* This function will call parse functions to determine if packet has relevant data
*
* @return 0 in case this packets has SIP/RTP data
* @return 1 otherwise
*/
int
capture_packet_parse(capture_packet_t *pkt);
/**
* @brief Create a capture thread for online mode
*
@ -355,7 +376,7 @@ capture_last_error();
* @brief Allocate memory to store new packet data
*/
capture_packet_t *
capture_packet_create(uint8_t proto, const char *ip_src, const char *ip_dst, uint32_t id);
capture_packet_create(uint8_t ip_ver, uint8_t proto, const char *ip_src, const char *ip_dst, uint32_t id);
/**
* @brief Set Transport layer information

519
src/capture_eep.c Normal file
View File

@ -0,0 +1,519 @@
/**************************************************************************
**
** sngrep - SIP Messages flow viewer
**
** Copyright (C) 2013,2014 Ivan Alonso (Kaian)
** Copyright (C) 2013,2014 Irontec SL. All rights reserved.
** Copyright (C) 2012 Homer Project (http://www.sipcapture.org)
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
/**
* @file capture.c
*
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
* @author Alexandr Dubovikov <alexandr.dubovikov@gmail.com>
*
* @brief Functions to manage eep protocol
*
* This file contains declaration of structure and functions to send and
* receive packet information through HEP-EEP (Extensible Encapsulation Protocol)
*
* Additional information about HEP-EEP protocol can be found in sipcature
* repositories at https://github.com/sipcapture/HEP
*
* @note Most of this code has been taken from hep-c and sipgrep (originally
* written by Alexandr Dubovikov). Modifications of sources to work with
* sngrep packet structures has been made by Ivan Alonso (Kaian)
*
*/
#include "config.h"
#include <sys/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <unistd.h>
#include <pcap.h>
#include "capture_eep.h"
#include "util.h"
#include "setting.h"
capture_eep_config_t eep_cfg = { 0 };
void *
accept_eep_client(void *data);
int
capture_eep_init()
{
struct addrinfo *ai, hints[1] = { { 0 } };
struct sockaddr_in srvaddr;
struct in_addr addr;
// Setting for EEP client
if (setting_enabled(SETTING_EEP_SEND)) {
// Fill configuration structure
eep_cfg.capt_host = setting_get_value(SETTING_EEP_SEND_ADDR);
eep_cfg.capt_port = setting_get_value(SETTING_EEP_SEND_PORT);
eep_cfg.capt_password = setting_get_value(SETTING_EEP_SEND_PASS);
eep_cfg.capt_id = 2002;
hints->ai_flags = AI_NUMERICSERV;
hints->ai_family = AF_UNSPEC;
hints->ai_socktype = SOCK_DGRAM;
hints->ai_protocol = IPPROTO_UDP;
if (getaddrinfo(eep_cfg.capt_host, eep_cfg.capt_port, hints, &ai)) {
fprintf(stderr, "capture: getaddrinfo() error\n");
return 1;
}
eep_cfg.client_sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (eep_cfg.client_sock < 0) {
fprintf(stderr, "Sender socket creation failed: %s\n", strerror(errno));
return 1;
}
if (connect(eep_cfg.client_sock, ai->ai_addr, (socklen_t) (ai->ai_addrlen)) == -1) {
if (errno != EINPROGRESS) {
fprintf(stderr, "Sender socket creation failed: %s\n", strerror(errno));
return 1;
}
}
}
if (setting_enabled(SETTING_EEP_LISTEN)) {
// Fill configuration structure
eep_cfg.capt_srv_host = setting_get_value(SETTING_EEP_LISTEN_ADDR);
eep_cfg.capt_srv_port = setting_get_value(SETTING_EEP_LISTEN_PORT);
eep_cfg.capt_srv_password = setting_get_value(SETTING_EEP_LISTEN_PASS);
hints->ai_flags = AI_NUMERICSERV;
hints->ai_family = AF_UNSPEC;
hints->ai_socktype = SOCK_DGRAM;
hints->ai_protocol = IPPROTO_UDP;
// Create a socket for a new TCP IPv4 connection
eep_cfg.server_sock = socket(AF_INET, SOCK_DGRAM, 0);
if (eep_cfg.client_sock < 0) {
fprintf(stderr, "Error creating server socket: %s\n", strerror(errno));
return 1;
}
// Get network address
if (inet_aton(eep_cfg.capt_srv_host, &addr) == 0) {
fprintf(stderr, "Error getting network address: %s\n", strerror(errno));
return 1;
}
// Bind that socket to the requested address and port
memset(&srvaddr, 0, sizeof(srvaddr));
srvaddr.sin_family = AF_INET;
srvaddr.sin_addr = addr;
srvaddr.sin_port = htons(atoi(eep_cfg.capt_srv_port));
if (bind(eep_cfg.server_sock, (struct sockaddr *) &srvaddr, sizeof(srvaddr)) == -1) {
fprintf(stderr, "Error binding address: %s\n", strerror(errno));
return 1;
}
// Create a new thread for accepting client connections
if (pthread_create(&eep_cfg.server_thread, NULL, accept_eep_client, NULL) != 0) {
fprintf(stderr, "Error creating accept thread: %s\n", strerror(errno));
return 1;
}
}
// Settings for EEP server
return 0;
}
void *
accept_eep_client(void *data)
{
capture_packet_t *pkt;
// Begin accepting connections
while (eep_cfg.server_sock > 0) {
if ((pkt = capture_eep_receive())) {
if (capture_packet_parse(pkt) != 0) {
capture_packet_destroy(pkt);
}
}
}
// Leave the thread gracefully
pthread_exit(NULL);
return 0;
}
void
capture_eep_deinit()
{
if (eep_cfg.client_sock)
close(eep_cfg.client_sock);
if (eep_cfg.server_sock) {
close(eep_cfg.server_sock);
eep_cfg.server_sock = -1;
//pthread_join(&eep_cfg.server_thread, &ret);
}
}
int
capture_eep_send(capture_packet_t *pkt)
{
struct hep_generic *hg = NULL;
void* buffer;
unsigned int buflen = 0, iplen = 0, tlen = 0;
hep_chunk_ip4_t src_ip4, dst_ip4;
#ifdef USE_IPV6
hep_chunk_ip6_t src_ip6, dst_ip6;
#endif
hep_chunk_t payload_chunk;
hep_chunk_t authkey_chunk;
capture_frame_t *frame = vector_first(pkt->frames);
unsigned char *data = capture_packet_get_payload(pkt);
unsigned int len = capture_packet_get_payload_len(pkt);
// Check we have a connection established
if (!eep_cfg.client_sock)
return 1;
// Dont send RTP packets
if (pkt->type == CAPTURE_PACKET_RTP)
return 1;
hg = sng_malloc(sizeof(struct hep_generic));
/* header set */
memcpy(hg->header.id, "\x48\x45\x50\x33", 4);
/* IP proto */
hg->ip_family.chunk.vendor_id = htons(0x0000);
hg->ip_family.chunk.type_id = htons(0x0001);
hg->ip_family.data = pkt->ip_version == 4 ? AF_INET : AF_INET6;
hg->ip_family.chunk.length = htons(sizeof(hg->ip_family));
/* Proto ID */
hg->ip_proto.chunk.vendor_id = htons(0x0000);
hg->ip_proto.chunk.type_id = htons(0x0002);
hg->ip_proto.data = pkt->proto;
hg->ip_proto.chunk.length = htons(sizeof(hg->ip_proto));
/* IPv4 */
if (pkt->ip_version == 4) {
/* SRC IP */
src_ip4.chunk.vendor_id = htons(0x0000);
src_ip4.chunk.type_id = htons(0x0003);
inet_pton(AF_INET, pkt->ip_src, &src_ip4.data);
src_ip4.chunk.length = htons(sizeof(src_ip4));
/* DST IP */
dst_ip4.chunk.vendor_id = htons(0x0000);
dst_ip4.chunk.type_id = htons(0x0004);
inet_pton(AF_INET, pkt->ip_dst, &dst_ip4.data);
dst_ip4.chunk.length = htons(sizeof(dst_ip4));
iplen = sizeof(dst_ip4) + sizeof(src_ip4);
}
#ifdef USE_IPV6
/* IPv6 */
else if(pkt->ip_version == 6) {
/* SRC IPv6 */
src_ip6.chunk.vendor_id = htons(0x0000);
src_ip6.chunk.type_id = htons(0x0005);
inet_pton(AF_INET6, pkt->ip_src, &src_ip6.data);
src_ip6.chunk.length = htonl(sizeof(src_ip6));
/* DST IPv6 */
dst_ip6.chunk.vendor_id = htons(0x0000);
dst_ip6.chunk.type_id = htons(0x0006);
inet_pton(AF_INET6, pkt->ip_dst, &dst_ip6.data);
dst_ip6.chunk.length = htonl(sizeof(dst_ip6));
iplen = sizeof(dst_ip6) + sizeof(src_ip6);
}
#endif
/* SRC PORT */
hg->src_port.chunk.vendor_id = htons(0x0000);
hg->src_port.chunk.type_id = htons(0x0007);
hg->src_port.data = htons(pkt->sport);
hg->src_port.chunk.length = htons(sizeof(hg->src_port));
/* DST PORT */
hg->dst_port.chunk.vendor_id = htons(0x0000);
hg->dst_port.chunk.type_id = htons(0x0008);
hg->dst_port.data = htons(pkt->dport);
hg->dst_port.chunk.length = htons(sizeof(hg->dst_port));
/* TIMESTAMP SEC */
hg->time_sec.chunk.vendor_id = htons(0x0000);
hg->time_sec.chunk.type_id = htons(0x0009);
hg->time_sec.data = htonl(frame->header->ts.tv_sec);
hg->time_sec.chunk.length = htons(sizeof(hg->time_sec));
/* TIMESTAMP USEC */
hg->time_usec.chunk.vendor_id = htons(0x0000);
hg->time_usec.chunk.type_id = htons(0x000a);
hg->time_usec.data = htonl(frame->header->ts.tv_usec);
hg->time_usec.chunk.length = htons(sizeof(hg->time_usec));
/* Protocol TYPE */
hg->proto_t.chunk.vendor_id = htons(0x0000);
hg->proto_t.chunk.type_id = htons(0x000b);
hg->proto_t.data = 1;
hg->proto_t.chunk.length = htons(sizeof(hg->proto_t));
/* Capture ID */
hg->capt_id.chunk.vendor_id = htons(0x0000);
hg->capt_id.chunk.type_id = htons(0x000c);
hg->capt_id.data = htons(eep_cfg.capt_id);
hg->capt_id.chunk.length = htons(sizeof(hg->capt_id));
/* Payload */
payload_chunk.vendor_id = htons(0x0000);
payload_chunk.type_id = htons(0x000f);
payload_chunk.length = htons(sizeof(payload_chunk) + len);
tlen = sizeof(struct hep_generic) + len + iplen + sizeof(hep_chunk_t);
/* auth key */
if (eep_cfg.capt_password != NULL) {
tlen += sizeof(hep_chunk_t);
/* Auth key */
authkey_chunk.vendor_id = htons(0x0000);
authkey_chunk.type_id = htons(0x000e);
authkey_chunk.length = htons(sizeof(authkey_chunk) + strlen(eep_cfg.capt_password));
tlen += strlen(eep_cfg.capt_password);
}
/* total */
hg->header.length = htons(tlen);
if (!(buffer = sng_malloc(tlen))) {
sng_free(hg);
return 1;
}
memcpy((void*) buffer, hg, sizeof(struct hep_generic));
buflen = sizeof(struct hep_generic);
/* IPv4 */
if (pkt->ip_version == 4) {
/* SRC IP */
memcpy((void*) buffer + buflen, &src_ip4, sizeof(struct hep_chunk_ip4));
buflen += sizeof(struct hep_chunk_ip4);
memcpy((void*) buffer + buflen, &dst_ip4, sizeof(struct hep_chunk_ip4));
buflen += sizeof(struct hep_chunk_ip4);
}
#ifdef USE_IPV6
/* IPv6 */
else if(pkt->ip_version == 6) {
/* SRC IPv6 */
memcpy((void*) buffer+buflen, &src_ip4, sizeof(struct hep_chunk_ip6));
buflen += sizeof(struct hep_chunk_ip6);
memcpy((void*) buffer+buflen, &dst_ip6, sizeof(struct hep_chunk_ip6));
buflen += sizeof(struct hep_chunk_ip6);
}
#endif
/* AUTH KEY CHUNK */
if (eep_cfg.capt_password != NULL) {
memcpy((void*) buffer + buflen, &authkey_chunk, sizeof(struct hep_chunk));
buflen += sizeof(struct hep_chunk);
/* Now copying payload self */
memcpy((void*) buffer + buflen, eep_cfg.capt_password, strlen(eep_cfg.capt_password));
buflen += strlen(eep_cfg.capt_password);
}
/* PAYLOAD CHUNK */
memcpy((void*) buffer + buflen, &payload_chunk, sizeof(struct hep_chunk));
buflen += sizeof(struct hep_chunk);
/* Now copying payload self */
memcpy((void*) buffer + buflen, data, len);
buflen += len;
if (send(eep_cfg.client_sock, buffer, buflen, 0) == -1) {
return 1;
}
/* FREE */
sng_free(buffer);
sng_free(hg);
return 0;
}
capture_packet_t *
capture_eep_receive()
{
struct hep_generic hg;
hep_chunk_ip4_t src_ip4, dst_ip4;
#ifdef USE_IPV6
hep_chunk_ip6_t src_ip6, dst_ip6;
#endif
hep_chunk_t payload_chunk;
hep_chunk_t authkey_chunk;
uint8_t family, proto;
char password[100];
int password_len;
unsigned char *payload = 0;
unsigned int len, pos;
char buffer[MAX_CAPTURE_LEN] ;
//! Source and Destination Address
char ip_src[ADDRESSLEN], ip_dst[ADDRESSLEN];
//! EEP client data
struct sockaddr eep_client;
socklen_t eep_client_len;
//! Source and Destination Port
u_short sport, dport;
//! Packet header
struct pcap_pkthdr header;
//! New created packet pointer
capture_packet_t *pkt;
/* Receive EEP generic header */
if (recvfrom(eep_cfg.server_sock, buffer, MAX_CAPTURE_LEN, 0, &eep_client, &eep_client_len) == -1)
return NULL;
/* Copy initial bytes to EEP Generic header */
memcpy(&hg, buffer, sizeof(struct hep_generic));
/* header set */
if (!memcpy(hg.header.id, "\x48\x45\x50\x33", 4))
return NULL;
/* IP proto */
family = hg.ip_family.data;
/* Proto ID */
proto = hg.ip_proto.data;
len = ntohs(hg.header.length) - sizeof(struct hep_generic);
pos = sizeof(struct hep_generic);
/* IPv4 */
if (family == AF_INET) {
/* SRC IP */
memcpy(&src_ip4, (void*) buffer + pos, sizeof(struct hep_chunk_ip4));
inet_ntop(AF_INET, &src_ip4.data, ip_src, sizeof(ip_src));
pos += sizeof(struct hep_chunk_ip4);
/* DST IP */
memcpy(&dst_ip4, (void*) buffer + pos, sizeof(struct hep_chunk_ip4));
inet_ntop(AF_INET, &dst_ip4.data, ip_dst, sizeof(ip_dst));
pos += sizeof(struct hep_chunk_ip4);
}
#ifdef USE_IPV6
/* IPv6 */
else if(family == AF_INET6) {
/* SRC IPv6 */
memcpy(&src_ip6, (void*) buffer + pos, sizeof(struct hep_chunk_ip6));
inet_ntop(AF_INET6, &src_ip6.data, ip_src, sizeof(ip_src));
pos += sizeof(struct hep_chunk_ip6);
/* DST IP */
memcpy(&src_ip6, (void*) buffer + pos, sizeof(struct hep_chunk_ip6));
inet_ntop(AF_INET6, &dst_ip6.data, ip_dst, sizeof(ip_dst));
pos += sizeof(struct hep_chunk_ip6);
}
#endif
/* SRC PORT */
sport = ntohs(hg.src_port.data);
/* DST PORT */
dport = ntohs(hg.dst_port.data);
/* TIMESTAMP*/
header.ts.tv_sec = ntohl(hg.time_sec.data);
header.ts.tv_usec = ntohl(hg.time_usec.data);
/* Protocol TYPE */
/* Capture ID */
/* auth key */
if (eep_cfg.capt_srv_password != NULL) {
memcpy(&authkey_chunk, (void*) buffer + pos, sizeof(authkey_chunk));
pos += sizeof(authkey_chunk);
password_len = ntohs(authkey_chunk.length) - sizeof(authkey_chunk);
memcpy(password, (void*) buffer + pos, password_len);
pos += password_len;
// Validate the password
if (strncmp(password, eep_cfg.capt_srv_password, password_len) != 0)
return NULL;
}
/* Payload */
memcpy(&payload_chunk, (void*) buffer + pos, sizeof(payload_chunk));
pos += sizeof(payload_chunk);
// Calculate payload size
header.caplen = header.len = ntohs(payload_chunk.length) - sizeof(payload_chunk);
// Receive packet payload
payload = sng_malloc(header.caplen);
memcpy(payload, (void*) buffer + pos, header.caplen);
// Create a new packet
pkt = capture_packet_create((family == AF_INET)?4:6, proto, ip_src, ip_dst, 0);
capture_packet_add_frame(pkt, &header, payload);
capture_packet_set_transport_data(pkt, sport, dport, CAPTURE_PACKET_SIP_UDP);
capture_packet_set_payload(pkt, payload, header.caplen);
/* FREE */
sng_free(payload);
return pkt;
}
int
capture_eep_set_server_url(const char *url)
{
char urlstr[256];
char address[256], port[256];
strncpy(urlstr, url, strlen(url));
if (sscanf(urlstr, "%*[^:]:%[^:]:%s", address, port) == 2) {
setting_set_value(SETTING_EEP_LISTEN, SETTING_ON);
setting_set_value(SETTING_EEP_LISTEN_ADDR, address);
setting_set_value(SETTING_EEP_LISTEN_PORT, port);
return 0;
}
return 1;
}
int
capture_eep_set_client_url(const char *url)
{
char urlstr[256];
char address[256], port[256];
strncpy(urlstr, url, strlen(url));
if (sscanf(urlstr, "%*[^:]:%[^:]:%s", address, port) == 2) {
setting_set_value(SETTING_EEP_SEND, SETTING_ON);
setting_set_value(SETTING_EEP_SEND_ADDR, address);
setting_set_value(SETTING_EEP_SEND_PORT, port);
return 0;
}
return 1;
}

214
src/capture_eep.h Normal file
View File

@ -0,0 +1,214 @@
/**************************************************************************
**
** sngrep - SIP Messages flow viewer
**
** Copyright (C) 2013,2014 Ivan Alonso (Kaian)
** Copyright (C) 2013,2014 Irontec SL. All rights reserved.
** Copyright (C) 2012 Homer Project (http://www.sipcapture.org)
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
/**
* @file capture.h
*
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
* @author Alexandr Dubovikov <alexandr.dubovikov@gmail.com>
*
* @brief Functions to manage eep protocol
*
* This file contains declaration of structure and functions to send and
* receive packet information through HEP-EEP (Extensible Encapsulation Protocol)
*
* Additional information about HEP-EEP protocol can be found in sipcature
* repositories at https://github.com/sipcapture/HEP
*
* @note Most of this code has been taken from hep-c and sipgrep (originally
* written by Alexandr Dubovikov). Modifications of sources to work with
* sngrep packet structures has been made by Ivan Alonso (Kaian)
*
*/
#include <pthread.h>
#include "capture.h"
typedef struct capture_eep_config capture_eep_config_t;
typedef struct eep_info eep_info_t;
struct capture_eep_config
{
int client_sock;
int server_sock;
int capt_id;
const char *capt_host;
const char *capt_port;
const char *capt_password;
const char *capt_srv_host;
const char *capt_srv_port;
const char *capt_srv_password;
pthread_t server_thread;
};
struct eep_info {
uint8_t ip_family; /* IP family IPv6 IPv4 */
uint8_t ip_proto; /* IP protocol ID : tcp/udp */
uint8_t proto_type; /* SIP: 0x001, SDP: 0x03 */
const char *ip_src;
const char *ip_dst;
uint16_t sport;
uint16_t dport;
uint32_t time_sec;
uint32_t time_usec;
} ;
/* HEPv3 types */
struct hep_chunk
{
u_int16_t vendor_id;
u_int16_t type_id;
u_int16_t length;
}__attribute__((packed));
typedef struct hep_chunk hep_chunk_t;
struct hep_chunk_uint8
{
hep_chunk_t chunk;
u_int8_t data;
}__attribute__((packed));
typedef struct hep_chunk_uint8 hep_chunk_uint8_t;
struct hep_chunk_uint16
{
hep_chunk_t chunk;
u_int16_t data;
}__attribute__((packed));
typedef struct hep_chunk_uint16 hep_chunk_uint16_t;
struct hep_chunk_uint32
{
hep_chunk_t chunk;
u_int32_t data;
}__attribute__((packed));
typedef struct hep_chunk_uint32 hep_chunk_uint32_t;
struct hep_chunk_str
{
hep_chunk_t chunk;
char *data;
}__attribute__((packed));
typedef struct hep_chunk_str hep_chunk_str_t;
struct hep_chunk_ip4
{
hep_chunk_t chunk;
struct in_addr data;
}__attribute__((packed));
typedef struct hep_chunk_ip4 hep_chunk_ip4_t;
struct hep_chunk_ip6
{
hep_chunk_t chunk;
struct in6_addr data;
}__attribute__((packed));
typedef struct hep_chunk_ip6 hep_chunk_ip6_t;
struct hep_ctrl
{
char id[4];
u_int16_t length;
}__attribute__((packed));
typedef struct hep_ctrl hep_ctrl_t;
struct hep_chunk_payload
{
hep_chunk_t chunk;
char *data;
}__attribute__((packed));
typedef struct hep_chunk_payload hep_chunk_payload_t;
/* Structure of HEP */
struct hep_generic
{
hep_ctrl_t header;
hep_chunk_uint8_t ip_family;
hep_chunk_uint8_t ip_proto;
hep_chunk_uint16_t src_port;
hep_chunk_uint16_t dst_port;
hep_chunk_uint32_t time_sec;
hep_chunk_uint32_t time_usec;
hep_chunk_uint8_t proto_t;
hep_chunk_uint32_t capt_id;
}__attribute__((packed));
typedef struct hep_generic hep_generic_t;
struct hep_hdr
{
u_int8_t hp_v; /* version */
u_int8_t hp_l; /* length */
u_int8_t hp_f; /* family */
u_int8_t hp_p; /* protocol */
u_int16_t hp_sport; /* source port */
u_int16_t hp_dport; /* destination port */
};
struct hep_timehdr
{
u_int32_t tv_sec; /* seconds */
u_int32_t tv_usec; /* useconds */
u_int16_t captid; /* Capture ID node */
};
struct hep_iphdr
{
struct in_addr hp_src;
struct in_addr hp_dst; /* source and dest address */
};
#ifdef USE_IPV6
struct hep_ip6hdr
{
struct in6_addr hp6_src; /* source address */
struct in6_addr hp6_dst; /* destination address */
};
#endif
int
capture_eep_init();
void
capture_eep_deinit();
int
capture_eep_send(capture_packet_t *pkt);
capture_packet_t *
capture_eep_receive();
int
capture_eep_set_server_url(const char *url);
int
capture_eep_set_client_url(const char *url);

View File

@ -131,7 +131,7 @@ capture_packet_reasm_ip(capture_info_t *capinfo, const struct pcap_pkthdr *heade
// If no fragmentation
if (ip_frag == 0) {
// Just create a new packet with given network data
pkt = capture_packet_create(ip_proto, ip_src, ip_dst, ip_id);
pkt = capture_packet_create(ip_ver, ip_proto, ip_src, ip_dst, ip_id);
capture_packet_add_frame(pkt, header, packet);
return pkt;
}
@ -148,7 +148,7 @@ capture_packet_reasm_ip(capture_info_t *capinfo, const struct pcap_pkthdr *heade
capture_packet_add_frame(pkt, header, packet);
} else {
// Add To the possible reassembly list
pkt = capture_packet_create(ip_proto, ip_src, ip_dst, ip_id);
pkt = capture_packet_create(ip_ver, ip_proto, ip_src, ip_dst, ip_id);
capture_packet_add_frame(pkt, header, packet);
vector_append(capture_cfg.ip_reasm, pkt);
return NULL;

View File

@ -36,6 +36,7 @@
#include "vector.h"
#include "ui_manager.h"
#include "capture.h"
#include "capture_eep.h"
#ifdef WITH_OPENSSL
#include "capture_tls.h"
#endif
@ -64,6 +65,8 @@ usage()
" -i --icase\t\t Make <match expression> case insensitive\n"
" -v --invert\t\t Invert <match expression>\n"
" -N --no-interface\t Don't display sngrep interface, just capture\n"
" -H --eep-send\t Homer sipcapture url (udp:X.X.X.X:XXXX)\n"
" -L --eep-listen\t Listen for encapsulated packets (udp:X.X.X.X:XXXX)\n"
" -q --quiet\t\t Don't print captured dialogs in no interface mode\n"
#ifdef WITH_OPENSSL
" -k --keyfile\t RSA private keyfile to decrypt captured packets\n"
@ -128,6 +131,8 @@ main(int argc, char* argv[])
{ "invert", no_argument, 0, 'v' },
{ "no-interface", no_argument, 0, 'N' },
{ "dump-config", no_argument, 0, 'D' },
{ "eep-listen", required_argument, 0, 'L' },
{ "eep-send", required_argument, 0, 'H' },
{ "quiet", no_argument, 0, 'q' },
};
@ -145,7 +150,7 @@ main(int argc, char* argv[])
// Parse command line arguments
opterr = 0;
char *options = "hVd:I:O:pqtW:k:crl:ivNqD";
char *options = "hVd:I:O:pqtW:k:crl:ivNqDL:H:";
while ((opt = getopt_long(argc, argv, options, long_options, &idx)) != -1) {
switch (opt) {
case 'h':
@ -188,6 +193,7 @@ main(int argc, char* argv[])
break;
case 'N':
no_interface = 1;
setting_set_value(SETTING_CAPTURE_STORAGE, "none");
break;
case 'q':
quiet = 1;
@ -200,6 +206,12 @@ main(int argc, char* argv[])
case 't':
case 'W':
break;
case 'L':
capture_eep_set_server_url(optarg);
break;
case 'H':
capture_eep_set_client_url(optarg);
break;
case '?':
if (strchr(options, optopt)) {
fprintf(stderr, "-%c option requires an argument.\n", optopt);
@ -237,6 +249,9 @@ main(int argc, char* argv[])
// Set capture options
capture_init(limit, rtp_capture);
// Initialize EEP if enabled
capture_eep_init();
// If we have an input file, load it
if (vector_count(infiles)) {
for (i = 0; i < vector_count(infiles); i++) {

View File

@ -36,38 +36,47 @@
//! Available configurable settings
setting_t settings[SETTING_COUNT] = {
{ SETTING_BACKGROUND, "background", SETTING_FMT_ENUM, "dark", SETTING_ENUM_BACKGROUND },
{ SETTING_COLORMODE, "colormode", SETTING_FMT_ENUM, "request", SETTING_ENUM_COLORMODE },
{ SETTING_SYNTAX, "syntax", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_SYNTAX_TAG, "syntax.tag", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_SYNTAX_BRANCH, "syntax.branch", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_ALTKEY_HINT, "hintkeyalt", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_EXITPROMPT, "exitprompt", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_CAPTURE_LIMIT, "capture.limit", SETTING_FMT_NUMBER, "20000", NULL },
{ SETTING_CAPTURE_LOOKUP, "capture.lookup", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_CAPTURE_DEVICE, "capture.device", SETTING_FMT_STRING, "any", NULL },
{ SETTING_CAPTURE_OUTFILE, "capture.outfile", SETTING_FMT_STRING, "", NULL },
{ SETTING_CAPTURE_KEYFILE, "capture.keyfile", SETTING_FMT_STRING, "", NULL },
{ SETTING_CAPTURE_RTP, "capture.rtp", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_SIP_NOINCOMPLETE, "sip.noincomplete", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_SIP_CALLS, "sip.calls", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_SAVEPATH, "savepath", SETTING_FMT_STRING, "", NULL },
{ SETTING_DISPLAY_HOST, "displayhost", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_DISPLAY_ALIAS, "displayalias", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_CL_FILTER, "cl.filter", SETTING_FMT_STRING, "", NULL },
{ SETTING_CL_SCROLLSTEP, "cl.scrollstep", SETTING_FMT_NUMBER, "4", NULL },
{ SETTING_CF_FORCERAW, "cf.forceraw", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_CF_RAWMINWIDTH, "cf.rawminwidth", SETTING_FMT_NUMBER, "40", NULL },
{ SETTING_CF_RAWFIXEDWIDTH, "cf.rawfixedwidth", SETTING_FMT_NUMBER, "", NULL },
{ SETTING_CF_SPLITCALLID, "cf.splitcallid", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_CF_HIGHTLIGHT, "cf.highlight", SETTING_FMT_ENUM, "bold", SETTING_ENUM_HIGHLIGHT },
{ SETTING_CF_SCROLLSTEP, "cf.scrollstep", SETTING_FMT_NUMBER, "4", NULL },
{ SETTING_CF_LOCALHIGHLIGHT, "cf.localhighlight", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_CF_SDP_INFO, "cf.sdpinfo", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_SDP_INFO },
{ SETTING_CF_MEDIA, "cf.media", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_CF_DELTA, "cf.deltatime", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_CR_SCROLLSTEP, "cr.scrollstep", SETTING_FMT_NUMBER, "10", NULL },
{ SETTING_FILTER_METHODS, "filter.methods", SETTING_FMT_STRING, "", NULL },
{ SETTING_BACKGROUND, "background", SETTING_FMT_ENUM, "dark", SETTING_ENUM_BACKGROUND },
{ SETTING_COLORMODE, "colormode", SETTING_FMT_ENUM, "request", SETTING_ENUM_COLORMODE },
{ SETTING_SYNTAX, "syntax", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_SYNTAX_TAG, "syntax.tag", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_SYNTAX_BRANCH, "syntax.branch", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_ALTKEY_HINT, "hintkeyalt", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_EXITPROMPT, "exitprompt", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_CAPTURE_LIMIT, "capture.limit", SETTING_FMT_NUMBER, "20000", NULL },
{ SETTING_CAPTURE_LOOKUP, "capture.lookup", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_CAPTURE_DEVICE, "capture.device", SETTING_FMT_STRING, "any", NULL },
{ SETTING_CAPTURE_OUTFILE, "capture.outfile", SETTING_FMT_STRING, "", NULL },
{ SETTING_CAPTURE_KEYFILE, "capture.keyfile", SETTING_FMT_STRING, "", NULL },
{ SETTING_CAPTURE_RTP, "capture.rtp", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_CAPTURE_STORAGE, "capture.storage", SETTING_FMT_ENUM, "memory", SETTING_ENUM_STORAGE },
{ SETTING_SIP_NOINCOMPLETE, "sip.noincomplete", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_SIP_CALLS, "sip.calls", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_SAVEPATH, "savepath", SETTING_FMT_STRING, "", NULL },
{ SETTING_DISPLAY_HOST, "displayhost", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_DISPLAY_ALIAS, "displayalias", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_CL_FILTER, "cl.filter", SETTING_FMT_STRING, "", NULL },
{ SETTING_CL_SCROLLSTEP, "cl.scrollstep", SETTING_FMT_NUMBER, "4", NULL },
{ SETTING_CF_FORCERAW, "cf.forceraw", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_CF_RAWMINWIDTH, "cf.rawminwidth", SETTING_FMT_NUMBER, "40", NULL },
{ SETTING_CF_RAWFIXEDWIDTH, "cf.rawfixedwidth", SETTING_FMT_NUMBER, "", NULL },
{ SETTING_CF_SPLITCALLID, "cf.splitcallid", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_CF_HIGHTLIGHT, "cf.highlight", SETTING_FMT_ENUM, "bold", SETTING_ENUM_HIGHLIGHT },
{ SETTING_CF_SCROLLSTEP, "cf.scrollstep", SETTING_FMT_NUMBER, "4", NULL },
{ SETTING_CF_LOCALHIGHLIGHT, "cf.localhighlight", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_CF_SDP_INFO, "cf.sdpinfo", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_SDP_INFO },
{ SETTING_CF_MEDIA, "cf.media", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_CF_DELTA, "cf.deltatime", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_CR_SCROLLSTEP, "cr.scrollstep", SETTING_FMT_NUMBER, "10", NULL },
{ SETTING_FILTER_METHODS, "filter.methods", SETTING_FMT_STRING, "", NULL },
{ SETTING_EEP_SEND, "eep.send", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_EEP_SEND_ADDR, "eep.send.address", SETTING_FMT_STRING, "", NULL },
{ SETTING_EEP_SEND_PORT, "eep.send.port", SETTING_FMT_NUMBER, "9060", NULL },
{ SETTING_EEP_SEND_PASS, "eep.send.pass", SETTING_FMT_STRING, "myHep", NULL },
{ SETTING_EEP_LISTEN, "eep.listen", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_EEP_LISTEN_ADDR, "eep.listen.address", SETTING_FMT_STRING, "0.0.0.0", NULL },
{ SETTING_EEP_LISTEN_PORT, "eep.listen.port", SETTING_FMT_NUMBER, "9060", NULL },
{ SETTING_EEP_LISTEN_PASS, "eep.listen.pass", SETTING_FMT_STRING, "myHep", NULL },
};
setting_t *

View File

@ -54,6 +54,7 @@ typedef struct setting_option setting_t;
#define SETTING_ENUM_COLORMODE (const char *[]){ "request", "cseq", "callid", NULL }
#define SETTING_ENUM_HIGHLIGHT (const char *[]){ "bold", "reverse", "reversebold", NULL }
#define SETTING_ENUM_SDP_INFO (const char *[]){ "off", "first", "full", NULL}
#define SETTING_ENUM_STORAGE (const char *[]){ "none", "memory", NULL }
//! Other useful defines
#define SETTING_ON "on"
@ -77,6 +78,7 @@ enum setting_id {
SETTING_CAPTURE_OUTFILE,
SETTING_CAPTURE_KEYFILE,
SETTING_CAPTURE_RTP,
SETTING_CAPTURE_STORAGE,
SETTING_SIP_NOINCOMPLETE,
SETTING_SIP_CALLS,
SETTING_SAVEPATH,
@ -96,6 +98,14 @@ enum setting_id {
SETTING_CF_DELTA,
SETTING_CR_SCROLLSTEP,
SETTING_FILTER_METHODS,
SETTING_EEP_SEND,
SETTING_EEP_SEND_ADDR,
SETTING_EEP_SEND_PORT,
SETTING_EEP_SEND_PASS,
SETTING_EEP_LISTEN,
SETTING_EEP_LISTEN_ADDR,
SETTING_EEP_LISTEN_PORT,
SETTING_EEP_LISTEN_PASS,
SETTING_COUNT
};