Coverage Report

Created: 2026-07-30 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/blacklists.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2007 Voice Sistem SRL
3
 *
4
 * This file is part of opensips, a free SIP server.
5
 *
6
 * opensips is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * opensips is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 */
20
21
/*!
22
 * \file
23
 * \brief OpenSIPS Blacklist functions
24
 */
25
26
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include <fnmatch.h>
31
#include <time.h>
32
#include <unistd.h>
33
34
#include "mem/mem.h"
35
#include "mem/shm_mem.h"
36
#include "mi/mi.h"
37
#include "dprint.h"
38
#include "socket_info.h"
39
#include "blacklists.h"
40
#include "context.h"
41
#include "timer.h"
42
#include "ut.h"
43
44
static struct bl_head *blst_heads;
45
static unsigned int bl_default_marker;
46
47
static unsigned int max_heads = 8 * sizeof(int);
48
static unsigned int used_heads;
49
50
static int bl_ctx_idx = -1;
51
52
static void delete_expired_routine(unsigned int ticks, void *param);
53
static mi_response_t *mi_print_blacklists(const mi_params_t *params,
54
                      struct mi_handler *async_hdl);
55
static mi_response_t *mi_check_all_blacklists(const mi_params_t *params,
56
                      struct mi_handler *async_hdl);
57
static mi_response_t *mi_check_blacklist(const mi_params_t *params,
58
                      struct mi_handler *async_hdl);
59
static mi_response_t *mi_add_blacklist_rule(const mi_params_t *params,
60
                      struct mi_handler *async_hdl);
61
static mi_response_t *mi_del_blacklist_rule(const mi_params_t *params,
62
                      struct mi_handler *async_hdl);
63
64
65
static const mi_export_t mi_bl_cmds[] = {
66
  { "list", "lists all the defined (static or learned) blacklists", 0, 0, {
67
    {mi_print_blacklists, {0}},
68
    {mi_print_blacklists, {"name", 0}},
69
    {EMPTY_MI_RECIPE}}, {"list_blacklists", 0}},
70
  { "check_all", "returns all the blacklists where proto:IP:port pattern pair matches", 0, 0, {
71
    {mi_check_all_blacklists, {"ip", 0}},
72
    {mi_check_all_blacklists, {"proto", "ip", 0}},
73
    {mi_check_all_blacklists, {"proto", "ip", "port", 0}},
74
    {mi_check_all_blacklists, {"proto", "ip", "port", "pattern", 0}},
75
    {EMPTY_MI_RECIPE}}, {"check_blacklists", 0}},
76
  { "check", "checks whether an proto:IP:port pattern matches a blacklist", 0, 0, {
77
    {mi_check_blacklist, {"name", "ip", 0}},
78
    {mi_check_blacklist, {"name", "proto", "ip", 0}},
79
    {mi_check_blacklist, {"name", "proto", "ip", "port", 0}},
80
    {mi_check_blacklist, {"name", "proto", "ip", "port", "pattern", 0}},
81
    {EMPTY_MI_RECIPE}}, {"check_blacklist", 0}},
82
  { "add_rule", "adds a new rule to a blacklist", 0, 0, {
83
    {mi_add_blacklist_rule, {"name", "rule", 0}},
84
    {mi_add_blacklist_rule, {"name", "rule", "expire", 0}},
85
    {EMPTY_MI_RECIPE}}, {"add_blacklist_rule", 0}},
86
  { "del_rule", "removes a rule from a blacklist", 0, 0, {
87
    {mi_del_blacklist_rule, {"name", "rule", 0}},
88
    {EMPTY_MI_RECIPE}}, {"del_blacklist_rule", 0}},
89
  {EMPTY_MI_EXPORT}
90
};
91
92
int init_black_lists(void)
93
0
{
94
0
  bl_ctx_idx = context_register_int(CONTEXT_GLOBAL, NULL);
95
0
  if (bl_ctx_idx < 0)
96
0
    return -1;
97
98
  /* register timer routine  */
99
0
  if (register_timer("blcore-expire", delete_expired_routine, 0, 1,
100
0
      TIMER_FLAG_SKIP_ON_DELAY) < 0) {
101
0
    LM_ERR("failed to register timer\n");
102
0
    return -1;
103
0
  }
104
105
  /* register MI commands */
106
0
  if (register_mi_mod("blacklists", mi_bl_cmds) < 0) {
107
0
    LM_ERR("unable to register MI cmds\n");
108
0
    return -1;
109
0
  }
110
111
0
  return 0;
112
0
}
113
114
/*
115
 * get_bl_marker() and store_bl_marker():
116
 *    easy manipulation of the blacklist bitmask stored in global context
117
 */
118
static int get_bl_marker(unsigned int *marker)
119
0
{
120
0
  if (!current_processing_ctx)
121
0
    return -1;
122
123
0
  if (marker)
124
0
    *marker = (unsigned int)context_get_int(
125
0
                       CONTEXT_GLOBAL, current_processing_ctx, bl_ctx_idx);
126
127
0
  return 0;
128
0
}
129
130
#define store_bl_marker(value) \
131
0
  (context_put_int( \
132
0
    CONTEXT_GLOBAL, current_processing_ctx, bl_ctx_idx, value))
133
134
struct bl_head *create_bl_head(const str *owner, int flags, struct bl_rule *head,
135
                      struct bl_rule *tail, str *name)
