You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cfg_utils.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <ctype.h>
  4. #include <errno.h>
  5. #include <stdarg.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/un.h>
  10. #include <netinet/in.h>
  11. #include <arpa/inet.h>
  12. #include <syslog.h>
  13. #include <netdb.h>
  14. #include <math.h>
  15. #include <netinet/in.h>
  16. #include <arpa/inet.h>
  17. #include "config.h"
  18. #include "cfg_file.h"
  19. #include "main.h"
  20. #ifndef HAVE_OWN_QUEUE_H
  21. #include <sys/queue.h>
  22. #else
  23. #include "queue.h"
  24. #endif
  25. extern int yylineno;
  26. extern char *yytext;
  27. int
  28. add_memcached_server (struct config_file *cf, char *str)
  29. {
  30. char *cur_tok, *err_str;
  31. struct memcached_server *mc;
  32. struct hostent *hent;
  33. uint16_t port;
  34. if (str == NULL) return 0;
  35. cur_tok = strsep (&str, ":");
  36. if (cur_tok == NULL || *cur_tok == '\0') return 0;
  37. if(cf->memcached_servers_num == MAX_MEMCACHED_SERVERS) {
  38. yywarn ("yyparse: maximum number of memcached servers is reached %d", MAX_MEMCACHED_SERVERS);
  39. }
  40. mc = &cf->memcached_servers[cf->memcached_servers_num];
  41. if (mc == NULL) return 0;
  42. /* cur_tok - server name, str - server port */
  43. if (str == NULL) {
  44. port = DEFAULT_MEMCACHED_PORT;
  45. }
  46. else {
  47. port = (uint16_t)strtoul (str, &err_str, 10);
  48. if (*err_str != '\0') {
  49. return 0;
  50. }
  51. }
  52. if (!inet_aton (cur_tok, &mc->addr)) {
  53. /* Try to call gethostbyname */
  54. hent = gethostbyname (cur_tok);
  55. if (hent == NULL) {
  56. return 0;
  57. }
  58. else {
  59. memcpy((char *)&mc->addr, hent->h_addr, sizeof(struct in_addr));
  60. }
  61. }
  62. mc->port = port;
  63. cf->memcached_servers_num++;
  64. return 1;
  65. }
  66. int
  67. parse_bind_line (struct config_file *cf, char *str, char is_control)
  68. {
  69. char *cur_tok, *err_str;
  70. struct hostent *hent;
  71. size_t s;
  72. if (str == NULL) return 0;
  73. cur_tok = strsep (&str, ":");
  74. if (cur_tok[0] == '/' || cur_tok[0] == '.') {
  75. if (is_control) {
  76. cf->control_host = memory_pool_strdup (cf->cfg_pool, cur_tok);
  77. cf->control_family = AF_UNIX;
  78. }
  79. else {
  80. cf->bind_host = memory_pool_strdup (cf->cfg_pool, cur_tok);
  81. cf->bind_family = AF_UNIX;
  82. }
  83. return 1;
  84. } else {
  85. if (str == '\0') {
  86. if (is_control) {
  87. cf->control_port = DEFAULT_CONTROL_PORT;
  88. }
  89. else {
  90. cf->bind_port = DEFAULT_BIND_PORT;
  91. }
  92. }
  93. else {
  94. if (is_control) {
  95. cf->control_port = (uint16_t)strtoul (str, &err_str, 10);
  96. }
  97. else {
  98. cf->bind_port = (uint16_t)strtoul (str, &err_str, 10);
  99. }
  100. if (*err_str != '\0') {
  101. return 0;
  102. }
  103. }
  104. if (is_control) {
  105. if (!inet_aton (cur_tok, &cf->control_addr)) {
  106. /* Try to call gethostbyname */
  107. hent = gethostbyname (cur_tok);
  108. if (hent == NULL) {
  109. return 0;
  110. }
  111. else {
  112. cf->bind_host = memory_pool_strdup (cf->cfg_pool, cur_tok);
  113. memcpy((char *)&cf->control_addr, hent->h_addr, sizeof(struct in_addr));
  114. s = strlen (cur_tok) + 1;
  115. }
  116. }
  117. cf->control_family = AF_INET;
  118. }
  119. else {
  120. if (!inet_aton (cur_tok, &cf->bind_addr)) {
  121. /* Try to call gethostbyname */
  122. hent = gethostbyname (cur_tok);
  123. if (hent == NULL) {
  124. return 0;
  125. }
  126. else {
  127. cf->bind_host = memory_pool_strdup (cf->cfg_pool, cur_tok);
  128. memcpy((char *)&cf->bind_addr, hent->h_addr, sizeof(struct in_addr));
  129. s = strlen (cur_tok) + 1;
  130. }
  131. }
  132. cf->bind_family = AF_INET;
  133. }
  134. return 1;
  135. }
  136. return 0;
  137. }
  138. void
  139. init_defaults (struct config_file *cfg)
  140. {
  141. cfg->memcached_error_time = DEFAULT_UPSTREAM_ERROR_TIME;
  142. cfg->memcached_dead_time = DEFAULT_UPSTREAM_DEAD_TIME;
  143. cfg->memcached_maxerrors = DEFAULT_UPSTREAM_MAXERRORS;
  144. cfg->memcached_protocol = TCP_TEXT;
  145. cfg->workers_number = DEFAULT_WORKERS_NUM;
  146. cfg->modules_opts = g_hash_table_new (g_str_hash, g_str_equal);
  147. cfg->variables = g_hash_table_new (g_str_hash, g_str_equal);
  148. cfg->metrics = g_hash_table_new (g_str_hash, g_str_equal);
  149. cfg->factors = g_hash_table_new (g_str_hash, g_str_equal);
  150. cfg->c_modules = g_hash_table_new (g_str_hash, g_str_equal);
  151. cfg->composite_symbols = g_hash_table_new (g_str_hash, g_str_equal);
  152. LIST_INIT (&cfg->perl_modules);
  153. }
  154. void
  155. free_config (struct config_file *cfg)
  156. {
  157. g_hash_table_remove_all (cfg->modules_opts);
  158. g_hash_table_unref (cfg->modules_opts);
  159. g_hash_table_remove_all (cfg->variables);
  160. g_hash_table_unref (cfg->variables);
  161. g_hash_table_remove_all (cfg->metrics);
  162. g_hash_table_unref (cfg->metrics);
  163. g_hash_table_remove_all (cfg->factors);
  164. g_hash_table_unref (cfg->factors);
  165. g_hash_table_remove_all (cfg->c_modules);
  166. g_hash_table_unref (cfg->c_modules);
  167. g_hash_table_remove_all (cfg->composite_symbols);
  168. g_hash_table_unref (cfg->composite_symbols);
  169. memory_pool_delete (cfg->cfg_pool);
  170. }
  171. char*
  172. get_module_opt (struct config_file *cfg, char *module_name, char *opt_name)
  173. {
  174. LIST_HEAD (moduleoptq, module_opt) *cur_module_opt = NULL;
  175. struct module_opt *cur;
  176. cur_module_opt = g_hash_table_lookup (cfg->modules_opts, module_name);
  177. if (cur_module_opt == NULL) {
  178. return NULL;
  179. }
  180. LIST_FOREACH (cur, cur_module_opt, next) {
  181. if (strcmp (cur->param, opt_name) == 0) {
  182. return cur->value;
  183. }
  184. }
  185. return NULL;
  186. }
  187. size_t
  188. parse_limit (const char *limit)
  189. {
  190. size_t result = 0;
  191. char *err_str;
  192. if (!limit || *limit == '\0') return 0;
  193. result = strtoul (limit, &err_str, 10);
  194. if (*err_str != '\0') {
  195. /* Megabytes */
  196. if (*err_str == 'm' || *err_str == 'M') {
  197. result *= 1048576L;
  198. }
  199. /* Kilobytes */
  200. else if (*err_str == 'k' || *err_str == 'K') {
  201. result *= 1024;
  202. }
  203. /* Gigabytes */
  204. else if (*err_str == 'g' || *err_str == 'G') {
  205. result *= 1073741824L;
  206. }
  207. }
  208. return result;
  209. }
  210. unsigned int
  211. parse_seconds (const char *t)
  212. {
  213. unsigned int result = 0;
  214. char *err_str;
  215. if (!t || *t == '\0') return 0;
  216. result = strtoul (t, &err_str, 10);
  217. if (*err_str != '\0') {
  218. /* Seconds */
  219. if (*err_str == 's' || *err_str == 'S') {
  220. result *= 1000;
  221. }
  222. }
  223. return result;
  224. }
  225. char
  226. parse_flag (const char *str)
  227. {
  228. if (!str || !*str) return -1;
  229. if ((*str == 'Y' || *str == 'y') && *(str + 1) == '\0') {
  230. return 1;
  231. }
  232. if ((*str == 'Y' || *str == 'y') &&
  233. (*(str + 1) == 'E' || *(str + 1) == 'e') &&
  234. (*(str + 2) == 'S' || *(str + 2) == 's') &&
  235. *(str + 3) == '\0') {
  236. return 1;
  237. }
  238. if ((*str == 'N' || *str == 'n') && *(str + 1) == '\0') {
  239. return 0;
  240. }
  241. if ((*str == 'N' || *str == 'n') &&
  242. (*(str + 1) == 'O' || *(str + 1) == 'o') &&
  243. *(str + 2) == '\0') {
  244. return 0;
  245. }
  246. return -1;
  247. }
  248. /*
  249. * Try to substitute all variables in given string
  250. * Return: newly allocated string with substituted variables (original string may be freed if variables are found)
  251. */
  252. char *
  253. substitute_variable (struct config_file *cfg, char *str, u_char recursive)
  254. {
  255. char *var, *new, *v_begin, *v_end;
  256. size_t len;
  257. while ((v_begin = strstr (str, "${")) != NULL) {
  258. len = strlen (str);
  259. *v_begin = '\0';
  260. v_begin += 2;
  261. if ((v_end = strstr (v_begin, "}")) == NULL) {
  262. /* Not a variable, skip */
  263. continue;
  264. }
  265. *v_end = '\0';
  266. var = g_hash_table_lookup (cfg->variables, v_begin);
  267. if (var == NULL) {
  268. yywarn ("substitute_variable: variable %s is not defined", v_begin);
  269. /* Substitute unknown variables with empty string */
  270. var = "";
  271. }
  272. else if (recursive) {
  273. var = substitute_variable (cfg, var, recursive);
  274. }
  275. /* Allocate new string */
  276. new = memory_pool_alloc (cfg->cfg_pool, len - strlen (v_begin) + strlen (var) + 1);
  277. snprintf (new, len - strlen (v_begin) + strlen (var) + 1, "%s%s%s",
  278. str, var, v_end + 1);
  279. str = new;
  280. }
  281. return str;
  282. }
  283. static void
  284. substitute_module_variables (gpointer key, gpointer value, gpointer data)
  285. {
  286. struct config_file *cfg = (struct config_file *)data;
  287. LIST_HEAD (moduleoptq, module_opt) *cur_module_opt = (struct moduleoptq *)value;
  288. struct module_opt *cur, *tmp;
  289. LIST_FOREACH_SAFE (cur, cur_module_opt, next, tmp) {
  290. if (cur->value) {
  291. cur->value = substitute_variable (cfg, cur->value, 0);
  292. }
  293. }
  294. }
  295. static void
  296. substitute_all_variables (gpointer key, gpointer value, gpointer data)
  297. {
  298. struct config_file *cfg = (struct config_file *)data;
  299. char *var;
  300. var = value;
  301. /* Do recursive substitution */
  302. var = substitute_variable (cfg, var, 1);
  303. }
  304. static void
  305. parse_filters_str (struct config_file *cfg, const char *str, enum script_type type)
  306. {
  307. gchar **strvec, **p;
  308. struct filter *cur;
  309. int i;
  310. if (str == NULL) {
  311. return;
  312. }
  313. strvec = g_strsplit (str, ",", 0);
  314. if (strvec == NULL) {
  315. return;
  316. }
  317. p = strvec;
  318. while (*p++) {
  319. cur = NULL;
  320. /* Search modules from known C modules */
  321. for (i = 0; i < MODULES_NUM; i++) {
  322. if (strcasecmp (modules[i].name, *p) == 0) {
  323. cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct filter));
  324. cur->type = C_FILTER;
  325. switch (type) {
  326. case SCRIPT_HEADER:
  327. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  328. LIST_INSERT_HEAD (&cfg->header_filters, cur, next);
  329. break;
  330. case SCRIPT_MIME:
  331. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  332. LIST_INSERT_HEAD (&cfg->mime_filters, cur, next);
  333. break;
  334. case SCRIPT_MESSAGE:
  335. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  336. LIST_INSERT_HEAD (&cfg->message_filters, cur, next);
  337. break;
  338. case SCRIPT_URL:
  339. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  340. LIST_INSERT_HEAD (&cfg->url_filters, cur, next);
  341. break;
  342. }
  343. break;
  344. }
  345. }
  346. if (cur != NULL) {
  347. /* Go to next iteration */
  348. continue;
  349. }
  350. cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct filter));
  351. cur->type = PERL_FILTER;
  352. switch (type) {
  353. case SCRIPT_HEADER:
  354. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  355. LIST_INSERT_HEAD (&cfg->header_filters, cur, next);
  356. break;
  357. case SCRIPT_MIME:
  358. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  359. LIST_INSERT_HEAD (&cfg->mime_filters, cur, next);
  360. break;
  361. case SCRIPT_MESSAGE:
  362. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  363. LIST_INSERT_HEAD (&cfg->message_filters, cur, next);
  364. break;
  365. case SCRIPT_URL:
  366. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  367. LIST_INSERT_HEAD (&cfg->url_filters, cur, next);
  368. break;
  369. }
  370. }
  371. g_strfreev (strvec);
  372. }
  373. /*
  374. * Substitute all variables in strings
  375. */
  376. void
  377. post_load_config (struct config_file *cfg)
  378. {
  379. g_hash_table_foreach (cfg->variables, substitute_all_variables, cfg);
  380. g_hash_table_foreach (cfg->modules_opts, substitute_module_variables, cfg);
  381. parse_filters_str (cfg, cfg->header_filters_str, SCRIPT_HEADER);
  382. parse_filters_str (cfg, cfg->mime_filters_str, SCRIPT_MIME);
  383. parse_filters_str (cfg, cfg->message_filters_str, SCRIPT_MESSAGE);
  384. parse_filters_str (cfg, cfg->url_filters_str, SCRIPT_URL);
  385. }
  386. /*
  387. * Rspamd regexp utility functions
  388. */
  389. struct rspamd_regexp*
  390. parse_regexp (memory_pool_t *pool, char *line)
  391. {
  392. char *begin, *end, *p;
  393. struct rspamd_regexp *result;
  394. int regexp_flags = 0;
  395. enum rspamd_regexp_type type = REGEXP_NONE;
  396. GError *err = NULL;
  397. result = memory_pool_alloc0 (pool, sizeof (struct rspamd_regexp));
  398. /* First try to find header name */
  399. begin = strchr (line, '=');
  400. if (begin != NULL) {
  401. *begin = '\0';
  402. result->header = memory_pool_strdup (pool, line);
  403. result->type = REGEXP_HEADER;
  404. *begin = '=';
  405. line = begin;
  406. }
  407. /* Find begin of regexp */
  408. while (*line != '/') {
  409. line ++;
  410. }
  411. if (*line != '\0') {
  412. begin = line + 1;
  413. }
  414. else if (result->header == NULL) {
  415. /* Assume that line without // is just a header name */
  416. result->header = memory_pool_strdup (pool, line);
  417. result->type = REGEXP_HEADER;
  418. return result;
  419. }
  420. else {
  421. /* We got header name earlier but have not found // expression, so it is invalid regexp */
  422. return NULL;
  423. }
  424. /* Find end */
  425. end = begin;
  426. while (*end && (*end != '/' || *(end - 1) == '\\')) {
  427. end ++;
  428. }
  429. if (end == begin || *end != '/') {
  430. return NULL;
  431. }
  432. /* Parse flags */
  433. p = end + 1;
  434. while (p != NULL) {
  435. switch (*p) {
  436. case 'i':
  437. regexp_flags |= G_REGEX_CASELESS;
  438. p ++;
  439. break;
  440. case 'm':
  441. regexp_flags |= G_REGEX_MULTILINE;
  442. p ++;
  443. break;
  444. case 's':
  445. regexp_flags |= G_REGEX_DOTALL;
  446. p ++;
  447. break;
  448. case 'x':
  449. regexp_flags |= G_REGEX_EXTENDED;
  450. p ++;
  451. break;
  452. case 'u':
  453. regexp_flags |= G_REGEX_UNGREEDY;
  454. p ++;
  455. break;
  456. case 'o':
  457. regexp_flags |= G_REGEX_OPTIMIZE;
  458. p ++;
  459. break;
  460. /* Type flags */
  461. case 'H':
  462. if (type != REGEXP_NONE) {
  463. type = REGEXP_HEADER;
  464. }
  465. p ++;
  466. break;
  467. case 'M':
  468. if (type != REGEXP_NONE) {
  469. type = REGEXP_MESSAGE;
  470. }
  471. p ++;
  472. break;
  473. case 'P':
  474. if (type != REGEXP_NONE) {
  475. type = REGEXP_MIME;
  476. }
  477. p ++;
  478. break;
  479. case 'U':
  480. if (type != REGEXP_NONE) {
  481. type = REGEXP_URL;
  482. }
  483. p ++;
  484. break;
  485. /* Stop flags parsing */
  486. default:
  487. p = NULL;
  488. break;
  489. }
  490. }
  491. result = memory_pool_alloc (pool, sizeof (struct rspamd_regexp));
  492. result->type = type;
  493. *end = '\0';
  494. result->regexp = g_regex_new (begin, regexp_flags, 0, &err);
  495. result->regexp_text = memory_pool_strdup (pool, begin);
  496. memory_pool_add_destructor (pool, (pool_destruct_func)g_regex_unref, (void *)result->regexp);
  497. *end = '/';
  498. return result;
  499. }
  500. /*
  501. * vi:ts=4
  502. */