dst_blacklist.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. /*
  2. * $Id$
  3. *
  4. * resolver related functions
  5. *
  6. * Copyright (C) 2006 iptelorg GmbH
  7. *
  8. * This file is part of ser, a free SIP server.
  9. *
  10. * ser is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version
  14. *
  15. * For a license to use the ser software under conditions
  16. * other than those described here, or to purchase support for this
  17. * software, please contact iptel.org by e-mail at the following addresses:
  18. * [email protected]
  19. *
  20. * ser is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program; if not, write to the Free Software
  27. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  28. */
  29. /* History:
  30. * --------
  31. * 2006-07-29 created by andrei
  32. * 2007-05-39 added hooks for add; more locks to reduce contention (andrei)
  33. * 2007-06-26 added hooks for search (andrei)
  34. * 2007-07-30 added dst_blacklist_del() and dst_blacklist_add_to() (andrei)
  35. * 2007-07-30 dst blacklist measurements added (Gergo)
  36. * 2008-02-11 dns_blacklist_init cfg parameter is introduced (Miklos)
  37. * 2009-02-26 added dst_blacklist_su* variant (andrei)
  38. */
  39. /*!
  40. * \file
  41. * \brief SIP-router core ::
  42. * \ingroup core
  43. * Module: \ref core
  44. */
  45. #ifdef USE_DST_BLACKLIST
  46. #include "dst_blacklist.h"
  47. #include "globals.h"
  48. #include "cfg_core.h"
  49. #include "mem/shm_mem.h"
  50. #include "hashes.h"
  51. #include "locking.h"
  52. #include "timer.h"
  53. #include "timer_ticks.h"
  54. #include "ip_addr.h"
  55. #include "error.h"
  56. #include "rpc.h"
  57. #include "compiler_opt.h"
  58. #include "resolve.h" /* for str2ip */
  59. #ifdef USE_DST_BLACKLIST_STATS
  60. #include "pt.h"
  61. #endif
  62. struct dst_blst_entry{
  63. struct dst_blst_entry* next;
  64. ticks_t expire;
  65. unsigned short port;
  66. unsigned char proto;
  67. unsigned char flags; /* contains the address type + error flags */
  68. unsigned char ip[4]; /* 4 for ipv4, 16 for ipv6 */
  69. };
  70. #define DST_BLST_ENTRY_SIZE(b) \
  71. (sizeof(struct dst_blst_entry)+((b).flags&BLST_IS_IPV6)*12)
  72. #define DST_BLST_HASH_SIZE 1024
  73. #define DEFAULT_BLST_TIMER_INTERVAL 60 /* 1 min */
  74. /* lock method */
  75. #ifdef GEN_LOCK_T_UNLIMITED
  76. #define BLST_LOCK_PER_BUCKET
  77. #elif defined GEN_LOCK_SET_T_UNLIMITED
  78. #define BLST_LOCK_SET
  79. #else
  80. #define BLST_ONE_LOCK
  81. #endif
  82. #ifdef BLST_LOCK_PER_BUCKET
  83. /* lock included in the hash bucket */
  84. #define LOCK_BLST(h) lock_get(&dst_blst_hash[(h)].lock)
  85. #define UNLOCK_BLST(h) lock_release(&dst_blst_hash[(h)].lock)
  86. #elif defined BLST_LOCK_SET
  87. static gen_lock_set_t* blst_lock_set=0;
  88. #define LOCK_BLST(h) lock_set_get(blst_lock_set, (h))
  89. #define UNLOCK_BLST(h) lock_set_release(blst_lock_set, (h))
  90. #else
  91. /* use only one lock */
  92. static gen_lock_t* blst_lock=0;
  93. #define LOCK_BLST(h) lock_get(blst_lock)
  94. #define UNLOCK_BLST(h) lock_release(blst_lock)
  95. #endif
  96. #define BLST_HASH_STATS
  97. #ifdef BLST_HASH_STATS
  98. #define BLST_HASH_STATS_DEC(h) dst_blst_hash[(h)].entries--
  99. #define BLST_HASH_STATS_INC(h) dst_blst_hash[(h)].entries++
  100. #else
  101. #define BLST_HASH_STATS_DEC(h) do{}while(0)
  102. #define BLST_HASH_STATS_INC(h) do{}while(0)
  103. #endif
  104. struct dst_blst_lst_head{
  105. struct dst_blst_entry* first;
  106. #ifdef BLST_LOCK_PER_BUCKET
  107. gen_lock_t lock;
  108. #endif
  109. #ifdef BLST_HASH_STATS
  110. unsigned int entries;
  111. #endif
  112. };
  113. int dst_blacklist_init=1; /* if 0, the dst blacklist is not initialized at startup */
  114. static struct timer_ln* blst_timer_h=0;
  115. static volatile unsigned int* blst_mem_used=0;
  116. unsigned int blst_timer_interval=DEFAULT_BLST_TIMER_INTERVAL;
  117. struct dst_blst_lst_head* dst_blst_hash=0;
  118. #ifdef USE_DST_BLACKLIST_STATS
  119. struct t_dst_blacklist_stats* dst_blacklist_stats=0;
  120. #endif
  121. /* blacklist per protocol event ignore mask array */
  122. unsigned blst_proto_imask[PROTO_LAST+1];
  123. #ifdef DST_BLACKLIST_HOOKS
  124. /* there 2 types of callbacks supported: on add new entry to the blacklist
  125. * (DST_BLACKLIST_ADD_CB) and on blacklist search (DST_BLACKLIST_SEARCH_CB).
  126. * Both of them take a struct dest_info*, a flags pointer(unsigned char*),
  127. * and a struct sip_msg* as parameters. The flags can be changed.
  128. * A callback should return one of:
  129. * DST_BLACKLIST_CONTINUE - do nothing, let other callbacks run
  130. * DST_BLACKLIST_ACCEPT - for blacklist add: force accept immediately,
  131. * for blacklist search: force match and use
  132. * the flags as the blacklist search return.
  133. * ( so the flags should be set to some valid
  134. * non zero BLST flags value )
  135. * DST_BLACKLIST_DENY - for blacklist add: don't allow adding the
  136. * destination to the blacklist.
  137. * for blacklist search: force return not found
  138. */
  139. #define MAX_BLST_HOOKS 1
  140. struct blst_callbacks_lst{
  141. struct blacklist_hook* hooks;
  142. unsigned int max_hooks;
  143. int last_idx;
  144. };
  145. static struct blst_callbacks_lst blst_add_cb;
  146. static struct blst_callbacks_lst blst_search_cb;
  147. static int init_blst_callback_lst(struct blst_callbacks_lst* cb_lst, int max)
  148. {
  149. cb_lst->max_hooks=MAX_BLST_HOOKS;
  150. cb_lst->last_idx=0;
  151. cb_lst->hooks=pkg_malloc(cb_lst->max_hooks*sizeof(struct blacklist_hook));
  152. if (cb_lst->hooks==0)
  153. goto error;
  154. memset(cb_lst->hooks, 0, cb_lst->max_hooks*sizeof(struct blacklist_hook));
  155. return 0;
  156. error:
  157. return -1;
  158. }
  159. static void destroy_blst_callback_lst(struct blst_callbacks_lst* cb_lst)
  160. {
  161. int r;
  162. if (cb_lst && cb_lst->hooks){
  163. for (r=0; r<cb_lst->last_idx; r++){
  164. if (cb_lst->hooks[r].destroy)
  165. cb_lst->hooks[r].destroy();
  166. }
  167. pkg_free(cb_lst->hooks);
  168. cb_lst->hooks=0;
  169. cb_lst->last_idx=0;
  170. cb_lst->max_hooks=0;
  171. }
  172. }
  173. static void destroy_blacklist_hooks()
  174. {
  175. destroy_blst_callback_lst(&blst_add_cb);
  176. destroy_blst_callback_lst(&blst_search_cb);
  177. }
  178. static int init_blacklist_hooks()
  179. {
  180. if (init_blst_callback_lst(&blst_add_cb, MAX_BLST_HOOKS)!=0)
  181. goto error;
  182. if (init_blst_callback_lst(&blst_search_cb, MAX_BLST_HOOKS)!=0)
  183. goto error;
  184. return 0;
  185. error:
  186. LM_ERR("failure initializing internal lists\n");
  187. destroy_blacklist_hooks();
  188. return -1;
  189. }
  190. /* allocates a new hook
  191. * returns 0 on success and -1 on error
  192. * must be called from mod init (from the main process, before forking)*/
  193. int register_blacklist_hook(struct blacklist_hook *h, int type)
  194. {
  195. struct blst_callbacks_lst* cb_lst;
  196. struct blacklist_hook* tmp;
  197. int new_max_hooks;
  198. if (dst_blacklist_init==0) {
  199. LM_ERR("blacklist is turned off, "
  200. "the hook cannot be registered\n");
  201. goto error;
  202. }
  203. switch(type){
  204. case DST_BLACKLIST_ADD_CB:
  205. cb_lst=&blst_add_cb;
  206. break;
  207. case DST_BLACKLIST_SEARCH_CB:
  208. cb_lst=&blst_search_cb;
  209. break;
  210. default:
  211. BUG("register_blacklist_hook: invalid type %d\n", type);
  212. goto error;
  213. }
  214. if (cb_lst==0 || cb_lst->hooks==0 || cb_lst->max_hooks==0){
  215. BUG("register_blacklist_hook: intialization error\n");
  216. goto error;
  217. }
  218. if (cb_lst->last_idx >= cb_lst->max_hooks){
  219. new_max_hooks=2*cb_lst->max_hooks;
  220. tmp=pkg_realloc(cb_lst->hooks,
  221. new_max_hooks*sizeof(struct blacklist_hook));
  222. if (tmp==0){
  223. goto error;
  224. }
  225. cb_lst->hooks=tmp;
  226. /* init the new chunk (but not the current entry which is
  227. * overwritten anyway) */
  228. memset(&cb_lst->hooks[cb_lst->max_hooks+1], 0,
  229. (new_max_hooks-cb_lst->max_hooks-1)*
  230. sizeof(struct blacklist_hook));
  231. cb_lst->max_hooks=new_max_hooks;
  232. }
  233. cb_lst->hooks[cb_lst->last_idx]=*h;
  234. cb_lst->last_idx++;
  235. return 0;
  236. error:
  237. return -1;
  238. }
  239. inline static int blacklist_run_hooks(struct blst_callbacks_lst *cb_lst,
  240. struct dest_info* si, unsigned char* flags,
  241. struct sip_msg* msg)
  242. {
  243. int r;
  244. int ret;
  245. ret=DST_BLACKLIST_CONTINUE; /* default, if no hook installed accept
  246. blacklist operation */
  247. if (likely(cb_lst->last_idx==0))
  248. return ret;
  249. for (r=0; r<cb_lst->last_idx; r++){
  250. ret=cb_lst->hooks[r].on_blst_action(si, flags, msg);
  251. if (ret!=DST_BLACKLIST_CONTINUE) break;
  252. }
  253. return ret;
  254. }
  255. #endif /* DST_BLACKLIST_HOOKS */
  256. /** init per protocol blacklist event ignore masks.
  257. * @return 0 on success, < 0 on error.
  258. */
  259. int blst_init_ign_masks(void)
  260. {
  261. if ((PROTO_UDP > PROTO_LAST) || (PROTO_TCP > PROTO_LAST) ||
  262. (PROTO_TLS > PROTO_LAST) || (PROTO_SCTP > PROTO_LAST)){
  263. BUG("protocol array too small\n");
  264. return -1;
  265. }
  266. blst_proto_imask[PROTO_UDP]=cfg_get(core, core_cfg, blst_udp_imask);
  267. blst_proto_imask[PROTO_TCP]=cfg_get(core, core_cfg, blst_tcp_imask);
  268. blst_proto_imask[PROTO_TLS]=cfg_get(core, core_cfg, blst_tls_imask);
  269. blst_proto_imask[PROTO_SCTP]=cfg_get(core, core_cfg, blst_sctp_imask);
  270. blst_proto_imask[PROTO_NONE]=blst_proto_imask[PROTO_UDP];
  271. return 0;
  272. }
  273. inline static void blst_destroy_entry(struct dst_blst_entry* e)
  274. {
  275. shm_free(e);
  276. }
  277. static ticks_t blst_timer(ticks_t ticks, struct timer_ln* tl, void* data);
  278. inline static void dst_blst_entry2ip(struct ip_addr* ip,
  279. struct dst_blst_entry* e)
  280. {
  281. if (e->flags & BLST_IS_IPV6){
  282. ip->af=AF_INET6;
  283. ip->len=16;
  284. }else
  285. {
  286. ip->af=AF_INET;
  287. ip->len=4;
  288. }
  289. memcpy(ip->u.addr, e->ip, ip->len);
  290. }
  291. inline static unsigned short dst_blst_hash_no(unsigned char proto,
  292. struct ip_addr* ip,
  293. unsigned short port)
  294. {
  295. str s1;
  296. str s2;
  297. s1.s=(char*)ip->u.addr;
  298. s1.len=ip->len;
  299. s2.s=(char*)&port;
  300. s2.len=sizeof(unsigned short);
  301. return get_hash2_raw(&s1, &s2)%DST_BLST_HASH_SIZE;
  302. }
  303. void destroy_dst_blacklist()
  304. {
  305. int r;
  306. struct dst_blst_entry** crt;
  307. struct dst_blst_entry* e;
  308. if (blst_timer_h){
  309. timer_del(blst_timer_h);
  310. timer_free(blst_timer_h);
  311. blst_timer_h=0;
  312. }
  313. #ifdef BLST_LOCK_PER_BUCKET
  314. if (dst_blst_hash)
  315. for(r=0; r<DST_BLST_HASH_SIZE; r++)
  316. lock_destroy(&dst_blst_hash[r].lock);
  317. #elif defined BLST_LOCK_SET
  318. if (blst_lock_set){
  319. lock_set_destroy(blst_lock_set);
  320. lock_set_dealloc(blst_lock_set);
  321. blst_lock_set=0;
  322. }
  323. #else
  324. if (blst_lock){
  325. lock_destroy(blst_lock);
  326. lock_dealloc(blst_lock);
  327. blst_lock=0;
  328. }
  329. #endif
  330. if (dst_blst_hash){
  331. for(r=0; r<DST_BLST_HASH_SIZE; r++){
  332. crt=&dst_blst_hash[r].first;
  333. while(*crt){
  334. e=*crt;
  335. *crt=(*crt)->next;
  336. blst_destroy_entry(e);
  337. }
  338. }
  339. shm_free(dst_blst_hash);
  340. dst_blst_hash=0;
  341. }
  342. if (blst_mem_used){
  343. shm_free((void*)blst_mem_used);
  344. blst_mem_used=0;
  345. }
  346. #ifdef DST_BLACKLIST_HOOKS
  347. destroy_blacklist_hooks();
  348. #endif
  349. #ifdef USE_DST_BLACKLIST_STATS
  350. if (dst_blacklist_stats)
  351. shm_free(dst_blacklist_stats);
  352. #endif
  353. }
  354. int init_dst_blacklist()
  355. {
  356. int ret;
  357. #ifdef BLST_LOCK_PER_BUCKET
  358. int r;
  359. #endif
  360. if (dst_blacklist_init==0) {
  361. /* the dst blacklist is turned off */
  362. default_core_cfg.use_dst_blacklist=0;
  363. return 0;
  364. }
  365. ret=-1;
  366. #ifdef DST_BLACKLIST_HOOKS
  367. if (init_blacklist_hooks()!=0){
  368. ret=E_OUT_OF_MEM;
  369. goto error;
  370. }
  371. #endif
  372. blst_mem_used=shm_malloc(sizeof(*blst_mem_used));
  373. if (blst_mem_used==0){
  374. ret=E_OUT_OF_MEM;
  375. goto error;
  376. }
  377. *blst_mem_used=0;
  378. dst_blst_hash=shm_malloc(sizeof(struct dst_blst_lst_head) *
  379. DST_BLST_HASH_SIZE);
  380. if (dst_blst_hash==0){
  381. ret=E_OUT_OF_MEM;
  382. goto error;
  383. }
  384. memset(dst_blst_hash, 0, sizeof(struct dst_blst_lst_head) *
  385. DST_BLST_HASH_SIZE);
  386. #ifdef BLST_LOCK_PER_BUCKET
  387. for (r=0; r<DST_BLST_HASH_SIZE; r++){
  388. if (lock_init(&dst_blst_hash[r].lock)==0){
  389. ret=-1;
  390. goto error;
  391. }
  392. }
  393. #elif defined BLST_LOCK_SET
  394. blst_lock_set=lock_set_alloc(DST_BLST_HASH_SIZE);
  395. if (blst_lock_set==0){
  396. ret=E_OUT_OF_MEM;
  397. goto error;
  398. }
  399. if (lock_set_init(blst_lock_set)==0){
  400. lock_set_dealloc(blst_lock_set);
  401. blst_lock_set=0;
  402. ret=-1;
  403. goto error;
  404. }
  405. #else /* BLST_ONE_LOCK */
  406. blst_lock=lock_alloc();
  407. if (blst_lock==0){
  408. ret=E_OUT_OF_MEM;
  409. goto error;
  410. }
  411. if (lock_init(blst_lock)==0){
  412. lock_dealloc(blst_lock);
  413. blst_lock=0;
  414. ret=-1;
  415. goto error;
  416. }
  417. #endif /* BLST*LOCK*/
  418. blst_timer_h=timer_alloc();
  419. if (blst_timer_h==0){
  420. ret=E_OUT_OF_MEM;
  421. goto error;
  422. }
  423. /* fix options */
  424. default_core_cfg.blst_max_mem<<=10; /* in Kb */ /* TODO: test with 0 */
  425. if (blst_timer_interval){
  426. timer_init(blst_timer_h, blst_timer, 0 ,0); /* slow timer */
  427. if (timer_add(blst_timer_h, S_TO_TICKS(blst_timer_interval))<0){
  428. LM_CRIT("failed to add the timer\n");
  429. timer_free(blst_timer_h);
  430. blst_timer_h=0;
  431. goto error;
  432. }
  433. }
  434. if (blst_init_ign_masks() < 0){
  435. ret=E_BUG;
  436. goto error;
  437. }
  438. return 0;
  439. error:
  440. destroy_dst_blacklist();
  441. return ret;
  442. }
  443. #ifdef USE_DST_BLACKLIST_STATS
  444. int init_dst_blacklist_stats(int iproc_num)
  445. {
  446. /* do not initialize the stats array if the dst blacklist will not be used */
  447. if (dst_blacklist_init==0) return 0;
  448. /* if it is already initialized */
  449. if (dst_blacklist_stats)
  450. shm_free(dst_blacklist_stats);
  451. dst_blacklist_stats=shm_malloc(sizeof(*dst_blacklist_stats) * iproc_num);
  452. if (dst_blacklist_stats==0){
  453. return E_OUT_OF_MEM;
  454. }
  455. memset(dst_blacklist_stats, 0, sizeof(*dst_blacklist_stats) * iproc_num);
  456. return 0;
  457. }
  458. #endif
  459. /* must be called with the lock held
  460. * struct dst_blst_entry** head, struct dst_blst_entry* e */
  461. #define dst_blacklist_lst_add(head, e)\
  462. do{ \
  463. (e)->next=*(head); \
  464. *(head)=(e); \
  465. }while(0)
  466. /* must be called with the lock held
  467. * returns a pointer to the blacklist entry if found, 0 otherwise
  468. * it also deletes expired elements (expire<=now) as it searches
  469. * proto==PROTO_NONE = wildcard */
  470. inline static struct dst_blst_entry* _dst_blacklist_lst_find(
  471. unsigned short hash,
  472. struct ip_addr* ip,
  473. unsigned char proto,
  474. unsigned short port,
  475. ticks_t now)
  476. {
  477. struct dst_blst_entry** crt;
  478. struct dst_blst_entry** tmp;
  479. struct dst_blst_entry* e;
  480. struct dst_blst_entry** head;
  481. unsigned char type;
  482. head=&dst_blst_hash[hash].first;
  483. type=(ip->af==AF_INET6)*BLST_IS_IPV6;
  484. for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
  485. e=*crt;
  486. prefetch_loc_r((*crt)->next, 1);
  487. /* remove old expired entries */
  488. if ((s_ticks_t)(now-(*crt)->expire)>=0){
  489. *crt=(*crt)->next;
  490. tmp=crt;
  491. *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
  492. BLST_HASH_STATS_DEC(hash);
  493. blst_destroy_entry(e);
  494. }else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
  495. ((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
  496. (e->proto==proto)) &&
  497. (memcmp(ip->u.addr, e->ip, ip->len)==0)){
  498. return e;
  499. }
  500. }
  501. return 0;
  502. }
  503. /* must be called with the lock held
  504. * returns 1 if a matching entry was deleted, 0 otherwise
  505. * it also deletes expired elements (expire<=now) as it searches
  506. * proto==PROTO_NONE = wildcard */
  507. inline static int _dst_blacklist_del(
  508. unsigned short hash,
  509. struct ip_addr* ip,
  510. unsigned char proto,
  511. unsigned short port,
  512. ticks_t now)
  513. {
  514. struct dst_blst_entry** crt;
  515. struct dst_blst_entry** tmp;
  516. struct dst_blst_entry* e;
  517. struct dst_blst_entry** head;
  518. unsigned char type;
  519. head=&dst_blst_hash[hash].first;
  520. type=(ip->af==AF_INET6)*BLST_IS_IPV6;
  521. for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
  522. e=*crt;
  523. prefetch_loc_r((*crt)->next, 1);
  524. /* remove old expired entries */
  525. if ((s_ticks_t)(now-(*crt)->expire)>=0){
  526. *crt=(*crt)->next;
  527. tmp=crt;
  528. *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
  529. BLST_HASH_STATS_DEC(hash);
  530. blst_destroy_entry(e);
  531. }else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
  532. ((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
  533. (e->proto==proto)) &&
  534. (memcmp(ip->u.addr, e->ip, ip->len)==0)){
  535. *crt=(*crt)->next;
  536. tmp=crt;
  537. *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
  538. BLST_HASH_STATS_DEC(hash);
  539. blst_destroy_entry(e);
  540. return 1;
  541. }
  542. }
  543. return 0;
  544. }
  545. /* frees all the expired entries until either there are no more of them
  546. * or the total memory used is <= target (to free all of them use -1 for
  547. * targer)
  548. * params: target - free expired entries until no more then taget memory
  549. * is used (use 0 to free all of them)
  550. * delta - consider an entry expired if it expires after delta
  551. * ticks from now
  552. * timeout - exit after timeout ticks
  553. *
  554. * returns: number of deleted entries
  555. * This function should be called periodically from a timer
  556. */
  557. inline static int dst_blacklist_clean_expired(unsigned int target,
  558. ticks_t delta,
  559. ticks_t timeout)
  560. {
  561. static unsigned int start=0;
  562. unsigned int h;
  563. struct dst_blst_entry** crt;
  564. struct dst_blst_entry** tmp;
  565. struct dst_blst_entry* e;
  566. ticks_t start_time;
  567. ticks_t now;
  568. int no=0;
  569. int i;
  570. now=start_time=get_ticks_raw();
  571. for(h=start; h!=(start+DST_BLST_HASH_SIZE); h++){
  572. i=h%DST_BLST_HASH_SIZE;
  573. if (dst_blst_hash[i].first){
  574. LOCK_BLST(i);
  575. for (crt=&dst_blst_hash[i].first, tmp=&(*crt)->next;
  576. *crt; crt=tmp, tmp=&(*crt)->next){
  577. e=*crt;
  578. prefetch_loc_r((*crt)->next, 1);
  579. if ((s_ticks_t)(now+delta-(*crt)->expire)>=0){
  580. *crt=(*crt)->next;
  581. tmp=crt;
  582. *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
  583. blst_destroy_entry(e);
  584. BLST_HASH_STATS_DEC(i);
  585. no++;
  586. if (*blst_mem_used<=target){
  587. UNLOCK_BLST(i);
  588. goto skip;
  589. }
  590. }
  591. }
  592. UNLOCK_BLST(i);
  593. /* check for timeout only "between" hash cells */
  594. now=get_ticks_raw();
  595. if ((now-start_time)>=timeout){
  596. DBG("_dst_blacklist_clean_expired_unsafe: timeout: %d > %d\n",
  597. TICKS_TO_MS(now-start_time), TICKS_TO_MS(timeout));
  598. goto skip;
  599. }
  600. }
  601. }
  602. skip:
  603. start=h; /* next time we start where we left */
  604. if (no){
  605. DBG("dst_blacklist_clean_expired, %d entries removed\n", no);
  606. }
  607. return no;
  608. }
  609. /* timer */
  610. static ticks_t blst_timer(ticks_t ticks, struct timer_ln* tl, void* data)
  611. {
  612. dst_blacklist_clean_expired(0, 0, 2); /*spend max. 2 ticks*/
  613. return (ticks_t)(-1);
  614. }
  615. /* adds a proto ip:port combination to the blacklist
  616. * returns 0 on success, -1 on error (blacklist full -- would use more then
  617. * blst:_max_mem, or out of shm. mem.)
  618. */
  619. inline static int dst_blacklist_add_ip(unsigned char err_flags,
  620. unsigned char proto,
  621. struct ip_addr* ip, unsigned short port,
  622. ticks_t timeout)
  623. {
  624. int size;
  625. struct dst_blst_entry* e;
  626. unsigned short hash;
  627. ticks_t now;
  628. int ret;
  629. ret=0;
  630. if (ip->af==AF_INET){
  631. err_flags&=~BLST_IS_IPV6; /* make sure the ipv6 flag is reset */
  632. size=sizeof(struct dst_blst_entry);
  633. }else{
  634. err_flags|=BLST_IS_IPV6;
  635. size=sizeof(struct dst_blst_entry)+12 /* ipv6 addr - 4 */;
  636. }
  637. now=get_ticks_raw();
  638. hash=dst_blst_hash_no(proto, ip, port);
  639. /* check if the entry already exists */
  640. LOCK_BLST(hash);
  641. e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
  642. if (e){
  643. e->flags|=err_flags;
  644. e->expire=now+timeout; /* update the timeout */
  645. }else{
  646. if (unlikely((*blst_mem_used+size) >=
  647. cfg_get(core, core_cfg, blst_max_mem))){
  648. #ifdef USE_DST_BLACKLIST_STATS
  649. dst_blacklist_stats[process_no].bkl_lru_cnt++;
  650. #endif
  651. UNLOCK_BLST(hash);
  652. /* first try to free some memory (~ 12%), but don't
  653. * spend more then 250 ms*/
  654. dst_blacklist_clean_expired(*blst_mem_used/16*14, 0,
  655. MS_TO_TICKS(250));
  656. if (unlikely(*blst_mem_used+size >=
  657. cfg_get(core, core_cfg, blst_max_mem))){
  658. ret=-1;
  659. goto error;
  660. }
  661. LOCK_BLST(hash);
  662. }
  663. e=shm_malloc(size);
  664. if (e==0){
  665. UNLOCK_BLST(hash);
  666. ret=E_OUT_OF_MEM;
  667. goto error;
  668. }
  669. *blst_mem_used+=size;
  670. e->flags=err_flags;
  671. e->proto=proto;
  672. e->port=port;
  673. memcpy(e->ip, ip->u.addr, ip->len);
  674. e->expire=now+timeout; /* update the timeout */
  675. e->next=0;
  676. dst_blacklist_lst_add(&dst_blst_hash[hash].first, e);
  677. BLST_HASH_STATS_INC(hash);
  678. }
  679. UNLOCK_BLST(hash);
  680. error:
  681. return ret;
  682. }
  683. /* if no blacklisted returns 0, else returns the blacklist flags */
  684. inline static int dst_is_blacklisted_ip(unsigned char proto,
  685. struct ip_addr* ip,
  686. unsigned short port)
  687. {
  688. struct dst_blst_entry* e;
  689. unsigned short hash;
  690. ticks_t now;
  691. int ret;
  692. ret=0;
  693. now=get_ticks_raw();
  694. hash=dst_blst_hash_no(proto, ip, port);
  695. if (unlikely(dst_blst_hash[hash].first)){
  696. LOCK_BLST(hash);
  697. e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
  698. if (e){
  699. ret=e->flags;
  700. }
  701. UNLOCK_BLST(hash);
  702. }
  703. return ret;
  704. }
  705. /** add dst to the blacklist, specifying the timeout.
  706. * @param err_flags - reason (bitmap)
  707. * @param si - destination (protocol, ip and port)
  708. * @param msg - sip message that triggered the blacklisting (can be 0 if
  709. * not known)
  710. * @param timeout - timeout in ticks
  711. * @return 0 on success, -1 on error
  712. */
  713. int dst_blacklist_force_add_to(unsigned char err_flags, struct dest_info* si,
  714. struct sip_msg* msg, ticks_t timeout)
  715. {
  716. struct ip_addr ip;
  717. #ifdef DST_BLACKLIST_HOOKS
  718. if (unlikely (blacklist_run_hooks(&blst_add_cb, si, &err_flags, msg) ==
  719. DST_BLACKLIST_DENY))
  720. return 0;
  721. #endif
  722. su2ip_addr(&ip, &si->to);
  723. return dst_blacklist_add_ip(err_flags, si->proto, &ip,
  724. su_getport(&si->to), timeout);
  725. }
  726. /** add dst to the blacklist, specifying the timeout.
  727. * (like @function dst_blacklist_force_add_to)= above, but uses
  728. * (proto, sockaddr_union) instead of struct dest_info)
  729. */
  730. int dst_blacklist_force_su_to(unsigned char err_flags, unsigned char proto,
  731. union sockaddr_union* dst,
  732. struct sip_msg* msg, ticks_t timeout)
  733. {
  734. struct ip_addr ip;
  735. #ifdef DST_BLACKLIST_HOOKS
  736. struct dest_info si;
  737. init_dest_info(&si);
  738. si.to=*dst;
  739. si.proto=proto;
  740. if (unlikely (blacklist_run_hooks(&blst_add_cb, &si, &err_flags, msg) ==
  741. DST_BLACKLIST_DENY))
  742. return 0;
  743. #endif
  744. su2ip_addr(&ip, dst);
  745. return dst_blacklist_add_ip(err_flags, proto, &ip,
  746. su_getport(dst), timeout);
  747. }
  748. int dst_is_blacklisted(struct dest_info* si, struct sip_msg* msg)
  749. {
  750. int ires;
  751. struct ip_addr ip;
  752. #ifdef DST_BLACKLIST_HOOKS
  753. unsigned char err_flags;
  754. int action;
  755. #endif
  756. su2ip_addr(&ip, &si->to);
  757. #ifdef DST_BLACKLIST_HOOKS
  758. err_flags=0;
  759. if (unlikely((action=(blacklist_run_hooks(&blst_search_cb, si, &err_flags, msg))
  760. ) != DST_BLACKLIST_CONTINUE)){
  761. if (action==DST_BLACKLIST_DENY)
  762. return 0;
  763. else /* if (action==DST_BLACKLIST_ACCEPT) */
  764. return err_flags;
  765. }
  766. #endif
  767. ires=dst_is_blacklisted_ip(si->proto, &ip, su_getport(&si->to));
  768. #ifdef USE_DST_BLACKLIST_STATS
  769. if (ires)
  770. dst_blacklist_stats[process_no].bkl_hit_cnt++;
  771. #endif
  772. return ires;
  773. }
  774. /* returns 1 if the entry was deleted, 0 if not found */
  775. int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg)
  776. {
  777. unsigned short hash;
  778. struct ip_addr ip;
  779. ticks_t now;
  780. int ret;
  781. unsigned short port;
  782. ret=0;
  783. su2ip_addr(&ip, &si->to);
  784. port=su_getport(&si->to);
  785. now=get_ticks_raw();
  786. hash=dst_blst_hash_no(si->proto, &ip, port);
  787. if (unlikely(dst_blst_hash[hash].first)){
  788. LOCK_BLST(hash);
  789. ret=_dst_blacklist_del(hash, &ip, si->proto, port, now);
  790. UNLOCK_BLST(hash);
  791. }
  792. return ret;
  793. }
  794. /* rpc functions */
  795. void dst_blst_mem_info(rpc_t* rpc, void* ctx)
  796. {
  797. if (!cfg_get(core, core_cfg, use_dst_blacklist)){
  798. rpc->fault(ctx, 500, "dst blacklist support disabled");
  799. return;
  800. }
  801. rpc->add(ctx, "dd", *blst_mem_used, cfg_get(core, core_cfg, blst_max_mem));
  802. }
  803. #ifdef USE_DST_BLACKLIST_STATS
  804. static unsigned long stat_sum(int ivar, int breset) {
  805. unsigned long isum=0;
  806. int i1=0;
  807. for (; i1 < get_max_procs(); i1++)
  808. switch (ivar) {
  809. case 0:
  810. isum+=dst_blacklist_stats[i1].bkl_hit_cnt;
  811. if (breset)
  812. dst_blacklist_stats[i1].bkl_hit_cnt=0;
  813. break;
  814. case 1:
  815. isum+=dst_blacklist_stats[i1].bkl_lru_cnt;
  816. if (breset)
  817. dst_blacklist_stats[i1].bkl_lru_cnt=0;
  818. break;
  819. }
  820. return isum;
  821. }
  822. void dst_blst_stats_get(rpc_t* rpc, void* c)
  823. {
  824. char *name=NULL;
  825. void *handle;
  826. int found=0,i=0;
  827. int reset=0;
  828. char* dst_blacklist_stats_names[] = {
  829. "bkl_hit_cnt",
  830. "bkl_lru_cnt",
  831. NULL
  832. };
  833. if (!cfg_get(core, core_cfg, use_dst_blacklist)){
  834. rpc->fault(c, 500, "dst blacklist support disabled");
  835. return;
  836. }
  837. if (rpc->scan(c, "s", &name) < 0)
  838. return;
  839. if (rpc->scan(c, "d", &reset) < 0)
  840. return;
  841. if (!strcasecmp(name, DST_BLACKLIST_ALL_STATS)) {
  842. /* dump all the dns cache stat values */
  843. rpc->add(c, "{", &handle);
  844. for (i=0; dst_blacklist_stats_names[i]; i++)
  845. rpc->struct_add(handle, "d",
  846. dst_blacklist_stats_names[i],
  847. stat_sum(i, reset));
  848. found=1;
  849. } else {
  850. for (i=0; dst_blacklist_stats_names[i]; i++)
  851. if (!strcasecmp(dst_blacklist_stats_names[i], name)) {
  852. rpc->add(c, "{", &handle);
  853. rpc->struct_add(handle, "d",
  854. dst_blacklist_stats_names[i],
  855. stat_sum(i, reset));
  856. found=1;
  857. break;
  858. }
  859. }
  860. if(!found)
  861. rpc->fault(c, 500, "unknown dst blacklist stat parameter");
  862. return;
  863. }
  864. #endif /* USE_DST_BLACKLIST_STATS */
  865. /* only for debugging, it helds the lock too long for "production" use */
  866. void dst_blst_debug(rpc_t* rpc, void* ctx)
  867. {
  868. int h;
  869. struct dst_blst_entry* e;
  870. ticks_t now;
  871. struct ip_addr ip;
  872. if (!cfg_get(core, core_cfg, use_dst_blacklist)){
  873. rpc->fault(ctx, 500, "dst blacklist support disabled");
  874. return;
  875. }
  876. now=get_ticks_raw();
  877. for(h=0; h<DST_BLST_HASH_SIZE; h++){
  878. LOCK_BLST(h);
  879. for(e=dst_blst_hash[h].first; e; e=e->next){
  880. dst_blst_entry2ip(&ip, e);
  881. rpc->add(ctx, "ssddd", get_proto_name(e->proto),
  882. ip_addr2a(&ip), e->port,
  883. (s_ticks_t)(now-e->expire)<=0?
  884. TICKS_TO_S(e->expire-now):
  885. -TICKS_TO_S(now-e->expire) ,
  886. e->flags);
  887. }
  888. UNLOCK_BLST(h);
  889. }
  890. }
  891. /* only for debugging, it helds the lock too long for "production" use */
  892. void dst_blst_hash_stats(rpc_t* rpc, void* ctx)
  893. {
  894. int h;
  895. struct dst_blst_entry* e;
  896. #ifdef BLST_HASH_STATS
  897. int n;
  898. n=0;
  899. #endif
  900. if (!cfg_get(core, core_cfg, use_dst_blacklist)){
  901. rpc->fault(ctx, 500, "dst blacklist support disabled");
  902. return;
  903. }
  904. for(h=0; h<DST_BLST_HASH_SIZE; h++){
  905. #ifdef BLST_HASH_STATS
  906. LOCK_BLST(h);
  907. for(e=dst_blst_hash[h].first; e; e=e->next) n++;
  908. UNLOCK_BLST(h);
  909. rpc->add(ctx, "dd", h, n);
  910. #else
  911. rpc->add(ctx, "dd", h, dst_blst_hash[h].entries);
  912. #endif
  913. }
  914. }
  915. /* dumps the content of the blacklist in a human-readable format */
  916. void dst_blst_view(rpc_t* rpc, void* ctx)
  917. {
  918. int h;
  919. int expires;
  920. struct dst_blst_entry* e;
  921. ticks_t now;
  922. struct ip_addr ip;
  923. if (!cfg_get(core, core_cfg, use_dst_blacklist)){
  924. rpc->fault(ctx, 500, "dst blacklist support disabled");
  925. return;
  926. }
  927. now=get_ticks_raw();
  928. for(h=0; h<DST_BLST_HASH_SIZE; h++) {
  929. LOCK_BLST(h);
  930. for(e=dst_blst_hash[h].first; e; e=e->next) {
  931. expires = (s_ticks_t)(now-e->expire)<=0?
  932. TICKS_TO_S(e->expire-now): -TICKS_TO_S(now-e->expire);
  933. /* don't include expired entries into view report */
  934. if (expires < 0) {
  935. continue;
  936. }
  937. dst_blst_entry2ip(&ip, e);
  938. rpc->rpl_printf(ctx, "{\n protocol: %s", get_proto_name(e->proto));
  939. rpc->rpl_printf(ctx, " ip: %s", ip_addr2a(&ip));
  940. rpc->rpl_printf(ctx, " port: %d", e->port);
  941. rpc->rpl_printf(ctx, " expires in (s): %d", expires);
  942. rpc->rpl_printf(ctx, " flags: %d\n}", e->flags);
  943. }
  944. UNLOCK_BLST(h);
  945. }
  946. }
  947. /* deletes all the entries from the blacklist except the permanent ones
  948. * (which are marked with BLST_PERMANENT)
  949. */
  950. void dst_blst_flush(void)
  951. {
  952. int h;
  953. struct dst_blst_entry* e;
  954. struct dst_blst_entry** crt;
  955. struct dst_blst_entry** tmp;
  956. for(h=0; h<DST_BLST_HASH_SIZE; h++){
  957. LOCK_BLST(h);
  958. for (crt=&dst_blst_hash[h].first, tmp=&(*crt)->next;
  959. *crt; crt=tmp, tmp=&(*crt)->next){
  960. e=*crt;
  961. prefetch_loc_r((*crt)->next, 1);
  962. if (!(e->flags & BLST_PERMANENT)){
  963. *crt=(*crt)->next;
  964. tmp=crt;
  965. *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
  966. blst_destroy_entry(e);
  967. BLST_HASH_STATS_DEC(h);
  968. }
  969. }
  970. UNLOCK_BLST(h);
  971. }
  972. }
  973. /* rpc wrapper function for dst_blst_flush() */
  974. void dst_blst_delete_all(rpc_t* rpc, void* ctx)
  975. {
  976. if (!cfg_get(core, core_cfg, use_dst_blacklist)){
  977. rpc->fault(ctx, 500, "dst blacklist support disabled");
  978. return;
  979. }
  980. dst_blst_flush();
  981. }
  982. /* Adds a new entry to the blacklist */
  983. void dst_blst_add(rpc_t* rpc, void* ctx)
  984. {
  985. str ip;
  986. int port, proto, flags;
  987. unsigned char err_flags;
  988. struct ip_addr *ip_addr;
  989. if (!cfg_get(core, core_cfg, use_dst_blacklist)){
  990. rpc->fault(ctx, 500, "dst blacklist support disabled");
  991. return;
  992. }
  993. if (rpc->scan(ctx, "Sddd", &ip, &port, &proto, &flags) < 4)
  994. return;
  995. err_flags = (unsigned char)flags;
  996. /* sanity checks */
  997. if ((unsigned char)proto > PROTO_SCTP) {
  998. rpc->fault(ctx, 400, "Unknown protocol");
  999. return;
  1000. }
  1001. if (err_flags & BLST_IS_IPV6) {
  1002. /* IPv6 address is specified */
  1003. ip_addr = str2ip6(&ip);
  1004. } else {
  1005. /* try IPv4 first, than IPv6 */
  1006. ip_addr = str2ip(&ip);
  1007. if (!ip_addr) {
  1008. ip_addr = str2ip6(&ip);
  1009. err_flags |= BLST_IS_IPV6;
  1010. }
  1011. }
  1012. if (!ip_addr) {
  1013. rpc->fault(ctx, 400, "Malformed ip address");
  1014. return;
  1015. }
  1016. if (dst_blacklist_add_ip(err_flags, proto, ip_addr, port,
  1017. S_TO_TICKS(cfg_get(core, core_cfg, blst_timeout))))
  1018. rpc->fault(ctx, 400, "Failed to add the entry to the blacklist");
  1019. }
  1020. /* fixup function for use_dst_blacklist
  1021. * verifies that dst_blacklist_init is set to 1
  1022. */
  1023. int use_dst_blacklist_fixup(void *handle, str *gname, str *name, void **val)
  1024. {
  1025. if ((int)(long)(*val) && !dst_blacklist_init) {
  1026. LM_ERR("dst blacklist is turned off by dst_blacklist_init=0, "
  1027. "it cannot be enabled runtime.\n");
  1028. return -1;
  1029. }
  1030. return 0;
  1031. }
  1032. /* KByte to Byte conversion */
  1033. int blst_max_mem_fixup(void *handle, str *gname, str *name, void **val)
  1034. {
  1035. unsigned int u;
  1036. u = ((unsigned int)(long)(*val))<<10;
  1037. (*val) = (void *)(long)u;
  1038. return 0;
  1039. }
  1040. /** re-inint per child blst_proto_ign_mask array. */
  1041. void blst_reinit_ign_masks(str* gname, str* name)
  1042. {
  1043. blst_init_ign_masks();
  1044. }
  1045. #endif /* USE_DST_BLACKLIST */