136
0
{
137
0
  unsigned int i;
138
139
0
  if (!blst_heads) {
140
0
    blst_heads = shm_malloc(max_heads * sizeof *blst_heads);
141
0
    if (!blst_heads) {
142
0
      LM_ERR("no more shared memory!\n");
143
0
      return NULL;
144
0
    }
145
0
    memset(blst_heads, 0, max_heads * sizeof *blst_heads);
146
0
  }
147
0
  i = used_heads;
148
0
  if (i == max_heads) {
149
0
    LM_ERR("too many lists\n");
150
0
    return NULL;
151
0
  }
152
153
0
  if (get_bl_head_by_name(name)) {
154
0
    LM_CRIT("duplicated name!\n");
155
0
    return NULL;
156
0
  }
157
158
0
  if (flags & BL_READONLY_LIST && flags & BL_DO_EXPIRE) {
159
0
    LM_CRIT("RO lists cannot accept EXPIRES!\n");
160
0
    return NULL;
161
0
  }
162
163
  /* copy list name */
164
0
  blst_heads[i].name.s = shm_malloc(name->len + 1);
165
0
  if (!blst_heads[i].name.s) {
166
0
    LM_ERR("no more shm memory!\n");
167
0
    return NULL;
168
0
  }
169
0
  memcpy(blst_heads[i].name.s, name->s, name->len);
170
0
  blst_heads[i].name.s[name->len] = '\0';
171
0
  blst_heads[i].name.len = name->len;
172
173
  /* build lock? */
174
0
  if (!(flags & BL_READONLY_LIST)) {
175
0
    if (!(blst_heads[i].lock = lock_init_rw())) {
176
0
      LM_ERR("failed to create lock!\n");
177
0
      shm_free(blst_heads[i].name.s);
178
0
      return NULL;
179
0
    }
180
0
  }
181
182
0
  used_heads++;
183
184
0
  blst_heads[i].owner = *owner;
185
0
  blst_heads[i].flags = flags;
186
0
  blst_heads[i].first = head;
187
0
  blst_heads[i].last = tail;
188
189
0
  if (flags & BL_BY_DEFAULT)
190
0
    bl_default_marker |= (1 << i);
191
192
0
  return blst_heads + i;
193
0
}
194
195
196
197
void destroy_black_lists(void)
198
0
{
199
0
  unsigned int i;
200
0
  struct bl_rule *p, *q;
201
202
0
  for (i = 0; i < used_heads; i++) {
203
0
    if (blst_heads[i].lock) {
204
0
      lock_destroy(blst_heads[i].lock);
205
0
      lock_dealloc(blst_heads[i].lock);
206
0
    }
207
208
0
    for (p = blst_heads[i].first; p; ) {
209
0
      q = p;
210
0
      p = p->next;
211
0
      shm_free(q);
212
0
    }
213
214
0
    if (blst_heads[i].name.s)
215
0
      shm_free(blst_heads[i].name.s);
216
217
0
    blst_heads[i].first = blst_heads[i].last = NULL;
218
0
  }
219
220
0
  if (blst_heads)
221
0
    shm_free(blst_heads);
222
0
}
223
224
225
226
static inline void delete_expired(struct bl_head *elem, unsigned int ticks)
227
0
{
228
0
  struct bl_rule *p, *q;
229
0
  struct bl_rule *last_no_expire;
230
231
0
  p = q = 0;
232
233
  /* get list for write */
234
0
  lock_start_write(elem->lock);
235
236
0
  if (!elem->first || elem->last->expire_end == 0)
237
0
    goto done;
238
239
0
  for (last_no_expire = 0, p = elem->first;
240
0
      p && p->expire_end == 0;
241
0
      last_no_expire = p, p = p->next);
242
243
  /* p continues from where it as left */
244
0
  for (q = 0; p; q = p, p = p->next)
245
0
    if (p->expire_end > ticks)
246
0
      break;
247
248
0
  if (!q)
249
0
    goto done; /* nothing to remove */
250
251
0
  if (!p) {
252
    /* remove everything */
253
0
    if (last_no_expire) {
254
0
      q = last_no_expire->next;
255
0
      elem->last = last_no_expire;
256
0
      last_no_expire->next = NULL;
257
0
    } else {
258
0
      q = elem->first;
259
0
      elem->first = elem->last = NULL;
260
0
    }
261
0
  } else {
262
    /* remove up to p */
263
0
    q->next = NULL;
264
0
    if (last_no_expire) {
265
0
      q = last_no_expire->next;
266
0
      last_no_expire->next = p;
267
0
    } else {
268
0
      q = elem->first;
269
0
      elem->first = p;
270
0
    }
271
0
  }
272
273
0
done:
274
0
  lock_stop_write(elem->lock);
275
276
0
  for (; q; ) {
277
0
    p = q;
278
0
    q = q->next;
279
0
    shm_free(p);
280
0
  }
281
0
}
282
283
284
285
static void delete_expired_routine(unsigned int ticks, void *param)
286
0
{
287
0
  unsigned int i;
288
289
0
  for (i = 0 ; i < used_heads ; i++)
290
0
    if (blst_heads[i].flags&BL_DO_EXPIRE && blst_heads[i].first)
291
0
        delete_expired(blst_heads + i, ticks);
292
0
}
293
294
295
296
static inline int ip_class_compare(struct net *net1, struct net *net2)
297
0
{
298
0
  unsigned int r;
299
300
0
  if (net1->ip.af == net2->ip.af){
301
    /* ipv4 & ipv6 addresses are all multiples of 4 */
302
0
    for(r=0; r<net1->ip.len/4; r++)
303
0
      if ((net1->ip.u.addr32[r]&net1->mask.u.addr32[r])!=
304
0
           (net2->ip.u.addr32[r]&net2->mask.u.addr32[r]))
305
0
        return 0;
306
0
    return 1;
307
0
  }
308
309
0
  return -1;
310
0
}
311
312
313
/*! \brief adds a new rule to a list of rules */
314
int add_rule_to_list(struct bl_rule **first, struct bl_rule **last,
315
      struct net *ip_net, str *body, unsigned short port,
316
      unsigned short proto, int flags)
