conf.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2009 1&1 Internet AG
  5. *
  6. * This file is part of Kamailio, a free SIP server.
  7. *
  8. * Kamailio is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version
  12. *
  13. * Kamailio is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. */
  22. /*!
  23. * \file
  24. * \brief SIP-router utils ::
  25. * \ingroup utils
  26. * Module: \ref utils
  27. */
  28. #include "conf.h"
  29. #include "../../mem/mem.h"
  30. #include "../../mem/shm_mem.h"
  31. #include "../../sr_module.h"
  32. #include "../../proxy.h"
  33. #include <ctype.h>
  34. #include <errno.h>
  35. #include <limits.h>
  36. #include <string.h>
  37. #include <stdlib.h>
  38. #include <stdio.h>
  39. #define BUFSIZE 1000
  40. /*! \brief special filter indices */
  41. enum {
  42. sfidx_request = 0,
  43. sfidx_reply,
  44. sfilter_cnt
  45. };
  46. /*! special filter masks */
  47. static int sfilter_mask[sfilter_cnt] = { 1, 2 };
  48. /*! special filter names */
  49. static char *sfilter_str[sfilter_cnt] = {
  50. "REQUEST",
  51. "REPLY"
  52. };
  53. struct fwd_setting {
  54. int active;
  55. int sfilter;
  56. char *filter_methods;
  57. struct proxy_l* proxy;
  58. };
  59. static struct fwd_setting *fwd_settings = NULL;
  60. static int fwd_max_id = 0;
  61. /*!
  62. * \brief Removes white spaces and new lines from s
  63. * \todo check if we can use the functions from ut.h
  64. * Removes white spaces and new lines from s, the contents of s are modified.
  65. * \param s the string.
  66. */
  67. static void remove_spaces(char *s)
  68. {
  69. char *p, *dst;
  70. for (p = s, dst = s; *p != '\0'; ++p) {
  71. if (!isspace(*p)) *dst++ = *p;
  72. }
  73. *dst = '\0';
  74. }
  75. /*!
  76. * \brief Converts a string to integer.
  77. * \todo check if we can use the functions from ut.h
  78. * params:
  79. * s: The string to be converted to int.
  80. * returns:
  81. * >=0 on success
  82. * -1 otherwise
  83. */
  84. static int conf_str2int(char *s)
  85. {
  86. if (s == NULL) return -1;
  87. errno = 0;
  88. char *end = NULL;
  89. long int i = strtol(s, &end, 10);
  90. if ((errno != 0) || (i == LONG_MIN) || (i == LONG_MAX) || (end == s)) {
  91. LM_ERR("invalid string '%s'.\n", s);
  92. return -1;
  93. }
  94. return i;
  95. }
  96. /*!
  97. * \brief Converts string to integer and checks for validity.
  98. * \todo check if we can use the functions from ut.h
  99. * params:
  100. * id_str: ID as string to be converted to int.
  101. * returns:
  102. * >=0 on success
  103. * -1 otherwise
  104. */
  105. int conf_str2id(char *id_str)
  106. {
  107. int id = conf_str2int(id_str);
  108. if ((id<0) || (id > fwd_max_id)) {
  109. LM_ERR("id %d is out of range.\n", id);
  110. return -1;
  111. }
  112. return id;
  113. }
  114. /*!
  115. * \brief Updates switch configuration
  116. * \param id Update the configuration with this ID.
  117. * \param param_str can be either "off" or "on".
  118. * \return 0 on success, -1 otherwise
  119. */
  120. static int update_switch(int id, char* param_str)
  121. {
  122. if (param_str == NULL) {
  123. LM_ERR("param_str is NULL.\n");
  124. return -1;
  125. }
  126. if (strcmp(param_str, "on") == 0) {
  127. fwd_settings[id].active = 1;
  128. return 0;
  129. } else if (strcmp(param_str, "off") == 0) {
  130. fwd_settings[id].active = 0;
  131. return 0;
  132. }
  133. LM_ERR("invalid switch '%s'.\n", param_str);
  134. return -1;
  135. }
  136. /*!
  137. * \brief Updates filter configuration.
  138. * Updates filter configuration.
  139. * If filter_methods is not NULL, memory is freed.
  140. * If filter methods are found, memory for the string is allocated,
  141. * otherwise filter_methods is set to NULL.
  142. * \param id update the configuration with this ID.
  143. * \param flist a list of filter names.
  144. * \return 0 on success, -1 otherwise
  145. */
  146. static int update_filter(int id, char *flist)
  147. {
  148. if (flist == NULL) {
  149. LM_ERR("flist is NULL.\n");
  150. return -1;
  151. }
  152. /* reset special filter mask and filter methods*/
  153. fwd_settings[id].sfilter = 0;
  154. if (fwd_settings[id].filter_methods != NULL) {
  155. shm_free(fwd_settings[id].filter_methods);
  156. fwd_settings[id].filter_methods = NULL;
  157. }
  158. int i;
  159. for (i=0; i<sfilter_cnt; i++) {
  160. if (strstr(flist, sfilter_str[i]) != NULL) {
  161. /* special filter name is found in flist -> add to special filter mask */
  162. fwd_settings[id].sfilter |= sfilter_mask[i];
  163. }
  164. }
  165. char buf[BUFSIZE+1], tmp[BUFSIZE+1];
  166. buf[0] = '\0';
  167. char *set_p = flist;
  168. char *token = NULL;
  169. while ((token = strsep(&set_p, ":"))) { /* iterate through list of filters */
  170. int found = 0;
  171. /* is it a special filter? */
  172. for (i=0; i<sfilter_cnt; i++) {
  173. if (strcmp(token, sfilter_str[i]) == 0) {
  174. found = 1;
  175. break;
  176. }
  177. }
  178. if (found == 0) {
  179. /* no special filter! */
  180. if (buf[0]) {
  181. strcpy(tmp, buf);
  182. snprintf(buf, BUFSIZE, "%s:%s", tmp, token);
  183. buf[BUFSIZE]='\0';
  184. } else {
  185. snprintf(buf, BUFSIZE, "%s", token);
  186. buf[BUFSIZE]='\0';
  187. }
  188. }
  189. }
  190. int len = strlen(buf);
  191. if (len > 0) {
  192. char *flc = shm_malloc(len+1);
  193. if (flc == NULL) {
  194. SHM_MEM_ERROR;
  195. return -1;
  196. }
  197. memcpy(flc, buf, len+1);
  198. fwd_settings[id].filter_methods = flc;
  199. }
  200. return 0;
  201. }
  202. /*!
  203. * Updates proxy configuration
  204. * \param id update the configuration with this ID.
  205. * \param host_str the destination host.
  206. * \param port_str the port number as string.
  207. * \return 0 on success, -1 otherwise
  208. */
  209. static int update_proxy(int id, char *host_str, char *port_str)
  210. {
  211. if (host_str == NULL) {
  212. LM_ERR("host_str is NULL.\n");
  213. return -1;
  214. }
  215. if (port_str == NULL) {
  216. LM_ERR("port_str is NULL.\n");
  217. return -1;
  218. }
  219. int port = conf_str2int(port_str);
  220. if (port < 0) {
  221. LM_ERR("invalid port '%s'.\n", port_str);
  222. return -1;
  223. }
  224. /* make copy of host string since mk_proxy does not */
  225. str host;
  226. host.len = strlen(host_str);
  227. host.s = shm_malloc(host.len+1);
  228. if (host.s == NULL) {
  229. SHM_MEM_ERROR;
  230. return -1;
  231. }
  232. strcpy(host.s, host_str);
  233. /* make proxy in shared memory */
  234. struct proxy_l* proxy;
  235. proxy = mk_shm_proxy(&host, port, PROTO_UDP);
  236. if (proxy == NULL) {
  237. LM_ERR("cannot make proxy (host='%s', port=%d).\n", host_str, port);
  238. shm_free(host.s);
  239. return -1;
  240. }
  241. if (fwd_settings[id].proxy) {
  242. /* cleaning up old proxy */
  243. if (fwd_settings[id].proxy->name.s) {
  244. shm_free(fwd_settings[id].proxy->name.s);
  245. }
  246. free_shm_proxy(fwd_settings[id].proxy);
  247. shm_free(fwd_settings[id].proxy);
  248. }
  249. fwd_settings[id].proxy = proxy; /* new proxy is now acitvated */
  250. return 0;
  251. }
  252. /*!
  253. * \brief Parses configuration string for the switch
  254. * Parses a configuration string for switch settings and updates
  255. * the configuration structure.
  256. * \param settings the configuration string in the following form:
  257. \verbatim
  258. * <id>=<switch>[,<id>=<switch>]...
  259. \endverbatim
  260. * \return 1 on success, -1 otherwise
  261. */
  262. int conf_parse_switch(char *settings)
  263. {
  264. /* make a copy since we are modifying it */
  265. int len = strlen(settings);
  266. if (len==0) return 1;
  267. char *strc = (char *)pkg_malloc(len+1);
  268. if (strc == NULL) {
  269. PKG_MEM_ERROR;
  270. return -1;
  271. }
  272. memcpy(strc, settings, len+1);
  273. remove_spaces(strc);
  274. char *set_p = strc;
  275. char *token = NULL;
  276. while ((token = strsep(&set_p, ","))) { /* iterate through list of settings */
  277. char *id_str = strsep(&token, "=");
  278. int id = conf_str2id(id_str);
  279. if (id < 0) {
  280. LM_ERR("cannot parse id '%s'.\n", id_str);
  281. pkg_free(strc);
  282. return -1;
  283. }
  284. /* got all data for one setting -> update configuration now */
  285. if (update_switch(id, token) < 0) {
  286. LM_ERR("cannot update switch.\n");
  287. pkg_free(strc);
  288. return -1;
  289. }
  290. }
  291. pkg_free(strc);
  292. return 1;
  293. }
  294. /*!
  295. * \brief Output configuration in FIFO format
  296. * \param rpl_tree FIFO root
  297. * \return 0 on success, -1 on failure
  298. */
  299. int conf_show(struct mi_root* rpl_tree)
  300. {
  301. int id, sfilter;
  302. struct mi_node * node = NULL;
  303. node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "id switch %30s proxy\n", "filter");
  304. if(node == NULL)
  305. goto error;
  306. for (id=0; id<=fwd_max_id; id++) {
  307. char buf[BUFSIZE+1];
  308. char tmp[BUFSIZE+1];
  309. buf[0]='\0';
  310. for (sfilter=0; sfilter<sfilter_cnt; sfilter++) {
  311. if (fwd_settings[id].sfilter&sfilter_mask[sfilter]) {
  312. if (buf[0]) {
  313. strcpy(tmp, buf);
  314. snprintf(buf, BUFSIZE, "%s:%s", tmp, sfilter_str[sfilter]);
  315. buf[BUFSIZE]='\0';
  316. } else {
  317. snprintf(buf, BUFSIZE, "%s", sfilter_str[sfilter]);
  318. buf[BUFSIZE]='\0';
  319. }
  320. }
  321. }
  322. if (fwd_settings[id].filter_methods) {
  323. if (buf[0]) {
  324. strcpy(tmp, buf);
  325. snprintf(buf, BUFSIZE, "%s:%s", tmp, fwd_settings[id].filter_methods);
  326. buf[BUFSIZE]='\0';
  327. } else {
  328. snprintf(buf, BUFSIZE, "%s", fwd_settings[id].filter_methods);
  329. buf[BUFSIZE]='\0';
  330. }
  331. }
  332. node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%2d %s %33s %s:%d\n", id,
  333. fwd_settings[id].active ? "on " : "off", buf,
  334. fwd_settings[id].proxy ? fwd_settings[id].proxy->name.s : "",
  335. fwd_settings[id].proxy ? fwd_settings[id].proxy->port : 0);
  336. if(node == NULL)
  337. goto error;
  338. }
  339. return 0;
  340. error:
  341. return -1;
  342. }
  343. /*!
  344. * \brief Parses a configuration string for the filter
  345. * Parses a configuration string for switch settings and
  346. * updates the configuration structure.
  347. * \param settings The configuration string in the following form:
  348. \verbatim
  349. * <id>=<filter>[:<filter>]...[,<id>=<filter>[:<filter>]...]...
  350. \endverbatim
  351. * \return 1 on success, -1 otherwise
  352. */
  353. int conf_parse_filter(char *settings)
  354. {
  355. /* make a copy since we are modifying it */
  356. int len = strlen(settings);
  357. if (len==0) return 1;
  358. char *strc = (char *)pkg_malloc(len+1);
  359. if (strc == NULL) {
  360. PKG_MEM_ERROR;
  361. return -1;
  362. }
  363. memcpy(strc, settings, len+1);
  364. remove_spaces(strc);
  365. char *set_p = strc;
  366. char *token = NULL;
  367. while ((token = strsep(&set_p, ","))) { /* iterate through list of settings */
  368. char *id_str = strsep(&token, "=");
  369. int id = conf_str2id(id_str);
  370. if (id<0) {
  371. LM_ERR("cannot parse id '%s'.\n", id_str);
  372. pkg_free(strc);
  373. return -1;
  374. }
  375. if (update_filter(id, token) < 0) {
  376. LM_ERR("cannot extract filters.\n");
  377. pkg_free(strc);
  378. return -1;
  379. }
  380. }
  381. pkg_free(strc);
  382. return 1;
  383. }
  384. /*!
  385. * \brief Parses a configuration string for proxy settings
  386. * Parses a configuration string for proxy settings and
  387. * updates the configuration structure.
  388. * \param settings: The configuration string in the following form:
  389. \verbatim
  390. * <id>=<host>:<port>[,<id>=<host>:<port>]...
  391. \endverbatim
  392. * \return: 1 on success, -1 otherwise
  393. */
  394. int conf_parse_proxy(char *settings)
  395. {
  396. /* make a copy since we are modifying it */
  397. int len = strlen(settings);
  398. if (len==0) return 1;
  399. char *strc = (char *)pkg_malloc(len+1);
  400. if (strc == NULL) {
  401. PKG_MEM_ERROR;
  402. return -1;
  403. }
  404. memcpy(strc, settings, len+1);
  405. remove_spaces(strc);
  406. char *set_p = strc;
  407. char *token = NULL;
  408. while ((token = strsep(&set_p, ","))) { /* iterate through list of settings */
  409. char *id_str = strsep(&token, "=");
  410. int id = conf_str2id(id_str);
  411. if (id<0) {
  412. LM_ERR("cannot parse id '%s'.\n", id_str);
  413. pkg_free(strc);
  414. return -1;
  415. }
  416. char *host = strsep(&token, ":");
  417. /* got all data for one setting -> update configuration now */
  418. if (update_proxy(id, host, token) < 0) {
  419. LM_ERR("cannot update proxy.\n");
  420. pkg_free(strc);
  421. return -1;
  422. }
  423. }
  424. pkg_free(strc);
  425. return 1;
  426. }
  427. /*!
  428. * \brief Checks if method string is in filter_methods
  429. * \param id use configuration with this ID when checking
  430. * \param method method string to be searched for
  431. * \param method_len length of method string
  432. * \return 1 if method is found in filter_methods, 0 otherwise
  433. */
  434. static int filter_methods_contains_request(int id, char *method, int method_len)
  435. {
  436. char *p = fwd_settings[id].filter_methods;
  437. while (p != NULL) {
  438. if (strncmp(p, method, method_len) == 0) {
  439. return 1;
  440. }
  441. p = strchr(p, ':');
  442. if (p != NULL) p++;
  443. }
  444. return 0;
  445. }
  446. /*!
  447. * \brief Checks forwarding is needed
  448. * \param msg the SIP message to be forwarded
  449. * \param id use configuration with this ID when checking
  450. * \return pointer to proxy structure of destination if forwarding is needed, NULL otherwise
  451. */
  452. struct proxy_l *conf_needs_forward(struct sip_msg *msg, int id)
  453. {
  454. if ((msg == NULL) || (fwd_settings[id].active == 0)) {
  455. return NULL;
  456. }
  457. if (msg->first_line.type == SIP_REPLY) {
  458. if (fwd_settings[id].sfilter&sfilter_mask[sfidx_reply]) {
  459. return fwd_settings[id].proxy;
  460. }
  461. }
  462. if (msg->first_line.type == SIP_REQUEST) {
  463. if (fwd_settings[id].sfilter&sfilter_mask[sfidx_request]) {
  464. return fwd_settings[id].proxy;
  465. }
  466. if (filter_methods_contains_request(id, msg->first_line.u.request.method.s, msg->first_line.u.request.method.len) > 0) {
  467. return fwd_settings[id].proxy;
  468. }
  469. }
  470. return NULL;
  471. }
  472. /*!
  473. * \brief Initialize configuration
  474. * \param max_id number of configuration statements
  475. * \return 0 on success, -1 on failure
  476. */
  477. int conf_init(int max_id)
  478. {
  479. /* allocate and initialize memory for configuration */
  480. fwd_settings = shm_malloc(sizeof(struct fwd_setting)*(max_id+1));
  481. if (fwd_settings == NULL) {
  482. SHM_MEM_ERROR;
  483. return -1;
  484. }
  485. memset(fwd_settings, 0, sizeof(struct fwd_setting)*(max_id+1));
  486. fwd_max_id = max_id;
  487. return 0;
  488. }
  489. /*!
  490. * \brief Destroy configuration
  491. */
  492. void conf_destroy(void)
  493. {
  494. int id;
  495. if (fwd_settings) {
  496. for (id=0; id<=fwd_max_id; id++) {
  497. fwd_settings[id].active = 0;
  498. if (fwd_settings[id].proxy) {
  499. if (fwd_settings[id].proxy->name.s) {
  500. shm_free(fwd_settings[id].proxy->name.s);
  501. }
  502. free_shm_proxy(fwd_settings[id].proxy);
  503. shm_free(fwd_settings[id].proxy);
  504. }
  505. }
  506. shm_free(fwd_settings);
  507. }
  508. }