acl.c File Reference

Various sorts of access control. More...

#include "asterisk.h"
#include "asterisk/network.h"
#include "asterisk/acl.h"
#include "asterisk/channel.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/srv.h"

Include dependency graph for acl.c:

Go to the source code of this file.

Data Structures

struct  dscp_codepoint

Functions

static int acl_new (struct ast_acl **pointer, const char *name)
int ast_acl_list_is_empty (struct ast_acl_list *acl_list)
 Determines if an ACL is empty or if it contains entries.
void ast_append_acl (const char *sense, const char *stuff, struct ast_acl_list **path, int *error, int *named_acl_flag)
 Add a rule to an ACL struct.
struct ast_haast_append_ha (const char *sense, const char *stuff, struct ast_ha *path, int *error)
 Add a new rule to a list of HAs.
enum ast_acl_sense ast_apply_acl (struct ast_acl_list *acl_list, const struct ast_sockaddr *addr, const char *purpose)
 Apply a set of rules to a given IP address.
enum ast_acl_sense ast_apply_ha (const struct ast_ha *ha, const struct ast_sockaddr *addr)
 Apply a set of rules to a given IP address.
void ast_copy_ha (const struct ast_ha *from, struct ast_ha *to)
 Copy the contents of one HA to another.
struct ast_acl_listast_duplicate_acl_list (struct ast_acl_list *original)
 Duplicates the contests of a list of lists of host access rules.
static struct ast_haast_duplicate_ha (struct ast_ha *original)
struct ast_haast_duplicate_ha_list (struct ast_ha *original)
 Duplicate the contents of a list of host access rules.
int ast_find_ourip (struct ast_sockaddr *ourip, const struct ast_sockaddr *bindaddr, int family)
 Find our IP address.
struct ast_acl_listast_free_acl_list (struct ast_acl_list *acl_list)
 Free a list of ACLs.
void ast_free_ha (struct ast_ha *ha)
 Free a list of HAs.
int ast_get_ip (struct ast_sockaddr *addr, const char *hostname)
 Get the IP address given a hostname.
int ast_get_ip_or_srv (struct ast_sockaddr *addr, const char *hostname, const char *service)
 Get the IP address given a hostname and optional service.
void ast_ha_join (const struct ast_ha *ha, struct ast_str **buf)
 Convert HAs to a comma separated string value.
void ast_ha_join_cidr (const struct ast_ha *ha, struct ast_str **buf)
 Convert HAs to a comma separated string value using CIDR notation.
int ast_ouraddrfor (const struct ast_sockaddr *them, struct ast_sockaddr *us)
 Get our local IP address when contacting a remote host.
int ast_str2cos (const char *value, unsigned int *cos)
 Convert a string to the appropriate COS value.
int ast_str2tos (const char *value, unsigned int *tos)
 Convert a string to the appropriate TOS value.
const char * ast_tos2str (unsigned int tos)
 Convert a TOS value into its string representation.
static int get_local_address (struct ast_sockaddr *ourip)
static int parse_cidr_mask (struct ast_sockaddr *addr, int is_v4, const char *mask_str)
 Parse a netmask in CIDR notation.
static int resolve_first (struct ast_sockaddr *addr, const char *name, int flag, int family)

Variables

static struct dscp_codepoint dscp_pool1 []


Detailed Description

Various sorts of access control.

Author:
Mark Spencer <markster@digium.com>

Definition in file acl.c.


Function Documentation

static int acl_new ( struct ast_acl **  pointer,
const char *  name 
) [static]

Definition at line 300 of file acl.c.

References ACL_NAME_LENGTH, ast_calloc, ast_copy_string(), and ast_acl::name.

Referenced by ast_append_acl(), and ast_duplicate_acl_list().

00300                                                                {
00301    struct ast_acl *acl;
00302    if (!(acl = ast_calloc(1, sizeof(*acl)))) {
00303       return 1;
00304    }
00305 
00306    *pointer = acl;
00307    ast_copy_string(acl->name, name, ACL_NAME_LENGTH);
00308    return 0;
00309 }

int ast_acl_list_is_empty ( struct ast_acl_list acl_list  ) 

Determines if an ACL is empty or if it contains entries.

Parameters:
acl_list The ACL list being checked
Return values:
0 - the list is not empty
1 - the list is empty

Definition at line 522 of file acl.c.

References AST_LIST_FIRST, AST_LIST_LOCK, and AST_LIST_UNLOCK.

Referenced by _sip_show_peer(), _sip_show_peers_one(), apply_acl(), apply_contact_acl(), handle_cli_iax2_show_peer(), handle_cli_iax2_show_users(), handle_showmanager(), sip_show_user(), sip_show_users(), and users_data_provider_get().

00523 {
00524    struct ast_acl *head;
00525 
00526    if (!acl_list) {
00527       return 1;
00528    }
00529 
00530    AST_LIST_LOCK(acl_list);
00531    head = AST_LIST_FIRST(acl_list);
00532    AST_LIST_UNLOCK(acl_list);
00533 
00534    if (head) {
00535       return 0;
00536    }
00537 
00538    return 1;
00539 }

void ast_append_acl ( const char *  sense,
const char *  stuff,
struct ast_acl_list **  path,
int *  error,
int *  named_acl_flag 
)

Add a rule to an ACL struct.

This adds a named ACL or an ACL rule to an ast_acl container. It works in a similar way to ast_append_ha.

Parameters:
sense Can be any among "permit", "deny", or "acl" this controls whether the rule being added will simply modify the unnamed ACL at the head of the list or if a new named ACL will be added to that ast_acl.
stuff If sense is 'permit'/'deny', this is the ip address and subnet mask separated with a '/' like in ast_append ha. If it sense is 'acl', then this will be the name of the ACL being appended to the container.
path Address of the ACL list being appended
[out] error The int that error points to will be set to 1 if an error occurs.
[out] named_acl_flag This will raise a flag under certain conditions to indicate that a named ACL has been added by this operation. This may be used to indicate that an event subscription should be made against the named ACL subsystem. Note: This flag may be raised by this function, but it will never be lowered by it.