317
0
{
318
0
  struct bl_rule *p;
319
0
  struct bl_rule *q;
320
321
0
  if (!first || !last || !ip_net){
322
0
    LM_ERR("wrong input parameter format\n");
323
0
    return -1;
324
0
  }
325
326
0
  if (body && body->len==0)
327
0
    body = 0;
328
329
  /* is it a duplicate? */
330
0
  for (q = *first; q; q = q->next) {
331
0
    if ( (flags==q->flags) && (port==q->port) &&
332
0
      (proto==q->proto) &&
333
0
      (ip_class_compare(ip_net, &q->ip_net)==1) &&
334
0
      ((body==NULL && q->body.s==NULL) || (body && q->body.s &&
335
0
        (body->len==q->body.len) &&
336
0
        !strncmp(body->s,q->body.s,body->len)) )
337
0
      ) {
338
0
        return 1;
339
0
    }
340
0
  }
341
342
  /* alloc memory */
343
0
  p = shm_malloc(sizeof *p + (body?(body->len + 1):0));
344
0
  if (!p) {
345
0
    LM_ERR("no more  shm memory!\n");
346
0
    return -1;
347
0
  }
348
349
  /* fill in the structure */
350
0
  p->flags = flags;
351
0
  p->ip_net = *ip_net;
352
0
  p->proto = proto;
353
0
  p->port = port;
354
0
  if (body) {
355
0
    p->body.s = (char *)(p + 1);
356
0
    memcpy(p->body.s, body->s, body->len);
357
0
    p->body.s[body->len] = '\0';
358
0
    p->body.len = body->len;
359
0
  } else {
360
0
    p->body.s = NULL;
361
0
    p->body.len = 0;
362
0
  }
363
0
  p->next = NULL;
364
0
  p->expire_end = 0;
365
366
  /* link the structure */
367
0
  if (!*first) {
368
0
    *first = *last = p;
369
0
  } else {
370
0
    (*last)->next = p;
371
0
    *last = p;
372
0
  }
373
374
0
  return 0;
375
0
}
376
377
378
static int del_rule_from_list(struct bl_head *head,
379
      struct net *ip_net, str *body, unsigned short port,
380
      unsigned short proto, int flags)
381
0
{
382
0
  struct bl_rule *r, *q;
383
0
  int ret = -1;
384
385
0
  lock_start_write(head->lock);
386
387
0
  for (q = NULL, r = head->first; r; q = r, r = r->next) {
388
0
    if ( (r->flags==flags) && (r->port==port) &&
389
0
      (r->proto==proto) &&
390
0
      (ip_class_compare(&r->ip_net, ip_net)==1) &&
391
0
      ((!r->body.s && !body->s) || ((r->body.len==body->len) &&
392
0
        r->body.s!=NULL && body->s!=NULL &&
393
0
        !strncmp(r->body.s,body->s,body->len)) )
394
0
       ) {
395
0
      if (q) {
396
0
        q->next = r->next;
397
0
      } else {
398
0
        head->first = r->next;
399
0
      }
400
0
      shm_free(r);
401
0
      ret = 0;
402
0
      break;
403
0
    }
404
0
  }
405
0
  lock_stop_write(head->lock);
406
0
  return ret;
407
0
}
408
409
static inline void rm_dups(struct bl_head *head,
410
            struct bl_rule **first, struct bl_rule **last)
411
0
{
412
0
  struct bl_rule *p, *q;
413
0
  struct bl_rule *r;
414
415
0
  for( p=0,q=*first ; q ; ) {
416
0
    for( r=head->first; r ; r = r->next) {
417
0
      if ( (r->flags==q->flags) && (r->port==q->port) &&
418
0
      (r->proto==q->proto) &&
419
0
      (ip_class_compare(&r->ip_net, &q->ip_net)==1) &&
420
0
      ((!r->body.s && !q->body.s) || ((r->body.len==q->body.len) &&
421
0
                r->body.s!=NULL && q->body.s!=NULL &&
422
0
        !strncmp(r->body.s,q->body.s,q->body.len)) )
423
0
      ) {
424
0
        break;
425
0
      }
426
0
    }
427
0
    if (r) {
428
      /* q duplicates r -> free q */
429
0
      if (q->next==NULL) *last=p;
430
0
      if (p) {
431
0
        p->next = q->next;
432
0
        shm_free(q);
433
0
        q = p->next;
434
0
      } else {
435
0
        *first = q->next;
436
0
        shm_free(q);
437
0
        q = *first;
438
0
      }
439
0
    } else {
440
0
      p=q;
441
0
      q=q->next;
442
0
    }
443
0
  }
444
0
}
445
446
447
448
static inline int reload_permanent_list(struct bl_rule *first,
449
          struct bl_rule *last,
450
          struct bl_head *head)
451
0
{
452
0
  struct bl_rule *p, *q;
453
454
  /* get list for write */
455
0
  lock_start_write(head->lock);
456
457
0
  for(p = head->first ; p ; ){
458
0
    q = p;
459
0
    p = p->next;
460
0
    shm_free(q);
461
0
  }
462
463
0
  head->first = first;
464
0
  head->last = last;
465
466
0
  lock_stop_write(head->lock);
467
468
0
  return 0;
469
0
}
470
471
472
473
/* should NOT add ANY DUPLICATES */
474
int add_list_to_head(struct bl_head *head,
475
      struct bl_rule *first, struct bl_rule *last,
476
      int truncate, int expire_limit)
