res_pjsip_logger.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2013, Digium, Inc.
  5. *
  6. * Mark Michelson <mmichelson@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*** MODULEINFO
  19. <depend>pjproject</depend>
  20. <depend>res_pjsip</depend>
  21. <defaultenabled>yes</defaultenabled>
  22. <support_level>core</support_level>
  23. ***/
  24. #include "asterisk.h"
  25. #include <netinet/in.h> /* For IPPROTO_UDP and in6_addr */
  26. #include <pjsip.h>
  27. #include "asterisk/res_pjsip.h"
  28. #include "asterisk/vector.h"
  29. #include "asterisk/module.h"
  30. #include "asterisk/logger.h"
  31. #include "asterisk/cli.h"
  32. #include "asterisk/netsock2.h"
  33. #include "asterisk/acl.h"
  34. /*! \brief PCAP Header */
  35. struct pcap_header {
  36. uint32_t magic_number; /*! \brief PCAP file format magic number */
  37. uint16_t version_major; /*! \brief Major version number of the file format */
  38. uint16_t version_minor; /*! \brief Minor version number of the file format */
  39. int32_t thiszone; /*! \brief GMT to local correction */
  40. uint32_t sigfigs; /*! \brief Accuracy of timestamps */
  41. uint32_t snaplen; /*! \brief The maximum size that can be recorded in the file */
  42. uint32_t network; /*! \brief Type of packets held within the file */
  43. };
  44. /*! \brief PCAP Packet Record Header */
  45. struct pcap_record_header {
  46. uint32_t ts_sec; /*! \brief When the record was created */
  47. uint32_t ts_usec; /*! \brief When the record was created */
  48. uint32_t incl_len; /*! \brief Length of packet as saved in the file */
  49. uint32_t orig_len; /*! \brief Length of packet as sent over network */
  50. };
  51. /*! \brief PCAP Ethernet Header */
  52. struct pcap_ethernet_header {
  53. uint8_t dst[6]; /*! \brief Destination MAC address */
  54. uint8_t src[6]; /*! \brief Source MAD address */
  55. uint16_t type; /*! \brief The type of packet contained within */
  56. } __attribute__((__packed__));
  57. /*! \brief PCAP IPv4 Header */
  58. struct pcap_ipv4_header {
  59. uint8_t ver_ihl; /*! \brief IP header version and other bits */
  60. uint8_t ip_tos; /*! \brief Type of service details */
  61. uint16_t ip_len; /*! \brief Total length of the packet (including IPv4 header) */
  62. uint16_t ip_id; /*! \brief Identification value */
  63. uint16_t ip_off; /*! \brief Fragment offset */
  64. uint8_t ip_ttl; /*! \brief Time to live for the packet */
  65. uint8_t ip_protocol; /*! \brief Protocol of the data held within the packet (always UDP) */
  66. uint16_t ip_sum; /*! \brief Checksum (not calculated for our purposes */
  67. uint32_t ip_src; /*! \brief Source IP address */
  68. uint32_t ip_dst; /*! \brief Destination IP address */
  69. };
  70. /*! \brief PCAP IPv6 Header */
  71. struct pcap_ipv6_header {
  72. union {
  73. struct ip6_hdrctl {
  74. uint32_t ip6_un1_flow; /*! \brief Version, traffic class, flow label */
  75. uint16_t ip6_un1_plen; /*! \brief Length of the packet (not including IPv6 header) */
  76. uint8_t ip6_un1_nxt; /*! \brief Next header field */
  77. uint8_t ip6_un1_hlim; /*! \brief Hop Limit */
  78. } ip6_un1;
  79. uint8_t ip6_un2_vfc; /*! \brief Version, traffic class */
  80. } ip6_ctlun;
  81. struct in6_addr ip6_src; /*! \brief Source IP address */
  82. struct in6_addr ip6_dst; /*! \brief Destination IP address */
  83. };
  84. /*! \brief PCAP UDP Header */
  85. struct pcap_udp_header {
  86. uint16_t src; /*! \brief Source IP port */
  87. uint16_t dst; /*! \brief Destination IP port */
  88. uint16_t length; /*! \brief Length of the UDP header plus UDP packet */
  89. uint16_t checksum; /*! \brief Packet checksum, left uncalculated for our purposes */
  90. };
  91. struct method_logging_info {
  92. pj_str_t pj_name; /*! \brief A PJSIP string for the method */
  93. pjsip_method method; /*! \brief The PJSIP method structure used for comparisons */
  94. char name[]; /*! \brief The method name */
  95. };
  96. /*! \brief PJSIP Logging Session */
  97. struct pjsip_logger_session {
  98. /*! \brief Explicit addresses or ranges being logged */
  99. struct ast_ha *matches;
  100. /*! \brief Filename used for the pcap file */
  101. char pcap_filename[PATH_MAX];
  102. /*! \brief The pcap file itself */
  103. FILE *pcap_file;
  104. /*! \brief Whether the session is enabled or not */
  105. unsigned int enabled:1;
  106. /*! \brief Whether the session is logging all traffic or not */
  107. unsigned int log_all_traffic:1;
  108. /*! \brief Whether to log to verbose or not */
  109. unsigned int log_to_verbose:1;
  110. /*! \brief Whether to log to pcap or not */
  111. unsigned int log_to_pcap:1;
  112. /*! \brief Vector of SIP methods to log */
  113. AST_VECTOR(, struct method_logging_info *) log_methods;
  114. };
  115. /*! \brief The default logger session */
  116. static struct pjsip_logger_session *default_logger;
  117. /*! \brief Destructor for logger session */
  118. static void pjsip_logger_session_destroy(void *obj)
  119. {
  120. struct pjsip_logger_session *session = obj;
  121. if (session->pcap_file) {
  122. fclose(session->pcap_file);
  123. }
  124. ast_free_ha(session->matches);
  125. AST_VECTOR_RESET(&session->log_methods, ast_free);
  126. AST_VECTOR_FREE(&session->log_methods);
  127. }
  128. /*! \brief Allocator for logger session */
  129. static struct pjsip_logger_session *pjsip_logger_session_alloc(void)
  130. {
  131. struct pjsip_logger_session *session;
  132. session = ao2_alloc_options(sizeof(struct pjsip_logger_session), pjsip_logger_session_destroy,
  133. AO2_ALLOC_OPT_LOCK_RWLOCK);
  134. if (!session) {
  135. return NULL;
  136. }
  137. session->log_to_verbose = 1;
  138. AST_VECTOR_INIT(&session->log_methods, 0);
  139. return session;
  140. }
  141. /*! \note Must be called with the pjsip_logger_session lock held */
  142. static int apply_method_filter(const struct pjsip_logger_session *session, const pjsip_method *method)
  143. {
  144. size_t size = AST_VECTOR_SIZE(&session->log_methods);
  145. size_t i;
  146. if (size == 0) {
  147. /* Nothing in the vector means everything matches */
  148. return 0;
  149. }
  150. for (i = 0; i < size; ++i) {
  151. struct method_logging_info *candidate = AST_VECTOR_GET(&session->log_methods, i);
  152. if (pjsip_method_cmp(&candidate->method, method) == 0) {
  153. return 0;
  154. }
  155. }
  156. /* Nothing matched */
  157. return 1;
  158. }
  159. /*! \brief See if we pass debug filter */
  160. static inline int pjsip_log_test_filter(const struct pjsip_logger_session *session, const char *address, int port, const pjsip_method *method)
  161. {
  162. struct ast_sockaddr test_addr;
  163. if (!session->enabled) {
  164. return 0;
  165. }
  166. if (session->log_all_traffic) {
  167. return 1;
  168. }
  169. if (apply_method_filter(session, method)) {
  170. /* The method filter didn't match anything, so reject. */
  171. return 0;
  172. }
  173. /* A null address was passed in or no explicit matches. Just reject it. */
  174. if (ast_strlen_zero(address) || !session->matches) {
  175. /* If we matched on method and host is empty, accept, otherwise reject. */
  176. return AST_VECTOR_SIZE(&session->log_methods) > 0;
  177. }
  178. ast_sockaddr_parse(&test_addr, address, PARSE_PORT_IGNORE);
  179. ast_sockaddr_set_port(&test_addr, port);
  180. /* Compare the address against the matches */
  181. if (ast_apply_ha(session->matches, &test_addr) != AST_SENSE_ALLOW) {
  182. return 1;
  183. } else {
  184. return 0;
  185. }
  186. }
  187. static void pjsip_logger_write_to_pcap(struct pjsip_logger_session *session, const char *msg, size_t msg_len,
  188. pj_sockaddr *source, pj_sockaddr *destination)
  189. {
  190. struct timeval now = ast_tvnow();
  191. struct pcap_record_header pcap_record_header = {
  192. .ts_sec = now.tv_sec,
  193. .ts_usec = now.tv_usec,
  194. };
  195. struct pcap_ethernet_header pcap_ethernet_header = {
  196. .type = 0,
  197. };
  198. struct pcap_ipv4_header pcap_ipv4_header = {
  199. .ver_ihl = 0x45, /* IPv4 + 20 bytes of header */
  200. .ip_ttl = 128, /* We always put a TTL of 128 to keep Wireshark less blue */
  201. };
  202. struct pcap_ipv6_header pcap_ipv6_header = {
  203. .ip6_ctlun.ip6_un2_vfc = 0x60,
  204. };
  205. void *pcap_ip_header;
  206. size_t pcap_ip_header_len;
  207. struct pcap_udp_header pcap_udp_header;
  208. /* Packets are always stored as UDP to simplify this logic */
  209. if (source) {
  210. pcap_udp_header.src = ntohs(pj_sockaddr_get_port(source));
  211. } else {
  212. pcap_udp_header.src = ntohs(0);
  213. }
  214. if (destination) {
  215. pcap_udp_header.dst = ntohs(pj_sockaddr_get_port(destination));
  216. } else {
  217. pcap_udp_header.dst = ntohs(0);
  218. }
  219. pcap_udp_header.length = ntohs(sizeof(struct pcap_udp_header) + msg_len);
  220. /* Construct the appropriate IP header */
  221. if ((source && source->addr.sa_family == pj_AF_INET()) ||
  222. (destination && destination->addr.sa_family == pj_AF_INET())) {
  223. pcap_ethernet_header.type = htons(0x0800); /* We are providing an IPv4 packet */
  224. pcap_ip_header = &pcap_ipv4_header;
  225. pcap_ip_header_len = sizeof(struct pcap_ipv4_header);
  226. if (source) {
  227. memcpy(&pcap_ipv4_header.ip_src, pj_sockaddr_get_addr(source), pj_sockaddr_get_addr_len(source));
  228. }
  229. if (destination) {
  230. memcpy(&pcap_ipv4_header.ip_dst, pj_sockaddr_get_addr(destination), pj_sockaddr_get_addr_len(destination));
  231. }
  232. pcap_ipv4_header.ip_len = htons(sizeof(struct pcap_udp_header) + sizeof(struct pcap_ipv4_header) + msg_len);
  233. pcap_ipv4_header.ip_protocol = IPPROTO_UDP; /* We always provide UDP */
  234. } else {
  235. pcap_ethernet_header.type = htons(0x86DD); /* We are providing an IPv6 packet */
  236. pcap_ip_header = &pcap_ipv6_header;
  237. pcap_ip_header_len = sizeof(struct pcap_ipv6_header);
  238. if (source) {
  239. memcpy(&pcap_ipv6_header.ip6_src, pj_sockaddr_get_addr(source), pj_sockaddr_get_addr_len(source));
  240. }
  241. if (destination) {
  242. memcpy(&pcap_ipv6_header.ip6_dst, pj_sockaddr_get_addr(destination), pj_sockaddr_get_addr_len(destination));
  243. }
  244. pcap_ipv6_header.ip6_ctlun.ip6_un1.ip6_un1_plen = htons(sizeof(struct pcap_udp_header) + msg_len);
  245. pcap_ipv6_header.ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_UDP;
  246. }
  247. /* Add up all the sizes for this record */
  248. pcap_record_header.incl_len = pcap_record_header.orig_len = sizeof(pcap_ethernet_header) + pcap_ip_header_len + sizeof(pcap_udp_header) + msg_len;
  249. /* We lock the logger session since we're writing these out in parts */
  250. ao2_wrlock(session);
  251. if (session->pcap_file) {
  252. if (fwrite(&pcap_record_header, sizeof(struct pcap_record_header), 1, session->pcap_file) != 1) {
  253. ast_log(LOG_WARNING, "Writing PCAP header failed: %s\n", strerror(errno));
  254. }
  255. if (fwrite(&pcap_ethernet_header, sizeof(struct pcap_ethernet_header), 1, session->pcap_file) != 1) {
  256. ast_log(LOG_WARNING, "Writing ethernet header to pcap failed: %s\n", strerror(errno));
  257. }
  258. if (fwrite(pcap_ip_header, pcap_ip_header_len, 1, session->pcap_file) != 1) {
  259. ast_log(LOG_WARNING, "Writing IP header to pcap failed: %s\n", strerror(errno));
  260. }
  261. if (fwrite(&pcap_udp_header, sizeof(struct pcap_udp_header), 1, session->pcap_file) != 1) {
  262. ast_log(LOG_WARNING, "Writing UDP header to pcap failed: %s\n", strerror(errno));
  263. }
  264. if (fwrite(msg, msg_len, 1, session->pcap_file) != 1) {
  265. ast_log(LOG_WARNING, "Writing UDP payload to pcap failed: %s\n", strerror(errno));
  266. }
  267. }
  268. ao2_unlock(session);
  269. }
  270. static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
  271. {
  272. char buffer[AST_SOCKADDR_BUFLEN];
  273. ao2_rdlock(default_logger);
  274. if (!pjsip_log_test_filter(default_logger, tdata->tp_info.dst_name, tdata->tp_info.dst_port, &tdata->msg->line.req.method)) {
  275. ao2_unlock(default_logger);
  276. return PJ_SUCCESS;
  277. }
  278. ao2_unlock(default_logger);
  279. if (default_logger->log_to_verbose) {
  280. ast_verbose("<--- Transmitting SIP %s (%d bytes) to %s:%s --->\n%.*s\n",
  281. tdata->msg->type == PJSIP_REQUEST_MSG ? "request" : "response",
  282. (int) (tdata->buf.cur - tdata->buf.start),
  283. tdata->tp_info.transport->type_name,
  284. pj_sockaddr_print(&tdata->tp_info.dst_addr, buffer, sizeof(buffer), 3),
  285. (int) (tdata->buf.end - tdata->buf.start), tdata->buf.start);
  286. }
  287. if (default_logger->log_to_pcap) {
  288. pjsip_logger_write_to_pcap(default_logger, tdata->buf.start, (int) (tdata->buf.cur - tdata->buf.start),
  289. NULL, &tdata->tp_info.dst_addr);
  290. }
  291. return PJ_SUCCESS;
  292. }
  293. static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
  294. {
  295. char buffer[AST_SOCKADDR_BUFLEN];
  296. if (!rdata->msg_info.msg) {
  297. return PJ_FALSE;
  298. }
  299. ao2_rdlock(default_logger);
  300. if (!pjsip_log_test_filter(default_logger, rdata->pkt_info.src_name, rdata->pkt_info.src_port, &rdata->msg_info.msg->line.req.method)) {
  301. ao2_unlock(default_logger);
  302. return PJ_FALSE;
  303. }
  304. ao2_unlock(default_logger);
  305. if (default_logger->log_to_verbose) {
  306. ast_verbose("<--- Received SIP %s (%d bytes) from %s:%s --->\n%s\n",
  307. rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ? "request" : "response",
  308. rdata->msg_info.len,
  309. rdata->tp_info.transport->type_name,
  310. pj_sockaddr_print(&rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
  311. rdata->pkt_info.packet);
  312. }
  313. if (default_logger->log_to_pcap) {
  314. pjsip_logger_write_to_pcap(default_logger, rdata->pkt_info.packet, rdata->msg_info.len,
  315. &rdata->pkt_info.src_addr, NULL);
  316. }
  317. return PJ_FALSE;
  318. }
  319. static pjsip_module logging_module = {
  320. .name = { "Logging Module", 14 },
  321. .priority = 0,
  322. .on_rx_request = logging_on_rx_msg,
  323. .on_rx_response = logging_on_rx_msg,
  324. .on_tx_request = logging_on_tx_msg,
  325. .on_tx_response = logging_on_tx_msg,
  326. };
  327. static char *pjsip_enable_logger_all(int fd)
  328. {
  329. ao2_wrlock(default_logger);
  330. default_logger->enabled = 1;
  331. default_logger->log_all_traffic = 1;
  332. ao2_unlock(default_logger);
  333. if (fd >= 0) {
  334. ast_cli(fd, "PJSIP Logging enabled\n");
  335. }
  336. return CLI_SUCCESS;
  337. }
  338. static char *pjsip_enable_logger_host(int fd, const char *arg, unsigned int add_host)
  339. {
  340. const char *host = arg;
  341. char *mask;
  342. struct ast_sockaddr address;
  343. int error = 0;
  344. ao2_wrlock(default_logger);
  345. default_logger->enabled = 1;
  346. if (!add_host) {
  347. /* If this is not adding an additional host or subnet then we have to
  348. * remove what already exists.
  349. */
  350. ast_free_ha(default_logger->matches);
  351. default_logger->matches = NULL;
  352. }
  353. mask = strrchr(host, '/');
  354. if (!mask && !ast_sockaddr_parse(&address, arg, 0)) {
  355. if (ast_sockaddr_resolve_first_af(&address, arg, 0, AST_AF_UNSPEC)) {
  356. ao2_unlock(default_logger);
  357. return CLI_SHOWUSAGE;
  358. }
  359. host = ast_sockaddr_stringify(&address);
  360. }
  361. default_logger->matches = ast_append_ha_with_port("d", host, default_logger->matches, &error);
  362. if (!default_logger->matches || error) {
  363. if (fd >= 0) {
  364. ast_cli(fd, "Failed to add address '%s' for logging\n", host);
  365. }
  366. ao2_unlock(default_logger);
  367. return CLI_SUCCESS;
  368. }
  369. ao2_unlock(default_logger);
  370. if (fd >= 0) {
  371. ast_cli(fd, "PJSIP Logging Enabled for host: %s\n", ast_sockaddr_stringify_addr(&address));
  372. }
  373. return CLI_SUCCESS;
  374. }
  375. static struct method_logging_info *method_logging_info_alloc(const char *method)
  376. {
  377. size_t method_bytes = strlen(method);
  378. struct method_logging_info *info;
  379. info = ast_calloc(1, sizeof(struct method_logging_info) + method_bytes + 1);
  380. if (!info) {
  381. return NULL;
  382. }
  383. memcpy(info->name, method, method_bytes + 1);
  384. pj_strset(&info->pj_name, info->name, method_bytes);
  385. pjsip_method_init_np(&info->method, &info->pj_name);
  386. return info;
  387. }
  388. static int method_logging_info_cmp(const struct method_logging_info *element,
  389. const struct method_logging_info *candidate)
  390. {
  391. return pjsip_method_cmp(&element->method, &candidate->method) == 0
  392. ? CMP_MATCH | CMP_STOP
  393. : 0;
  394. }
  395. static int method_logging_info_sort_cmp(const void *a, const void *b)
  396. {
  397. const struct method_logging_info *const *m_a = a;
  398. const struct method_logging_info *const *m_b = b;
  399. return strcasecmp((*m_a)->name, (*m_b)->name);
  400. }
  401. /*! \brief Add the current or an additional method to match for filtering */
  402. static char *pjsip_enable_logger_method(int fd, const char *arg, int add_method)
  403. {
  404. struct ast_str *str;
  405. struct method_logging_info *method;
  406. method = method_logging_info_alloc(arg);
  407. if (!method) {
  408. return CLI_FAILURE;
  409. }
  410. ao2_wrlock(default_logger);
  411. default_logger->enabled = 1;
  412. if (!add_method) {
  413. /* Remove what already exists */
  414. AST_VECTOR_RESET(&default_logger->log_methods, ast_free);
  415. }
  416. /* Already in the list? */
  417. if (AST_VECTOR_CALLBACK(&default_logger->log_methods, method_logging_info_cmp, NULL, method) != NULL) {
  418. ast_cli(fd, "Method '%s' is already enabled\n", method->name);
  419. ao2_unlock(default_logger);
  420. ast_free(method);
  421. return CLI_SUCCESS;
  422. }
  423. if (AST_VECTOR_APPEND(&default_logger->log_methods, method)) {
  424. ast_log(LOG_ERROR, "Cannot register logger method '%s'. Unable to append.\n", method->name);
  425. ao2_unlock(default_logger);
  426. ast_free(method);
  427. return CLI_SUCCESS;
  428. }
  429. AST_VECTOR_SORT(&default_logger->log_methods, method_logging_info_sort_cmp);
  430. str = ast_str_create(256);
  431. if (str) {
  432. size_t i;
  433. for (i = 0; i < AST_VECTOR_SIZE(&default_logger->log_methods); i++) {
  434. method = AST_VECTOR_GET(&default_logger->log_methods, i);
  435. ast_str_append(&str, 0, "%s%.*s",
  436. ast_str_strlen(str) ? ", " : "",
  437. (int) method->pj_name.slen, method->pj_name.ptr);
  438. }
  439. ast_cli(fd, "PJSIP Logging Enabled for SIP Methods: %s\n", ast_str_buffer(str));
  440. ast_free(str);
  441. }
  442. ao2_unlock(default_logger);
  443. return CLI_SUCCESS;
  444. }
  445. static char *pjsip_disable_logger(int fd)
  446. {
  447. ao2_wrlock(default_logger);
  448. /* Default the settings back to the way they were */
  449. default_logger->enabled = 0;
  450. default_logger->log_all_traffic = 0;
  451. default_logger->pcap_filename[0] = '\0';
  452. default_logger->log_to_verbose = 1;
  453. default_logger->log_to_pcap = 0;
  454. AST_VECTOR_RESET(&default_logger->log_methods, ast_free);
  455. /* Stop logging to the PCAP file if active */
  456. if (default_logger->pcap_file) {
  457. fclose(default_logger->pcap_file);
  458. default_logger->pcap_file = NULL;
  459. }
  460. ast_free_ha(default_logger->matches);
  461. default_logger->matches = NULL;
  462. ao2_unlock(default_logger);
  463. if (fd >= 0) {
  464. ast_cli(fd, "PJSIP Logging disabled\n");
  465. }
  466. return CLI_SUCCESS;
  467. }
  468. static char *pjsip_set_logger_verbose(int fd, const char *arg)
  469. {
  470. ao2_wrlock(default_logger);
  471. default_logger->log_to_verbose = ast_true(arg);
  472. ao2_unlock(default_logger);
  473. ast_cli(fd, "PJSIP Logging to verbose has been %s\n", ast_true(arg) ? "enabled" : "disabled");
  474. return CLI_SUCCESS;
  475. }
  476. static char *pjsip_set_logger_pcap(int fd, const char *arg)
  477. {
  478. struct pcap_header pcap_header = {
  479. .magic_number = 0xa1b2c3d4,
  480. .version_major = 2,
  481. .version_minor = 4,
  482. .snaplen = 65535,
  483. .network = 1, /* We always use ethernet so we can combine IPv4 and IPv6 in same pcap */
  484. };
  485. ao2_wrlock(default_logger);
  486. ast_copy_string(default_logger->pcap_filename, arg, sizeof(default_logger->pcap_filename));
  487. if (default_logger->pcap_file) {
  488. fclose(default_logger->pcap_file);
  489. default_logger->pcap_file = NULL;
  490. }
  491. default_logger->pcap_file = fopen(arg, "wb");
  492. if (!default_logger->pcap_file) {
  493. ao2_unlock(default_logger);
  494. ast_cli(fd, "Failed to open file '%s' for pcap writing\n", arg);
  495. return CLI_SUCCESS;
  496. }
  497. fwrite(&pcap_header, 1, sizeof(struct pcap_header), default_logger->pcap_file);
  498. default_logger->log_to_pcap = 1;
  499. ao2_unlock(default_logger);
  500. ast_cli(fd, "PJSIP logging to pcap file '%s'\n", arg);
  501. return CLI_SUCCESS;
  502. }
  503. enum pjsip_logger_mask {
  504. AST_PJSIP_LOGGER_UNSET = 0,
  505. AST_PJSIP_LOGGER_NONE = (1 << 0),
  506. AST_PJSIP_LOGGER_HOST = (1 << 1),
  507. AST_PJSIP_LOGGER_METHOD = (1 << 2),
  508. AST_PJSIP_LOGGER_VERBOSE = (1 << 3),
  509. AST_PJSIP_LOGGER_PCAP = (1 << 4),
  510. AST_PJSIP_LOGGER_ALL = (1 << 5),
  511. };
  512. static enum pjsip_logger_mask logger_cli_settings = AST_PJSIP_LOGGER_UNSET;
  513. static enum pjsip_logger_mask logger_config_settings = AST_PJSIP_LOGGER_UNSET;
  514. static char *pjsip_set_logger(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  515. {
  516. static const char * const method_choices[] = {
  517. "INVITE", "CANCEL", "ACK",
  518. "BYE", "REGISTER", "OPTIONS",
  519. "SUBSCRIBE", "NOTIFY", "PUBLISH",
  520. "INFO", "MESSAGE",
  521. NULL
  522. };
  523. const char *what;
  524. if (cmd == CLI_INIT) {
  525. e->command = "pjsip set logger {on|off|host|add|method|methodadd|verbose|pcap}";
  526. e->usage =
  527. "Usage: pjsip set logger {on|off|host <name/subnet>|add <name/subnet>|method <method>|methodadd <method>|verbose <on/off>|pcap <filename>}\n"
  528. " Enables or disabling logging of SIP packets\n"
  529. " read on ports bound to PJSIP transports either\n"
  530. " globally or enables logging for an individual\n"
  531. " host or particular SIP method(s).\n"
  532. " Messages can be filtered by SIP request methods\n"
  533. " INVITE, CANCEL, ACK, BYE, REGISTER, OPTIONS,\n"
  534. " SUBSCRIBE, NOTIFY, PUBLISH, INFO, and MESSAGE\n";
  535. return NULL;
  536. } else if (cmd == CLI_GENERATE) {
  537. if (a->argc && !strncasecmp(a->argv[e->args - 1], "method", 6)) {
  538. return ast_cli_complete(a->word, method_choices, a->n);
  539. }
  540. return NULL;
  541. }
  542. what = a->argv[e->args - 1]; /* Guaranteed to exist */
  543. if (a->argc == e->args) { /* on/off */
  544. if (!strcasecmp(what, "on")) {
  545. logger_cli_settings |= AST_PJSIP_LOGGER_ALL;
  546. return pjsip_enable_logger_all(a->fd);
  547. } else if (!strcasecmp(what, "off")) {
  548. logger_cli_settings = AST_PJSIP_LOGGER_NONE;
  549. return pjsip_disable_logger(a->fd);
  550. }
  551. } else if (a->argc == e->args + 1) {
  552. if (!strcasecmp(what, "host")) {
  553. logger_cli_settings |= AST_PJSIP_LOGGER_HOST;
  554. return pjsip_enable_logger_host(a->fd, a->argv[e->args], 0);
  555. } else if (!strcasecmp(what, "add")) {
  556. logger_cli_settings |= AST_PJSIP_LOGGER_HOST;
  557. return pjsip_enable_logger_host(a->fd, a->argv[e->args], 1);
  558. } else if (!strcasecmp(what, "method")) {
  559. logger_cli_settings |= AST_PJSIP_LOGGER_METHOD;
  560. return pjsip_enable_logger_method(a->fd, a->argv[e->args], 0);
  561. } else if (!strcasecmp(what, "methodadd")) {
  562. logger_cli_settings |= AST_PJSIP_LOGGER_METHOD;
  563. return pjsip_enable_logger_method(a->fd, a->argv[e->args], 1);
  564. } else if (!strcasecmp(what, "verbose")) {
  565. logger_cli_settings |= AST_PJSIP_LOGGER_VERBOSE;
  566. return pjsip_set_logger_verbose(a->fd, a->argv[e->args]);
  567. } else if (!strcasecmp(what, "pcap")) {
  568. logger_cli_settings |= AST_PJSIP_LOGGER_PCAP;
  569. return pjsip_set_logger_pcap(a->fd, a->argv[e->args]);
  570. }
  571. }
  572. return CLI_SHOWUSAGE;
  573. }
  574. static struct ast_cli_entry cli_pjsip[] = {
  575. AST_CLI_DEFINE(pjsip_set_logger, "Enable/Disable PJSIP Logger Output")
  576. };
  577. static void check_debug(void)
  578. {
  579. RAII_VAR(char *, debug, ast_sip_get_debug(), ast_free);
  580. /* Got directive to disable debug */
  581. if (ast_false(debug)) {
  582. /* If the logger was enabled via the CLI instead of through the config file,
  583. * then we shouldn't disable it on a reload.
  584. * Only disable logging if logging isn't enabled via the CLI. */
  585. if (logger_cli_settings == AST_PJSIP_LOGGER_NONE || logger_cli_settings == AST_PJSIP_LOGGER_UNSET) {
  586. /* Logger not enabled via CLI currently so good to go ahead and disable. */
  587. pjsip_disable_logger(-1);
  588. } else {
  589. ast_debug(3, "Leaving logger enabled since logging settings overridden using CLI\n");
  590. }
  591. logger_config_settings = AST_PJSIP_LOGGER_NONE;
  592. return;
  593. }
  594. /* Got directive to enable debug */
  595. if (ast_true(debug)) {
  596. if (logger_cli_settings != AST_PJSIP_LOGGER_UNSET) {
  597. /* Logging was modified using the CLI command,
  598. * and this overrides the default from the config. */
  599. ast_debug(3, "Leaving logger alone since logging has been overridden using CLI\n");
  600. return;
  601. }
  602. /* If logger already enabled via config, then nothing has changed. */
  603. if (!(logger_config_settings & AST_PJSIP_LOGGER_ALL)) {
  604. /* Logging was not previously enabled via config,
  605. * but has been enabled via CLI. */
  606. logger_config_settings |= AST_PJSIP_LOGGER_ALL;
  607. pjsip_enable_logger_all(-1);
  608. }
  609. return;
  610. }
  611. /* Enabling debug, only for specific host */
  612. logger_config_settings = AST_PJSIP_LOGGER_HOST;
  613. if (pjsip_enable_logger_host(-1, debug, 0) != CLI_SUCCESS) {
  614. ast_log(LOG_WARNING, "Could not resolve host %s for debug "
  615. "logging\n", debug);
  616. }
  617. }
  618. static void global_reloaded(const char *object_type)
  619. {
  620. check_debug();
  621. }
  622. static const struct ast_sorcery_observer global_observer = {
  623. .loaded = global_reloaded
  624. };
  625. static int load_module(void)
  626. {
  627. if (ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &global_observer)) {
  628. ast_log(LOG_WARNING, "Unable to add global observer\n");
  629. return AST_MODULE_LOAD_DECLINE;
  630. }
  631. default_logger = pjsip_logger_session_alloc();
  632. if (!default_logger) {
  633. ast_sorcery_observer_remove(
  634. ast_sip_get_sorcery(), "global", &global_observer);
  635. ast_log(LOG_WARNING, "Unable to create default logger\n");
  636. return AST_MODULE_LOAD_DECLINE;
  637. }
  638. check_debug();
  639. ast_sip_register_service(&logging_module);
  640. ast_cli_register_multiple(cli_pjsip, ARRAY_LEN(cli_pjsip));
  641. return AST_MODULE_LOAD_SUCCESS;
  642. }
  643. static int unload_module(void)
  644. {
  645. ast_cli_unregister_multiple(cli_pjsip, ARRAY_LEN(cli_pjsip));
  646. ast_sip_unregister_service(&logging_module);
  647. ast_sorcery_observer_remove(
  648. ast_sip_get_sorcery(), "global", &global_observer);
  649. ao2_cleanup(default_logger);
  650. default_logger = NULL;
  651. return 0;
  652. }
  653. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Packet Logger",
  654. .support_level = AST_MODULE_SUPPORT_CORE,
  655. .load = load_module,
  656. .unload = unload_module,
  657. .load_pri = AST_MODPRI_APP_DEPEND,
  658. .requires = "res_pjsip",
  659. );