72ebc415fe0b277f50b889533614948f22f243d8
[sip-router] / modules_k / permissions / hash.c
1 /*
2  * Hash functions for cached trusted and address tables
3  *
4  * Copyright (C) 2003-2012 Juha Heinanen
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License 
19  * along with this program; if not, write to the Free Software 
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <sys/types.h>
24 #include <regex.h>
25 #include "../../mem/shm_mem.h"
26 #include "../../parser/parse_from.h"
27 #include "../../ut.h"
28 #include "../../hashes.h"
29 #include "../../usr_avp.h"
30 #include "../../ip_addr.h"
31 #include "../../pvar.h"
32 #include "hash.h"
33 #include "trusted.h"
34 #include "address.h"
35
36 #define perm_hash(_s)  core_hash( &(_s), 0, PERM_HASH_SIZE)
37
38
39 /* tag AVP specs */
40 static int     tag_avp_type;
41 static int_str tag_avp;
42
43 extern int peer_tag_mode;
44
45
46
47 /*
48  * Parse and set tag AVP specs
49  */
50 int init_tag_avp(str *tag_avp_param)
51 {
52         pv_spec_t avp_spec;
53         unsigned short avp_flags;
54
55         if (tag_avp_param->s && tag_avp_param->len > 0) {
56                 if (pv_parse_spec(tag_avp_param, &avp_spec)==0
57                                 || avp_spec.type != PVT_AVP) {
58                         LM_ERR("malformed or non "
59                                         "AVP %.*s peer_tag_avp definition\n", tag_avp_param->len, tag_avp_param->s);
60                         return -1;
61                 }
62                 if(pv_get_avp_name(0, &avp_spec.pvp, &tag_avp, &avp_flags)!=0) {
63                         LM_ERR("[%.*s]- invalid "
64                                         "peer_tag_avp AVP definition\n", tag_avp_param->len, tag_avp_param->s);
65                         return -1;
66                 }
67                 tag_avp_type = avp_flags;
68         } else {
69                 tag_avp.n = 0;
70         }
71         return 0;
72 }
73
74
75 /*
76  * Gets tag avp specs
77  */
78 void get_tag_avp(int_str *tag_avp_p, int *tag_avp_type_p)
79 {
80         *tag_avp_p = tag_avp;
81         *tag_avp_type_p = tag_avp_type;
82 }
83
84
85 /*
86  * Create and initialize a hash table
87  */
88 struct trusted_list** new_hash_table(void)
89 {
90         struct trusted_list** ptr;
91
92         /* Initializing hash tables and hash table variable */
93         ptr = (struct trusted_list **)shm_malloc
94                 (sizeof(struct trusted_list*) * PERM_HASH_SIZE);
95         if (!ptr) {
96                 LM_ERR("no shm memory for hash table\n");
97                 return 0;
98         }
99
100         memset(ptr, 0, sizeof(struct trusted_list*) * PERM_HASH_SIZE);
101         return ptr;
102 }
103
104
105 /*
106  * Release all memory allocated for a hash table
107  */
108 void free_hash_table(struct trusted_list** table)
109 {
110         if (!table)
111                 return;
112
113         empty_hash_table(table);
114         shm_free(table);
115 }
116
117
118 /* 
119  * Add <src_ip, proto, pattern, tag> into hash table, where proto is integer
120  * representation of string argument proto.
121  */
122 int hash_table_insert(struct trusted_list** table, char* src_ip, 
123                 char* proto, char* pattern, char* tag)
124 {
125         struct trusted_list *np;
126         unsigned int hash_val;
127
128         np = (struct trusted_list *) shm_malloc(sizeof(*np));
129         if (np == NULL) {
130                 LM_ERR("cannot allocate shm memory for table entry\n");
131                 return -1;
132         }
133
134         if (strcasecmp(proto, "any") == 0) {
135                 np->proto = PROTO_NONE;
136         } else if (strcasecmp(proto, "udp") == 0) {
137                 np->proto = PROTO_UDP;
138         } else if (strcasecmp(proto, "tcp") == 0) {
139                 np->proto = PROTO_TCP;
140         } else if (strcasecmp(proto, "tls") == 0) {
141                 np->proto = PROTO_TLS;
142         } else if (strcasecmp(proto, "sctp") == 0) {
143                 np->proto = PROTO_SCTP;
144         } else if (strcasecmp(proto, "none") == 0) {
145                 shm_free(np);
146                 return 1;
147         } else {
148                 LM_CRIT("unknown protocol\n");
149                 shm_free(np);
150                 return -1;
151         }
152
153         np->src_ip.len = strlen(src_ip);
154         np->src_ip.s = (char *) shm_malloc(np->src_ip.len);
155
156         if (np->src_ip.s == NULL) {
157                 LM_CRIT("cannot allocate shm memory for src_ip string\n");
158                 shm_free(np);
159                 return -1;
160         }
161
162         (void) strncpy(np->src_ip.s, src_ip, np->src_ip.len);
163
164         if (pattern) {
165                 np->pattern = (char *) shm_malloc(strlen(pattern)+1);
166                 if (np->pattern == NULL) {
167                         LM_CRIT("cannot allocate shm memory for pattern string\n");
168                         shm_free(np->src_ip.s);
169                         shm_free(np);
170                         return -1;
171                 }
172                 (void) strcpy(np->pattern, pattern);
173         } else {
174                 np->pattern = 0;
175         }
176
177         if (tag) {
178                 np->tag.len = strlen(tag);
179                 np->tag.s = (char *) shm_malloc((np->tag.len) + 1);
180                 if (np->tag.s == NULL) {
181                         LM_CRIT("cannot allocate shm memory for pattern string\n");
182                         shm_free(np->src_ip.s);
183                         shm_free(np->pattern);
184                         shm_free(np);
185                         return -1;
186                 }
187                 (void) strcpy(np->tag.s, tag);
188         } else {
189                 np->tag.len = 0;
190                 np->tag.s = 0;
191         }
192
193         hash_val = perm_hash(np->src_ip);
194         np->next = table[hash_val];
195         table[hash_val] = np;
196
197         return 1;
198 }
199
200
201 /* 
202  * Check if an entry exists in hash table that has given src_ip and protocol
203  * value and pattern that matches to From URI.  If an entry exists and tag_avp
204  * has been defined, tag of the entry is added as a value to tag_avp.
205  * Returns number of matches or -1 if none matched.
206  */
207 int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
208                 char *src_ip_c_str, int proto)
209 {
210         str uri;
211         char uri_string[MAX_URI_SIZE + 1];
212         regex_t preg;
213         struct trusted_list *np;
214         str src_ip;
215         int_str val;
216         int count = 0;
217
218         src_ip.s = src_ip_c_str;
219         src_ip.len = strlen(src_ip.s);
220
221         if (IS_SIP(msg))
222         {
223                 if (parse_from_header(msg) < 0) return -1;
224                 uri = get_from(msg)->uri;
225                 if (uri.len > MAX_URI_SIZE) {
226                         LM_ERR("from URI too large\n");
227                         return -1;
228                 }
229                 memcpy(uri_string, uri.s, uri.len);
230                 uri_string[uri.len] = (char)0;
231         }
232
233         for (np = table[perm_hash(src_ip)]; np != NULL; np = np->next) {
234             if ((np->src_ip.len == src_ip.len) && 
235                 (strncmp(np->src_ip.s, src_ip.s, src_ip.len) == 0) &&
236                 ((np->proto == PROTO_NONE) || (proto == PROTO_NONE) ||
237                  (np->proto == proto))) {
238                 if (np->pattern && IS_SIP(msg)) {
239                     if (regcomp(&preg, np->pattern, REG_NOSUB)) {
240                         LM_ERR("invalid regular expression\n");
241                         continue;
242                     }
243                     if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
244                         regfree(&preg);
245                         continue;
246                     }
247                     regfree(&preg);
248                 }
249                 /* Found a match */
250                 if (tag_avp.n && np->tag.s) {
251                     val.s = np->tag;
252                     if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) {
253                         LM_ERR("setting of tag_avp failed\n");
254                         return -1;
255                     }
256                 }
257                 if (!peer_tag_mode)
258                     return 1;
259                 count++;
260             }
261         }
262         if (!count)
263             return -1;
264         else 
265             return count;
266 }
267
268
269 /* 
270  * Print trusted entries stored in hash table 
271  */
272 int hash_table_mi_print(struct trusted_list** table, struct mi_node* rpl)
273 {
274         int i;
275         struct trusted_list *np;
276
277         for (i = 0; i < PERM_HASH_SIZE; i++) {
278                 np = table[i];
279                 while (np) {
280                         if (addf_mi_node_child(rpl, 0, 0, 0,
281                                                 "%4d <%.*s, %d, %s, %s>",
282                                                 i,
283                                                 np->src_ip.len, ZSW(np->src_ip.s),
284                                                 np->proto,
285                                                 np->pattern?np->pattern:"NULL",
286                                                 np->tag.len?np->tag.s:"NULL") == 0) {
287                                 return -1;
288                         }
289                         np = np->next;
290                 }
291         }
292         return 0;
293 }
294
295
296 /* 
297  * Free contents of hash table, it doesn't destroy the
298  * hash table itself
299  */
300 void empty_hash_table(struct trusted_list **table)
301 {
302         int i;
303         struct trusted_list *np, *next;
304
305         for (i = 0; i < PERM_HASH_SIZE; i++) {
306                 np = table[i];
307                 while (np) {
308                         if (np->src_ip.s) shm_free(np->src_ip.s);
309                         if (np->pattern) shm_free(np->pattern);
310                         if (np->tag.s) shm_free(np->tag.s);
311                         next = np->next;
312                         shm_free(np);
313                         np = next;
314                 }
315                 table[i] = 0;
316         }
317 }
318
319
320 /*
321  * Create and initialize an address hash table
322  */
323 struct addr_list** new_addr_hash_table(void)
324 {
325         struct addr_list** ptr;
326
327         /* Initializing hash tables and hash table variable */
328         ptr = (struct addr_list **)shm_malloc
329                 (sizeof(struct addr_list*) * PERM_HASH_SIZE);
330         if (!ptr) {
331                 LM_ERR("no shm memory for hash table\n");
332                 return 0;
333         }
334
335         memset(ptr, 0, sizeof(struct addr_list*) * PERM_HASH_SIZE);
336         return ptr;
337 }
338
339
340 /*
341  * Release all memory allocated for a hash table
342  */
343 void free_addr_hash_table(struct addr_list** table)
344 {
345         if (!table)
346                 return;
347
348         empty_addr_hash_table(table);
349         shm_free(table);
350 }
351
352
353 /* 
354  * Add <grp, ip_addr, port> into hash table
355  */
356 int addr_hash_table_insert(struct addr_list** table, unsigned int grp,
357                 ip_addr_t *addr, unsigned int port, char *tagv)
358 {
359         struct addr_list *np;
360         unsigned int hash_val;
361         str addr_str;
362         int len;
363
364         len = sizeof(struct addr_list);
365         if(tagv!=NULL)
366                 len += strlen(tagv) + 1;
367
368         np = (struct addr_list *) shm_malloc(len);
369         if (np == NULL) {
370                 LM_ERR("no shm memory for table entry\n");
371                 return -1;
372         }
373
374         memset(np, 0, len);
375
376         np->grp = grp;
377         memcpy(&np->addr, addr, sizeof(ip_addr_t));
378         np->port = port;
379         if(tagv!=NULL)
380         {
381                 np->tag.s = (char*)np + sizeof(struct addr_list);
382                 np->tag.len = strlen(tagv);
383                 strcpy(np->tag.s, tagv);
384         }
385
386         addr_str.s = (char*)addr->u.addr;
387         addr_str.len = 4;
388         hash_val = perm_hash(addr_str);
389         np->next = table[hash_val];
390         table[hash_val] = np;
391
392         return 1;
393 }
394
395
396 /* 
397  * Check if an entry exists in hash table that has given group, ip_addr, and
398  * port.  Port 0 in hash table matches any port.
399  */
400 int match_addr_hash_table(struct addr_list** table, unsigned int group,
401                 ip_addr_t *addr, unsigned int port)
402 {
403         struct addr_list *np;
404         str addr_str;
405         avp_value_t val;
406
407         addr_str.s = (char*)addr->u.addr;
408         addr_str.len = 4;
409
410         for (np = table[perm_hash(addr_str)]; np != NULL; np = np->next) {
411                 if ( (np->grp == group)
412                                 && ((np->port == 0) || (np->port == port))
413                                 && ip_addr_cmp(&np->addr, addr)) {
414
415                         if (tag_avp.n && np->tag.s) {
416                                 val.s = np->tag;
417                                 if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) {
418                                         LM_ERR("setting of tag_avp failed\n");
419                                         return -1;
420                                 }
421                         }
422
423                         return 1;
424                 }
425         }
426
427         return -1;
428 }
429
430
431 /* 
432  * Check if an ip_addr/port entry exists in hash table in any group.
433  * Returns first group in which ip_addr/port is found.
434  * Port 0 in hash table matches any port. 
435  */
436 int find_group_in_addr_hash_table(struct addr_list** table,
437                 ip_addr_t *addr, unsigned int port)
438 {
439         struct addr_list *np;
440         str addr_str;
441
442         addr_str.s = (char*)addr->u.addr;
443         addr_str.len = 4;
444
445         for (np = table[perm_hash(addr_str)]; np != NULL; np = np->next) {
446                 if (((np->port == 0) || (np->port == port))
447                                 && ip_addr_cmp(&np->addr, addr)) {
448                         return np->grp;
449                 }
450         }
451
452         return -1;
453 }
454
455
456 /* 
457  * Print addresses stored in hash table 
458  */
459 int addr_hash_table_mi_print(struct addr_list** table, struct mi_node* rpl)
460 {
461         int i;
462         struct addr_list *np;
463
464         for (i = 0; i < PERM_HASH_SIZE; i++) {
465                 np = table[i];
466                 while (np) {
467                         if (addf_mi_node_child(rpl, 0, 0, 0,
468                                                 "%4d <%u, %s, %u> [%s]",
469                                                 i, np->grp, ip_addr2a(&np->addr),
470                                                 np->port, (np->tag.s==NULL)?"":np->tag.s) == 0)
471                                 return -1;
472                         np = np->next;
473                 }
474         }
475         return 0;
476 }
477
478
479 /* 
480  * Free contents of hash table, it doesn't destroy the
481  * hash table itself
482  */
483 void empty_addr_hash_table(struct addr_list **table)
484 {
485         int i;
486         struct addr_list *np, *next;
487
488         for (i = 0; i < PERM_HASH_SIZE; i++) {
489                 np = table[i];
490                 while (np) {
491                         next = np->next;
492                         shm_free(np);
493                         np = next;
494                 }
495                 table[i] = 0;
496         }
497 }
498
499
500 /*
501  * Create and initialize a subnet table
502  */
503 struct subnet* new_subnet_table(void)
504 {
505         struct subnet* ptr;
506
507         /* subnet record [PERM_MAX_SUBNETS] contains in its grp field 
508            the number of subnet records in the subnet table */
509         ptr = (struct subnet *)shm_malloc
510                 (sizeof(struct subnet) * (PERM_MAX_SUBNETS + 1));
511         if (!ptr) {
512                 LM_ERR("no shm memory for subnet table\n");
513                 return 0;
514         }
515         memset(ptr, 0, sizeof(struct subnet) * (PERM_MAX_SUBNETS + 1));
516         return ptr;
517 }
518
519
520 /* 
521  * Add <grp, subnet, mask, port, tag> into subnet table so that table is
522  * kept in increasing ordered according to grp.
523  */
524 int subnet_table_insert(struct subnet* table, unsigned int grp,
525                 ip_addr_t *subnet, unsigned int mask,
526                 unsigned int port, char *tagv)
527 {
528         int i;
529         unsigned int count;
530         str tags;
531
532         count = table[PERM_MAX_SUBNETS].grp;
533
534         if (count == PERM_MAX_SUBNETS) {
535                 LM_CRIT("subnet table is full\n");
536                 return 0;
537         }
538
539         if(tagv==NULL)
540         {
541                 tags.s = NULL;
542                 tags.len = 0;
543         } else {
544                 tags.len = strlen(tagv);
545                 tags.s = (char*)shm_malloc(tags.len+1);
546                 if(tags.s==NULL)
547                 {
548                         LM_ERR("No more shared memory\n");
549                         return 0;
550                 }
551                 strcpy(tags.s, tagv);
552         }
553
554         i = count - 1;
555
556         while ((i >= 0) && (table[i].grp > grp)) {
557                 table[i + 1] = table[i];
558                 i--;
559         }
560
561         table[i + 1].grp = grp;
562         memcpy(&table[i + 1].subnet, subnet, sizeof(ip_addr_t));
563         table[i + 1].port = port;
564         table[i + 1].mask = mask;
565         table[i + 1].tag = tags;
566
567         table[PERM_MAX_SUBNETS].grp = count + 1;
568
569         return 1;
570 }
571
572
573 /* 
574  * Check if an entry exists in subnet table that matches given group, ip_addr,
575  * and port.  Port 0 in subnet table matches any port.
576  */
577 int match_subnet_table(struct subnet* table, unsigned int grp,
578                 ip_addr_t *addr, unsigned int port)
579 {
580         unsigned int count, i;
581         avp_value_t val;
582
583         count = table[PERM_MAX_SUBNETS].grp;
584
585         i = 0;
586         while ((i < count) && (table[i].grp < grp))
587                 i++;
588
589         if (i == count) return -1;
590
591         while ((i < count) && (table[i].grp == grp)) {
592                 if (((table[i].port == port) || (table[i].port == 0))
593                         && (ip_addr_match_net(addr, &table[i].subnet, table[i].mask)==0))
594                 {
595                         if (tag_avp.n && table[i].tag.s) {
596                                 val.s = table[i].tag;
597                                 if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) {
598                                         LM_ERR("setting of tag_avp failed\n");
599                                         return -1;
600                                 }
601                         }
602                         return 1;
603                 }
604                 i++;
605         }
606
607         return -1;
608 }
609
610
611 /* 
612  * Check if an entry exists in subnet table that matches given ip_addr,
613  * and port.  Port 0 in subnet table matches any port.  Return group of
614  * first match or -1 if no match is found.
615  */
616 int find_group_in_subnet_table(struct subnet* table,
617                 ip_addr_t *addr, unsigned int port)
618 {
619         unsigned int count, i;
620
621         count = table[PERM_MAX_SUBNETS].grp;
622
623         i = 0;
624         while (i < count) {
625                 if ( ((table[i].port == port) || (table[i].port == 0))
626                         && (ip_addr_match_net(addr, &table[i].subnet, table[i].mask)==0))
627                         return table[i].grp;
628                 i++;
629         }
630
631         return -1;
632 }
633
634
635 /* 
636  * Print subnets stored in subnet table 
637  */
638 int subnet_table_mi_print(struct subnet* table, struct mi_node* rpl)
639 {
640         unsigned int count, i;
641
642         count = table[PERM_MAX_SUBNETS].grp;
643
644         for (i = 0; i < count; i++) {
645                 if (addf_mi_node_child(rpl, 0, 0, 0,
646                                         "%4d <%u, %s, %u, %u> [%s]",
647                                         i, table[i].grp, ip_addr2a(&table[i].subnet),
648                                         table[i].mask, table[i].port,
649                                         (table[i].tag.s==NULL)?"":table[i].tag.s) == 0) {
650                         return -1;
651                 }
652         }
653         return 0;
654 }
655
656
657 /* 
658  * Empty contents of subnet table
659  */
660 void empty_subnet_table(struct subnet *table)
661 {
662         int i;
663         table[PERM_MAX_SUBNETS].grp = 0;
664         for(i=0; i<PERM_MAX_SUBNETS; i++)
665         {
666                 if(table[i].tag.s!=NULL)
667                 {
668                         shm_free(table[i].tag.s);
669                         table[i].tag.s = NULL;
670                         table[i].tag.len =0;
671                 }
672         }
673 }
674
675
676 /*
677  * Release memory allocated for a subnet table
678  */
679 void free_subnet_table(struct subnet* table)
680 {
681         int i;
682         if (!table)
683                 return;
684         for(i=0; i<PERM_MAX_SUBNETS; i++)
685         {
686                 if(table[i].tag.s!=NULL)
687                 {
688                         shm_free(table[i].tag.s);
689                         table[i].tag.s = NULL;
690                         table[i].tag.len =0;
691                 }
692         }
693
694         shm_free(table);
695 }