477
0
{
478
0
  struct bl_rule *p;
479
0
  unsigned int expire_end = 0;
480
481
0
  if (!head || !first || !last)
482
0
    return -1;
483
484
  /* may I add to this list? */
485
0
  if (head->flags & BL_READONLY_LIST) {
486
0
    LM_CRIT("list is readonly!!!\n");
487
0
    return -1;
488
0
  }
489
490
0
  LM_DBG("adding to bl %.*s %p,%p\n",
491
0
       head->name.len, head->name.s, first, last);
492
493
  /* for expiring lists, sets the timeout */
494
0
  if (head->flags & BL_DO_EXPIRE) {
495
0
    if (expire_limit!=0) {
496
0
      expire_end = get_ticks() + expire_limit;
497
0
      for (p = first; p; p = p->next)
498
0
        p->expire_end = expire_end;
499
0
    } else {
500
0
      LM_DBG("expire is zero - rule never expires\n");
501
0
    }
502
0
  }
503
504
  /* truncate? -> just do reload */
505
0
  if (truncate)
506
0
    return reload_permanent_list( first, last, head);
507
508
  /* get list for write */
509
0
  lock_start_write(head->lock);
510
511
0
  rm_dups(head, &first, &last);
512
0
  if (!first)
513
0
    goto done;
514
515
  /* the list is built as it follows:
516
   * - rules that do not expire are always first
517
   * - rules that expire are oredered based on their expiration time
518
   */
519
520
0
  if (!head->first) {
521
0
    head->last  = last;
522
0
    head->first = first;
523
0
  } else if (!(head->flags & BL_DO_EXPIRE)) {
524
0
    head->last->next = first;
525
0
    head->last = last;
526
0
  } else if (expire_end == 0) {
527
    /* non-expiry rules are always first */
528
0
    last->next = head->first;
529
0
    head->first = first;
530
0
  } else {
531
    /* find first element with expiration */
532
0
    for (p = head->first;
533
0
      p->next && p->next->expire_end == 0;
534
0
      p = p->next);
535
0
    if (p == head->last || head->last->expire_end <= expire_end) {
536
      /* no expiration rules, add at last */
537
0
      head->last->next = first;
538
0
      head->last = last;
539
0
    } else {
540
0
      for (;; p = p->next)
541
0
        if (p->next->expire_end >= expire_end)
542
0
          break;
543
0
      last->next = p->next;
544
0
      p->next = first;
545
0
    }
546
0
  }
547
548
0
done:
549
0
  lock_stop_write(head->lock);
550
551
0
  return 0;
552
0
}
553
554
555
556
struct bl_head *get_bl_head_by_name(str *name)
557
0
{
558
0
  unsigned int i;
559
560
0
  for (i = 0; i < used_heads; i++)
561
0
    if ((name->len == blst_heads[i].name.len) &&
562
0
        !strncmp(name->s, blst_heads[i].name.s, name->len))
563
0
      return blst_heads + i;
564
565
0
  return NULL;
566
0
}
567
568
569
570
int mark_for_search(struct bl_head *list, unsigned int set)
571
0
{
572
0
  unsigned int n;
573
0
  unsigned int bl_marker;
574
575
0
  if (get_bl_marker(&bl_marker) != 0)
576
0
    return 1;
577
578
  /* is it an "all" operation? */
579
0
  if (!list) {
580
0
    store_bl_marker(set ? (unsigned int)-1 : 0);
581
0
    return 0;
582
0
  }
583
584
0
  n = list - blst_heads;
585
0
  if (list < blst_heads || n >= used_heads)
586
0
    return 1;
587
588
0
  if (set)
589
0
    store_bl_marker(bl_marker | (1 << n));
590
0
  else
591
0
    store_bl_marker(bl_marker & ~(1 << n));
592
593
0
  return 0;
594
0
}
595
596
597
598
/*
599
 * If possible, reset the bitmask stored in the current global context
600
 */
601
void reset_bl_markers(void)
602
0
{
603
0
  if (get_bl_marker(NULL) == 0)
604
0
    store_bl_marker(bl_default_marker);
605
0
}
606
607
static inline int match_bl_rule(struct ip_addr *ip, str *text,
608
            unsigned short port,
609
            unsigned short proto,
610
            struct bl_rule *p)
611
0
{
612
0
  int t_val = (p->port==0 || p->port==port) &&
613
0
    (p->proto==PROTO_NONE || p->proto==proto) &&
614
0
    (matchnet(ip, &(p->ip_net)) == 1) &&
615
0
    (p->body.s==NULL || !fnmatch(p->body.s, text->s, 0));
616
0
  return (!!(p->flags & BLR_APPLY_CONTRARY) ^ !!(t_val));
617
0
}
618
619
620
static inline int check_against_rule_list(struct ip_addr *ip, str *text,
621
            unsigned short port,
622
            unsigned short proto,
623
            int i)
624
0
{
625
0
  struct bl_rule *p;
626
0
  int ret = 0;
627
628
0
  LM_DBG("using list %.*s \n",
629
0
    blst_heads[i].name.len, blst_heads[i].name.s);
630
631
0
  if( !(blst_heads[i].flags&BL_READONLY_LIST) ) {
632
    /* get list for read */
633
0
    lock_start_read(blst_heads[i].lock);
634
0
  }
635
636
0
  for(p = blst_heads[i].first ; p ; p = p->next) {
637
0
    if(match_bl_rule(ip, text, port, proto, p)) {
638
0
      ret = 1;
639
0
      LM_DBG("matched list %.*s \n",
640
0
        blst_heads[i].name.len,blst_heads[i].name.s);
641
0
      break;
642
0
    }
643
0
  }
644
645
0
  if( !(blst_heads[i].flags&BL_READONLY_LIST) )
646
0
    lock_stop_read(blst_heads[i].lock);
647
648
0
  return ret;
649
0
}
650
651
652
653
int check_against_blacklist(struct ip_addr *ip, str *text,
654
      unsigned short port, unsigned short proto)
655
0
{
656
0
  unsigned int i;
657
0
  unsigned int bl_marker;
658
659
  /* no context -> no blacklists at all -> successful check */
660
0
  if (get_bl_marker(&bl_marker) != 0)
661
0
    return 0;
662
663
0
  for (i = 0; i < used_heads; i++)
664
0
    if (bl_marker & (1 << i) &&
665
0
        check_against_rule_list(ip, text, port, proto, i))
666
0
      return 1;
667
668
0
  return 0;
669
0
}
670
671
static int mi_print_blacklist_rule(mi_item_t *rule_item,
672
    struct bl_rule *blr, int expire)