Definition at line 414 of file acl.c.

References ast_acl::acl, acl_new(), ast_append_ha(), ast_calloc, AST_LIST_FIRST, AST_LIST_HEAD_INIT, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_named_acl_find(), ast_skip_blanks(), ast_strdupa, ast_strlen_zero, ast_acl::is_invalid, ast_acl::is_realtime, LOG_ERROR, ast_acl::name, NULL, strsep(), and tmp().

Referenced by __init_manager(), acl_handler(), build_peer(), build_user(), and reload_config().

00415 {
00416    struct ast_acl *acl = NULL;
00417    struct ast_acl *current;
00418    struct ast_acl_list *working_list;
00419 
00420    char *tmp, *list;
00421 
00422    /* If the ACL list is currently uninitialized, it must be initialized. */
00423    if (*path == NULL) {
00424       struct ast_acl_list *list;
00425       list = ast_calloc(1, sizeof(*list));
00426       if (!list) {
00427          /* Allocation Error */
00428          if (error) {
00429             *error = 1;
00430          }
00431          return;
00432       }
00433 
00434       AST_LIST_HEAD_INIT(list);
00435       *path = list;
00436    }
00437 
00438    working_list = *path;
00439 
00440    AST_LIST_LOCK(working_list);
00441 
00442    /* First we need to determine if we will need to add a new ACL node or if we can use an existing one. */
00443    if (strncasecmp(sense, "a", 1)) {
00444       /* The first element in the path should be the unnamed, base ACL. If that's the case, we use it. If not,
00445        * we have to make one and link it up appropriately. */
00446       current = AST_LIST_FIRST(working_list);
00447 
00448       if (!current || !ast_strlen_zero(current->name)) {
00449          if (acl_new(&acl, "")) {
00450             if (error) {
00451                *error = 1;
00452             }
00453          }
00454          // Need to INSERT the ACL at the head here.
00455          AST_LIST_INSERT_HEAD(working_list, acl, list);
00456       } else {
00457          /* If the first element was already the unnamed base ACL, we just use that one. */
00458          acl = current;
00459       }
00460 
00461       /* With the proper ACL set for modification, we can just pass this off to the ast_ha append function. */
00462       acl->acl = ast_append_ha(sense, stuff, acl->acl, error);
00463 
00464       AST_LIST_UNLOCK(working_list);
00465       return;
00466    }
00467 
00468    /* We are in ACL append mode, so we know we'll be adding one or more named ACLs. */
00469    list = ast_strdupa(stuff);
00470 
00471    while ((tmp = strsep(&list, ","))) {
00472       struct ast_ha *named_ha;
00473       int already_included = 0;
00474 
00475       /* Remove leading whitespace from the string in case the user put spaces between items */
00476       tmp = ast_skip_blanks(tmp);
00477 
00478       /* The first step is to check for a duplicate */
00479       AST_LIST_TRAVERSE(working_list, current, list) {
00480          if (!strcasecmp(current->name, tmp)) { /* ACL= */
00481             /* Inclusion of the same ACL multiple times isn't a catastrophic error, but it will raise the error flag and skip the entry. */
00482             ast_log(LOG_ERROR, "Named ACL '%s' is already included in the ast_acl container.", tmp);
00483             if (error) {
00484                *error = 1;
00485             }
00486             already_included = 1;
00487             break;
00488          }
00489       }
00490 
00491       if (already_included) {
00492          continue;
00493       }
00494 
00495       if (acl_new(&acl, tmp)) {
00496          /* This is a catastrophic allocation error and we'll return immediately if this happens. */
00497          if (error) {
00498             *error = 1;
00499          }
00500          AST_LIST_UNLOCK(working_list);
00501          return;
00502       }
00503 
00504       /* Attempt to grab the Named ACL we are looking for. */
00505       named_ha = ast_named_acl_find(tmp, &acl->is_realtime, &acl->is_invalid);
00506 
00507       /* Set the ACL's ast_ha to the duplicated named ACL retrieved above. */
00508       acl->acl = named_ha;
00509 
00510       /* Raise the named_acl_flag since we are adding a named ACL to the ACL container. */
00511       if (named_acl_flag) {
00512          *named_acl_flag = 1;
00513       }
00514 
00515       /* Now insert the new ACL at the end of the list. */
00516       AST_LIST_INSERT_TAIL(working_list, acl, list);
00517    }
00518 
00519    AST_LIST_UNLOCK(working_list);
00520 }

struct ast_ha* ast_append_ha ( const char *  sense,
const char *  stuff,
struct ast_ha path,
int *  error 
) [read]

Add a new rule to a list of HAs.

This adds the new host access rule to the end of the list whose head is specified by the path parameter. Rules are evaluated in a way such that if multiple rules apply to a single IP address/subnet mask, then the rule latest in the list will be used.

Parameters:
sense Either "permit" or "deny" (Actually any 'p' word will result in permission, and any other word will result in denial)
stuff The IP address and subnet mask, separated with a '/'. The subnet mask can either be in dotted-decimal format or in CIDR notation (i.e. 0-32).
path The head of the HA list to which we wish to append our new rule. If NULL is passed, then the new rule will become the head of the list
[out] error The integer error points to will be set non-zero if an error occurs
Returns:
The head of the HA list

Definition at line 541 of file acl.c.

References ast_ha::addr, ast_calloc, ast_debug, ast_free_ha(), ast_log, AST_SENSE_ALLOW, AST_SENSE_DENY, ast_sockaddr_apply_netmask(), ast_sockaddr_ipv4_mapped(), ast_sockaddr_is_ipv4(), ast_sockaddr_parse(), ast_sockaddr_stringify(), ast_strdupa, LOG_NOTICE, LOG_WARNING, ast_ha::netmask, ast_ha::next, NULL, parse_cidr_mask(), PARSE_PORT_FORBID, ast_ha::sense, strsep(), and tmp().

