res_pjsip_logger.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  26. #include <pjsip.h>
  27. #include "asterisk/res_pjsip.h"
  28. #include "asterisk/module.h"
  29. #include "asterisk/logger.h"
  30. #include "asterisk/cli.h"
  31. #include "asterisk/netsock2.h"
  32. enum pjsip_logging_mode {
  33. LOGGING_MODE_DISABLED, /* No logging is enabled */
  34. LOGGING_MODE_ENABLED, /* Logging is enabled */
  35. };
  36. static enum pjsip_logging_mode logging_mode;
  37. static struct ast_sockaddr log_addr;
  38. /*! \brief Return the first entry from ast_sockaddr_resolve filtered by address family
  39. *
  40. * \warning Using this function probably means you have a faulty design.
  41. * \note This function was taken from the function of the same name in chan_sip.c
  42. */
  43. static int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr,
  44. const char* name, int flag, int family)
  45. {
  46. struct ast_sockaddr *addrs;
  47. int addrs_cnt;
  48. addrs_cnt = ast_sockaddr_resolve(&addrs, name, flag, family);
  49. if (addrs_cnt <= 0) {
  50. return 1;
  51. }
  52. if (addrs_cnt > 1) {
  53. ast_debug(1, "Multiple addresses, using the first one only\n");
  54. }
  55. ast_sockaddr_copy(addr, &addrs[0]);
  56. ast_free(addrs);
  57. return 0;
  58. }
  59. /*! \brief See if we pass debug IP filter */
  60. static inline int pjsip_log_test_addr(const char *address, int port)
  61. {
  62. struct ast_sockaddr test_addr;
  63. if (logging_mode == LOGGING_MODE_DISABLED) {
  64. return 0;
  65. }
  66. /* A null logging address means we'll debug any address */
  67. if (ast_sockaddr_isnull(&log_addr)) {
  68. return 1;
  69. }
  70. /* A null address was passed in. Just reject it. */
  71. if (ast_strlen_zero(address)) {
  72. return 0;
  73. }
  74. ast_sockaddr_parse(&test_addr, address, PARSE_PORT_IGNORE);
  75. ast_sockaddr_set_port(&test_addr, port);
  76. /* If no port was specified for a debug address, just compare the
  77. * addresses, otherwise compare the address and port
  78. */
  79. if (ast_sockaddr_port(&log_addr)) {
  80. return !ast_sockaddr_cmp(&log_addr, &test_addr);
  81. } else {
  82. return !ast_sockaddr_cmp_addr(&log_addr, &test_addr);
  83. }
  84. }
  85. static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
  86. {
  87. if (!pjsip_log_test_addr(tdata->tp_info.dst_name, tdata->tp_info.dst_port)) {
  88. return PJ_SUCCESS;
  89. }
  90. ast_verbose("<--- Transmitting SIP %s (%d bytes) to %s:%s:%d --->\n%.*s\n",
  91. tdata->msg->type == PJSIP_REQUEST_MSG ? "request" : "response",
  92. (int) (tdata->buf.cur - tdata->buf.start),
  93. tdata->tp_info.transport->type_name,
  94. tdata->tp_info.dst_name,
  95. tdata->tp_info.dst_port,
  96. (int) (tdata->buf.end - tdata->buf.start), tdata->buf.start);
  97. return PJ_SUCCESS;
  98. }
  99. static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
  100. {
  101. if (!pjsip_log_test_addr(rdata->pkt_info.src_name, rdata->pkt_info.src_port)) {
  102. return PJ_FALSE;
  103. }
  104. if (!rdata->msg_info.msg) {
  105. return PJ_FALSE;
  106. }
  107. ast_verbose("<--- Received SIP %s (%d bytes) from %s:%s:%d --->\n%s\n",
  108. rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ? "request" : "response",
  109. rdata->msg_info.len,
  110. rdata->tp_info.transport->type_name,
  111. rdata->pkt_info.src_name,
  112. rdata->pkt_info.src_port,
  113. rdata->pkt_info.packet);
  114. return PJ_FALSE;
  115. }
  116. static pjsip_module logging_module = {
  117. .name = { "Logging Module", 14 },
  118. .priority = 0,
  119. .on_rx_request = logging_on_rx_msg,
  120. .on_rx_response = logging_on_rx_msg,
  121. .on_tx_request = logging_on_tx_msg,
  122. .on_tx_response = logging_on_tx_msg,
  123. };
  124. static char *pjsip_enable_logger_host(int fd, const char *arg)
  125. {
  126. if (ast_sockaddr_resolve_first_af(&log_addr, arg, 0, AST_AF_UNSPEC)) {
  127. return CLI_SHOWUSAGE;
  128. }
  129. ast_cli(fd, "PJSIP Logging Enabled for host: %s\n", ast_sockaddr_stringify_addr(&log_addr));
  130. logging_mode = LOGGING_MODE_ENABLED;
  131. return CLI_SUCCESS;
  132. }
  133. static char *pjsip_set_logger(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  134. {
  135. const char *what;
  136. if (cmd == CLI_INIT) {
  137. e->command = "pjsip set logger {on|off|host}";
  138. e->usage =
  139. "Usage: pjsip set logger {on|off|host <name>}\n"
  140. " Enables or disabling logging of SIP packets\n"
  141. " read on ports bound to PJSIP transports either\n"
  142. " globally or enables logging for an individual\n"
  143. " host.\n";
  144. return NULL;
  145. } else if (cmd == CLI_GENERATE) {
  146. return NULL;
  147. }
  148. what = a->argv[e->args - 1]; /* Guaranteed to exist */
  149. if (a->argc == e->args) { /* on/off */
  150. if (!strcasecmp(what, "on")) {
  151. logging_mode = LOGGING_MODE_ENABLED;
  152. ast_cli(a->fd, "PJSIP Logging enabled\n");
  153. ast_sockaddr_setnull(&log_addr);
  154. return CLI_SUCCESS;
  155. } else if (!strcasecmp(what, "off")) {
  156. logging_mode = LOGGING_MODE_DISABLED;
  157. ast_cli(a->fd, "PJSIP Logging disabled\n");
  158. return CLI_SUCCESS;
  159. }
  160. } else if (a->argc == e->args + 1) {
  161. if (!strcasecmp(what, "host")) {
  162. return pjsip_enable_logger_host(a->fd, a->argv[e->args]);
  163. }
  164. }
  165. return CLI_SHOWUSAGE;
  166. }
  167. static struct ast_cli_entry cli_pjsip[] = {
  168. AST_CLI_DEFINE(pjsip_set_logger, "Enable/Disable PJSIP Logger Output")
  169. };
  170. static void check_debug(void)
  171. {
  172. RAII_VAR(char *, debug, ast_sip_get_debug(), ast_free);
  173. if (ast_false(debug)) {
  174. logging_mode = LOGGING_MODE_DISABLED;
  175. return;
  176. }
  177. logging_mode = LOGGING_MODE_ENABLED;
  178. if (ast_true(debug)) {
  179. ast_sockaddr_setnull(&log_addr);
  180. return;
  181. }
  182. /* assume host */
  183. if (ast_sockaddr_resolve_first_af(&log_addr, debug, 0, AST_AF_UNSPEC)) {
  184. ast_log(LOG_WARNING, "Could not resolve host %s for debug "
  185. "logging\n", debug);
  186. }
  187. }
  188. static void global_reloaded(const char *object_type)
  189. {
  190. check_debug();
  191. }
  192. static const struct ast_sorcery_observer global_observer = {
  193. .loaded = global_reloaded
  194. };
  195. static int load_module(void)
  196. {
  197. CHECK_PJSIP_MODULE_LOADED();
  198. if (ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &global_observer)) {
  199. ast_log(LOG_WARNING, "Unable to add global observer\n");
  200. return AST_MODULE_LOAD_DECLINE;
  201. }
  202. check_debug();
  203. ast_sip_register_service(&logging_module);
  204. ast_cli_register_multiple(cli_pjsip, ARRAY_LEN(cli_pjsip));
  205. return AST_MODULE_LOAD_SUCCESS;
  206. }
  207. static int unload_module(void)
  208. {
  209. ast_cli_unregister_multiple(cli_pjsip, ARRAY_LEN(cli_pjsip));
  210. ast_sip_unregister_service(&logging_module);
  211. ast_sorcery_observer_remove(
  212. ast_sip_get_sorcery(), "global", &global_observer);
  213. return 0;
  214. }
  215. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Packet Logger",
  216. .support_level = AST_MODULE_SUPPORT_CORE,
  217. .load = load_module,
  218. .unload = unload_module,
  219. .load_pri = AST_MODPRI_APP_DEPEND,
  220. );