673
0
{
674
0
  char *p;
675
0
  int len;
676
677
0
  if (add_mi_number(rule_item, MI_SSTR("flags"), blr->flags) < 0)
678
0
    return -1;
679
680
0
  p = ip_addr2a(&blr->ip_net.ip);
681
0
  len = p?strlen(p):0;
682
0
  if (add_mi_string(rule_item, MI_SSTR("IP"), p, len) < 0)
683
0
    return -1;
684
685
0
  p = ip_addr2a(&blr->ip_net.mask);
686
0
  len = p?strlen(p):0;
687
0
  if (add_mi_string(rule_item, MI_SSTR("Mask"), p, len) < 0)
688
0
    return -1;
689
690
0
  if (blr->proto == PROTO_NONE)
691
0
    p = "any";
692
0
  else
693
0
    p = proto2a(blr->proto);
694
0
  len = strlen(p);
695
0
  if (add_mi_string(rule_item, MI_SSTR("Proto"), p, len) < 0)
696
0
    return -1;
697
698
0
  if (add_mi_number(rule_item, MI_SSTR("Port"), blr->port) < 0)
699
0
    return -1;
700
701
0
  if (blr->body.s) {
702
0
    if (add_mi_string(rule_item, MI_SSTR("Match"),
703
0
        blr->body.s, blr->body.len) < 0)
704
0
      return -1;
705
0
  }
706
707
0
  if (expire && blr->expire_end && add_mi_number(rule_item,
708
0
      MI_SSTR("Expire"), (blr->expire_end - get_ticks())) < 0)
709
0
    return -1;
710
0
  return 0;
711
0
}
712
713
static int mi_print_blacklist_head(mi_item_t *list_item, struct bl_head *head)
714
0
{
715
0
  int ret = -1;
716
0
  struct bl_rule *blr;
717
0
  mi_item_t *rules_arr, *rule_item, *flags_arr;
718
719
0
  if (!(head->flags&BL_READONLY_LIST) )
720
0
    lock_start_read(head->lock);
721
722
0
  if (add_mi_string(list_item, MI_SSTR("name"),
723
0
      head->name.s, head->name.len) < 0)
724
0
    goto end;
725
726
0
  if (add_mi_string(list_item, MI_SSTR("owner"),
727
0
      head->owner.s, head->owner.len) < 0)
728
0
    goto end;
729
730
0
  flags_arr = add_mi_array(list_item, MI_SSTR("flags"));
731
0
  if (!flags_arr)
732
0
    goto end;
733
0
  if (head->flags & BL_READONLY_LIST &&
734
0
      add_mi_string(flags_arr, NULL, 0, MI_SSTR("read-only")) < 0)
735
0
    goto end;
736
0
  if (head->flags & BL_DO_EXPIRE &&
737
0
      add_mi_string(flags_arr, NULL, 0, MI_SSTR("expire")) < 0)
738
0
    goto end;
739
0
  if (head->flags & BL_BY_DEFAULT &&
740
0
      add_mi_string(flags_arr, NULL, 0, MI_SSTR("default")) < 0)
741
0
    goto end;
742
743
0
  rules_arr = add_mi_array(list_item, MI_SSTR("Rules"));
744
0
  if (!rules_arr)
745
0
    goto end;
746
747
0
  for (blr = head->first; blr; blr = blr->next) {
748
0
    rule_item = add_mi_object(rules_arr, NULL, 0);
749
0
    if (!rule_item)
750
0
      goto end;
751
752
0
    if (mi_print_blacklist_rule(rule_item, blr,
753
0
        head->flags&BL_DO_EXPIRE) < 0)
754
0
      goto end;
755
0
  }
756
757
0
  ret = 0;
758
0
end:
759
0
  if (!(head->flags&BL_READONLY_LIST) )
760
0
    lock_stop_read(head->lock);
761
0
  return ret;
762
0
}
763
764
static mi_response_t *mi_print_blacklists(const mi_params_t *params,
765
  struct mi_handler *async_hdl)
766
0
{
767
0
  mi_response_t *resp;
768
0
  mi_item_t *resp_obj;
769
0
  mi_item_t *lists_arr, *list_item;
770
0
  struct bl_head *head;
771
0
  unsigned int i;
772
0
  str name;
773
774
0
  switch (try_get_mi_string_param(params, "name", &name.s, &name.len)) {
775
0
    case -1:
776
0
      head = NULL;
777
0
      break;
778
0
    case 0:
779
0
      head = get_bl_head_by_name(&name);
780
0
      if (!head)
781
0
        return init_mi_error(404, MI_SSTR("Unknown name"));
782
0
      break;
783
0
    default:
784
0
      return NULL;
785
0
  }
786
787
0
  resp = init_mi_result_object(&resp_obj);
788
0
  if (!resp)
789
0
    return 0;
790
791
0
  if (head) {
792
    /* already have a head, print only it */
793
0
    if(mi_print_blacklist_head(resp_obj, head) < 0)
794
0
      goto error;
795
0
    return resp;
796
0
  }
797
798
0
  lists_arr = add_mi_array(resp_obj, MI_SSTR("Lists"));
799
0
  if (!lists_arr)
800
0
    goto error;
801
802
0
  for (i=0; i<used_heads; i++ ) {
803
0
    list_item = add_mi_object(lists_arr, NULL, 0);
804
0
    if (!list_item)
805
0
      goto error;
806
807
0
    if (mi_print_blacklist_head(list_item, &blst_heads[i]) < 0)
808
0
      goto error;
809
0
  }
810
811
0
  return resp;
812
813
0
error:
814
815
0
  free_mi_response(resp);
816
0
  return NULL;
817
0
}
818
819
static struct bl_head *mi_bl_get_head(const mi_params_t *params)
820
0
{
821
0
  str name;
822
823
0
  if (get_mi_string_param(params, "name", &name.s, &name.len) < 0)
824
0
    return NULL;
825
0
  return get_bl_head_by_name(&name);
826
0
}
827
828
static struct ip_addr *mi_bl_get_ip(const mi_params_t *params)
829
0
{
830
0
  str ip;
831
832
0
  if (get_mi_string_param(params, "ip", &ip.s, &ip.len) < 0)
833
0
    return NULL;
834
0
  return str2ip(&ip);
835
0
}
836
837
static int mi_bl_get_extra(const mi_params_t *params,
838
    unsigned short *proto, unsigned short *port, str *text)
