res_hep.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2014, Digium, Inc.
  5. *
  6. * Alexandr Dubovikov <alexandr.dubovikov@sipcapture.org>
  7. * Matt Jordan <mjordan@digium.com>
  8. *
  9. * See http://www.asterisk.org for more information about
  10. * the Asterisk project. Please do not directly contact
  11. * any of the maintainers of this project for assistance;
  12. * the project provides a web site, mailing lists and IRC
  13. * channels for your use.
  14. *
  15. * This program is free software, distributed under the terms of
  16. * the GNU General Public License Version 2. See the LICENSE file
  17. * at the top of the source tree.
  18. */
  19. /*!
  20. * \file
  21. * \brief Routines for integration with Homer using HEPv3
  22. *
  23. * \author Alexandr Dubovikov <alexandr.dubovikov@sipcapture.org>
  24. * \author Matt Jordan <mjordan@digium.com>
  25. *
  26. */
  27. /*!
  28. * \li \ref res_hep.c uses the configuration file \ref hep.conf
  29. * \addtogroup configuration_file Configuration Files
  30. */
  31. /*!
  32. * \page hep.conf hep.conf
  33. * \verbinclude hep.conf.sample
  34. */
  35. /*** MODULEINFO
  36. <support_level>extended</support_level>
  37. ***/
  38. /*** DOCUMENTATION
  39. <configInfo name="res_hep" language="en_US">
  40. <synopsis>Resource for integration with Homer using HEPv3</synopsis>
  41. <configFile name="hep.conf">
  42. <configObject name="general">
  43. <synopsis>General settings.</synopsis>
  44. <description><para>
  45. The <emphasis>general</emphasis> settings section contains information
  46. to configure Asterisk as a Homer capture agent.
  47. </para>
  48. </description>
  49. <configOption name="enabled" default="yes">
  50. <synopsis>Enable or disable packet capturing.</synopsis>
  51. <description>
  52. <enumlist>
  53. <enum name="no" />
  54. <enum name="yes" />
  55. </enumlist>
  56. </description>
  57. </configOption>
  58. <configOption name="uuid_type" default="call-id">
  59. <synopsis>The preferred type of UUID to pass to Homer.</synopsis>
  60. <description>
  61. <enumlist>
  62. <enum name="call-id"><para>Use the PJSIP Call-Id</para></enum>
  63. <enum name="channel"><para>Use the Asterisk channel name</para></enum>
  64. </enumlist>
  65. </description>
  66. </configOption>
  67. <configOption name="capture_address">
  68. <synopsis>The address and port of the Homer server to send packets to.</synopsis>
  69. </configOption>
  70. <configOption name="capture_password">
  71. <synopsis>If set, the authentication password to send to Homer.</synopsis>
  72. </configOption>
  73. <configOption name="capture_id" default="0">
  74. <synopsis>The ID for this capture agent.</synopsis>
  75. </configOption>
  76. </configObject>
  77. </configFile>
  78. </configInfo>
  79. ***/
  80. #include "asterisk.h"
  81. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  82. #include "asterisk/module.h"
  83. #include "asterisk/astobj2.h"
  84. #include "asterisk/config_options.h"
  85. #include "asterisk/taskprocessor.h"
  86. #include "asterisk/res_hep.h"
  87. #include <netinet/ip.h>
  88. #include <netinet/tcp.h>
  89. #include <netinet/udp.h>
  90. #include <netinet/ip6.h>
  91. /*! Generic vendor ID. Used for HEPv3 standard packets */
  92. #define GENERIC_VENDOR_ID 0x0000
  93. /*! Asterisk vendor ID. Used for custom data to send to a capture node */
  94. #define ASTERISK_VENDOR_ID 0x0004
  95. /*! Chunk types from the HEPv3 Spec */
  96. enum hepv3_chunk_types {
  97. /*! THE IP PROTOCOL FAMILY */
  98. CHUNK_TYPE_IP_PROTOCOL_FAMILY = 0X0001,
  99. /*! THE IP PROTOCOL ID (UDP, TCP, ETC.) */
  100. CHUNK_TYPE_IP_PROTOCOL_ID = 0X0002,
  101. /*! IF IPV4, THE SOURCE ADDRESS */
  102. CHUNK_TYPE_IPV4_SRC_ADDR = 0X0003,
  103. /*! IF IPV4, THE DESTINATION ADDRESS */
  104. CHUNK_TYPE_IPV4_DST_ADDR = 0X0004,
  105. /*! IF IPV6, THE SOURCE ADDRESS */
  106. CHUNK_TYPE_IPV6_SRC_ADDR = 0X0005,
  107. /*! IF IPV6, THE DESTINATION ADDRESS */
  108. CHUNK_TYPE_IPV6_DST_ADDR = 0X0006,
  109. /*! THE SOURCE PORT */
  110. CHUNK_TYPE_SRC_PORT = 0X0007,
  111. /*! THE DESTINATION PORT */
  112. CHUNK_TYPE_DST_PORT = 0X0008,
  113. /*! THE CAPTURE TIME (SECONDS) */
  114. CHUNK_TYPE_TIMESTAMP_SEC = 0X0009,
  115. /*! THE CAPTURE TIME (MICROSECONDS) */
  116. CHUNK_TYPE_TIMESTAMP_USEC = 0X000A,
  117. /*! THE PROTOCOL PACKET TYPE. SEE /REF HEPV3_CAPTURE_TYPE */
  118. CHUNK_TYPE_PROTOCOL_TYPE = 0X000B,
  119. /*! OUR CAPTURE AGENT ID */
  120. CHUNK_TYPE_CAPTURE_AGENT_ID = 0X000C,
  121. /*! A KEEP ALIVE TIMER */
  122. CHUNK_TYPE_KEEP_ALIVE_TIMER = 0X000D,
  123. /*! THE \REF CAPTURE_PASSWORD IF DEFINED */
  124. CHUNK_TYPE_AUTH_KEY = 0X000E,
  125. /*! THE ONE AND ONLY PAYLOAD */
  126. CHUNK_TYPE_PAYLOAD = 0X000F,
  127. /*! THE ONE AND ONLY (ZIPPED) PAYLOAD */
  128. CHUNK_TYPE_PAYLOAD_ZIP = 0X0010,
  129. /*! THE UUID FOR THIS PACKET */
  130. CHUNK_TYPE_UUID = 0X0011,
  131. };
  132. #define INITIALIZE_GENERIC_HEP_IDS(hep_chunk, type) do { \
  133. (hep_chunk)->vendor_id = htons(GENERIC_VENDOR_ID); \
  134. (hep_chunk)->type_id = htons((type)); \
  135. } while (0)
  136. #define INITIALIZE_GENERIC_HEP_IDS_VAR(hep_chunk, type, len) do { \
  137. INITIALIZE_GENERIC_HEP_IDS((hep_chunk), (type)); \
  138. (hep_chunk)->length = htons(sizeof(*(hep_chunk)) + len); \
  139. } while (0)
  140. #define INITIALIZE_GENERIC_HEP_CHUNK(hep_item, type) do { \
  141. INITIALIZE_GENERIC_HEP_IDS(&(hep_item)->chunk, (type)); \
  142. (hep_item)->chunk.length = htons(sizeof(*(hep_item))); \
  143. } while (0)
  144. #define INITIALIZE_GENERIC_HEP_CHUNK_DATA(hep_item, type, value) do { \
  145. INITIALIZE_GENERIC_HEP_CHUNK((hep_item), (type)); \
  146. (hep_item)->data = (value); \
  147. } while (0)
  148. /*
  149. * HEPv3 Types.
  150. * Note that the content in these is stored in network byte order.
  151. */
  152. struct hep_chunk {
  153. u_int16_t vendor_id;
  154. u_int16_t type_id;
  155. u_int16_t length;
  156. } __attribute__((packed));
  157. struct hep_chunk_uint8 {
  158. struct hep_chunk chunk;
  159. u_int8_t data;
  160. } __attribute__((packed));
  161. struct hep_chunk_uint16 {
  162. struct hep_chunk chunk;
  163. u_int16_t data;
  164. } __attribute__((packed));
  165. struct hep_chunk_uint32 {
  166. struct hep_chunk chunk;
  167. u_int32_t data;
  168. } __attribute__((packed));
  169. struct hep_chunk_ip4 {
  170. struct hep_chunk chunk;
  171. struct in_addr data;
  172. } __attribute__((packed));
  173. struct hep_chunk_ip6 {
  174. struct hep_chunk chunk;
  175. struct in6_addr data;
  176. } __attribute__((packed));
  177. struct hep_ctrl {
  178. char id[4];
  179. u_int16_t length;
  180. } __attribute__((packed));
  181. /* HEP structures */
  182. struct hep_generic {
  183. struct hep_ctrl header;
  184. struct hep_chunk_uint8 ip_family;
  185. struct hep_chunk_uint8 ip_proto;
  186. struct hep_chunk_uint16 src_port;
  187. struct hep_chunk_uint16 dst_port;
  188. struct hep_chunk_uint32 time_sec;
  189. struct hep_chunk_uint32 time_usec;
  190. struct hep_chunk_uint8 proto_t;
  191. struct hep_chunk_uint32 capt_id;
  192. } __attribute__((packed));
  193. /*! \brief Global configuration for the module */
  194. struct hepv3_global_config {
  195. unsigned int enabled; /*!< Whether or not sending is enabled */
  196. unsigned int capture_id; /*!< Capture ID for this agent */
  197. enum hep_uuid_type uuid_type; /*!< The preferred type of the UUID */
  198. AST_DECLARE_STRING_FIELDS(
  199. AST_STRING_FIELD(capture_address); /*!< Address to send to */
  200. AST_STRING_FIELD(capture_password); /*!< Password for Homer server */
  201. );
  202. };
  203. /*! \brief The actual module config */
  204. struct module_config {
  205. struct hepv3_global_config *general; /*!< The general config settings */
  206. };
  207. /*! \brief Run-time data derived from \ref hepv3_global_config */
  208. struct hepv3_runtime_data {
  209. struct ast_sockaddr remote_addr; /*!< The address to send to */
  210. int sockfd; /*!< The socket file descriptor */
  211. };
  212. static struct aco_type global_option = {
  213. .type = ACO_GLOBAL,
  214. .name = "general",
  215. .item_offset = offsetof(struct module_config, general),
  216. .category_match = ACO_WHITELIST_EXACT,
  217. .category = "general",
  218. };
  219. struct aco_type *global_options[] = ACO_TYPES(&global_option);
  220. struct aco_file hepv3_conf = {
  221. .filename = "hep.conf",
  222. .types = ACO_TYPES(&global_option),
  223. };
  224. /*! \brief The module configuration container */
  225. static AO2_GLOBAL_OBJ_STATIC(global_config);
  226. /*! \brief Current module data */
  227. static AO2_GLOBAL_OBJ_STATIC(global_data);
  228. static struct ast_taskprocessor *hep_queue_tp;
  229. static void *module_config_alloc(void);
  230. static int hepv3_config_pre_apply(void);
  231. static void hepv3_config_post_apply(void);
  232. /*! \brief Register information about the configs being processed by this module */
  233. CONFIG_INFO_STANDARD(cfg_info, global_config, module_config_alloc,
  234. .files = ACO_FILES(&hepv3_conf),
  235. .pre_apply_config = hepv3_config_pre_apply,
  236. .post_apply_config = hepv3_config_post_apply,
  237. );
  238. static void hepv3_config_dtor(void *obj)
  239. {
  240. struct hepv3_global_config *config = obj;
  241. ast_string_field_free_memory(config);
  242. }
  243. /*! \brief HEPv3 configuration object allocation */
  244. static void *hepv3_config_alloc(void)
  245. {
  246. struct hepv3_global_config *config;
  247. config = ao2_alloc(sizeof(*config), hepv3_config_dtor);
  248. if (!config || ast_string_field_init(config, 32)) {
  249. return NULL;
  250. }
  251. return config;
  252. }
  253. /*! \brief Configuration object destructor */
  254. static void module_config_dtor(void *obj)
  255. {
  256. struct module_config *config = obj;
  257. if (config->general) {
  258. ao2_ref(config->general, -1);
  259. }
  260. }
  261. /*! \brief Module config constructor */
  262. static void *module_config_alloc(void)
  263. {
  264. struct module_config *config;
  265. config = ao2_alloc(sizeof(*config), module_config_dtor);
  266. if (!config) {
  267. return NULL;
  268. }
  269. config->general = hepv3_config_alloc();
  270. if (!config->general) {
  271. ao2_ref(config, -1);
  272. config = NULL;
  273. }
  274. return config;
  275. }
  276. /*! \brief Handler for the uuid_type attribute */
  277. static int uuid_type_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
  278. {
  279. struct hepv3_global_config *global_config = obj;
  280. if (strcasecmp(var->name, "uuid_type")) {
  281. return -1;
  282. }
  283. if (!strcasecmp(var->value, "channel")) {
  284. global_config->uuid_type = HEP_UUID_TYPE_CHANNEL;
  285. } else if (!strcasecmp(var->value, "call-id")) {
  286. global_config->uuid_type = HEP_UUID_TYPE_CALL_ID;
  287. } else {
  288. return -1;
  289. }
  290. return 0;
  291. }
  292. /*! \brief HEPv3 run-time data destructor */
  293. static void hepv3_data_dtor(void *obj)
  294. {
  295. struct hepv3_runtime_data *data = obj;
  296. if (data->sockfd > -1) {
  297. close(data->sockfd);
  298. data->sockfd = -1;
  299. }
  300. }
  301. /*! \brief Pulls first resolved address and returns it */
  302. static int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr,
  303. const char* name, int flag, int family)
  304. {
  305. struct ast_sockaddr *addrs;
  306. int addrs_cnt;
  307. addrs_cnt = ast_sockaddr_resolve(&addrs, name, flag, family);
  308. if (addrs_cnt <= 0) {
  309. return 1;
  310. }
  311. if (addrs_cnt > 1) {
  312. ast_debug(1, "Multiple addresses resolving %s, using the first one only\n", name);
  313. }
  314. ast_sockaddr_copy(addr, &addrs[0]);
  315. ast_free(addrs);
  316. return 0;
  317. }
  318. /*! \brief Allocate the HEPv3 run-time data */
  319. static struct hepv3_runtime_data *hepv3_data_alloc(struct hepv3_global_config *config)
  320. {
  321. struct hepv3_runtime_data *data;
  322. data = ao2_alloc(sizeof(*data), hepv3_data_dtor);
  323. if (!data) {
  324. return NULL;
  325. }
  326. data->sockfd = -1;
  327. if (ast_sockaddr_resolve_first_af(&data->remote_addr, config->capture_address, PARSE_PORT_REQUIRE, AST_AF_UNSPEC)) {
  328. ast_log(AST_LOG_WARNING, "Failed to create address from %s\n", config->capture_address);
  329. ao2_ref(data, -1);
  330. return NULL;
  331. }
  332. data->sockfd = socket(ast_sockaddr_is_ipv6(&data->remote_addr) ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
  333. if (data->sockfd < 0) {
  334. ast_log(AST_LOG_WARNING, "Failed to create socket for address %s: %s\n",
  335. config->capture_address, strerror(errno));
  336. ao2_ref(data, -1);
  337. return NULL;
  338. }
  339. return data;
  340. }
  341. /*! \brief Destructor for a \ref hepv3_capture_info object */
  342. static void capture_info_dtor(void *obj)
  343. {
  344. struct hepv3_capture_info *info = obj;
  345. ast_free(info->uuid);
  346. ast_free(info->payload);
  347. }
  348. enum hep_uuid_type hepv3_get_uuid_type(void)
  349. {
  350. RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
  351. if (!config) {
  352. /* Well, that's unfortunate. Return something. */
  353. return HEP_UUID_TYPE_CALL_ID;
  354. }
  355. return config->general->uuid_type;
  356. }
  357. int hepv3_is_loaded(void)
  358. {
  359. RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
  360. return config && config->general->enabled;
  361. }
  362. struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t len)
  363. {
  364. struct hepv3_capture_info *info;
  365. info = ao2_alloc(sizeof(*info), capture_info_dtor);
  366. if (!info) {
  367. return NULL;
  368. }
  369. info->payload = ast_malloc(len);
  370. if (!info->payload) {
  371. ao2_ref(info, -1);
  372. return NULL;
  373. }
  374. memcpy(info->payload, payload, len);
  375. info->len = len;
  376. /* Set a reasonable default */
  377. info->protocol_id = IPPROTO_UDP;
  378. return info;
  379. }
  380. /*! \brief Callback function for the \ref hep_queue_tp taskprocessor */
  381. static int hep_queue_cb(void *data)
  382. {
  383. RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
  384. RAII_VAR(struct hepv3_runtime_data *, hepv3_data, ao2_global_obj_ref(global_data), ao2_cleanup);
  385. RAII_VAR(struct hepv3_capture_info *, capture_info, data, ao2_cleanup);
  386. struct hep_generic hg_pkt;
  387. unsigned int packet_len = 0, sock_buffer_len;
  388. struct hep_chunk_ip4 ipv4_src, ipv4_dst;
  389. struct hep_chunk_ip6 ipv6_src, ipv6_dst;
  390. struct hep_chunk auth_key, payload, uuid;
  391. void *sock_buffer;
  392. int res;
  393. if (!capture_info || !config || !hepv3_data) {
  394. return 0;
  395. }
  396. if (ast_sockaddr_is_ipv4(&capture_info->src_addr) != ast_sockaddr_is_ipv4(&capture_info->dst_addr)) {
  397. ast_log(AST_LOG_NOTICE, "Unable to send packet: Address Family mismatch between source/destination\n");
  398. return -1;
  399. }
  400. packet_len = sizeof(hg_pkt);
  401. /* Build HEPv3 header, capture info, and calculate the total packet size */
  402. memcpy(hg_pkt.header.id, "\x48\x45\x50\x33", 4);
  403. INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_proto, CHUNK_TYPE_IP_PROTOCOL_ID, capture_info->protocol_id);
  404. INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.src_port, CHUNK_TYPE_SRC_PORT, htons(ast_sockaddr_port(&capture_info->src_addr)));
  405. INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.dst_port, CHUNK_TYPE_DST_PORT, htons(ast_sockaddr_port(&capture_info->dst_addr)));
  406. INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.time_sec, CHUNK_TYPE_TIMESTAMP_SEC, htonl(capture_info->capture_time.tv_sec));
  407. INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.time_usec, CHUNK_TYPE_TIMESTAMP_USEC, htonl(capture_info->capture_time.tv_usec));
  408. INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.proto_t, CHUNK_TYPE_PROTOCOL_TYPE, capture_info->capture_type);
  409. INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.capt_id, CHUNK_TYPE_CAPTURE_AGENT_ID, htonl(config->general->capture_id));
  410. if (ast_sockaddr_is_ipv4(&capture_info->src_addr)) {
  411. INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_family,
  412. CHUNK_TYPE_IP_PROTOCOL_FAMILY, AF_INET);
  413. INITIALIZE_GENERIC_HEP_CHUNK(&ipv4_src, CHUNK_TYPE_IPV4_SRC_ADDR);
  414. inet_pton(AF_INET, ast_sockaddr_stringify_addr(&capture_info->src_addr), &ipv4_src.data);
  415. INITIALIZE_GENERIC_HEP_CHUNK(&ipv4_dst, CHUNK_TYPE_IPV4_DST_ADDR);
  416. inet_pton(AF_INET, ast_sockaddr_stringify_addr(&capture_info->dst_addr), &ipv4_dst.data);
  417. packet_len += (sizeof(ipv4_src) + sizeof(ipv4_dst));
  418. } else {
  419. INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_family,
  420. CHUNK_TYPE_IP_PROTOCOL_FAMILY, AF_INET6);
  421. INITIALIZE_GENERIC_HEP_CHUNK(&ipv6_src, CHUNK_TYPE_IPV6_SRC_ADDR);
  422. inet_pton(AF_INET6, ast_sockaddr_stringify_addr(&capture_info->src_addr), &ipv6_src.data);
  423. INITIALIZE_GENERIC_HEP_CHUNK(&ipv6_dst, CHUNK_TYPE_IPV6_DST_ADDR);
  424. inet_pton(AF_INET6, ast_sockaddr_stringify_addr(&capture_info->dst_addr), &ipv6_dst.data);
  425. packet_len += (sizeof(ipv6_src) + sizeof(ipv6_dst));
  426. }
  427. if (!ast_strlen_zero(config->general->capture_password)) {
  428. INITIALIZE_GENERIC_HEP_IDS_VAR(&auth_key, CHUNK_TYPE_AUTH_KEY, strlen(config->general->capture_password));
  429. packet_len += (sizeof(auth_key) + strlen(config->general->capture_password));
  430. }
  431. INITIALIZE_GENERIC_HEP_IDS_VAR(&uuid, CHUNK_TYPE_UUID, strlen(capture_info->uuid));
  432. packet_len += (sizeof(uuid) + strlen(capture_info->uuid));
  433. INITIALIZE_GENERIC_HEP_IDS_VAR(&payload,
  434. capture_info->zipped ? CHUNK_TYPE_PAYLOAD_ZIP : CHUNK_TYPE_PAYLOAD, capture_info->len);
  435. packet_len += (sizeof(payload) + capture_info->len);
  436. hg_pkt.header.length = htons(packet_len);
  437. /* Build the buffer to send */
  438. sock_buffer = ast_malloc(packet_len);
  439. if (!sock_buffer) {
  440. return -1;
  441. }
  442. /* Copy in the header */
  443. memcpy(sock_buffer, &hg_pkt, sizeof(hg_pkt));
  444. sock_buffer_len = sizeof(hg_pkt);
  445. /* Addresses */
  446. if (ast_sockaddr_is_ipv4(&capture_info->src_addr)) {
  447. memcpy(sock_buffer + sock_buffer_len, &ipv4_src, sizeof(ipv4_src));
  448. sock_buffer_len += sizeof(ipv4_src);
  449. memcpy(sock_buffer + sock_buffer_len, &ipv4_dst, sizeof(ipv4_dst));
  450. sock_buffer_len += sizeof(ipv4_dst);
  451. } else {
  452. memcpy(sock_buffer + sock_buffer_len, &ipv6_src, sizeof(ipv6_src));
  453. sock_buffer_len += sizeof(ipv6_src);
  454. memcpy(sock_buffer + sock_buffer_len, &ipv6_dst, sizeof(ipv6_dst));
  455. sock_buffer_len += sizeof(ipv6_dst);
  456. }
  457. /* Auth Key */
  458. if (!ast_strlen_zero(config->general->capture_password)) {
  459. memcpy(sock_buffer + sock_buffer_len, &auth_key, sizeof(auth_key));
  460. sock_buffer_len += sizeof(auth_key);
  461. memcpy(sock_buffer + sock_buffer_len, config->general->capture_password, strlen(config->general->capture_password));
  462. sock_buffer_len += strlen(config->general->capture_password);
  463. }
  464. /* UUID */
  465. memcpy(sock_buffer + sock_buffer_len, &uuid, sizeof(uuid));
  466. sock_buffer_len += sizeof(uuid);
  467. memcpy(sock_buffer + sock_buffer_len, capture_info->uuid, strlen(capture_info->uuid));
  468. sock_buffer_len += strlen(capture_info->uuid);
  469. /* Packet! */
  470. memcpy(sock_buffer + sock_buffer_len, &payload, sizeof(payload));
  471. sock_buffer_len += sizeof(payload);
  472. memcpy(sock_buffer + sock_buffer_len, capture_info->payload, capture_info->len);
  473. sock_buffer_len += capture_info->len;
  474. ast_assert(sock_buffer_len == packet_len);
  475. res = ast_sendto(hepv3_data->sockfd, sock_buffer, sock_buffer_len, 0, &hepv3_data->remote_addr);
  476. if (res < 0) {
  477. ast_log(AST_LOG_ERROR, "Error [%d] while sending packet to HEPv3 server: %s\n",
  478. errno, strerror(errno));
  479. } else if (res != sock_buffer_len) {
  480. ast_log(AST_LOG_WARNING, "Failed to send complete packet to HEPv3 server: %d of %u sent\n",
  481. res, sock_buffer_len);
  482. res = -1;
  483. }
  484. ast_free(sock_buffer);
  485. return res;
  486. }
  487. int hepv3_send_packet(struct hepv3_capture_info *capture_info)
  488. {
  489. RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
  490. int res;
  491. if (!config || !config->general->enabled) {
  492. ao2_ref(capture_info, -1);
  493. return 0;
  494. }
  495. res = ast_taskprocessor_push(hep_queue_tp, hep_queue_cb, capture_info);
  496. if (res == -1) {
  497. ao2_ref(capture_info, -1);
  498. }
  499. return res;
  500. }
  501. /*!
  502. * \brief Pre-apply callback for the config framework.
  503. *
  504. * This validates that required fields exist and are populated.
  505. */
  506. static int hepv3_config_pre_apply(void)
  507. {
  508. struct module_config *config = aco_pending_config(&cfg_info);
  509. if (!config->general->enabled) {
  510. /* If we're not enabled, we don't care about anything else */
  511. return 0;
  512. }
  513. if (ast_strlen_zero(config->general->capture_address)) {
  514. ast_log(AST_LOG_ERROR, "Missing required configuration option 'capture_address'\n");
  515. return -1;
  516. }
  517. return 0;
  518. }
  519. /*!
  520. * \brief Post-apply callback for the config framework.
  521. *
  522. * This will create the run-time information from the supplied
  523. * configuration.
  524. */
  525. static void hepv3_config_post_apply(void)
  526. {
  527. RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(global_config), ao2_cleanup);
  528. struct hepv3_runtime_data *data;
  529. data = hepv3_data_alloc(mod_cfg->general);
  530. if (!data) {
  531. return;
  532. }
  533. ao2_global_obj_replace_unref(global_data, data);
  534. ao2_ref(data, -1);
  535. }
  536. /*!
  537. * \brief Reload the module
  538. */
  539. static int reload_module(void)
  540. {
  541. if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
  542. return -1;
  543. }
  544. return 0;
  545. }
  546. /*!
  547. * \brief Unload the module
  548. */
  549. static int unload_module(void)
  550. {
  551. hep_queue_tp = ast_taskprocessor_unreference(hep_queue_tp);
  552. ao2_global_obj_release(global_config);
  553. ao2_global_obj_release(global_data);
  554. aco_info_destroy(&cfg_info);
  555. return 0;
  556. }
  557. /*!
  558. * \brief Load the module
  559. */
  560. static int load_module(void)
  561. {
  562. if (aco_info_init(&cfg_info)) {
  563. goto error;
  564. }
  565. hep_queue_tp = ast_taskprocessor_get("hep_queue_tp", TPS_REF_DEFAULT);
  566. if (!hep_queue_tp) {
  567. goto error;
  568. }
  569. aco_option_register(&cfg_info, "enabled", ACO_EXACT, global_options, "yes", OPT_BOOL_T, 1, FLDSET(struct hepv3_global_config, enabled));
  570. aco_option_register(&cfg_info, "capture_address", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 1, STRFLDSET(struct hepv3_global_config, capture_address));
  571. aco_option_register(&cfg_info, "capture_password", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_password));
  572. aco_option_register(&cfg_info, "capture_id", ACO_EXACT, global_options, "0", OPT_UINT_T, 0, STRFLDSET(struct hepv3_global_config, capture_id));
  573. aco_option_register_custom(&cfg_info, "uuid_type", ACO_EXACT, global_options, "call-id", uuid_type_handler, 0);
  574. if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
  575. goto error;
  576. }
  577. return AST_MODULE_LOAD_SUCCESS;
  578. error:
  579. aco_info_destroy(&cfg_info);
  580. return AST_MODULE_LOAD_DECLINE;
  581. }
  582. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "HEPv3 API",
  583. .support_level = AST_MODULE_SUPPORT_EXTENDED,
  584. .load = load_module,
  585. .unload = unload_module,
  586. .reload = reload_module,
  587. .load_pri = AST_MODPRI_APP_DEPEND,
  588. );