Referenced by acl_handler_fn(), add_calltoken_ignore(), ast_append_acl(), AST_TEST_DEFINE(), build_callno_limits(), build_device(), build_gateway(), build_ha(), config_parse_variables(), ip_identify_match_handler(), named_acl_find_realtime(), reload_config(), and transport_localnet_handler().

00542 {
00543    struct ast_ha *ha;
00544    struct ast_ha *prev = NULL;
00545    struct ast_ha *ret;
00546    char *tmp, *list = ast_strdupa(stuff);
00547    char *address = NULL, *mask = NULL;
00548    int addr_is_v4;
00549    int allowing = strncasecmp(sense, "p", 1) ? AST_SENSE_DENY : AST_SENSE_ALLOW;
00550    const char *parsed_addr, *parsed_mask;
00551 
00552    ret = path;
00553    while (path) {
00554       prev = path;
00555       path = path->next;
00556    }
00557 
00558    while ((tmp = strsep(&list, ","))) {
00559       if (!(ha = ast_calloc(1, sizeof(*ha)))) {
00560          if (error) {
00561             *error = 1;
00562          }
00563          return ret;
00564       }
00565 
00566       address = strsep(&tmp, "/");
00567       if (!address) {
00568          address = tmp;
00569       } else {
00570          mask = tmp;
00571       }
00572 
00573       if (*address == '!') {
00574          ha->sense = (allowing == AST_SENSE_DENY) ? AST_SENSE_ALLOW : AST_SENSE_DENY;
00575          address++;
00576       } else {
00577          ha->sense = allowing;
00578       }
00579 
00580       if (!ast_sockaddr_parse(&ha->addr, address, PARSE_PORT_FORBID)) {
00581          ast_log(LOG_WARNING, "Invalid IP address: %s\n", address);
00582          ast_free_ha(ha);
00583          if (error) {
00584             *error = 1;
00585          }
00586          return ret;
00587       }
00588 
00589       /* If someone specifies an IPv4-mapped IPv6 address,
00590        * we just convert this to an IPv4 ACL
00591        */
00592       if (ast_sockaddr_ipv4_mapped(&ha->addr, &ha->addr)) {
00593          ast_log(LOG_NOTICE, "IPv4-mapped ACL network address specified. "
00594             "Converting to an IPv4 ACL network address.\n");
00595       }
00596 
00597       addr_is_v4 = ast_sockaddr_is_ipv4(&ha->addr);
00598 
00599       if (!mask) {
00600          parse_cidr_mask(&ha->netmask, addr_is_v4, addr_is_v4 ? "32" : "128");
00601       } else if (strchr(mask, ':') || strchr(mask, '.')) {
00602          int mask_is_v4;
00603          /* Mask is of x.x.x.x or x:x:x:x:x:x:x:x variety */
00604          if (!ast_sockaddr_parse(&ha->netmask, mask, PARSE_PORT_FORBID)) {
00605             ast_log(LOG_WARNING, "Invalid netmask: %s\n", mask);
00606             ast_free_ha(ha);
00607             if (error) {
00608                *error = 1;
00609             }
00610             return ret;
00611          }
00612          /* If someone specifies an IPv4-mapped IPv6 netmask,
00613           * we just convert this to an IPv4 ACL
00614           */
00615          if (ast_sockaddr_ipv4_mapped(&ha->netmask, &ha->netmask)) {
00616             ast_log(LOG_NOTICE, "IPv4-mapped ACL netmask specified. "
00617                "Converting to an IPv4 ACL netmask.\n");
00618          }
00619          mask_is_v4 = ast_sockaddr_is_ipv4(&ha->netmask);
00620          if (addr_is_v4 ^ mask_is_v4) {
00621             ast_log(LOG_WARNING, "Address and mask are not using same address scheme.\n");
00622             ast_free_ha(ha);
00623             if (error) {
00624                *error = 1;
00625             }
00626             return ret;
00627          }
00628       } else if (parse_cidr_mask(&ha->netmask, addr_is_v4, mask)) {
00629          ast_log(LOG_WARNING, "Invalid CIDR netmask: %s\n", mask);
00630          ast_free_ha(ha);
00631          if (error) {
00632             *error = 1;
00633          }
00634          return ret;
00635       }
00636 
00637       if (ast_sockaddr_apply_netmask(&ha->addr, &ha->netmask, &ha->addr)) {
00638          /* This shouldn't happen because ast_sockaddr_parse would
00639           * have failed much earlier on an unsupported address scheme
00640           */
00641          char *failmask = ast_strdupa(ast_sockaddr_stringify(&ha->netmask));
00642          char *failaddr = ast_strdupa(ast_sockaddr_stringify(&ha->addr));
00643          ast_log(LOG_WARNING, "Unable to apply netmask %s to address %s\n", failmask, failaddr);
00644          ast_free_ha(ha);
00645          if (error) {
00646             *error = 1;
00647          }
00648          return ret;
00649       }
00650 
00651       if (prev) {
00652          prev->next = ha;
00653       } else {
00654          ret = ha;
00655       }
00656       prev = ha;
00657 
00658       parsed_addr = ast_strdupa(ast_sockaddr_stringify(&ha->addr));
00659       parsed_mask = ast_strdupa(ast_sockaddr_stringify(&ha->netmask));
00660 
00661       ast_debug(3, "%s/%s sense %u appended to ACL\n", parsed_addr, parsed_mask, ha->sense);
00662    }
00663 
00664    return ret;
00665 }

enum ast_acl_sense ast_apply_acl ( struct ast_acl_list acl_list,
const struct ast_sockaddr addr,
const char *  purpose 
)

Apply a set of rules to a given IP address.

