29 #include "asterisk/res_pjsip.h"
30 #include "asterisk/res_pjsip_cli.h"
34 #include "res_pjsip/include/res_pjsip_private.h"
136 #define HOSTS_BUCKETS 53
172 static void ip_identify_destroy(
void *obj)
178 ao2_cleanup(identify->
hosts);
188 static void *ip_identify_alloc(
const char *name)
193 ao2_cleanup(identify);
201 static int header_identify_match_check(
void *obj,
void *arg,
int flags)
204 struct pjsip_rx_data *rdata = arg;
206 pj_str_t pj_header_name;
218 (header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &pj_header_name, header));
219 header = header->next) {
227 len = pjsip_hdr_print_on(header, buf,
sizeof(buf) - 1);
236 pos = strchr(buf,
':');
253 ast_debug(3,
"Identify '%s': SIP message has '%s' header but value '%s' does not match '%s'.\n",
259 if (!header_present) {
260 ast_debug(3,
"Identify '%s': SIP message does not have '%s' header.\n",
268 static int request_identify_match_check(
void *obj,
void *arg,
int flags)
271 struct pjsip_rx_data *rdata = arg;
273 char buf[PJSIP_MAX_URL_SIZE];
280 len = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, buf,
sizeof(buf) - 1);
295 ast_debug(3,
"Identify '%s': request URI not match '%s' (value='%s').\n",
303 static int ip_identify_match_check(
void *obj,
void *arg,
int flags)
310 if (sense != AST_SENSE_ALLOW) {
311 ast_debug(3,
"Source address %s matches identify '%s'\n",
316 ast_debug(3,
"Source address %s does not match identify '%s'\n",
333 ast_debug(3,
"No identify sections to match against\n");
337 match =
ao2_callback(candidates, 0, identify_match_cb, arg);
345 ast_debug(3,
"Identify '%s' SIP message matched to endpoint %s\n",
348 ast_log(LOG_WARNING,
"Identify '%s' points to endpoint '%s' but endpoint could not be found\n",
363 return common_identify(ip_identify_match_check, &addr);
372 return common_identify(header_identify_match_check, rdata);
377 return common_identify(request_identify_match_check, rdata);
389 static int ip_identify_match_host_lookup(
struct ip_identify_match *identify,
const char *host)
392 int num_addrs = 0, error = 0, i;
400 for (i = 0; i < num_addrs; ++i) {
409 if (!identify->
matches || error) {
423 static int ip_identify_match_srv_lookup(
struct ip_identify_match *identify,
const char *prefix,
const char *host,
int results)
425 char service[NI_MAXHOST];
429 unsigned short srvport;
431 snprintf(service,
sizeof(service),
"%s.%s", prefix, host);
433 while (!(srv_ret =
ast_srv_lookup(&context, service, &srvhost, &srvport))) {
439 hosts = ip_identify_match_host_lookup(identify, srvhost);
458 char *current_string;
460 if (ast_strlen_zero(var->
value)) {
464 while ((current_string =
ast_strip(strsep(&input_string,
",")))) {
469 if (ast_strlen_zero(current_string)) {
473 mask = strrchr(current_string,
'/');
480 if (!identify->
matches || error) {
481 ast_log(LOG_ERROR,
"Failed to add address '%s' to ip endpoint identifier '%s'\n",
489 if (!identify->
hosts) {
491 if (!identify->
hosts) {
492 ast_log(LOG_ERROR,
"Failed to create container to store hosts on ip endpoint identifier '%s'\n",
500 ast_log(LOG_ERROR,
"Failed to store host '%s' for resolution on ip endpoint identifier '%s'\n",
510 static int ip_identify_apply(
const struct ast_sorcery *sorcery,
void *obj)
513 char *current_string;
518 ast_log(LOG_ERROR,
"Identify '%s' missing required endpoint name.\n",
528 ast_log(LOG_ERROR,
"Identify '%s' is not configured to match anything.\n",
540 c_value = strchr(c_header,
':');
542 ast_log(LOG_ERROR,
"Identify '%s' missing ':' separator in match_header '%s'.\n",
550 if (ast_strlen_zero(c_header)) {
551 ast_log(LOG_ERROR,
"Identify '%s' has no SIP header to match in match_header '%s'.\n",
556 if (!strcmp(c_value,
"//")) {
566 len = strlen(c_value);
567 if (2 < len && c_value[0] ==
'/' && c_value[len - 1] ==
'/') {
569 c_value[len - 1] =
'\0';
572 if (regcomp(&identify->
regex_header_buf, c_value, REG_EXTENDED | REG_NOSUB)) {
573 ast_log(LOG_ERROR,
"Identify '%s' failed to compile match_request_uri regex '%s'.\n",
588 if (!strcmp(c_string,
"//")) {
593 if (2 < len && c_string[0] ==
'/' && c_string[len - 1] ==
'/') {
595 c_string[len - 1] =
'\0';
599 ast_log(LOG_ERROR,
"Identify '%s' failed to compile match_header regex '%s'.\n",
607 if (!identify->
hosts) {
617 while ((current_string = ao2_iterator_next(&i))) {
619 char *colon = strrchr(current_string,
':');
625 results = ip_identify_match_srv_lookup(identify,
"_sip._udp", current_string,
628 results = ip_identify_match_srv_lookup(identify,
"_sip._tcp",
629 current_string, results);
632 results = ip_identify_match_srv_lookup(identify,
"_sips._tcp",
633 current_string, results);
640 results = ip_identify_match_host_lookup(identify, current_string);
644 ast_log(LOG_WARNING,
"Identify '%s' provided address '%s' did not resolve to any address\n",
646 }
else if (results == -1) {
647 ast_log(LOG_ERROR,
"Identify '%s' failed when adding resolution results of '%s'\n",
659 identify->
hosts = NULL;
664 static int match_to_str(
const void *obj,
const intptr_t *args,
char **buf)
685 snprintf(str,
MAX_OBJECT_FIELD,
"%s%s/%s", ha->sense == AST_SENSE_ALLOW ?
"!" :
"",
688 ast_variable_list_append(head, ast_variable_new(
"match", str,
""));
691 static int match_to_var_list(
const void *obj,
struct ast_variable **fields)
697 for (; ha; ha = ha->next) {
698 match_to_var_list_append(&head, ha);
711 return ast_sip_sorcery_object_to_ami(identify, buf);
714 static int send_identify_ami_event(
void *obj,
void *arg,
void *data,
int flags)
722 buf = ast_sip_create_ami_event(
"IdentifyDetail", ami);
726 if (sip_identify_to_ami(identify, &buf)) {
740 static int format_ami_endpoint_identify(
const struct ast_sip_endpoint *endpoint,
757 send_identify_ami_event,
787 ao2_cleanup(identifies);
792 static struct ao2_container *cli_get_container(
const char *regex)
816 static void *cli_retrieve_by_id(
const char *
id)
821 static int cli_print_header(
void *obj,
void *arg,
int flags)
824 int indent = CLI_INDENT_TO_SPACES(context->
indent_level);
825 int filler = CLI_MAX_WIDTH - indent - 22;
830 "%*s: <Identify/Endpoint%*.*s>\n",
831 indent,
"Identify", filler, filler, CLI_HEADER_FILLER);
836 filler = CLI_LAST_TABSTOP - indent - 24;
839 "%*s: <criteria%*.*s>\n",
840 indent,
"Match", filler, filler, CLI_HEADER_FILLER);
848 static int cli_print_body(
void *obj,
void *arg,
int flags)
859 CLI_INDENT_TO_SPACES(context->
indent_level),
"Identify",
866 for (match = ident->
matches; match; match = match->next) {
878 match->sense == AST_SENSE_ALLOW ?
"!" :
"",
906 ast_sip_cli_print_sorcery_objectset(ident, context, 0);
917 static char *my_cli_traverse_objects(
struct ast_cli_entry *e,
int cmd,
920 return ast_sip_cli_traverse_objects(e, cmd, a);
924 AST_CLI_DEFINE(my_cli_traverse_objects,
"List PJSIP Identifies",
925 .
command =
"pjsip list identifies",
926 .
usage =
"Usage: pjsip list identifies [ like <pattern> ]\n"
927 " List the configured PJSIP Identifies\n"
928 " Optional regular expression pattern is used to filter the list.\n"),
929 AST_CLI_DEFINE(my_cli_traverse_objects,
"Show PJSIP Identifies",
930 .
command =
"pjsip show identifies",
931 .
usage =
"Usage: pjsip show identifies [ like <pattern> ]\n"
932 " Show the configured PJSIP Identifies\n"
933 " Optional regular expression pattern is used to filter the list.\n"),
934 AST_CLI_DEFINE(my_cli_traverse_objects,
"Show PJSIP Identify",
935 .
command =
"pjsip show identify",
936 .
usage =
"Usage: pjsip show identify <id>\n"
937 " Show the configured PJSIP Identify\n"),
942 static int load_module(
void)
944 ast_sorcery_apply_config(ast_sip_get_sorcery(),
"res_pjsip_endpoint_identifier_ip");
945 ast_sorcery_apply_default(ast_sip_get_sorcery(),
"identify",
"config",
"pjsip.conf,criteria=type=identify");
959 ast_sip_register_endpoint_identifier_with_name(&ip_identifier,
"ip");
960 ast_sip_register_endpoint_identifier_with_name(&header_identifier,
"header");
961 ast_sip_register_endpoint_identifier_with_name(&request_identifier,
"request_uri");
962 ast_sip_register_endpoint_formatter(&endpoint_identify_formatter);
965 if (!cli_formatter) {
966 ast_log(LOG_ERROR,
"Unable to allocate memory for cli formatter\n");
969 cli_formatter->
name =
"identify";
973 cli_formatter->
iterate = cli_iterator;
977 ast_sip_register_cli_formatter(cli_formatter);
983 static int reload_module(
void)
990 static int unload_module(
void)
993 ast_sip_unregister_cli_formatter(cli_formatter);
994 ast_sip_unregister_endpoint_formatter(&endpoint_identify_formatter);
995 ast_sip_unregister_endpoint_identifier(&header_identifier);
996 ast_sip_unregister_endpoint_identifier(&request_identifier);
997 ast_sip_unregister_endpoint_identifier(&ip_identifier);
1002 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"PJSIP IP endpoint identifier",
1003 .support_level = AST_MODULE_SUPPORT_CORE,
1004 .load = load_module,
1005 .reload = reload_module,
1006 .unload = unload_module,
1008 .requires =
"res_pjsip",
static char * ast_sockaddr_stringify_addr(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
struct ast_str * output_buffer
struct ao2_container *(* get_container)(const char *regex)
void astman_append(struct mansession *s, const char *fmt,...)
Asterisk main include file. File version handling, generic pbx functions.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
CLI Formatter Registry Entry.
int( ao2_callback_fn)(void *obj, void *arg, int flags)
Type of a generic callback function.
regex_t regex_request_uri_buf
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
descriptor for a cli entry.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Structure for variables, used for configurations and for channel variables.
void ast_srv_cleanup(struct srv_context **context)
Cleanup resources associated with ast_srv_lookup.
Perform no matching, return all objects.
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Full structure for sorcery.
int(* iterate)(void *container, ao2_callback_fn callback, void *args)
Type for a default handler that should do nothing.
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.
unsigned int is_request_uri_regex
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Return all matching objects.
#define ast_strdup(str)
A wrapper for strdup()
struct ast_sip_endpoint *(* identify_endpoint)(pjsip_rx_data *rdata)
Callback used to identify the source of a message. See ast_sip_identify_endpoint for more details...
CLI Formatter Context passed to all formatters.
void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to load persistent objects.
Socket address structure.
void ast_ha_join(const struct ast_ha *ha, struct ast_str **buf)
Convert HAs to a comma separated string value.
struct ao2_container * ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
Retrieve multiple objects using a regular expression on their id.
const ast_string_field match_request_uri
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
internal representation of ACL entries In principle user applications would have no need for this...
struct ao2_container * hosts
Hosts to be resolved when applying configuration.
#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags,...)
Register a field within an object with custom handlers.
unsigned int srv_lookups
Perform SRV resolution of hostnames.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
struct ao2_container * ast_str_container_alloc_options(enum ao2_alloc_opts opts, int buckets)
Allocates a hash container for bare strings.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Access Control of various sorts.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
#define AST_STRING_FIELD(name)
Declare a string field.
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
void *(* retrieve_by_id)(const char *id)
struct ao2_container * container
#define ast_debug(level,...)
Log a DEBUG message.
An entity with which Asterisk communicates.
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
#define MAX_OBJECT_FIELD
Maximum length of an object field name.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
unsigned int is_header_regex
Support for dynamic strings.
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Type for default option handler for bools (ast_true/ast_false)
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
const ast_string_field match_header_name
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
Module has failed to load, may be in an inconsistent state.
An entity responsible for identifying the source of a SIP message.
const char *(* get_id)(const void *obj)
int ast_sockaddr_cidr_bits(const struct ast_sockaddr *sa)
Count the 1 bits in a netmask.
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
void ast_free_ha(struct ast_ha *ha)
Free a list of HAs.
int ast_srv_lookup(struct srv_context **context, const char *service, const char **host, unsigned short *port)
Retrieve set of SRV lookups, in order.
SORCERY_OBJECT(details)
Sorcery object details.
void ast_sorcery_object_set_has_dynamic_contents(const void *object)
Set the dynamic contents flag on a sorcery object.
struct ast_ha * ast_append_ha_with_port(const char *sense, const char *stuff, struct ast_ha *path, int *error)
Add a new rule with optional port to a list of HAs.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Type for default option handler for stringfields.
ao2_callback_fn * print_header
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
ao2_callback_fn * print_body
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
const ast_string_field endpoint_name
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Structure for an IP identification matching object.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
const ast_string_field match_header
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects.
struct ast_ha * matches
Networks or addresses that should match this.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, int flags, int family)
Parses a string with an IPv4 or IPv6 address and place results into an array.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
unsigned show_details_only_level_0
const ast_string_field match_header_value