839
0
{
840
0
  str proto_str;
841
0
  int tmp;
842
843
0
  switch (try_get_mi_string_param(params, "proto", &proto_str.s, &proto_str.len)) {
844
0
    case -1:
845
0
      *proto = PROTO_NONE;
846
0
      break;
847
0
    case 0:
848
0
      if (parse_proto((unsigned char *)proto_str.s,
849
0
          proto_str.len, &tmp) < 0) {
850
0
        LM_ERR("could not parse protocol %.*s\n",
851
0
            proto_str.len, proto_str.s);
852
0
        return -1;
853
0
      }
854
0
      *proto = tmp;
855
0
      break;
856
0
    default:
857
0
      return -1;
858
0
  }
859
0
  switch (try_get_mi_int_param(params, "port", &tmp)) {
860
0
    case -1:
861
0
      *port = 0;
862
0
      break;
863
0
    case 0:
864
0
      *port = tmp;
865
0
      break;
866
0
    default:
867
0
      return -1;
868
0
  }
869
0
  switch (try_get_mi_string_param(params, "pattern", &text->s, &text->len)) {
870
0
    case -1:
871
0
      text->s = NULL;
872
0
      text->len = 0;
873
0
      break;
874
0
    case 0:
875
0
      break;
876
0
    default:
877
0
      return -1;
878
0
  }
879
0
  return 0;
880
0
}
881
882
static int parse_ip_net(char *in, int len, struct net *ipnet)
883
0
{
884
0
  char *p = NULL;
885
0
  str ip_s, mask_s;
886
0
  struct ip_addr ip, *mask = NULL, *ip_tmp;
887
0
  struct net *ipnet_tmp;
888
0
  int af;
889
0
  unsigned int bitlen;
890
891
0
  p = q_memchr(in, '.', len);
892
0
  if (p)
893
0
    af = AF_INET;
894
0
  else if (q_memchr(in, ':', len)) {
895
0
    af = AF_INET6;
896
0
  } else {
897
0
    LM_ERR("Not an IP");
898
0
    return -1;
899
0
  }
900
901
0
  p = q_memchr(in, '/', len);
902
0
  if (p) {
903
0
    ip_s.s = in;
904
0
    ip_s.len = p - in;
905
0
  } else {
906
0
    ip_s.s = in;
907
0
    ip_s.len = len;
908
0
  }
909
910
0
  ip_tmp = (af == AF_INET) ? str2ip(&ip_s) : str2ip6(&ip_s);
911
0
  if (!ip_tmp) {
912
0
    LM_ERR("Invalid IP address\n");
913
0
    return -1;
914
0
  }
915
916
  /* save the IP */
917
0
  ip = *ip_tmp;
918
919
0
  if (p) {
920
0
    mask_s.s = p + 1;
921
0
    mask_s.len = len - ip_s.len - 1;
922
0
    if (!mask_s.s || mask_s.len == 0) {
923
0
      LM_ERR("Empty netmask\n");
924
0
      return -1;
925
0
    }
926
0
    if ((p = (af == AF_INET)?
927
0
      q_memchr(p, '.', len-(p-in)+1):
928
0
      q_memchr(p, ':', len-(p-in)+1)) != NULL) {
929
      /* has net */
930
0
      mask = (af == AF_INET) ? str2ip(&mask_s) : str2ip6(&mask_s);
931
0
      if (!mask) {
932
0
        LM_ERR("Invalid netmask\n");
933
0
        return -1;
934
0
      }
935
0
      ipnet_tmp = mk_net(&ip, mask);
936
0
    } else {
937
0
      if (str2int(&mask_s, &bitlen) < 0) {
938
0
        LM_ERR("Invalid netmask bitlen\n");
939
0
        return -1;
940
0
      }
941
942
0
      ipnet_tmp = mk_net_bitlen(&ip, bitlen);
943
0
    }
944
0
  } else {
945
0
    ipnet_tmp = mk_net_bitlen(&ip, ip.len*8);
946
0
  }
947
948
0
  *ipnet = *ipnet_tmp;
949
0
  pkg_free(ipnet_tmp);
950
951
0
  return 0;
952
0
}
953
954
static int mi_bl_get_rule(const mi_params_t *params,
955
    struct net *ip_net, unsigned short *proto,
956
    unsigned short *port, str *text, int *flags)
957
0
{
958
0
  str rule, token;
959
0
  char *p;
960
0
  int tmp;
961
962
0
  *proto = PROTO_NONE;
963
0
  *port = 0;
964
0
  text->s = NULL;
965
0
  text->len = 0;
966
0
  *flags = 0;
967
968
0
  if (get_mi_string_param(params, "rule", &rule.s, &rule.len) < 0) {
969
0
    LM_INFO("command does not contain a rule\n");
970
0
    return -1;
971
0
  }
972
0
  trim_leading(&rule);
973
0
  if (rule.len > 0 && rule.s[0] == '!') {
974
0
    rule.s++;
975
0
    rule.len--;
976
0
    *flags = BLR_APPLY_CONTRARY;
977
0
  }
978
  /* first token should always be ip or net*/
979
0
  p = q_memchr(rule.s, ',', rule.len);
980
0
  token.s = rule.s;
981
0
  token.len = (p? (p - rule.s): rule.len);
982
0
  rule.s += token.len + 1;
983
0
  rule.len -= token.len + 1;
984
0
  if (str_casematch_nt(&token, "any")) {
985
0
    *proto = PROTO_NONE;
986
0
  } else if (parse_proto((unsigned char *)token.s, token.len, &tmp) >= 0) {
987
    /* valid proto */
988
0
    *proto = tmp;
989
990
    /* advance to next token */
991
0
    p = q_memchr(rule.s, ',', rule.len);
992
0
    token.s = rule.s;
993
0
    token.len = (p? (p - rule.s): rule.len);
994
0
    rule.s += token.len + 1;
995
0
    rule.len -= token.len + 1;
996
0
  }
997
0
  if (parse_ip_net(token.s, token.len, ip_net) < 0)
998
0
    return -1;
999
0
  if (rule.len <= 0)
1000
0
    return 0;
1001
1002
0
  p = q_memchr(rule.s, ',', rule.len);
1003
0
  token.s = rule.s;
1004
0
  token.len = (p? (p - rule.s): rule.len);
1005
1006
1007
  /* we should have a port here */
1008
0
  if (str2int(&token, (unsigned int *)&tmp) < 0) {
1009
0
    LM_INFO("invalid port %.*s\n", token.len, token.s);
1010
0
    return -1;
1011
0
  }
1012
0
  *port = tmp;
1013
0
  text->s = rule.s + token.len + 1;
1014
0
  text->len = rule.len - token.len - 1;
1015
0
  if (text->len <= 0) {
1016
0
    text->s = NULL;
1017
0
    text->len = 0;
1018
0
  }
1019
1020
1021
0
  return 0;
1022
0
}
1023
1024
1025
static mi_response_t *mi_check_all_blacklists(const mi_params_t *params,
1026
    struct mi_handler *async_hdl)