Similar to the above, only uses an acl container, which is a whole slew of ast_ha lists. It runs ast_apply_ha on each of the ast_ha structs contained in the acl container. It will deny if any of the ast_ha lists fail, and it will pass only if all of the rules pass.

Parameters:
acl_list The head of the list of ACLs to evaluate
addr An ast_sockaddr whose address is considered when matching rules
purpose Context for which the ACL is being applied - Establishes purpose of a notice when rejected
Return values:
AST_SENSE_ALLOW The IP address passes our ACLs
AST_SENSE_DENY The IP address fails our ACLs

Definition at line 693 of file acl.c.

References ast_acl::acl, ast_apply_ha(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, AST_SENSE_ALLOW, AST_SENSE_DENY, ast_sockaddr_stringify_addr(), ast_strlen_zero, ast_acl::is_invalid, ast_acl::list, LOG_NOTICE, LOG_WARNING, and ast_acl::name.

Referenced by apply_acl(), apply_contact_acl(), auth_http_callback(), authenticate(), check_access(), check_peer_ok(), parse_register_contact(), register_verify(), and sip_allow_anyrtp_remote().

00694 {
00695    struct ast_acl *acl;
00696 
00697    /* If the list is NULL, there are no rules, so we'll allow automatically. */
00698    if (!acl_list) {
00699       return AST_SENSE_ALLOW;
00700    }
00701 
00702    AST_LIST_LOCK(acl_list);
00703 
00704    AST_LIST_TRAVERSE(acl_list, acl, list) {
00705       if (acl->is_invalid) {
00706          /* In this case, the baseline ACL shouldn't ever trigger this, but if that somehow happens, it'll still be shown. */
00707          ast_log(LOG_WARNING, "%sRejecting '%s' due to use of an invalid ACL '%s'.\n", purpose ? purpose : "", ast_sockaddr_stringify_addr(addr),
00708                ast_strlen_zero(acl->name) ? "(BASELINE)" : acl->name);
00709          AST_LIST_UNLOCK(acl_list);
00710          return AST_SENSE_DENY;
00711       }
00712 
00713       if (acl->acl) {
00714          if (ast_apply_ha(acl->acl, addr) == AST_SENSE_DENY) {
00715             ast_log(LOG_NOTICE, "%sRejecting '%s' due to a failure to pass ACL '%s'\n", purpose ? purpose : "", ast_sockaddr_stringify_addr(addr),
00716                   ast_strlen_zero(acl->name) ? "(BASELINE)" : acl->name);
00717             AST_LIST_UNLOCK(acl_list);
00718             return AST_SENSE_DENY;
00719          }
00720       }
00721    }
00722 
00723    AST_LIST_UNLOCK(acl_list);
00724 
00725    return AST_SENSE_ALLOW;
00726 }

enum ast_acl_sense ast_apply_ha ( const struct ast_ha ha,
const struct ast_sockaddr addr 
)

Apply a set of rules to a given IP address.

The list of host access rules is traversed, beginning with the input rule. If the IP address given matches a rule, the "sense" of that rule is used as the return value. Note that if an IP address matches multiple rules that the last one matched will be the one whose sense will be returned.

Parameters:
ha The head of the list of host access rules to follow
addr An ast_sockaddr whose address is considered when matching rules
Return values:
AST_SENSE_ALLOW The IP address passes our ACL
AST_SENSE_DENY The IP address fails our ACL

Definition at line 728 of file acl.c.

References ast_ha::addr, ast_copy_string(), ast_debug, ast_inet_ntoa(), ast_log, AST_SENSE_ALLOW, ast_sockaddr_apply_netmask(), ast_sockaddr_cmp_addr(), ast_sockaddr_ipv4_mapped(), ast_sockaddr_is_ipv4(), ast_sockaddr_is_ipv4_mapped(), ast_sockaddr_is_ipv6(), ast_sockaddr_stringify(), LOG_ERROR, ast_ha::netmask, ast_ha::next, and ast_ha::sense.

Referenced by ast_apply_acl(), ast_sip_ouraddrfor(), AST_TEST_DEFINE(), change_outgoing_sdp_stream_media_address(), ip_identify_match_check(), nat_on_tx_message(), session_outgoing_nat_hook(), and skinny_register().

00729 {
00730    /* Start optimistic */
00731    enum ast_acl_sense res = AST_SENSE_ALLOW;
00732    const struct ast_ha *current_ha;
00733 
00734    for (current_ha = ha; current_ha; current_ha = current_ha->next) {
00735       struct ast_sockaddr result;
00736       struct ast_sockaddr mapped_addr;
00737       const struct ast_sockaddr *addr_to_use;
00738 #if 0 /* debugging code */
00739       char iabuf[INET_ADDRSTRLEN];
00740       char iabuf2[INET_ADDRSTRLEN];
00741       /* DEBUG */
00742       ast_copy_string(iabuf, ast_inet_ntoa(sin->sin_addr), sizeof(iabuf));
00743       ast_copy_string(iabuf2, ast_inet_ntoa(ha->netaddr), sizeof(iabuf2));
00744       ast_debug(1, "##### Testing %s with %s\n", iabuf, iabuf2);
00745 #endif
00746       if (ast_sockaddr_is_ipv4(&current_ha->addr)) {
00747          if (ast_sockaddr_is_ipv6(addr)) {
00748             if (ast_sockaddr_is_ipv4_mapped(addr)) {
00749                /* IPv4 ACLs apply to IPv4-mapped addresses */
00750                if (!ast_sockaddr_ipv4_mapped(addr, &mapped_addr)) {
00751                   ast_log(LOG_ERROR, "%s provided to ast_sockaddr_ipv4_mapped could not be converted. That shouldn't be possible.\n",
00752                      ast_sockaddr_stringify(addr));
00753                   continue;
00754                }
00755                addr_to_use = &mapped_addr;
00756             } else {
00757                /* An IPv4 ACL does not apply to an IPv6 address */
00758                continue;
00759             }
00760          } else {
00761             /* Address is IPv4 and ACL is IPv4. No biggie */
00762             addr_to_use = addr;
00763          }
00764       } else {
00765          if (ast_sockaddr_is_ipv6(addr) && !ast_sockaddr_is_ipv4_mapped(addr)) {
00766             addr_to_use = addr;
00767          } else {
00768             /* Address is IPv4 or IPv4 mapped but ACL is IPv6. Skip */
00769             continue;
00770          }
00771       }
00772 
00773       /* For each rule, if this address and the netmask = the net address
00774          apply the current rule */
00775       if (ast_sockaddr_apply_netmask(addr_to_use, &current_ha->netmask, &result)) {
00776          /* Unlikely to happen since we know the address to be IPv4 or IPv6 */
00777          continue;
00778       }
00779       if (!ast_sockaddr_cmp_addr(&result, &current_ha->addr)) {
00780          res = current_ha->sense;
00781       }
00782    }
00783    return res;
00784 }

void ast_copy_ha ( const struct ast_ha from,
struct ast_ha to 
)

Copy the contents of one HA to another.

This copies the internals of the 'from' HA to the 'to' HA. It is important that the 'to' HA has been allocated prior to calling this function

Parameters:
from Source HA to copy
to Destination HA to copy to
Return values:
void 

Definition at line 256 of file acl.c.

References ast_ha::addr, ast_sockaddr_copy(), ast_ha::netmask, and ast_ha::sense.

Referenced by add_calltoken_ignore(), ast_duplicate_ha(), and build_callno_limits().

00257 {
00258    ast_sockaddr_copy(&to->addr, &from->addr);
00259    ast_sockaddr_copy(&to->netmask, &from->netmask);
00260    to->sense = from->sense;
00261 }

struct ast_acl_list* ast_duplicate_acl_list ( struct ast_acl_list original  )  [read]

Duplicates the contests of a list of lists of host access rules.

A deep copy of an ast_acl list is made (which in turn means a deep copy of each of the ast_ha structs contained within). The returned value is allocated on the heap and must be freed independently of the input paramater when finished.

Parameters:
original The ast_acl_list to copy
Return values:
The new duplicated ast_acl_list

Definition at line 311 of file acl.c.

References ast_acl::acl, acl_new(), ast_calloc, ast_duplicate_ha_list(), AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_acl::is_invalid, ast_acl::is_realtime, ast_acl::list, LOG_WARNING, ast_acl::name, and NULL.

Referenced by create_addr_from_peer(), and sip_allow_anyrtp_remote().

00312 {
00313    struct ast_acl_list *clone;
00314    struct ast_acl *current_cursor;
00315    struct ast_acl *current_clone;
00316 
00317    /* Early return if we receive a duplication request for a NULL original. */
00318    if (!original) {
00319       return NULL;
00320    }
00321 
00322    if (!(clone = ast_calloc(1, sizeof(*clone)))) {
00323       ast_log(LOG_WARNING, "Failed to allocate ast_acl_list struct while cloning an ACL\n");
00324       return NULL;
00325    }
00326    AST_LIST_HEAD_INIT(clone);
00327 
00328    AST_LIST_LOCK(original);
00329 
00330    AST_LIST_TRAVERSE(original, current_cursor, list) {
00331       if ((acl_new(&current_clone, current_cursor->name))) {
00332          ast_log(LOG_WARNING, "Failed to allocate ast_acl struct while cloning an ACL.");
00333          continue;
00334       }
00335 
00336       /* Copy data from original ACL to clone ACL */
00337       current_clone->acl = ast_duplicate_ha_list(current_cursor->acl);
00338 
00339       current_clone->is_invalid = current_cursor->is_invalid;
00340       current_clone->is_realtime = current_cursor->is_realtime;
00341 
00342       AST_LIST_INSERT_TAIL(clone, current_clone, list);
00343    }
00344 
00345    AST_LIST_UNLOCK(original);
00346 
00347    return clone;
00348 }

static struct ast_ha* ast_duplicate_ha ( struct ast_ha original  )  [static, read]

Definition at line 264 of file acl.c.

References ast_calloc, and ast_copy_ha().

Referenced by ast_duplicate_ha_list().

00265 {
00266    struct ast_ha *new_ha;
00267 
00268    if ((new_ha = ast_calloc(1, sizeof(*new_ha)))) {
00269       /* Copy from original to new object */
00270       ast_copy_ha(original, new_ha);
00271    }
00272 
00273    return new_ha;
00274 }

struct ast_ha* ast_duplicate_ha_list ( struct ast_ha original  )  [read]

Duplicate the contents of a list of host access rules.

A deep copy of all ast_has in the list is made. The returned value is allocated on the heap and must be freed independently of the input parameter when finished.

Parameters:
original The ast_ha to copy
Return values:
The head of the list of duplicated ast_has

Definition at line 278 of file acl.c.

References ast_duplicate_ha(), ast_ha::next, and NULL.

Referenced by ast_duplicate_acl_list(), and ast_named_acl_find().

00279 {
00280    struct ast_ha *start = original;
00281    struct ast_ha *ret = NULL;
00282    struct ast_ha *current, *prev = NULL;
00283 
00284    while (start) {
00285       current = ast_duplicate_ha(start);  /* Create copy of this object */
00286       if (prev) {
00287          prev->next = current;           /* Link previous to this object */
00288       }
00289 
00290       if (!ret) {
00291          ret = current;                  /* Save starting point */
00292       }
00293 
00294       start = start->next;                /* Go to next object */
00295       prev = current;                     /* Save pointer to this object */
00296    }
00297    return ret;                             /* Return start of list */
00298 }

int ast_find_ourip ( struct ast_sockaddr ourip,
const struct ast_sockaddr bindaddr,
int  family 
)

Find our IP address.

This function goes through many iterations in an attempt to find our IP address. If any step along the way should fail, we move to the next item in the list. Here are the steps taken:

  • If bindaddr has a non-zero IP address, that is copied into ourip
  • We use a combination of gethostname and ast_gethostbyname to find our IP address.
  • We use ast_ouraddrfor with 198.41.0.4 as the destination IP address
  • We try some platform-specific socket operations to find the IP address

Parameters:
[out] ourip Our IP address is written here when it is found
bindaddr A hint used for finding our IP. See the steps above for more details
family Only addresses of the given family will be returned. Use 0 or AST_SOCKADDR_UNSPEC to get addresses of all families.
Return values:
0 Success
-1 Failure

Definition at line 954 of file acl.c.

References ast_debug, ast_log, ast_ouraddrfor(), ast_sockaddr_copy(), ast_sockaddr_is_any(), ast_sockaddr_port, ast_sockaddr_set_port, get_local_address(), LOG_WARNING, MAXHOSTNAMELEN, ourhost, PARSE_PORT_FORBID, and resolve_first().

Referenced by ast_rtcp_read(), ast_rtcp_write_report(), and reload_config().

00955 {
00956    char ourhost[MAXHOSTNAMELEN] = "";
00957    struct ast_sockaddr root;
00958    int res, port = ast_sockaddr_port(ourip);
00959 
00960    /* just use the bind address if it is nonzero */
00961    if (!ast_sockaddr_is_any(bindaddr)) {
00962       ast_sockaddr_copy(ourip, bindaddr);
00963       ast_debug(3, "Attached to given IP address\n");
00964       return 0;
00965    }
00966    /* try to use our hostname */
00967    if (gethostname(ourhost, sizeof(ourhost) - 1)) {
00968       ast_log(LOG_WARNING, "Unable to get hostname\n");
00969    } else {
00970       if (resolve_first(ourip, ourhost, PARSE_PORT_FORBID, family) == 0) {
00971          /* reset port since resolve_first wipes this out */
00972          ast_sockaddr_set_port(ourip, port);
00973          return 0;
00974       }
00975    }
00976    ast_debug(3, "Trying to check A.ROOT-SERVERS.NET and get our IP address for that connection\n");
00977    /* A.ROOT-SERVERS.NET. */
00978    if (!resolve_first(&root, "A.ROOT-SERVERS.NET", PARSE_PORT_FORBID, 0) &&
00979        !ast_ouraddrfor(&root, ourip)) {
00980       /* reset port since resolve_first wipes this out */
00981       ast_sockaddr_set_port(ourip, port);
00982       return 0;
00983    }
00984    res = get_local_address(ourip);
00985    ast_sockaddr_set_port(ourip, port);
00986    return res;
00987 }

struct ast_acl_list* ast_free_acl_list ( struct ast_acl_list acl  )  [read]

Free a list of ACLs.

Given the head of a list of ast_acl structs, it and all appended acl structs will be freed. This includes the ast_ha structs within the individual nodes.

Parameters:
acl The list of ACLs to free
Return values:
NULL 

Definition at line 234 of file acl.c.

References ast_acl::acl, ast_free, ast_free_ha(), AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_acl::list, and NULL.

Referenced by __init_manager(), __sip_destroy(), acl_destroy(), build_peer(), build_user(), manager_free_user(), peer_destructor(), reload_config(), sip_allow_anyrtp_remote(), sip_destroy_peer(), unload_module(), and user_destructor().

00235 {
00236    struct ast_acl *current;
00237 
00238    if (!acl_list) {
00239       return NULL;
00240    }
00241 
00242    AST_LIST_LOCK(acl_list);
00243    while ((current = AST_LIST_REMOVE_HEAD(acl_list, list))) {
00244       ast_free_ha(current->acl);
00245       ast_free(current);
00246    }
00247    AST_LIST_UNLOCK(acl_list);
00248 
00249    AST_LIST_HEAD_DESTROY(acl_list);
00250    ast_free(acl_list);
00251 
00252    return NULL;
00253 }

void ast_free_ha ( struct ast_ha ha  ) 

Free a list of HAs.

Given the head of a list of HAs, it and all appended HAs are freed

Parameters:
ha The head of the list of HAs to free
Return values:
void 

Definition at line 223 of file acl.c.

References ast_free, and ast_ha::next.

Referenced by add_calltoken_ignore(), ast_append_ha(), ast_free_acl_list(), AST_TEST_DEFINE(), build_callno_limits(), destroy_gateway(), destroy_named_acl(), ip_identify_destroy(), named_acl_find_realtime(), reload_config(), test_item_destructor(), transport_destroy(), transport_localnet_handler(), and unload_module().

00224 {
00225    struct ast_ha *hal;
00226    while (ha) {
00227       hal = ha;
00228       ha = ha->next;
00229       ast_free(hal);
00230    }
00231 }

int ast_get_ip ( struct ast_sockaddr addr,
const char *  hostname 
)

Get the IP address given a hostname.

Similar in nature to ast_gethostbyname, except that instead of getting an entire hostent structure, you instead are given only the IP address inserted into a ast_sockaddr structure.

Parameters:
addr The IP address found. The address family is used as an input parameter to filter the returned addresses. If it is AST_AF_UNSPEC, both IPv4 and IPv6 addresses can be returned.
hostname The hostname to look up
Return values:
0 Success
-1 Failure

Definition at line 910 of file acl.c.

References ast_get_ip_or_srv(), and NULL.

Referenced by build_gateway(), build_peer(), config_parse_variables(), peer_set_srcaddr(), setup_stunaddr(), and stun_monitor_request().

00911 {
00912    return ast_get_ip_or_srv(addr, hostname, NULL);
00913 }

int ast_get_ip_or_srv ( struct ast_sockaddr addr,
const char *  hostname,
const char *  service 
)

Get the IP address given a hostname and optional service.

If the service parameter is non-NULL, then an SRV lookup will be made by prepending the service to the hostname parameter, separated by a '.' For example, if hostname is "example.com" and service is "_sip._udp" then an SRV lookup will be done for "_sip._udp.example.com". If service is NULL, then this function acts exactly like a call to ast_get_ip.

Parameters:
addr The IP address found. The address family is used as an input parameter to filter the returned addresses. If it is 0, both IPv4 and IPv6 addresses can be returned.
hostname The hostname to look up
service A specific service provided by the host. A NULL service results in an A-record lookup instead of an SRV lookup
Return values:
0 Success
-1 Failure

Definition at line 807 of file acl.c.

References ast_get_srv(), ast_sockaddr_set_port, host, NULL, PARSE_PORT_FORBID, resolve_first(), and ast_sockaddr::ss.

Referenced by ast_get_ip(), create_addr(), dnsmgr_refresh(), internal_dnsmgr_lookup(), and proxy_update().

00808 {
00809    char srv[256];
00810    char host[256];
00811    int srv_ret = 0;
00812    int tportno;
00813 
00814    if (service) {
00815       snprintf(srv, sizeof(srv), "%s.%s", service, hostname);
00816       if ((srv_ret = ast_get_srv(NULL, host, sizeof(host), &tportno, srv)) > 0) {
00817          hostname = host;
00818       }
00819    }
00820 
00821    if (resolve_first(addr, hostname, PARSE_PORT_FORBID, addr->ss.ss_family) != 0) {
00822       return -1;
00823    }
00824 
00825    if (srv_ret > 0) {
00826       ast_sockaddr_set_port(addr, tportno);
00827    }
00828 
00829    return 0;
00830 }

void ast_ha_join ( const struct ast_ha ha,
struct ast_str **  buf 
)

Convert HAs to a comma separated string value.

Parameters:
ha the starting ha head
buf string buffer to convert data to

Definition at line 667 of file acl.c.

References ast_ha::addr, AST_SENSE_ALLOW, ast_sockaddr_stringify_addr(), ast_str_append(), ast_strdupa, ast_ha::netmask, ast_ha::next, and ast_ha::sense.

Referenced by localnet_to_str(), and match_to_str().

00668 {
00669    for (; ha; ha = ha->next) {
00670       const char *addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr));
00671       ast_str_append(buf, 0, "%s%s/%s",
00672                 ha->sense == AST_SENSE_ALLOW ? "!" : "",
00673                 addr, ast_sockaddr_stringify_addr(&ha->netmask));
00674       if (ha->next) {
00675          ast_str_append(buf, 0, ",");
00676       }
00677    }
00678 }

