permissions/hash.c

Go to the documentation of this file.
00001 /*
00002  * Hash functions for cached trusted and address tables
00003  *
00004  * Copyright (C) 2003-2006 Juha Heinanen
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00023 #include <sys/types.h>
00024 #include <regex.h>
00025 #include "../../mem/shm_mem.h"
00026 #include "../../parser/parse_from.h"
00027 #include "../../ut.h"
00028 #include "../../hash_func.h"
00029 #include "../../usr_avp.h"
00030 #include "../../ip_addr.h"
00031 #include "../../pvar.h"
00032 #include "hash.h"
00033 #include "trusted.h"
00034 #include "address.h"
00035 
00036 #define perm_hash(_s)  core_hash( &(_s), 0, PERM_HASH_SIZE)
00037 
00038 
00039 /* tag AVP specs */
00040 static int     tag_avp_type;
00041 static int_str tag_avp;
00042 
00043 
00044 /*
00045  * Parse and set tag AVP specs
00046  */
00047 int init_tag_avp(str *tag_avp_param)
00048 {
00049     pv_spec_t avp_spec;
00050     unsigned short avp_flags;
00051 
00052     if (tag_avp_param->s && tag_avp_param->len > 0) {
00053    if (pv_parse_spec(tag_avp_param, &avp_spec)==0
00054        || avp_spec.type != PVT_AVP) {
00055        LM_ERR("malformed or non "
00056       "AVP %.*s peer_tag_avp definition\n", tag_avp_param->len, tag_avp_param->s);
00057        return -1;
00058    }
00059    if(pv_get_avp_name(0, &avp_spec.pvp, &tag_avp, &avp_flags)!=0) {
00060        LM_ERR("[%.*s]- invalid "
00061       "peer_tag_avp AVP definition\n", tag_avp_param->len, tag_avp_param->s);
00062        return -1;
00063    }
00064    tag_avp_type = avp_flags;
00065     } else {
00066    tag_avp.n = 0;
00067     }
00068     return 0;
00069 }
00070 
00071 
00072 /*
00073  * Gets tag avp specs
00074  */
00075 void get_tag_avp(int_str *tag_avp_p, int *tag_avp_type_p)
00076 {
00077    *tag_avp_p = tag_avp;
00078    *tag_avp_type_p = tag_avp_type;
00079 }
00080 
00081 
00082 /*
00083  * Create and initialize a hash table
00084  */
00085 struct trusted_list** new_hash_table(void)
00086 {
00087    struct trusted_list** ptr;
00088 
00089    /* Initializing hash tables and hash table variable */
00090    ptr = (struct trusted_list **)shm_malloc
00091       (sizeof(struct trusted_list*) * PERM_HASH_SIZE);
00092    if (!ptr) {
00093       LM_ERR("no shm memory for hash table\n");
00094       return 0;
00095    }
00096 
00097    memset(ptr, 0, sizeof(struct trusted_list*) * PERM_HASH_SIZE);
00098    return ptr;
00099 }
00100 
00101 
00102 /*
00103  * Release all memory allocated for a hash table
00104  */
00105 void free_hash_table(struct trusted_list** table)
00106 {
00107    if (!table)
00108       return;
00109 
00110    empty_hash_table(table);
00111    shm_free(table);
00112 }
00113 
00114 
00115 /* 
00116  * Add <src_ip, proto, pattern, tag> into hash table, where proto is integer
00117  * representation of string argument proto.
00118  */
00119 int hash_table_insert(struct trusted_list** table, char* src_ip, 
00120             char* proto, char* pattern, char* tag)
00121 {
00122    struct trusted_list *np;
00123    unsigned int hash_val;
00124 
00125    np = (struct trusted_list *) shm_malloc(sizeof(*np));
00126    if (np == NULL) {
00127       LM_ERR("cannot allocate shm memory for table entry\n");
00128       return -1;
00129    }
00130 
00131    if (strcasecmp(proto, "any") == 0) {
00132       np->proto = PROTO_NONE;
00133    } else if (strcasecmp(proto, "udp") == 0) {
00134       np->proto = PROTO_UDP;
00135    } else if (strcasecmp(proto, "tcp") == 0) {
00136       np->proto = PROTO_TCP;
00137    } else if (strcasecmp(proto, "tls") == 0) {
00138       np->proto = PROTO_TLS;
00139    } else if (strcasecmp(proto, "sctp") == 0) {
00140       np->proto = PROTO_SCTP;
00141    } else if (strcasecmp(proto, "none") == 0) {
00142            shm_free(np);
00143       return 1;
00144    } else {
00145       LM_CRIT("unknown protocol\n");
00146       shm_free(np);
00147       return -1;
00148    }
00149 
00150    np->src_ip.len = strlen(src_ip);
00151    np->src_ip.s = (char *) shm_malloc(np->src_ip.len);
00152 
00153    if (np->src_ip.s == NULL) {
00154       LM_CRIT("cannot allocate shm memory for src_ip string\n");
00155       shm_free(np);
00156       return -1;
00157    }
00158 
00159    (void) strncpy(np->src_ip.s, src_ip, np->src_ip.len);
00160 
00161    if (pattern) {
00162        np->pattern = (char *) shm_malloc(strlen(pattern)+1);
00163        if (np->pattern == NULL) {
00164       LM_CRIT("cannot allocate shm memory for pattern string\n");
00165       shm_free(np->src_ip.s);
00166       shm_free(np);
00167       return -1;
00168        }
00169        (void) strcpy(np->pattern, pattern);
00170    } else {
00171        np->pattern = 0;
00172    }
00173 
00174    if (tag) {
00175        np->tag.len = strlen(tag);
00176        np->tag.s = (char *) shm_malloc((np->tag.len) + 1);
00177        if (np->tag.s == NULL) {
00178       LM_CRIT("cannot allocate shm memory for pattern string\n");
00179       shm_free(np->src_ip.s);
00180       shm_free(np->pattern);
00181       shm_free(np);
00182       return -1;
00183        }
00184        (void) strcpy(np->tag.s, tag);
00185    } else {
00186        np->tag.len = 0;
00187        np->tag.s = 0;
00188    }
00189 
00190    hash_val = perm_hash(np->src_ip);
00191    np->next = table[hash_val];
00192    table[hash_val] = np;
00193 
00194    return 1;
00195 }
00196 
00197 
00198 /* 
00199  * Check if an entry exists in hash table that has given src_ip and protocol
00200  * value and pattern that matches to From URI.  If an entry exists and tag_avp
00201  * has been defined, tag of the entry is added as a value to tag_avp.
00202  */
00203 int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
00204            char *src_ip_c_str, int proto)
00205 {
00206    str uri;
00207    char uri_string[MAX_URI_SIZE + 1];
00208    regex_t preg;
00209    struct trusted_list *np;
00210    str src_ip;
00211    int_str val;
00212 
00213    src_ip.s = src_ip_c_str;
00214    src_ip.len = strlen(src_ip.s);
00215 
00216    if (parse_from_header(msg) < 0) return -1;
00217    uri = get_from(msg)->uri;
00218    if (uri.len > MAX_URI_SIZE) {
00219       LM_ERR("from URI too large\n");
00220       return -1;
00221    }
00222    memcpy(uri_string, uri.s, uri.len);
00223    uri_string[uri.len] = (char)0;
00224 
00225    for (np = table[perm_hash(src_ip)]; np != NULL; np = np->next) {
00226        if ((np->src_ip.len == src_ip.len) && 
00227       (strncmp(np->src_ip.s, src_ip.s, src_ip.len) == 0) &&
00228       ((np->proto == PROTO_NONE) || (np->proto == proto))) {
00229       if (!(np->pattern)) goto found;
00230       if (regcomp(&preg, np->pattern, REG_NOSUB)) {
00231           LM_ERR("invalid regular expression\n");
00232           return -1;
00233       }
00234       if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
00235           regfree(&preg);
00236       } else {
00237           regfree(&preg);
00238           goto found;
00239       }
00240        }
00241    }
00242    return -1;
00243 found:
00244    if (tag_avp.n && np->tag.s) {
00245        val.s = np->tag;
00246        if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) {
00247       LM_ERR("setting of tag_avp failed\n");
00248       return -1;
00249        }
00250    }
00251    return 1;
00252 }
00253 
00254 
00255 /* 
00256  * Print trusted entries stored in hash table 
00257  */
00258 int hash_table_mi_print(struct trusted_list** table, struct mi_node* rpl)
00259 {
00260     int i;
00261     struct trusted_list *np;
00262     
00263     for (i = 0; i < PERM_HASH_SIZE; i++) {
00264    np = table[i];
00265    while (np) {
00266        if (addf_mi_node_child(rpl, 0, 0, 0,
00267                "%4d <%.*s, %d, %s, %s>",
00268                i,
00269                np->src_ip.len, ZSW(np->src_ip.s),
00270                np->proto,
00271                np->pattern?np->pattern:"NULL",
00272                np->tag.len?np->tag.s:"NULL") == 0) {
00273       return -1;
00274        }
00275        np = np->next;
00276    }
00277     }
00278     return 0;
00279 }
00280 
00281 
00282 /* 
00283  * Free contents of hash table, it doesn't destroy the
00284  * hash table itself
00285  */
00286 void empty_hash_table(struct trusted_list **table)
00287 {
00288     int i;
00289     struct trusted_list *np, *next;
00290     
00291     for (i = 0; i < PERM_HASH_SIZE; i++) {
00292    np = table[i];
00293    while (np) {
00294        if (np->src_ip.s) shm_free(np->src_ip.s);
00295        if (np->pattern) shm_free(np->pattern);
00296        if (np->tag.s) shm_free(np->tag.s);
00297        next = np->next;
00298        shm_free(np);
00299        np = next;
00300    }
00301    table[i] = 0;
00302     }
00303 }
00304 
00305 
00306 /*
00307  * Create and initialize an address hash table
00308  */
00309 struct addr_list** new_addr_hash_table(void)
00310 {
00311     struct addr_list** ptr;
00312 
00313     /* Initializing hash tables and hash table variable */
00314     ptr = (struct addr_list **)shm_malloc
00315    (sizeof(struct addr_list*) * PERM_HASH_SIZE);
00316     if (!ptr) {
00317    LM_ERR("no shm memory for hash table\n");
00318    return 0;
00319     }
00320 
00321     memset(ptr, 0, sizeof(struct addr_list*) * PERM_HASH_SIZE);
00322     return ptr;
00323 }
00324 
00325 
00326 /*
00327  * Release all memory allocated for a hash table
00328  */
00329 void free_addr_hash_table(struct addr_list** table)
00330 {
00331     if (!table)
00332    return;
00333 
00334     empty_addr_hash_table(table);
00335     shm_free(table);
00336 }
00337 
00338 
00339 /* 
00340  * Add <grp, ip_addr, port> into hash table
00341  */
00342 int addr_hash_table_insert(struct addr_list** table, unsigned int grp,
00343             unsigned int ip_addr, unsigned int port)
00344 {
00345     struct addr_list *np;
00346     unsigned int hash_val;
00347     str addr_str;
00348    
00349     np = (struct addr_list *) shm_malloc(sizeof(*np));
00350     if (np == NULL) {
00351    LM_ERR("no shm memory for table entry\n");
00352    return -1;
00353     }
00354 
00355     np->grp = grp;
00356     np->ip_addr = ip_addr;
00357     np->port = port;
00358     
00359     addr_str.s = (char *)(&ip_addr);
00360     addr_str.len = 4;
00361     hash_val = perm_hash(addr_str);
00362     np->next = table[hash_val];
00363     table[hash_val] = np;
00364 
00365     return 1;
00366 }
00367 
00368 
00369 /* 
00370  * Check if an entry exists in hash table that has given group, ip_addr, and
00371  * port.  Port 0 in hash table matches any port.
00372  */
00373 int match_addr_hash_table(struct addr_list** table, unsigned int group,
00374            unsigned int ip_addr, unsigned int port)
00375 {
00376    struct addr_list *np;
00377    str addr_str;
00378 
00379    addr_str.s = (char *)(&ip_addr);
00380    addr_str.len = 4;
00381 
00382    for (np = table[perm_hash(addr_str)]; np != NULL; np = np->next) {
00383        if ((np->ip_addr == ip_addr) && (np->grp == group) &&
00384       ((np->port == 0) || (np->port == port))) {
00385       return 1;
00386        }
00387    }
00388 
00389    return -1;
00390 }
00391 
00392 
00393 /* 
00394  * Check if an ip_addr/port entry exists in hash table in any group.
00395  * Returns first group in which ip_addr/port is found.
00396  * Port 0 in hash table matches any port. 
00397  */
00398 int find_group_in_addr_hash_table(struct addr_list** table,
00399               unsigned int ip_addr, unsigned int port)
00400 {
00401    struct addr_list *np;
00402    str addr_str;
00403 
00404    addr_str.s = (char *)(&ip_addr);
00405    addr_str.len = 4;
00406 
00407    for (np = table[perm_hash(addr_str)]; np != NULL; np = np->next) {
00408        if ((np->ip_addr == ip_addr) &&
00409       ((np->port == 0) || (np->port == port))) {
00410       return np->grp;
00411        }
00412    }
00413 
00414    return -1;
00415 }
00416 
00417 
00418 /* 
00419  * Print addresses stored in hash table 
00420  */
00421 int addr_hash_table_mi_print(struct addr_list** table, struct mi_node* rpl)
00422 {
00423     int i;
00424     struct addr_list *np;
00425     struct ip_addr addr;
00426     
00427     for (i = 0; i < PERM_HASH_SIZE; i++) {
00428    np = table[i];
00429    while (np) {
00430        addr.af = AF_INET;
00431        addr.len = 4;
00432        addr.u.addr32[0] = np->ip_addr;
00433        if (addf_mi_node_child(rpl, 0, 0, 0,
00434                "%4d <%u, %s, %u>",
00435                i, np->grp, ip_addr2a(&addr),
00436                np->port) == 0)
00437       return -1;
00438        np = np->next;
00439    }
00440     }
00441     return 0;
00442 }
00443 
00444 
00445 /* 
00446  * Free contents of hash table, it doesn't destroy the
00447  * hash table itself
00448  */
00449 void empty_addr_hash_table(struct addr_list **table)
00450 {
00451     int i;
00452     struct addr_list *np, *next;
00453 
00454     for (i = 0; i < PERM_HASH_SIZE; i++) {
00455    np = table[i];
00456    while (np) {
00457        next = np->next;
00458        shm_free(np);
00459        np = next;
00460    }
00461    table[i] = 0;
00462     }
00463 }
00464 
00465 
00466 /*
00467  * Create and initialize a subnet table
00468  */
00469 struct subnet* new_subnet_table(void)
00470 {
00471     struct subnet* ptr;
00472 
00473     /* subnet record [PERM_MAX_SUBNETS] contains in its grp field 
00474        the number of subnet records in the subnet table */
00475     ptr = (struct subnet *)shm_malloc
00476    (sizeof(struct subnet) * (PERM_MAX_SUBNETS + 1));
00477     if (!ptr) {
00478    LM_ERR("no shm memory for subnet table\n");
00479    return 0;
00480     }
00481     ptr[PERM_MAX_SUBNETS].grp = 0;
00482     return ptr;
00483 }
00484 
00485     
00486 /* 
00487  * Add <grp, subnet, mask, port> into subnet table so that table is
00488  * kept in increasing ordered according to grp.
00489  */
00490 int subnet_table_insert(struct subnet* table, unsigned int grp,
00491          unsigned int subnet, unsigned int mask,
00492          unsigned int port)
00493 {
00494     int i;
00495     unsigned int count;
00496 
00497     count = table[PERM_MAX_SUBNETS].grp;
00498 
00499     if (count == PERM_MAX_SUBNETS) {
00500    LM_CRIT("subnet table is full\n");
00501    return 0;
00502     }
00503 
00504     mask = 32 - mask;
00505     subnet = htonl(ntohl(subnet) >> mask); //subnet << mask;
00506 
00507     i = count - 1;
00508 
00509     while ((i >= 0) && (table[i].grp > grp)) {
00510    table[i + 1] = table[i];
00511    i--;
00512     }
00513     
00514     table[i + 1].grp = grp;
00515     table[i + 1].subnet = subnet;
00516     table[i + 1].port = port;
00517     table[i + 1].mask = mask;
00518 
00519     table[PERM_MAX_SUBNETS].grp = count + 1;
00520 
00521     return 1;
00522 }
00523 
00524 
00525 /* 
00526  * Check if an entry exists in subnet table that matches given group, ip_addr,
00527  * and port.  Port 0 in subnet table matches any port.
00528  */
00529 int match_subnet_table(struct subnet* table, unsigned int grp,
00530              unsigned int ip_addr, unsigned int port)
00531 {
00532     unsigned int count, i, subnet;
00533 
00534     count = table[PERM_MAX_SUBNETS].grp;
00535 
00536     i = 0;
00537     while ((i < count) && (table[i].grp < grp))
00538    i++;
00539     
00540     if (i == count) return -1;
00541 
00542     while ((i < count) && (table[i].grp == grp)) {
00543    subnet = htonl(ntohl(ip_addr) >> table[i].mask); //ip_addr << table[i].mask;
00544    if ((table[i].subnet == subnet) &&
00545        ((table[i].port == port) || (table[i].port == 0)))
00546        return 1;
00547    i++;
00548     }
00549 
00550     return -1;
00551 }
00552 
00553 
00554 /* 
00555  * Check if an entry exists in subnet table that matches given ip_addr,
00556  * and port.  Port 0 in subnet table matches any port.  Return group of
00557  * first match or -1 if no match is found.
00558  */
00559 int find_group_in_subnet_table(struct subnet* table,
00560                 unsigned int ip_addr, unsigned int port)
00561 {
00562     unsigned int count, i, subnet;
00563 
00564     count = table[PERM_MAX_SUBNETS].grp;
00565 
00566     i = 0;
00567     while (i < count) {
00568    subnet = ip_addr << table[i].mask;
00569    if ((table[i].subnet == subnet) &&
00570        ((table[i].port == port) || (table[i].port == 0)))
00571        return table[i].grp;
00572    i++;
00573     }
00574 
00575     return -1;
00576 }
00577 
00578 
00579 /* 
00580  * Print subnets stored in subnet table 
00581  */
00582 int subnet_table_mi_print(struct subnet* table, struct mi_node* rpl)
00583 {
00584     unsigned int count, i;
00585     struct ip_addr addr;
00586     
00587     count = table[PERM_MAX_SUBNETS].grp;
00588 
00589     for (i = 0; i < count; i++) {
00590    addr.af = AF_INET;
00591    addr.len = 4;
00592    addr.u.addr32[0] = htonl(ntohl(table[i].subnet) << table[i].mask); //table[i].subnet >> table[i].mask;
00593    if (addf_mi_node_child(rpl, 0, 0, 0,
00594                 "%4d <%u, %s, %u, %u>",
00595                 i, table[i].grp, ip_addr2a(&addr),
00596                 32 - table[i].mask, table[i].port) == 0) {
00597        return -1;
00598    }
00599     }
00600     return 0;
00601 }
00602 
00603 
00604 /* 
00605  * Empty contents of subnet table
00606  */
00607 void empty_subnet_table(struct subnet *table)
00608 {
00609     table[PERM_MAX_SUBNETS].grp = 0;
00610 }
00611 
00612 
00613 /*
00614  * Release memory allocated for a subnet table
00615  */
00616 void free_subnet_table(struct subnet* table)
00617 {
00618     if (!table)
00619    return;
00620 
00621     shm_free(table);
00622 }

Generated on Thu May 24 02:00:26 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6