1027
0
{
1028
0
  mi_response_t *resp;
1029
0
  mi_item_t *resp_arr;
1030
0
  unsigned short proto, port;
1031
0
  struct ip_addr *ip;
1032
0
  str text, text_nt;
1033
0
  unsigned int i;
1034
1035
0
  ip = mi_bl_get_ip(params);
1036
0
  if (!ip)
1037
0
    return init_mi_error(400, MI_SSTR("Missing or bad IP"));
1038
1039
0
  if (mi_bl_get_extra(params, &proto, &port, &text) < 0)
1040
0
    return init_mi_error(404, MI_SSTR("Bad params"));
1041
1042
0
  resp = init_mi_result_array(&resp_arr);
1043
0
  if (!resp)
1044
0
    return NULL;
1045
1046
  /* if there is a text, duplicate it to obtain NULL-terminated */
1047
0
  if (text.len) {
1048
0
    if (pkg_nt_str_dup(&text_nt, &text) < 0) {
1049
0
      free_mi_response(resp);
1050
0
      return NULL;
1051
0
    }
1052
0
  } else {
1053
0
    text_nt.s = "";
1054
0
    text_nt.len = 0;
1055
0
  }
1056
1057
0
  for (i = 0; i < used_heads; i++) {
1058
0
    if (!check_against_rule_list(ip, &text_nt, port, proto, i))
1059
0
      continue;
1060
0
    if (add_mi_string(resp_arr, NULL, 0, blst_heads[i].name.s,
1061
0
        blst_heads[i].name.len) < 0) {
1062
0
      LM_ERR("cannot add blacklist %.*s\n",
1063
0
          blst_heads[i].name.len, blst_heads[i].name.s);
1064
0
      free_mi_response(resp);
1065
0
      resp = NULL;
1066
0
      goto end;
1067
0
    }
1068
0
  }
1069
1070
0
end:
1071
0
  if (text.len)
1072
0
    pkg_free(text_nt.s);
1073
0
  return resp;
1074
0
}
1075
1076
static mi_response_t *mi_check_blacklist(const mi_params_t *params,
1077
    struct mi_handler *async_hdl)
1078
0
{
1079
0
  static mi_response_t *resp;
1080
0
  unsigned short proto, port;
1081
0
  mi_item_t *obj;
1082
0
  struct bl_head *head;
1083
0
  struct bl_rule *p;
1084
0
  struct ip_addr *ip;
1085
0
  str text, text_nt;
1086
1087
0
  ip = mi_bl_get_ip(params);
1088
0
  if (!ip)
1089
0
    return init_mi_error(400, MI_SSTR("Missing or bad IP"));
1090
1091
0
  head = mi_bl_get_head(params);
1092
0
  if (!head)
1093
0
    return init_mi_error(400, MI_SSTR("Missing or bad blacklist name"));
1094
1095
0
  if (mi_bl_get_extra(params, &proto, &port, &text) < 0)
1096
0
    return init_mi_error(404, MI_SSTR("Bad params"));
1097
1098
  /* if there is a text, duplicate it to obtain NULL-terminated */
1099
0
  if (text.len) {
1100
0
    if (pkg_nt_str_dup(&text_nt, &text) < 0)
1101
0
      return NULL;
1102
0
  } else {
1103
0
    text_nt.s = "";
1104
0
    text_nt.len = 0;
1105
0
  }
1106
1107
0
  if (!(head->flags&BL_READONLY_LIST))
1108
0
    lock_start_read(head->lock);
1109
1110
0
  for(p = head->first; p; p = p->next)
1111
0
    if(match_bl_rule(ip, &text_nt, port, proto, p))
1112
0
      break;
1113
1114
0
  if (text.len)
1115
0
    pkg_free(text_nt.s);
1116
1117
0
  if (p) {
1118
0
    resp = init_mi_result_object(&obj);
1119
0
    if (resp && mi_print_blacklist_rule(obj, p, head->flags&BL_DO_EXPIRE) < 0) {
1120
0
      free_mi_response(resp);
1121
0
      resp = NULL;
1122
0
    }
1123
1124
0
  } else {
1125
0
    resp = init_mi_error(404, MI_SSTR("Not Matched"));
1126
0
  }
1127
0
  if (!(head->flags&BL_READONLY_LIST))
1128
0
    lock_stop_read(head->lock);
1129
0
  return resp;
1130
0
}
1131
1132
static mi_response_t *mi_add_blacklist_rule(const mi_params_t *params,
1133
                      struct mi_handler *async_hdl)
1134
0
{
1135
0
  struct bl_head *head;
1136
0
  struct bl_rule *list = NULL;
1137
0
  struct net ip_net;
1138
0
  unsigned short proto, port;
1139
0
  int expire, flags;
1140
0
  str text;
1141
1142
0
  head = mi_bl_get_head(params);
1143
0
  if (!head)
1144
0
    return init_mi_error(400, MI_SSTR("Missing or bad blacklist name"));
1145
  /* if a read-only list, we cannot modify */
1146
0
  if (head->flags & BL_READONLY_LIST)
1147
0
    return init_mi_error(403, MI_SSTR("Cannot modify read-only blacklist"));
1148
1149
0
  if (mi_bl_get_rule(params, &ip_net, &proto, &port, &text, &flags) < 0)
1150
0
    return init_mi_error(404, MI_SSTR("Bad rule"));
1151
1152
0
  switch (try_get_mi_int_param(params, "expire", &expire)) {
1153
0
    case -1:
1154
0
      expire = 0;
1155
0
      break;
1156
0
    case 0:
1157
0
      if (expire <= 0)
1158
0
        return init_mi_error(404, MI_SSTR("Bad expire value"));
1159
0
      if (!(head->flags & BL_DO_EXPIRE))
1160
0
        return init_mi_error(404, MI_SSTR("Blacklist without expire support"));
1161
0
      break;
1162
0
    default:
1163
0
      return NULL;
1164
0
  }
1165
0
  if (add_rule_to_list(&list, &list, &ip_net, &text, port, proto, flags) != 0) {
1166
0
    LM_ERR("cannot build blacklist rule!\n");
1167
0
    return NULL;
1168
0
  }
1169
0
  if (add_list_to_head(head, list, list, 0, expire) < 0) {
1170
0
    LM_ERR("cannot add blacklist rule!\n");
1171
0
    return NULL;
1172
0
  }
1173
0
  return init_mi_result_ok();
1174
0
}
1175
1176
static mi_response_t *mi_del_blacklist_rule(const mi_params_t *params,
1177
                      struct mi_handler *async_hdl)