void ast_ha_join_cidr ( const struct ast_ha ha,
struct ast_str **  buf 
)

Convert HAs to a comma separated string value using CIDR notation.

Parameters:
ha the starting ha head
buf string buffer to convert data to

Definition at line 680 of file acl.c.

References ast_ha::addr, AST_SENSE_ALLOW, ast_sockaddr_cidr_bits(), ast_sockaddr_stringify_addr(), ast_str_append(), ast_ha::netmask, ast_ha::next, and ast_ha::sense.

00681 {
00682    for (; ha; ha = ha->next) {
00683       const char *addr = ast_sockaddr_stringify_addr(&ha->addr);
00684       ast_str_append(buf, 0, "%s%s/%d",
00685                 ha->sense == AST_SENSE_ALLOW ? "!" : "",
00686                 addr, ast_sockaddr_cidr_bits(&ha->netmask));
00687       if (ha->next) {
00688          ast_str_append(buf, 0, ",");
00689       }
00690    }
00691 }

int ast_ouraddrfor ( const struct ast_sockaddr them,
struct ast_sockaddr us 
)

Get our local IP address when contacting a remote host.

This function will attempt to connect(2) to them over UDP using a source port of 5060. If the connect(2) call is successful, then we inspect the sockaddr_in output parameter of connect(2) to determine the IP address used to connect to them. This IP address is then copied into us.

