mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-03 11:25:35 +00:00
res_hep/res_hep_pjsip: Add a HEPv3 capture agent module and a logger for PJSIP
This patch adds the following: (1) A new module, res_hep, which implements a generic packet capture agent for the Homer Encapsulation Protocol (HEP) version 3. Note that this code is based on a patch provided by Alexandr Dubovikov; I basically just wrapped it up, added configuration via the configuration framework, and threw in a taskprocessor. (2) A new module, res_hep_pjsip, which forwards all SIP message traffic that passes through the res_pjsip stack over to res_hep for encapsulation and transmission to a HEPv3 capture server. Much thanks to Alexandr for his Asterisk patch for this code and for a *lot* of patience waiting for me to port it to 12/trunk. Due to some dithering on my part, this has taken the better part of a year to port forward (I still blame CDRs for the delay). ASTERISK-23557 #close Review: https://reviewboard.asterisk.org/r/3207/ ........ Merged revisions 411534 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@411556 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
23
CHANGES
23
CHANGES
@@ -89,21 +89,11 @@ Debugging
|
|||||||
without configuration changes. These dynamic logger channels will only
|
without configuration changes. These dynamic logger channels will only
|
||||||
exist until the next restart of asterisk.
|
exist until the next restart of asterisk.
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
--- Functionality changes from Asterisk 12.1.0 to Asterisk 12.2.0 ------------
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
ARI
|
|
||||||
------------------
|
|
||||||
* The live recording object on recording events now contains a target_uri
|
|
||||||
field which contains the URI of what is being recorded.
|
|
||||||
|
|
||||||
Core
|
Core
|
||||||
------------------
|
------------------
|
||||||
* Exposed sorcery-based configuration files like pjsip.conf to dialplans via
|
* Exposed sorcery-based configuration files like pjsip.conf to dialplans via
|
||||||
the new AST_SORCERY diaplan function.
|
the new AST_SORCERY diaplan function.
|
||||||
|
|
||||||
=======
|
|
||||||
ARI
|
ARI
|
||||||
------------------
|
------------------
|
||||||
* The live recording object on recording events now contains a target_uri
|
* The live recording object on recording events now contains a target_uri
|
||||||
@@ -138,6 +128,19 @@ RealTime
|
|||||||
* A new set of Alembic scripts has been added for CDR tables. This will create
|
* A new set of Alembic scripts has been added for CDR tables. This will create
|
||||||
a 'cdr' table with the default schema that Asterisk expects.
|
a 'cdr' table with the default schema that Asterisk expects.
|
||||||
|
|
||||||
|
res_hep
|
||||||
|
------------------
|
||||||
|
* A new module, res_hep, has been added, that acts as a generic packet
|
||||||
|
capture agent for the Homer Encapsulation Protocol (HEP) version 3.
|
||||||
|
It can be configured via hep.conf. Other modules can use res_hep to send
|
||||||
|
message traffic to a HEP capture server.
|
||||||
|
|
||||||
|
res_hep_pjsip
|
||||||
|
------------------
|
||||||
|
* A new module, res_hep_pjsip, has been added that will forward PJSIP
|
||||||
|
message traffic to a HEP capture server. See res_hep for more
|
||||||
|
information.
|
||||||
|
|
||||||
res_pjsip
|
res_pjsip
|
||||||
------------------
|
------------------
|
||||||
* transport and endpoint ToS options (tos, tos_audio, and tos_video) may now
|
* transport and endpoint ToS options (tos, tos_audio, and tos_video) may now
|
||||||
|
16
configs/hep.conf.sample
Normal file
16
configs/hep.conf.sample
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
;
|
||||||
|
; res_hep Module configuration for Asterisk
|
||||||
|
;
|
||||||
|
|
||||||
|
; All settings are currently set in the general section.
|
||||||
|
[general]
|
||||||
|
enabled = yes ; Enable/disable forwarding of packets to a
|
||||||
|
; HEP server. Default is "yes".
|
||||||
|
capture_address = 192.168.1.1:9061 ; The address of the HEP capture server.
|
||||||
|
capture_password = foo ; If specified, the authorization passsword
|
||||||
|
; for the HEP server. If not specified, no
|
||||||
|
; authorization password will be sent.
|
||||||
|
capture_id = 1234 ; A unique integer identifier for this
|
||||||
|
; server. This ID will be embedded sent
|
||||||
|
; with each packet from this server.
|
||||||
|
|
111
include/asterisk/res_hep.h
Normal file
111
include/asterisk/res_hep.h
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Asterisk -- An open source telephony toolkit.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 - 2014, Digium, Inc.
|
||||||
|
*
|
||||||
|
* Alexandr Dubovikov <alexandr.dubovikov@sipcapture.org>
|
||||||
|
* Matt Jordan <mjordan@digium.com>
|
||||||
|
*
|
||||||
|
* See http://www.asterisk.org for more information about
|
||||||
|
* the Asterisk project. Please do not directly contact
|
||||||
|
* any of the maintainers of this project for assistance;
|
||||||
|
* the project provides a web site, mailing lists and IRC
|
||||||
|
* channels for your use.
|
||||||
|
*
|
||||||
|
* This program is free software, distributed under the terms of
|
||||||
|
* the GNU General Public License Version 2. See the LICENSE file
|
||||||
|
* at the top of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \file
|
||||||
|
* \brief Routines for integration with Homer using HEPv3
|
||||||
|
*
|
||||||
|
* \author Alexandr Dubovikov <alexandr.dubovikov@sipcapture.org>
|
||||||
|
* \author Matt Jordan <mjordan@digium.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ASTERISK_RES_HEPV3_H
|
||||||
|
#define _ASTERISK_RES_HEPV3_H
|
||||||
|
|
||||||
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "asterisk/netsock2.h"
|
||||||
|
|
||||||
|
/*! \brief HEPv3 Packet Capture Types */
|
||||||
|
enum hepv3_capture_type {
|
||||||
|
HEPV3_CAPTURE_TYPE_SIP = 0x01,
|
||||||
|
HEPV3_CAPTURE_TYPE_H323 = 0x02,
|
||||||
|
HEPV3_CAPTURE_TYPE_SDP = 0x03,
|
||||||
|
HEPV3_CAPTURE_TYPE_RTP = 0x04,
|
||||||
|
HEPV3_CAPTURE_TYPE_RTCP = 0x05,
|
||||||
|
HEPV3_CAPTURE_TYPE_MGCP = 0x06,
|
||||||
|
HEPV3_CAPTURE_TYPE_MEGACO = 0x07,
|
||||||
|
HEPV3_CAPTURE_TYPE_M2UA = 0x08,
|
||||||
|
HEPV3_CAPTURE_TYPE_M3UA = 0x09,
|
||||||
|
HEPV3_CAPTURE_TYPE_IAX = 0x10,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! \brief HEPv3 Capture Info */
|
||||||
|
struct hepv3_capture_info {
|
||||||
|
/*! The source address of the packet */
|
||||||
|
struct ast_sockaddr src_addr;
|
||||||
|
/*! The destination address of the packet */
|
||||||
|
struct ast_sockaddr dst_addr;
|
||||||
|
/*! The time the packet was captured */
|
||||||
|
struct timeval capture_time;
|
||||||
|
/*! The actual payload */
|
||||||
|
void *payload;
|
||||||
|
/*! Some UUID for the packet */
|
||||||
|
char *uuid;
|
||||||
|
/*! The \ref hepv3_capture_type packet type captured */
|
||||||
|
enum hepv3_capture_type capture_type;
|
||||||
|
/*! The size of the payload */
|
||||||
|
size_t len;
|
||||||
|
/*! If non-zero, the payload accompanying this capture info will be compressed */
|
||||||
|
unsigned int zipped:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Create a \ref hepv3_capture_info object
|
||||||
|
*
|
||||||
|
* This returned object is an ao2 reference counted object.
|
||||||
|
*
|
||||||
|
* Any attribute in the returned \ref hepv3_capture_info that is a
|
||||||
|
* pointer should point to something that is allocated on the heap,
|
||||||
|
* as it will be free'd when the \ref hepv3_capture_info object is
|
||||||
|
* reclaimed.
|
||||||
|
*
|
||||||
|
* \param payload The payload to send to the HEP capture node
|
||||||
|
* \param len Length of \ref payload
|
||||||
|
*
|
||||||
|
* \retval A \ref hepv3_capture_info ref counted object on success
|
||||||
|
* \retval NULL on error
|
||||||
|
*/
|
||||||
|
struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t len);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Send a generic packet capture to HEPv3
|
||||||
|
*
|
||||||
|
* \param capture_info Information describing the packet. This
|
||||||
|
* should be a reference counted object, created via
|
||||||
|
* \ref hepv3_create_capture_info.
|
||||||
|
*
|
||||||
|
* Once this function is called, it assumes ownership of the
|
||||||
|
* \ref capture_info object and steals the reference of the
|
||||||
|
* object. Regardless of success or failure, the calling function
|
||||||
|
* should assumed that this function will own the object.
|
||||||
|
*
|
||||||
|
* \retval 0 on success
|
||||||
|
* \retval -1 on error
|
||||||
|
*/
|
||||||
|
int hepv3_send_packet(struct hepv3_capture_info *capture_info);
|
||||||
|
|
||||||
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _ASTERISK_RES_HEPV3_H */
|
626
res/res_hep.c
Normal file
626
res/res_hep.c
Normal file
@@ -0,0 +1,626 @@
|
|||||||
|
/*
|
||||||
|
* Asterisk -- An open source telephony toolkit.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 - 2014, Digium, Inc.
|
||||||
|
*
|
||||||
|
* Alexandr Dubovikov <alexandr.dubovikov@sipcapture.org>
|
||||||
|
* Matt Jordan <mjordan@digium.com>
|
||||||
|
*
|
||||||
|
* See http://www.asterisk.org for more information about
|
||||||
|
* the Asterisk project. Please do not directly contact
|
||||||
|
* any of the maintainers of this project for assistance;
|
||||||
|
* the project provides a web site, mailing lists and IRC
|
||||||
|
* channels for your use.
|
||||||
|
*
|
||||||
|
* This program is free software, distributed under the terms of
|
||||||
|
* the GNU General Public License Version 2. See the LICENSE file
|
||||||
|
* at the top of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \file
|
||||||
|
* \brief Routines for integration with Homer using HEPv3
|
||||||
|
*
|
||||||
|
* \author Alexandr Dubovikov <alexandr.dubovikov@sipcapture.org>
|
||||||
|
* \author Matt Jordan <mjordan@digium.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \li \ref res_hep.c uses the configuration file \ref hep.conf
|
||||||
|
* \addtogroup configuration_file Configuration Files
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \page hep.conf hep.conf
|
||||||
|
* \verbinclude hep.conf.sample
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*** MODULEINFO
|
||||||
|
<defaultenabled>no</defaultenabled>
|
||||||
|
<support_level>extended</support_level>
|
||||||
|
***/
|
||||||
|
|
||||||
|
/*** DOCUMENTATION
|
||||||
|
<configInfo name="res_hep" language="en_US">
|
||||||
|
<synopsis>Resource for integration with Homer using HEPv3</synopsis>
|
||||||
|
<configFile name="hep.conf">
|
||||||
|
<configObject name="general">
|
||||||
|
<synopsis>General settings.</synopsis>
|
||||||
|
<description><para>
|
||||||
|
The <emphasis>general</emphasis> settings section contains information
|
||||||
|
to configure Asterisk as a Homer capture agent.
|
||||||
|
</para>
|
||||||
|
</description>
|
||||||
|
<configOption name="enabled" default="yes">
|
||||||
|
<synopsis>Enable or disable packet capturing.</synopsis>
|
||||||
|
<description>
|
||||||
|
<enumlist>
|
||||||
|
<enum name="no" />
|
||||||
|
<enum name="yes" />
|
||||||
|
</enumlist>
|
||||||
|
</description>
|
||||||
|
</configOption>
|
||||||
|
<configOption name="capture_address" default="192.168.1.1:9061">
|
||||||
|
<synopsis>The address and port of the Homer server to send packets to.</synopsis>
|
||||||
|
</configOption>
|
||||||
|
<configOption name="capture_password">
|
||||||
|
<synopsis>If set, the authentication password to send to Homer.</synopsis>
|
||||||
|
</configOption>
|
||||||
|
<configOption name="capture_id" default="0">
|
||||||
|
<synopsis>The ID for this capture agent.</synopsis>
|
||||||
|
</configOption>
|
||||||
|
</configObject>
|
||||||
|
</configFile>
|
||||||
|
</configInfo>
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include "asterisk.h"
|
||||||
|
|
||||||
|
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
|
|
||||||
|
#include "asterisk/module.h"
|
||||||
|
#include "asterisk/astobj2.h"
|
||||||
|
#include "asterisk/config_options.h"
|
||||||
|
#include "asterisk/taskprocessor.h"
|
||||||
|
#include "asterisk/res_hep.h"
|
||||||
|
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <netinet/udp.h>
|
||||||
|
#include <netinet/ip6.h>
|
||||||
|
|
||||||
|
#define DEFAULT_HEP_SERVER ""
|
||||||
|
|
||||||
|
/*! Generic vendor ID. Used for HEPv3 standard packets */
|
||||||
|
#define GENERIC_VENDOR_ID 0x0000
|
||||||
|
|
||||||
|
/*! Asterisk vendor ID. Used for custom data to send to a capture node */
|
||||||
|
#define ASTERISK_VENDOR_ID 0x0004
|
||||||
|
|
||||||
|
/*! Chunk types from the HEPv3 Spec */
|
||||||
|
enum hepv3_chunk_types {
|
||||||
|
|
||||||
|
/*! THE IP PROTOCOL FAMILY */
|
||||||
|
CHUNK_TYPE_IP_PROTOCOL_FAMILY = 0X0001,
|
||||||
|
|
||||||
|
/*! THE IP PROTOCOL ID (UDP, TCP, ETC.) */
|
||||||
|
CHUNK_TYPE_IP_PROTOCOL_ID = 0X0002,
|
||||||
|
|
||||||
|
/*! IF IPV4, THE SOURCE ADDRESS */
|
||||||
|
CHUNK_TYPE_IPV4_SRC_ADDR = 0X0003,
|
||||||
|
|
||||||
|
/*! IF IPV4, THE DESTINATION ADDRESS */
|
||||||
|
CHUNK_TYPE_IPV4_DST_ADDR = 0X0004,
|
||||||
|
|
||||||
|
/*! IF IPV6, THE SOURCE ADDRESS */
|
||||||
|
CHUNK_TYPE_IPV6_SRC_ADDR = 0X0005,
|
||||||
|
|
||||||
|
/*! IF IPV6, THE DESTINATION ADDRESS */
|
||||||
|
CHUNK_TYPE_IPV6_DST_ADDR = 0X0006,
|
||||||
|
|
||||||
|
/*! THE SOURCE PORT */
|
||||||
|
CHUNK_TYPE_SRC_PORT = 0X0007,
|
||||||
|
|
||||||
|
/*! THE DESTINATION PORT */
|
||||||
|
CHUNK_TYPE_DST_PORT = 0X0008,
|
||||||
|
|
||||||
|
/*! THE CAPTURE TIME (SECONDS) */
|
||||||
|
CHUNK_TYPE_TIMESTAMP_SEC = 0X0009,
|
||||||
|
|
||||||
|
/*! THE CAPTURE TIME (MICROSECONDS) */
|
||||||
|
CHUNK_TYPE_TIMESTAMP_USEC = 0X000A,
|
||||||
|
|
||||||
|
/*! THE PROTOCOL PACKET TYPE. SEE /REF HEPV3_CAPTURE_TYPE */
|
||||||
|
CHUNK_TYPE_PROTOCOL_TYPE = 0X000B,
|
||||||
|
|
||||||
|
/*! OUR CAPTURE AGENT ID */
|
||||||
|
CHUNK_TYPE_CAPTURE_AGENT_ID = 0X000C,
|
||||||
|
|
||||||
|
/*! A KEEP ALIVE TIMER */
|
||||||
|
CHUNK_TYPE_KEEP_ALIVE_TIMER = 0X000D,
|
||||||
|
|
||||||
|
/*! THE \REF CAPTURE_PASSWORD IF DEFINED */
|
||||||
|
CHUNK_TYPE_AUTH_KEY = 0X000E,
|
||||||
|
|
||||||
|
/*! THE ONE AND ONLY PAYLOAD */
|
||||||
|
CHUNK_TYPE_PAYLOAD = 0X000F,
|
||||||
|
|
||||||
|
/*! THE ONE AND ONLY (ZIPPED) PAYLOAD */
|
||||||
|
CHUNK_TYPE_PAYLOAD_ZIP = 0X0010,
|
||||||
|
|
||||||
|
/*! THE UUID FOR THIS PACKET */
|
||||||
|
CHUNK_TYPE_UUID = 0X0011,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define INITIALIZE_GENERIC_HEP_IDS(hep_chunk, type) do { \
|
||||||
|
(hep_chunk)->vendor_id = htons(GENERIC_VENDOR_ID); \
|
||||||
|
(hep_chunk)->type_id = htons((type)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define INITIALIZE_GENERIC_HEP_IDS_VAR(hep_chunk, type, len) do { \
|
||||||
|
INITIALIZE_GENERIC_HEP_IDS((hep_chunk), (type)); \
|
||||||
|
(hep_chunk)->length = htons(sizeof(*(hep_chunk)) + len); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define INITIALIZE_GENERIC_HEP_CHUNK(hep_item, type) do { \
|
||||||
|
INITIALIZE_GENERIC_HEP_IDS(&(hep_item)->chunk, (type)); \
|
||||||
|
(hep_item)->chunk.length = htons(sizeof(*(hep_item))); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define INITIALIZE_GENERIC_HEP_CHUNK_DATA(hep_item, type, value) do { \
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK((hep_item), (type)); \
|
||||||
|
(hep_item)->data = (value); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HEPv3 Types.
|
||||||
|
* Note that the content in these is stored in network byte order.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct hep_chunk {
|
||||||
|
u_int16_t vendor_id;
|
||||||
|
u_int16_t type_id;
|
||||||
|
u_int16_t length;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct hep_chunk_uint8 {
|
||||||
|
struct hep_chunk chunk;
|
||||||
|
u_int8_t data;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct hep_chunk_uint16 {
|
||||||
|
struct hep_chunk chunk;
|
||||||
|
u_int16_t data;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct hep_chunk_uint32 {
|
||||||
|
struct hep_chunk chunk;
|
||||||
|
u_int32_t data;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct hep_chunk_ip4 {
|
||||||
|
struct hep_chunk chunk;
|
||||||
|
struct in_addr data;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct hep_chunk_ip6 {
|
||||||
|
struct hep_chunk chunk;
|
||||||
|
struct in6_addr data;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct hep_ctrl {
|
||||||
|
char id[4];
|
||||||
|
u_int16_t length;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* HEP structures */
|
||||||
|
|
||||||
|
struct hep_generic {
|
||||||
|
struct hep_ctrl header;
|
||||||
|
struct hep_chunk_uint8 ip_family;
|
||||||
|
struct hep_chunk_uint8 ip_proto;
|
||||||
|
struct hep_chunk_uint16 src_port;
|
||||||
|
struct hep_chunk_uint16 dst_port;
|
||||||
|
struct hep_chunk_uint32 time_sec;
|
||||||
|
struct hep_chunk_uint32 time_usec;
|
||||||
|
struct hep_chunk_uint8 proto_t;
|
||||||
|
struct hep_chunk_uint32 capt_id;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/*! \brief Global configuration for the module */
|
||||||
|
struct hepv3_global_config {
|
||||||
|
unsigned int enabled; /*!< Whether or not sending is enabled */
|
||||||
|
unsigned int capture_id; /*!< Capture ID for this agent */
|
||||||
|
AST_DECLARE_STRING_FIELDS(
|
||||||
|
AST_STRING_FIELD(capture_address); /*!< Address to send to */
|
||||||
|
AST_STRING_FIELD(capture_password); /*!< Password for Homer server */
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! \brief The actual module config */
|
||||||
|
struct module_config {
|
||||||
|
struct hepv3_global_config *general; /*!< The general config settings */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! \brief Run-time data derived from \ref hepv3_global_config */
|
||||||
|
struct hepv3_runtime_data {
|
||||||
|
struct ast_sockaddr remote_addr; /*!< The address to send to */
|
||||||
|
int sockfd; /*!< The socket file descriptor */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct aco_type global_option = {
|
||||||
|
.type = ACO_GLOBAL,
|
||||||
|
.name = "general",
|
||||||
|
.item_offset = offsetof(struct module_config, general),
|
||||||
|
.category_match = ACO_WHITELIST,
|
||||||
|
.category = "^general$",
|
||||||
|
};
|
||||||
|
|
||||||
|
struct aco_type *global_options[] = ACO_TYPES(&global_option);
|
||||||
|
|
||||||
|
struct aco_file hepv3_conf = {
|
||||||
|
.filename = "hep.conf",
|
||||||
|
.types = ACO_TYPES(&global_option),
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! \brief The module configuration container */
|
||||||
|
static AO2_GLOBAL_OBJ_STATIC(global_config);
|
||||||
|
|
||||||
|
/*! \brief Current module data */
|
||||||
|
static AO2_GLOBAL_OBJ_STATIC(global_data);
|
||||||
|
|
||||||
|
static struct ast_taskprocessor *hep_queue_tp;
|
||||||
|
|
||||||
|
static void *module_config_alloc(void);
|
||||||
|
static void hepv3_config_post_apply(void);
|
||||||
|
|
||||||
|
/*! \brief Register information about the configs being processed by this module */
|
||||||
|
CONFIG_INFO_STANDARD(cfg_info, global_config, module_config_alloc,
|
||||||
|
.files = ACO_FILES(&hepv3_conf),
|
||||||
|
.post_apply_config = hepv3_config_post_apply,
|
||||||
|
);
|
||||||
|
|
||||||
|
static void hepv3_config_dtor(void *obj)
|
||||||
|
{
|
||||||
|
struct hepv3_global_config *config = obj;
|
||||||
|
|
||||||
|
ast_string_field_free_memory(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief HEPv3 configuration object allocation */
|
||||||
|
static void *hepv3_config_alloc(void)
|
||||||
|
{
|
||||||
|
struct hepv3_global_config *config;
|
||||||
|
|
||||||
|
config = ao2_alloc(sizeof(*config), hepv3_config_dtor);
|
||||||
|
if (!config || ast_string_field_init(config, 32)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Configuration object destructor */
|
||||||
|
static void module_config_dtor(void *obj)
|
||||||
|
{
|
||||||
|
struct module_config *config = obj;
|
||||||
|
|
||||||
|
if (config->general) {
|
||||||
|
ao2_ref(config->general, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Module config constructor */
|
||||||
|
static void *module_config_alloc(void)
|
||||||
|
{
|
||||||
|
struct module_config *config;
|
||||||
|
|
||||||
|
config = ao2_alloc(sizeof(*config), module_config_dtor);
|
||||||
|
if (!config) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
config->general = hepv3_config_alloc();
|
||||||
|
if (!config->general) {
|
||||||
|
ao2_ref(config, -1);
|
||||||
|
config = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief HEPv3 run-time data destructor */
|
||||||
|
static void hepv3_data_dtor(void *obj)
|
||||||
|
{
|
||||||
|
struct hepv3_runtime_data *data = obj;
|
||||||
|
|
||||||
|
if (data->sockfd > -1) {
|
||||||
|
close(data->sockfd);
|
||||||
|
data->sockfd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Allocate the HEPv3 run-time data */
|
||||||
|
static struct hepv3_runtime_data *hepv3_data_alloc(struct hepv3_global_config *config)
|
||||||
|
{
|
||||||
|
struct hepv3_runtime_data *data;
|
||||||
|
|
||||||
|
data = ao2_alloc(sizeof(*data), hepv3_data_dtor);
|
||||||
|
if (!data) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ast_sockaddr_parse(&data->remote_addr, config->capture_address, PARSE_PORT_REQUIRE)) {
|
||||||
|
ast_log(AST_LOG_WARNING, "Failed to create address from %s\n", config->capture_address);
|
||||||
|
ao2_ref(data, -1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->sockfd = socket(ast_sockaddr_is_ipv6(&data->remote_addr) ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (data->sockfd < 0) {
|
||||||
|
ast_log(AST_LOG_WARNING, "Failed to create socket for address %s: %s\n",
|
||||||
|
config->capture_address, strerror(errno));
|
||||||
|
ao2_ref(data, -1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Destructor for a \ref hepv3_capture_info object */
|
||||||
|
static void capture_info_dtor(void *obj)
|
||||||
|
{
|
||||||
|
struct hepv3_capture_info *info = obj;
|
||||||
|
|
||||||
|
ast_free(info->uuid);
|
||||||
|
ast_free(info->payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t len)
|
||||||
|
{
|
||||||
|
struct hepv3_capture_info *info;
|
||||||
|
|
||||||
|
info = ao2_alloc(sizeof(*info), capture_info_dtor);
|
||||||
|
if (!info) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->payload = ast_malloc(len);
|
||||||
|
if (!info->payload) {
|
||||||
|
ao2_ref(info, -1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(info->payload, payload, len);
|
||||||
|
info->len = len;
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Callback function for the \ref hep_queue_tp taskprocessor */
|
||||||
|
static int hep_queue_cb(void *data)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
|
||||||
|
RAII_VAR(struct hepv3_runtime_data *, hepv3_data, ao2_global_obj_ref(global_data), ao2_cleanup);
|
||||||
|
RAII_VAR(struct hepv3_capture_info *, capture_info, data, ao2_cleanup);
|
||||||
|
struct hep_generic hg_pkt;
|
||||||
|
unsigned int packet_len = 0, sock_buffer_len;
|
||||||
|
struct hep_chunk_ip4 ipv4_src, ipv4_dst;
|
||||||
|
struct hep_chunk_ip6 ipv6_src, ipv6_dst;
|
||||||
|
struct hep_chunk auth_key, payload, uuid;
|
||||||
|
void *sock_buffer;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (!capture_info || !config || !hepv3_data) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ast_sockaddr_is_ipv4(&capture_info->src_addr) != ast_sockaddr_is_ipv4(&capture_info->dst_addr)) {
|
||||||
|
ast_log(AST_LOG_NOTICE, "Unable to send packet: Address Family mismatch between source/destination\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
packet_len = sizeof(hg_pkt);
|
||||||
|
|
||||||
|
/* Build HEPv3 header, capture info, and calculate the total packet size */
|
||||||
|
memcpy(hg_pkt.header.id, "\x48\x45\x50\x33", 4);
|
||||||
|
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_proto, CHUNK_TYPE_IP_PROTOCOL_ID, 0x11);
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.src_port, CHUNK_TYPE_SRC_PORT, htons(ast_sockaddr_port(&capture_info->src_addr)));
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.dst_port, CHUNK_TYPE_DST_PORT, htons(ast_sockaddr_port(&capture_info->dst_addr)));
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.time_sec, CHUNK_TYPE_TIMESTAMP_SEC, htonl(capture_info->capture_time.tv_sec));
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.time_usec, CHUNK_TYPE_TIMESTAMP_USEC, htonl(capture_info->capture_time.tv_usec));
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.proto_t, CHUNK_TYPE_PROTOCOL_TYPE, capture_info->capture_type);
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.capt_id, CHUNK_TYPE_CAPTURE_AGENT_ID, htonl(config->general->capture_id));
|
||||||
|
|
||||||
|
if (ast_sockaddr_is_ipv4(&capture_info->src_addr)) {
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_family,
|
||||||
|
CHUNK_TYPE_IP_PROTOCOL_FAMILY, AF_INET);
|
||||||
|
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK(&ipv4_src, CHUNK_TYPE_IPV4_SRC_ADDR);
|
||||||
|
inet_pton(AF_INET, ast_sockaddr_stringify_addr(&capture_info->src_addr), &ipv4_src.data);
|
||||||
|
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK(&ipv4_dst, CHUNK_TYPE_IPV4_DST_ADDR);
|
||||||
|
inet_pton(AF_INET, ast_sockaddr_stringify_addr(&capture_info->dst_addr), &ipv4_dst.data);
|
||||||
|
|
||||||
|
packet_len += (sizeof(ipv4_src) + sizeof(ipv4_dst));
|
||||||
|
} else {
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_family,
|
||||||
|
CHUNK_TYPE_IP_PROTOCOL_FAMILY, AF_INET6);
|
||||||
|
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK(&ipv6_src, CHUNK_TYPE_IPV6_SRC_ADDR);
|
||||||
|
inet_pton(AF_INET6, ast_sockaddr_stringify_addr(&capture_info->src_addr), &ipv6_src.data);
|
||||||
|
|
||||||
|
INITIALIZE_GENERIC_HEP_CHUNK(&ipv6_dst, CHUNK_TYPE_IPV6_DST_ADDR);
|
||||||
|
inet_pton(AF_INET6, ast_sockaddr_stringify_addr(&capture_info->dst_addr), &ipv6_dst.data);
|
||||||
|
|
||||||
|
packet_len += (sizeof(ipv6_src) + sizeof(ipv6_dst));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ast_strlen_zero(config->general->capture_password)) {
|
||||||
|
INITIALIZE_GENERIC_HEP_IDS_VAR(&auth_key, CHUNK_TYPE_AUTH_KEY, strlen(config->general->capture_password));
|
||||||
|
packet_len += (sizeof(auth_key) + strlen(config->general->capture_password));
|
||||||
|
}
|
||||||
|
INITIALIZE_GENERIC_HEP_IDS_VAR(&uuid, CHUNK_TYPE_UUID, strlen(capture_info->uuid));
|
||||||
|
packet_len += (sizeof(uuid) + strlen(capture_info->uuid));
|
||||||
|
INITIALIZE_GENERIC_HEP_IDS_VAR(&payload,
|
||||||
|
capture_info->zipped ? CHUNK_TYPE_PAYLOAD_ZIP : CHUNK_TYPE_PAYLOAD, capture_info->len);
|
||||||
|
packet_len += (sizeof(payload) + capture_info->len);
|
||||||
|
hg_pkt.header.length = htons(packet_len);
|
||||||
|
|
||||||
|
/* Build the buffer to send */
|
||||||
|
sock_buffer = ast_malloc(packet_len);
|
||||||
|
if (!sock_buffer) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy in the header */
|
||||||
|
memcpy(sock_buffer, &hg_pkt, sizeof(hg_pkt));
|
||||||
|
sock_buffer_len = sizeof(hg_pkt);
|
||||||
|
|
||||||
|
/* Addresses */
|
||||||
|
if (ast_sockaddr_is_ipv4(&capture_info->src_addr)) {
|
||||||
|
memcpy(sock_buffer + sock_buffer_len, &ipv4_src, sizeof(ipv4_src));
|
||||||
|
sock_buffer_len += sizeof(ipv4_src);
|
||||||
|
memcpy(sock_buffer + sock_buffer_len, &ipv4_dst, sizeof(ipv4_dst));
|
||||||
|
sock_buffer_len += sizeof(ipv4_dst);
|
||||||
|
} else {
|
||||||
|
memcpy(sock_buffer + sock_buffer_len, &ipv6_src, sizeof(ipv6_src));
|
||||||
|
sock_buffer_len += sizeof(ipv6_src);
|
||||||
|
memcpy(sock_buffer + sock_buffer_len, &ipv6_dst, sizeof(ipv6_dst));
|
||||||
|
sock_buffer_len += sizeof(ipv6_dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Auth Key */
|
||||||
|
if (!ast_strlen_zero(config->general->capture_password)) {
|
||||||
|
memcpy(sock_buffer + sock_buffer_len, &auth_key, sizeof(auth_key));
|
||||||
|
sock_buffer_len += sizeof(auth_key);
|
||||||
|
memcpy(sock_buffer + sock_buffer_len, config->general->capture_password, strlen(config->general->capture_password));
|
||||||
|
sock_buffer_len += strlen(config->general->capture_password);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UUID */
|
||||||
|
memcpy(sock_buffer + sock_buffer_len, &uuid, sizeof(uuid));
|
||||||
|
sock_buffer_len += sizeof(uuid);
|
||||||
|
memcpy(sock_buffer + sock_buffer_len, capture_info->uuid, strlen(capture_info->uuid));
|
||||||
|
sock_buffer_len += strlen(capture_info->uuid);
|
||||||
|
|
||||||
|
/* Packet! */
|
||||||
|
memcpy(sock_buffer + sock_buffer_len, &payload, sizeof(payload));
|
||||||
|
sock_buffer_len += sizeof(payload);
|
||||||
|
memcpy(sock_buffer + sock_buffer_len, capture_info->payload, capture_info->len);
|
||||||
|
sock_buffer_len += capture_info->len;
|
||||||
|
|
||||||
|
ast_assert(sock_buffer_len == packet_len);
|
||||||
|
|
||||||
|
res = ast_sendto(hepv3_data->sockfd, sock_buffer, sock_buffer_len, 0, &hepv3_data->remote_addr);
|
||||||
|
if (res < 0) {
|
||||||
|
ast_log(AST_LOG_ERROR, "Error [%d] while sending packet to HEPv3 server: %s\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
} else if (res != sock_buffer_len) {
|
||||||
|
ast_log(AST_LOG_WARNING, "Failed to send complete packet to HEPv3 server: %d of %u sent\n",
|
||||||
|
res, sock_buffer_len);
|
||||||
|
res = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_free(sock_buffer);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hepv3_send_packet(struct hepv3_capture_info *capture_info)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (!config->general->enabled) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ast_taskprocessor_push(hep_queue_tp, hep_queue_cb, capture_info);
|
||||||
|
if (res == -1) {
|
||||||
|
ao2_ref(capture_info, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Post-apply callback for the config framework.
|
||||||
|
*
|
||||||
|
* This will create the run-time information from the supplied
|
||||||
|
* configuration.
|
||||||
|
*/
|
||||||
|
static void hepv3_config_post_apply(void)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(global_config), ao2_cleanup);
|
||||||
|
struct hepv3_runtime_data *data;
|
||||||
|
|
||||||
|
data = hepv3_data_alloc(mod_cfg->general);
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ao2_global_obj_replace_unref(global_data, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Reload the module
|
||||||
|
*/
|
||||||
|
static int reload_module(void)
|
||||||
|
{
|
||||||
|
if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Unload the module
|
||||||
|
*/
|
||||||
|
static int unload_module(void)
|
||||||
|
{
|
||||||
|
hep_queue_tp = ast_taskprocessor_unreference(hep_queue_tp);
|
||||||
|
|
||||||
|
ao2_global_obj_release(global_config);
|
||||||
|
ao2_global_obj_release(global_data);
|
||||||
|
aco_info_destroy(&cfg_info);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Load the module
|
||||||
|
*/
|
||||||
|
static int load_module(void)
|
||||||
|
{
|
||||||
|
if (aco_info_init(&cfg_info)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
hep_queue_tp = ast_taskprocessor_get("hep_queue_tp", TPS_REF_DEFAULT);
|
||||||
|
if (!hep_queue_tp) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
aco_option_register(&cfg_info, "enabled", ACO_EXACT, global_options, "yes", OPT_BOOL_T, 1, FLDSET(struct hepv3_global_config, enabled));
|
||||||
|
aco_option_register(&cfg_info, "capture_address", ACO_EXACT, global_options, DEFAULT_HEP_SERVER, OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_address));
|
||||||
|
aco_option_register(&cfg_info, "capture_password", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_password));
|
||||||
|
aco_option_register(&cfg_info, "capture_id", ACO_EXACT, global_options, "0", OPT_UINT_T, 0, STRFLDSET(struct hepv3_global_config, capture_id));
|
||||||
|
|
||||||
|
if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AST_MODULE_LOAD_SUCCESS;
|
||||||
|
|
||||||
|
error:
|
||||||
|
aco_info_destroy(&cfg_info);
|
||||||
|
return AST_MODULE_LOAD_DECLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "HEPv3 API",
|
||||||
|
.load = load_module,
|
||||||
|
.unload = unload_module,
|
||||||
|
.reload = reload_module,
|
||||||
|
.load_pri = AST_MODPRI_APP_DEPEND,
|
||||||
|
);
|
7
res/res_hep.exports.in
Normal file
7
res/res_hep.exports.in
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
global:
|
||||||
|
LINKER_SYMBOL_PREFIX*hepv3_send_packet;
|
||||||
|
LINKER_SYMBOL_PREFIX*hepv3_create_capture_info;
|
||||||
|
local:
|
||||||
|
*;
|
||||||
|
};
|
144
res/res_hep_pjsip.c
Normal file
144
res/res_hep_pjsip.c
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Asterisk -- An open source telephony toolkit.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 - 2014, Digium, Inc.
|
||||||
|
*
|
||||||
|
* Matt Jordan <mjordan@digium.com>
|
||||||
|
*
|
||||||
|
* See http://www.asterisk.org for more information about
|
||||||
|
* the Asterisk project. Please do not directly contact
|
||||||
|
* any of the maintainers of this project for assistance;
|
||||||
|
* the project provides a web site, mailing lists and IRC
|
||||||
|
* channels for your use.
|
||||||
|
*
|
||||||
|
* This program is free software, distributed under the terms of
|
||||||
|
* the GNU General Public License Version 2. See the LICENSE file
|
||||||
|
* at the top of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \file
|
||||||
|
* \brief PJSIP logging with Homer
|
||||||
|
*
|
||||||
|
* \author Matt Jordan <mjordan@digium.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*** MODULEINFO
|
||||||
|
<depend>pjproject</depend>
|
||||||
|
<depend>res_pjsip</depend>
|
||||||
|
<depend>res_hep</depend>
|
||||||
|
<defaultenabled>no</defaultenabled>
|
||||||
|
<support_level>extended</support_level>
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include "asterisk.h"
|
||||||
|
|
||||||
|
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
|
|
||||||
|
#include <pjsip.h>
|
||||||
|
|
||||||
|
#include "asterisk/res_pjsip.h"
|
||||||
|
#include "asterisk/res_hep.h"
|
||||||
|
#include "asterisk/module.h"
|
||||||
|
#include "asterisk/netsock2.h"
|
||||||
|
|
||||||
|
static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
|
||||||
|
{
|
||||||
|
char local_buf[256];
|
||||||
|
char remote_buf[256];
|
||||||
|
char *uuid;
|
||||||
|
struct hepv3_capture_info *capture_info;
|
||||||
|
pjsip_cid_hdr *cid_hdr;
|
||||||
|
|
||||||
|
capture_info = hepv3_create_capture_info(tdata->buf.start, (size_t)(tdata->buf.cur - tdata->buf.start));
|
||||||
|
if (!capture_info) {
|
||||||
|
return PJ_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);
|
||||||
|
pj_sockaddr_print(&tdata->tp_info.dst_addr, remote_buf, sizeof(remote_buf), 3);
|
||||||
|
|
||||||
|
cid_hdr = PJSIP_MSG_CID_HDR(tdata->msg);
|
||||||
|
uuid = ast_malloc(pj_strlen(&cid_hdr->id) + 1);
|
||||||
|
if (!uuid) {
|
||||||
|
ao2_ref(capture_info, -1);
|
||||||
|
return PJ_SUCCESS;
|
||||||
|
}
|
||||||
|
ast_copy_pj_str(uuid, &cid_hdr->id, pj_strlen(&cid_hdr->id) + 1);
|
||||||
|
|
||||||
|
ast_sockaddr_parse(&capture_info->src_addr, local_buf, PARSE_PORT_REQUIRE);
|
||||||
|
ast_sockaddr_parse(&capture_info->dst_addr, remote_buf, PARSE_PORT_REQUIRE);
|
||||||
|
|
||||||
|
capture_info->capture_time = ast_tvnow();
|
||||||
|
capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP;
|
||||||
|
capture_info->uuid = uuid;
|
||||||
|
capture_info->zipped = 0;
|
||||||
|
|
||||||
|
hepv3_send_packet(capture_info);
|
||||||
|
|
||||||
|
return PJ_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
|
||||||
|
{
|
||||||
|
char local_buf[256];
|
||||||
|
char remote_buf[256];
|
||||||
|
char *uuid;
|
||||||
|
struct hepv3_capture_info *capture_info;
|
||||||
|
|
||||||
|
capture_info = hepv3_create_capture_info(&rdata->pkt_info.packet, rdata->pkt_info.len);
|
||||||
|
if (!capture_info) {
|
||||||
|
return PJ_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);
|
||||||
|
pj_sockaddr_print(&rdata->pkt_info.src_addr, remote_buf, sizeof(remote_buf), 3);
|
||||||
|
|
||||||
|
uuid = ast_malloc(pj_strlen(&rdata->msg_info.cid->id) + 1);
|
||||||
|
if (!uuid) {
|
||||||
|
ao2_ref(capture_info, -1);
|
||||||
|
return PJ_SUCCESS;
|
||||||
|
}
|
||||||
|
ast_copy_pj_str(uuid, &rdata->msg_info.cid->id, pj_strlen(&rdata->msg_info.cid->id) + 1);
|
||||||
|
|
||||||
|
ast_sockaddr_parse(&capture_info->src_addr, remote_buf, PARSE_PORT_REQUIRE);
|
||||||
|
ast_sockaddr_parse(&capture_info->dst_addr, local_buf, PARSE_PORT_REQUIRE);
|
||||||
|
capture_info->capture_time.tv_sec = rdata->pkt_info.timestamp.sec;
|
||||||
|
capture_info->capture_time.tv_usec = rdata->pkt_info.timestamp.msec * 1000;
|
||||||
|
capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP;
|
||||||
|
capture_info->uuid = uuid;
|
||||||
|
capture_info->zipped = 0;
|
||||||
|
|
||||||
|
hepv3_send_packet(capture_info);
|
||||||
|
|
||||||
|
return PJ_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static pjsip_module logging_module = {
|
||||||
|
.name = { "HEPv3 Logging Module", 20 },
|
||||||
|
.priority = 0,
|
||||||
|
.on_rx_request = logging_on_rx_msg,
|
||||||
|
.on_rx_response = logging_on_rx_msg,
|
||||||
|
.on_tx_request = logging_on_tx_msg,
|
||||||
|
.on_tx_response = logging_on_tx_msg,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int load_module(void)
|
||||||
|
{
|
||||||
|
ast_sip_register_service(&logging_module);
|
||||||
|
return AST_MODULE_LOAD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int unload_module(void)
|
||||||
|
{
|
||||||
|
ast_sip_unregister_service(&logging_module);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP HEPv3 Logger",
|
||||||
|
.load = load_module,
|
||||||
|
.unload = unload_module,
|
||||||
|
.load_pri = AST_MODPRI_DEFAULT,
|
||||||
|
);
|
Reference in New Issue
Block a user