1178
0
{
1179
0
  struct bl_head *head;
1180
0
  unsigned short proto, port;
1181
0
  struct net ip_net;
1182
0
  str text;
1183
0
  int flags;
1184
1185
0
  head = mi_bl_get_head(params);
1186
0
  if (!head)
1187
0
    return init_mi_error(400, MI_SSTR("Missing or bad blacklist name"));
1188
  /* if a read-only list, we cannot modify */
1189
0
  if (head->flags & BL_READONLY_LIST)
1190
0
    return init_mi_error(403, MI_SSTR("Cannot modify read-only blacklist"));
1191
1192
0
  if (mi_bl_get_rule(params, &ip_net, &proto, &port, &text, &flags) < 0)
1193
0
    return init_mi_error(404, MI_SSTR("Bad rule"));
1194
1195
0
  if (del_rule_from_list(head, &ip_net, &text, port, proto, flags) != 0)
1196
0
    return init_mi_error(404, MI_SSTR("Rule not found"));
1197
1198
0
  return init_mi_result_ok();
1199
0
}
1200
1201
int w_check_blacklist(struct sip_msg *msg, struct bl_head *head,
1202
    struct ip_addr *ip, int *_port, unsigned short _proto, str *_pattern)
1203
0
{
1204
0
  int ret, idx;
1205
0
  unsigned short port = (_port?*_port:0);
1206
1207
0
  if (head) {
1208
    /* we need to check against a specific list */
1209
0
    idx = head - blst_heads;
1210
0
    ret = check_against_rule_list(ip, _pattern, port, _proto, idx);
1211
0
  } else {
1212
    /* if we do not have a head, we check against all enabled */
1213
0
    ret = check_against_blacklist(ip, _pattern, port, _proto);
1214
0
  }
1215
0
  return ret ?1:-1;
1216
0
}
1217
1218
int fixup_blacklist_proto(void** param)
1219
0
{
1220
0
  int proto = PROTO_NONE;
1221
0
  str *s = (str*)*param;
1222
0
  if (s && parse_proto((unsigned char *)s->s, s->len, &proto) < 0)
1223
0
    return E_BAD_PROTO;
1224
1225
0
  *param = (void *)(unsigned long)proto;
1226
0
  return 0;
1227
0
}
1228
1229
int fixup_blacklist_net(void** param)
1230
0
{
1231
0
  str *s = (str*)*param;
1232
0
  str tmp = *s;
1233
0
  struct bl_net_flags *nf = pkg_malloc(sizeof *nf);
1234
0
  if (!nf)
1235
0
    return E_OUT_OF_MEM;
1236
0
  memset(nf, 0, sizeof *nf);
1237
0
  trim(&tmp);
1238
0
  if (tmp.s[0] == '!') {
1239
0
    nf->flags = BLR_APPLY_CONTRARY;
1240
0
    tmp.s++;
1241
0
    tmp.len--;
1242
0
    trim(&tmp);
1243
0
  }
1244
1245
0
  if (parse_ip_net(tmp.s, tmp.len, &nf->ipnet) < 0) {
1246
0
    pkg_free(nf);
1247
0
    return E_BAD_ADDRESS;
1248
0
  }
1249
0
  *param = nf;
1250
0
  return 0;
1251
0
}
1252
1253
int fixup_blacklist_net_free(void** param)
1254
0
{
1255
0
  pkg_free(*param);
1256
0
  return 0;
1257
0
}
1258
1259
int w_add_blacklist_rule(struct sip_msg *msg, struct bl_head *head,
1260
    struct bl_net_flags *nf, int *_port, unsigned short _proto,
1261
    str *_pattern, int *_exp)
1262
0
{
1263
0
  struct bl_rule *list = NULL;
1264
0
  unsigned short port = (_port?*_port:0);
1265
1266
0
  if (head->flags & BL_READONLY_LIST) {
1267
0
    LM_ERR("cannot modify read-only blacklist!\n");
1268
0
    return -1;
1269
0
  }
1270
1271
0
  if (_exp && *_exp && !(head->flags & BL_DO_EXPIRE)) {
1272
0
    LM_ERR("blacklist does not support expiring rules!\n");
1273
0
    return -1;
1274
0
  }
1275
1276
0
  if (add_rule_to_list(&list, &list, &nf->ipnet, _pattern,
1277
0
      port, _proto, nf->flags) != 0) {
1278
0
    LM_ERR("cannot build blacklist rule!\n");
1279
0
    return -1;
1280
0
  }
1281
0
  if (add_list_to_head(head, list, list, 0, (_exp?*_exp:0)) < 0) {
1282
0
    LM_ERR("cannot add blacklist rule!\n");
1283
0
    return -1;
1284
0
  }
1285
0
  return 1;
1286
0
}
1287
1288
int w_del_blacklist_rule(struct sip_msg *msg, struct bl_head *head,
1289
    struct bl_net_flags *nf, int *_port, unsigned short _proto,
1290
    str *_pattern)
1291
0
{
1292
0
  unsigned short port = (_port?*_port:0);
1293
1294
0
  if (head->flags & BL_READONLY_LIST) {
1295
0
    LM_ERR("cannot modify read-only blacklist!\n");
1296
0
    return -1;
1297
0
  }
1298
0
  if (del_rule_from_list(head, &nf->ipnet,
1299
0
      _pattern, port, _proto, nf->flags) != 0)
1300
0
    return -1;
1301
0
  return 1;
1302
0
}