Parameters:
them The IP address to which we wish to attempt to connect
[out] us The source IP address used to connect to them
Return values:
-1 Failure
0 Success

Definition at line 915 of file acl.c.

References ast_connect(), ast_debug, ast_getsockname(), ast_log, ast_sockaddr_is_ipv6(), ast_sockaddr_port, ast_sockaddr_set_port, ast_sockaddr_stringify_addr(), ast_strdupa, LOG_ERROR, and LOG_WARNING.

Referenced by ast_find_ourip(), ast_sip_ouraddrfor(), build_gateway(), find_subchannel_and_lock(), sip_acf_channel_read(), and unicast_rtp_request().

00916 {
00917    int port;
00918    int s;
00919 
00920    port = ast_sockaddr_port(us);
00921 
00922    if ((s = socket(ast_sockaddr_is_ipv6(them) ? AF_INET6 : AF_INET,
00923          SOCK_DGRAM, 0)) < 0) {
00924       ast_log(LOG_ERROR, "Cannot create socket\n");
00925       return -1;
00926    }
00927 
00928    if (ast_connect(s, them)) {
00929       ast_log(LOG_WARNING, "Cannot connect\n");
00930       close(s);
00931       return -1;
00932    }
00933    if (ast_getsockname(s, us)) {
00934 
00935       ast_log(LOG_WARNING, "Cannot get socket name\n");
00936       close(s);
00937       return -1;
00938    }
00939    close(s);
00940 
00941    {
00942       const char *them_addr = ast_strdupa(ast_sockaddr_stringify_addr(them));
00943       const char *us_addr = ast_strdupa(ast_sockaddr_stringify_addr(us));
00944 
00945       ast_debug(3, "For destination '%s', our source address is '%s'.\n",
00946             them_addr, us_addr);
00947    }
00948 
00949    ast_sockaddr_set_port(us, port);
00950 
00951    return 0;
00952 }

