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.

util.h 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. /*
  2. * Copyright 2024 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #ifndef RSPAMD_UTIL_H
  17. #define RSPAMD_UTIL_H
  18. #include "config.h"
  19. #include "mem_pool.h"
  20. #include "printf.h"
  21. #include "fstring.h"
  22. #include "addr.h"
  23. #include "str_util.h"
  24. #ifdef HAVE_NETDB_H
  25. #include <netdb.h>
  26. #endif
  27. #include <time.h>
  28. #ifdef __cplusplus
  29. extern "C" {
  30. #endif
  31. struct rspamd_config;
  32. enum rspamd_exception_type {
  33. RSPAMD_EXCEPTION_NEWLINE = 0,
  34. RSPAMD_EXCEPTION_URL,
  35. RSPAMD_EXCEPTION_GENERIC,
  36. };
  37. /**
  38. * Structure to point exception in text from processing
  39. */
  40. struct rspamd_process_exception {
  41. goffset pos;
  42. guint len;
  43. gpointer ptr;
  44. enum rspamd_exception_type type;
  45. };
  46. /**
  47. * Create generic socket
  48. * @param af address family
  49. * @param type socket type
  50. * @param protocol socket protocol
  51. * @param async set non-blocking on a socket
  52. * @return socket FD or -1 in case of error
  53. */
  54. gint rspamd_socket_create(gint af, gint type, gint protocol, gboolean async);
  55. /*
  56. * Create socket and bind or connect it to specified address and port
  57. */
  58. gint rspamd_socket_tcp(struct addrinfo *, gboolean is_server, gboolean async);
  59. /*
  60. * Create socket and bind or connect it to specified address and port
  61. */
  62. gint rspamd_socket_udp(struct addrinfo *, gboolean is_server, gboolean async);
  63. /*
  64. * Create and bind or connect unix socket
  65. */
  66. gint rspamd_socket_unix(const gchar *,
  67. struct sockaddr_un *,
  68. gint type,
  69. gboolean is_server,
  70. gboolean async);
  71. /**
  72. * Make a universal socket
  73. * @param credits host, ip or path to unix socket
  74. * @param port port (used for network sockets)
  75. * @param type type of socket (SO_STREAM or SO_DGRAM)
  76. * @param async make this socket async
  77. * @param is_server make this socket as server socket
  78. * @param try_resolve try name resolution for a socket (BLOCKING)
  79. */
  80. gint rspamd_socket(const gchar *credits, guint16 port, gint type,
  81. gboolean async, gboolean is_server, gboolean try_resolve);
  82. /*
  83. * Create socketpair
  84. */
  85. gboolean rspamd_socketpair(gint pair[2], gint af);
  86. /*
  87. * Make specified socket non-blocking
  88. */
  89. gint rspamd_socket_nonblocking(gint);
  90. /*
  91. * Make specified socket blocking
  92. */
  93. gint rspamd_socket_blocking(gint);
  94. /*
  95. * Poll a sync socket for specified events
  96. */
  97. gint rspamd_socket_poll(gint fd, gint timeout, short events);
  98. /*
  99. * Init signals
  100. */
  101. #ifdef HAVE_SA_SIGINFO
  102. void rspamd_signals_init(struct sigaction *sa, void (*sig_handler)(gint,
  103. siginfo_t *,
  104. void *));
  105. #else
  106. void rspamd_signals_init(struct sigaction *sa, void (*sig_handler)(gint));
  107. #endif
  108. /*
  109. * Process title utility functions
  110. */
  111. gint rspamd_init_title(rspamd_mempool_t *pool, gint argc, gchar *argv[], gchar *envp[]);
  112. gint rspamd_setproctitle(const gchar *fmt, ...);
  113. #ifndef HAVE_PIDFILE
  114. /*
  115. * Pidfile functions from FreeBSD libutil code
  116. */
  117. typedef struct rspamd_pidfh_s {
  118. gint pf_fd;
  119. #ifdef HAVE_PATH_MAX
  120. gchar pf_path[PATH_MAX + 1];
  121. #elif defined(HAVE_MAXPATHLEN)
  122. gchar pf_path[MAXPATHLEN + 1];
  123. #else
  124. gchar pf_path[1024 + 1];
  125. #endif
  126. dev_t pf_dev;
  127. ino_t pf_ino;
  128. } rspamd_pidfh_t;
  129. rspamd_pidfh_t *rspamd_pidfile_open(const gchar *path,
  130. mode_t mode,
  131. pid_t *pidptr);
  132. gint rspamd_pidfile_write(rspamd_pidfh_t *pfh);
  133. gint rspamd_pidfile_close(rspamd_pidfh_t *pfh);
  134. gint rspamd_pidfile_remove(rspamd_pidfh_t *pfh);
  135. #else
  136. typedef struct pidfh rspamd_pidfh_t;
  137. #define rspamd_pidfile_open pidfile_open
  138. #define rspamd_pidfile_write pidfile_write
  139. #define rspamd_pidfile_close pidfile_close
  140. #define rspamd_pidfile_remove pidfile_remove
  141. #endif
  142. /*
  143. * Replace %r with rcpt value and %f with from value, new string is allocated in pool
  144. */
  145. gchar *resolve_stat_filename(rspamd_mempool_t *pool,
  146. gchar *pattern,
  147. gchar *rcpt,
  148. gchar *from);
  149. const gchar *
  150. rspamd_log_check_time(gdouble start, gdouble end, gint resolution);
  151. /*
  152. * File locking functions
  153. */
  154. gboolean rspamd_file_lock(gint fd, gboolean async);
  155. gboolean rspamd_file_unlock(gint fd, gboolean async);
  156. /*
  157. * Workarounds for older versions of glib
  158. */
  159. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION < 22))
  160. void g_ptr_array_unref(GPtrArray *array);
  161. gboolean g_int64_equal(gconstpointer v1, gconstpointer v2);
  162. guint g_int64_hash(gconstpointer v);
  163. #endif
  164. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION < 14))
  165. void g_queue_clear(GQueue *queue);
  166. #endif
  167. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION < 32))
  168. void g_queue_free_full(GQueue *queue, GDestroyNotify free_func);
  169. #endif
  170. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION < 40))
  171. void g_ptr_array_insert(GPtrArray *array, gint index_, gpointer data);
  172. #endif
  173. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION < 30))
  174. GPtrArray *g_ptr_array_new_full(guint reserved_size,
  175. GDestroyNotify element_free_func);
  176. #endif
  177. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION < 32))
  178. const gchar *g_environ_getenv(gchar **envp, const gchar *variable);
  179. #endif
  180. /*
  181. * Convert milliseconds to timeval fields
  182. */
  183. #define msec_to_tv(msec, tv) \
  184. do { \
  185. (tv)->tv_sec = (msec) / 1000; \
  186. (tv)->tv_usec = \
  187. ((msec) - (tv)->tv_sec * 1000) * 1000; \
  188. } while (0)
  189. #define double_to_tv(dbl, tv) \
  190. do { \
  191. (tv)->tv_sec = (int) (dbl); \
  192. (tv)->tv_usec = \
  193. ((dbl) - (int) (dbl)) * 1000 * 1000; \
  194. } while (0)
  195. #define double_to_ts(dbl, ts) \
  196. do { \
  197. (ts)->tv_sec = (int) (dbl); \
  198. (ts)->tv_nsec = \
  199. ((dbl) - (int) (dbl)) * 1e9; \
  200. } while (0)
  201. #define tv_to_msec(tv) ((tv)->tv_sec * 1000LLU + (tv)->tv_usec / 1000LLU)
  202. #define tv_to_double(tv) ((double) (tv)->tv_sec + (tv)->tv_usec / 1.0e6)
  203. #define ts_to_usec(ts) ((ts)->tv_sec * 1000000LLU + \
  204. (ts)->tv_nsec / 1000LLU)
  205. #define ts_to_double(tv) ((double) (tv)->tv_sec + (tv)->tv_nsec / 1.0e9)
  206. /**
  207. * Try to allocate a file on filesystem (using fallocate or posix_fallocate)
  208. * @param fd descriptor
  209. * @param offset offset of file
  210. * @param len length to allocate
  211. * @return -1 in case of failure
  212. */
  213. gint rspamd_fallocate(gint fd, off_t offset, off_t len);
  214. /**
  215. * Utils for working with threads to be compatible with all glib versions
  216. */
  217. typedef struct rspamd_mutex_s {
  218. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
  219. GMutex mtx;
  220. #else
  221. GStaticMutex mtx;
  222. #endif
  223. } rspamd_mutex_t;
  224. /**
  225. * Create new mutex
  226. * @return mutex or NULL
  227. */
  228. rspamd_mutex_t *rspamd_mutex_new(void);
  229. /**
  230. * Lock mutex
  231. * @param mtx
  232. */
  233. void rspamd_mutex_lock(rspamd_mutex_t *mtx);
  234. /**
  235. * Unlock mutex
  236. * @param mtx
  237. */
  238. void rspamd_mutex_unlock(rspamd_mutex_t *mtx);
  239. /**
  240. * Clear rspamd mutex
  241. * @param mtx
  242. */
  243. void rspamd_mutex_free(rspamd_mutex_t *mtx);
  244. /**
  245. * Deep copy of one hash table to another
  246. * @param src source hash
  247. * @param dst destination hash
  248. * @param key_copy_func function called to copy or modify keys (or NULL)
  249. * @param value_copy_func function called to copy or modify values (or NULL)
  250. * @param ud user data for copy functions
  251. */
  252. void rspamd_hash_table_copy(GHashTable *src, GHashTable *dst,
  253. gpointer (*key_copy_func)(gconstpointer data, gpointer ud),
  254. gpointer (*value_copy_func)(gconstpointer data, gpointer ud),
  255. gpointer ud);
  256. /**
  257. * Read passphrase from tty
  258. * @param buf buffer to fill with a password
  259. * @param size size of the buffer
  260. * @param echo turn echo on or off
  261. * @param key unused key
  262. * @return size of password read
  263. */
  264. #define rspamd_read_passphrase(buf, size, echo, key) (rspamd_read_passphrase_with_prompt("Enter passphrase: ", (buf), (size), (echo), (key)))
  265. /**
  266. * Read passphrase from tty with prompt
  267. * @param prompt prompt to use
  268. * @param buf buffer to fill with a password
  269. * @param size size of the buffer
  270. * @param echo turn echo on or off
  271. * @param key unused key
  272. * @return
  273. */
  274. gint rspamd_read_passphrase_with_prompt(const gchar *prompt, gchar *buf, gint size, bool echo, gpointer key);
  275. /**
  276. * Portably return the current clock ticks as seconds
  277. * @return
  278. */
  279. gdouble rspamd_get_ticks(gboolean rdtsc_ok);
  280. /**
  281. * Portably return the current virtual clock ticks as seconds
  282. * @return
  283. */
  284. gdouble rspamd_get_virtual_ticks(void);
  285. /**
  286. * Return the real timestamp as unixtime
  287. */
  288. gdouble rspamd_get_calendar_ticks(void);
  289. /**
  290. * Special utility to help array freeing in rspamd_mempool
  291. * @param p
  292. */
  293. void rspamd_ptr_array_free_hard(gpointer p);
  294. /**
  295. * Special utility to help array freeing in rspamd_mempool
  296. * @param p
  297. */
  298. void rspamd_array_free_hard(gpointer p);
  299. /**
  300. * Special utility to help GString freeing in rspamd_mempool
  301. * @param p
  302. */
  303. void rspamd_gstring_free_hard(gpointer p);
  304. /**
  305. * Special utility to help GError freeing in rspamd_mempool
  306. * @param p
  307. */
  308. void rspamd_gerror_free_maybe(gpointer p);
  309. /**
  310. * Special utility to help GString freeing (without freeing the memory segment) in rspamd_mempool
  311. * @param p
  312. */
  313. void rspamd_gstring_free_soft(gpointer p);
  314. /**
  315. * Returns some statically initialized random hash seed
  316. * @return hash seed
  317. */
  318. uint64_t rspamd_hash_seed(void);
  319. /**
  320. * Returns random hex string of the specified length
  321. * @param buf
  322. * @param len
  323. */
  324. void rspamd_random_hex(gchar *buf, uint64_t len);
  325. /**
  326. * Returns
  327. * @param pattern pattern to create (should end with some number of X symbols), modified by this function
  328. * @return
  329. */
  330. gint rspamd_shmem_mkstemp(gchar *pattern);
  331. /**
  332. * Return jittered time value
  333. */
  334. gdouble rspamd_time_jitter(gdouble in, gdouble jitter);
  335. /**
  336. * Return random double in range [0..1)
  337. * @return
  338. */
  339. gdouble rspamd_random_double(void);
  340. /**
  341. * Return random double in range [0..1) using xoroshiro128+ algorithm (not crypto secure)
  342. * @return
  343. */
  344. gdouble rspamd_random_double_fast(void);
  345. gdouble rspamd_random_double_fast_seed(uint64_t *seed);
  346. uint64_t rspamd_random_uint64_fast_seed(uint64_t *seed);
  347. uint64_t rspamd_random_uint64_fast(void);
  348. /**
  349. * Seed fast rng
  350. */
  351. void rspamd_random_seed_fast(void);
  352. /**
  353. * Constant time version of memcmp
  354. */
  355. gboolean rspamd_constant_memcmp(const void *a, const void *b, gsize len);
  356. /**
  357. * Open file without following symlinks or special stuff
  358. * @param fname filename
  359. * @param oflags open flags
  360. * @param mode mode to open
  361. * @return fd or -1 in case of error
  362. */
  363. int rspamd_file_xopen(const char *fname, int oflags, guint mode,
  364. gboolean allow_symlink);
  365. /**
  366. * Map file without following symlinks or special stuff
  367. * @param fname filename
  368. * @param mode mode to open
  369. * @param size target size (must NOT be NULL)
  370. * @return pointer to memory (should be freed using munmap) or NULL in case of error
  371. */
  372. gpointer rspamd_file_xmap(const char *fname, guint mode, gsize *size,
  373. gboolean allow_symlink);
  374. /**
  375. * Map named shared memory segment
  376. * @param fname filename
  377. * @param mode mode to open
  378. * @param size target size (must NOT be NULL)
  379. * @return pointer to memory (should be freed using munmap) or NULL in case of error
  380. */
  381. gpointer rspamd_shmem_xmap(const char *fname, guint mode,
  382. gsize *size);
  383. /**
  384. * Normalize probabilities using polynomial function
  385. * @param x probability (bias .. 1)
  386. * @return
  387. */
  388. gdouble rspamd_normalize_probability(gdouble x, gdouble bias);
  389. /**
  390. * Converts struct tm to time_t
  391. * @param tm
  392. * @param tz timezone in format (hours * 100) + minutes
  393. * @return
  394. */
  395. uint64_t rspamd_tm_to_time(const struct tm *tm, glong tz);
  396. /**
  397. * Splits unix timestamp into struct tm using GMT timezone
  398. * @param ts
  399. * @param dest
  400. */
  401. void rspamd_gmtime(int64_t ts, struct tm *dest);
  402. /**
  403. * Split unix timestamp into struct tm using local timezone
  404. * @param ts
  405. * @param dest
  406. */
  407. void rspamd_localtime(int64_t ts, struct tm *dest);
  408. #define PTR_ARRAY_FOREACH(ar, i, cur) for ((i) = 0; (ar) != NULL && (i) < (ar)->len && (((cur) = (__typeof__(cur)) g_ptr_array_index((ar), (i))) || 1); ++(i))
  409. /**
  410. * Compresses the input string using gzip+zlib. Old string is replaced and freed
  411. * if compressed.
  412. * @param in
  413. * @return TRUE if a string has been compressed
  414. */
  415. gboolean rspamd_fstring_gzip(rspamd_fstring_t **in);
  416. /**
  417. * Compresses the input string using gzip+zlib. Old string is replaced and freed
  418. * if compressed. If not compressed it is untouched.
  419. * @param in
  420. * @return TRUE if a string has been compressed
  421. */
  422. gboolean rspamd_fstring_gunzip(rspamd_fstring_t **in);
  423. /**
  424. * Perform globbing searching for the specified path. Allow recursion,
  425. * returns an error if maximum nesting is reached.
  426. * @param pattern
  427. * @param recursive
  428. * @param err
  429. * @return GPtrArray of gchar *, elements are freed when array is freed
  430. */
  431. GPtrArray *rspamd_glob_path(const gchar *dir,
  432. const gchar *pattern,
  433. gboolean recursive,
  434. GError **err);
  435. struct rspamd_counter_data {
  436. float mean;
  437. float stddev;
  438. uint64_t number;
  439. };
  440. /**
  441. * Sets counter's data using exponential moving average
  442. * @param cd counter
  443. * @param value new counter value
  444. * @param alpha decay coefficient (0..1)
  445. * @return new counter value
  446. */
  447. float rspamd_set_counter_ema(struct rspamd_counter_data *cd,
  448. float value,
  449. float alpha);
  450. /**
  451. * Sets counter's data using flat moving average
  452. * @param cd counter
  453. * @param value new counter value
  454. * @return new counter value
  455. */
  456. double rspamd_set_counter(struct rspamd_counter_data *cd,
  457. gdouble value);
  458. /**
  459. * Shuffle elements in an array inplace
  460. * @param ar
  461. */
  462. void rspamd_ptr_array_shuffle(GPtrArray *ar);
  463. enum rspamd_pbkdf_version_id {
  464. RSPAMD_PBKDF_ID_V1 = 1,
  465. RSPAMD_PBKDF_ID_V2 = 2,
  466. RSPAMD_PBKDF_ID_MAX
  467. };
  468. struct rspamd_controller_pbkdf {
  469. const char *name;
  470. const char *alias;
  471. const char *description;
  472. int type; /* enum rspamd_cryptobox_pbkdf_type */
  473. gint id;
  474. guint complexity;
  475. gsize salt_len;
  476. gsize key_len;
  477. };
  478. extern const struct rspamd_controller_pbkdf pbkdf_list[];
  479. /**
  480. * Sum array of floats using Kahan sum algorithm
  481. * @param ar
  482. * @param nelts
  483. * @return
  484. */
  485. float rspamd_sum_floats(float *ar, gsize *nelts);
  486. /**
  487. * Normalize file path removing dot sequences and repeating '/' symbols as
  488. * per rfc3986#section-5.2
  489. * @param path
  490. * @param len
  491. * @param nlen
  492. */
  493. void rspamd_normalize_path_inplace(gchar *path, guint len, gsize *nlen);
  494. #ifdef __cplusplus
  495. }
  496. #endif
  497. #endif