int ast_str2cos ( const char *  value,
unsigned int *  cos 
)

Convert a string to the appropriate COS value.

Parameters:
value The COS string to convert
[out] cos The integer representation of that COS value
Return values:
-1 Failure
0 Success

Definition at line 863 of file acl.c.

Referenced by config_parse_variables(), reload_config(), and set_config().

00864 {
00865    int fval;
00866 
00867    if (sscanf(value, "%30d", &fval) == 1) {
00868       if (fval < 8) {
00869           *cos = fval;
00870           return 0;
00871       }
00872    }
00873 
00874    return -1;
00875 }

int ast_str2tos ( const char *  value,
unsigned int *  tos 
)

Convert a string to the appropriate TOS value.

Parameters:
value The TOS string to convert
[out] tos The integer representation of that TOS value
Return values:
-1 Failure
0 Success

Definition at line 877 of file acl.c.

References ARRAY_LEN, name, and dscp_codepoint::space.

Referenced by config_parse_variables(), iax_template_parse(), reload_config(), set_config(), tos_handler(), and transport_tos_handler().

00878 {
00879    int fval;
00880    unsigned int x;
00881 
00882    if (sscanf(value, "%30i", &fval) == 1) {
00883       *tos = fval & 0xFF;
00884       return 0;
00885    }
00886 
00887    for (x = 0; x < ARRAY_LEN(dscp_pool1); x++) {
00888       if (!strcasecmp(value, dscp_pool1[x].name)) {
00889          *tos = dscp_pool1[x].space << 2;
00890          return 0;
00891       }
00892    }
00893 
00894    return -1;
00895 }

const char* ast_tos2str ( unsigned int  tos  ) 

Convert a TOS value into its string representation.

Parameters:
tos The TOS value to look up
Returns:
The string equivalent of the TOS value

Definition at line 897 of file acl.c.

References ARRAY_LEN, dscp_codepoint::name, and dscp_codepoint::space.

Referenced by sip_show_settings().

00898 {
00899    unsigned int x;
00900 
00901    for (x = 0; x < ARRAY_LEN(dscp_pool1); x++) {
00902       if (dscp_pool1[x].space == (tos >> 2)) {
00903          return dscp_pool1[x].name;
00904       }
00905    }
00906 
00907    return "unknown";
00908 }

static int get_local_address ( struct ast_sockaddr ourip  )  [static]

Definition at line 55 of file acl.c.

Referenced by ast_find_ourip().

00056 {
00057    return -1;
00058 }

static int parse_cidr_mask ( struct ast_sockaddr addr,
int  is_v4,
const char *  mask_str 
) [static]

Parse a netmask in CIDR notation.

For a mask of an IPv4 address, this should be a number between 0 and 32. For a mask of an IPv6 address, this should be a number between 0 and 128. This function creates an IPv6 ast_sockaddr from the given netmask. For masks of IPv4 addresses, this is accomplished by adding 96 to the original netmask.

Parameters:
[out] addr The ast_sockaddr produced from the CIDR netmask
is_v4 Tells if the address we are masking is IPv4.
mask_str The CIDR mask to convert
Return values:
-1 Failure
0 Success

Definition at line 366 of file acl.c.

References ast_sockaddr_from_sin, ast_sockaddr::len, ast_sockaddr::ss, and V6_WORD.

Referenced by ast_append_ha().

00367 {
00368    int mask;
00369 
00370    if (sscanf(mask_str, "%30d", &mask) != 1) {
00371       return -1;
00372    }
00373 
00374    if (is_v4) {
00375       struct sockaddr_in sin;
00376       if (mask < 0 || mask > 32) {
00377          return -1;
00378       }
00379       memset(&sin, 0, sizeof(sin));
00380       sin.sin_family = AF_INET;
00381       /* If mask is 0, then we already have the
00382        * appropriate all 0s address in sin from
00383        * the above memset.
00384        */
00385       if (mask != 0) {
00386          sin.sin_addr.s_addr = htonl(0xFFFFFFFF << (32 - mask));
00387       }
00388       ast_sockaddr_from_sin(addr, &sin);
00389    } else {
00390       struct sockaddr_in6 sin6;
00391       int i;
00392       if (mask < 0 || mask > 128) {
00393          return -1;
00394       }
00395       memset(&sin6, 0, sizeof(sin6));
00396       sin6.sin6_family = AF_INET6;
00397       for (i = 0; i < 4; ++i) {
00398          /* Once mask reaches 0, we don't have
00399           * to explicitly set anything anymore
00400           * since sin6 was zeroed out already
00401           */
00402          if (mask > 0) {
00403             V6_WORD(&sin6, i) = htonl(0xFFFFFFFF << (mask < 32 ? (32 - mask) : 0));
00404             mask -= mask < 32 ? mask : 32;
00405          }
00406       }
00407       memcpy(&addr->ss, &sin6, sizeof(sin6));
00408       addr->len = sizeof(sin6);
00409    }
00410 
00411    return 0;
00412 }

static int resolve_first ( struct ast_sockaddr addr,
const char *  name,
int  flag,
int  family 
) [static]

Definition at line 786 of file acl.c.

References ast_debug, ast_free, ast_log, ast_sockaddr_copy(), ast_sockaddr_resolve(), and LOG_WARNING.

Referenced by ast_find_ourip(), and ast_get_ip_or_srv().

00788 {
00789    struct ast_sockaddr *addrs;
00790    int addrs_cnt;
00791 
00792    addrs_cnt = ast_sockaddr_resolve(&addrs, name, flag, family);
00793    if (addrs_cnt > 0) {
00794       if (addrs_cnt > 1) {
00795          ast_debug(1, "Multiple addresses. Using the first only\n");
00796       }
00797       ast_sockaddr_copy(addr, &addrs[0]);
00798       ast_free(addrs);
00799    } else {
00800       ast_log(LOG_WARNING, "Unable to lookup '%s'\n", name);
00801       return -1;
00802    }
00803 
00804    return 0;
00805 }


Variable Documentation

struct dscp_codepoint dscp_pool1[] [static]

Definition at line 839 of file acl.c.


Generated on Thu Apr 16 06:28:08 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6