Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
res_pjsip_endpoint_identifier_ip.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Mark Michelson <mmichelson@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*** MODULEINFO
20 <depend>pjproject</depend>
21 <depend>res_pjsip</depend>
22 <support_level>core</support_level>
23 ***/
24
25#include "asterisk.h"
26
27#include <pjsip.h>
28
29#include "asterisk/res_pjsip.h"
31#include "asterisk/module.h"
32#include "asterisk/acl.h"
33#include "asterisk/manager.h"
35
36/*** DOCUMENTATION
37 <configInfo name="res_pjsip_endpoint_identifier_ip" language="en_US">
38 <synopsis>Module that identifies endpoints</synopsis>
39 <configFile name="pjsip.conf">
40 <configObject name="identify">
41 <since>
42 <version>13.14.0</version>
43 <version>14.3.0</version>
44 </since>
45 <synopsis>Identifies endpoints via some criteria.</synopsis>
46 <description>
47 <para>This module provides alternatives to matching inbound requests to
48 a configured endpoint. At least one of the matching mechanisms
49 must be provided, or the object configuration is invalid.</para>
50 <para>The matching mechanisms are provided by the following
51 configuration options:</para>
52 <enumlist>
53 <enum name="match"><para>Match by source IP address.</para></enum>
54 <enum name="match_header"><para>Match by SIP header.</para></enum>
55 </enumlist>
56 <note><para>If multiple matching criteria are provided then an inbound
57 request will be matched to the endpoint if it matches
58 <emphasis>any</emphasis> of the criteria.</para></note>
59 </description>
60 <configOption name="endpoint">
61 <since>
62 <version>12.0.0</version>
63 </since>
64 <synopsis>Name of endpoint identified</synopsis>
65 </configOption>
66 <configOption name="match">
67 <since>
68 <version>12.2.0</version>
69 </since>
70 <synopsis>IP addresses or networks to match against.</synopsis>
71 <description>
72 <para>The value is a comma-delimited list of IP addresses or
73 hostnames.</para>
74 <para>IP addresses may have a subnet mask appended. The subnet
75 mask may be written in either CIDR or dotted-decimal
76 notation. Separate the IP address and subnet mask with a slash
77 ('/'). A source port can also be specified by adding a colon (':')
78 after the address but before the subnet mask, e.g.
79 3.2.1.0:5061/24. To specify a source port for an IPv6 address, the
80 address itself must be enclosed in square brackets
81 ('[2001:db8:0::1]:5060')</para>
82 <para>When a hostname is used, the behavior depends on whether
83 <replaceable>srv_lookups</replaceable> is enabled and/or a source
84 port is provided. If <replaceable>srv_lookups</replaceable> is
85 enabled and a source port is not provided, Asterisk will perform
86 an SRV lookup on the provided hostname, adding all of the A and
87 AAAA records that are resolved.</para>
88 <para>If the SRV lookup fails,
89 <replaceable>srv_lookups</replaceable> is disabled, or a source
90 port is specified when the hostname is configured, Asterisk will
91 resolve the hostname and add all A and AAAA records that are
92 resolved.</para>
93 </description>
94 </configOption>
95 <configOption name="srv_lookups" default="yes">
96 <since>
97 <version>13.14.0</version>
98 <version>14.3.0</version>
99 </since>
100 <synopsis>Perform SRV lookups for provided hostnames.</synopsis>
101 <description>
102 <para>When enabled, <replaceable>srv_lookups</replaceable> will
103 perform SRV lookups for _sip._udp, _sip._tcp, and _sips._tcp of
104 the given hostnames to determine additional addresses that traffic
105 may originate from.
106 </para>
107 </description>
108 </configOption>
109 <configOption name="match_header">
110 <since>
111 <version>13.15.0</version>
112 <version>14.4.0</version>
113 </since>
114 <synopsis>Header/value pair to match against.</synopsis>
115 <description>
116 <para>A SIP header whose value is used to match against. SIP
117 requests containing the header, along with the specified value,
118 will be mapped to the specified endpoint. The header must be
119 specified with a <literal>:</literal>, as in
120 <literal>match_header = SIPHeader: value</literal>.
121 </para>
122 <para>The specified SIP header value can be a regular
123 expression if the value is of the form
124 /<replaceable>regex</replaceable>/.
125 </para>
126 <note><para>Use of a regex is expensive so be sure you need
127 to use a regex to match your endpoint.
128 </para></note>
129 </description>
130 </configOption>
131 <configOption name="match_request_uri">
132 <since>
133 <version>18.23.0</version>
134 <version>20.8.0</version>
135 <version>21.3.0</version>
136 </since>
137 <synopsis>Request URI to match against.</synopsis>
138 <description>
139 <para>The SIP request URI is used to match against.
140 </para>
141 <para>The specified SIP request URI can be a regular
142 expression if the value is of the form
143 /<replaceable>regex</replaceable>/.
144 </para>
145 <note><para>Use of a regex is expensive so be sure you need
146 to use a regex to match your endpoint.
147 </para></note>
148 </description>
149 </configOption>
150 <configOption name="type">
151 <since>
152 <version>12.0.0</version>
153 </since>
154 <synopsis>Must be of type 'identify'.</synopsis>
155 </configOption>
156 </configObject>
157 </configFile>
158 </configInfo>
159 ***/
160
161/*! \brief The number of buckets for storing hosts for resolution */
162#define HOSTS_BUCKETS 53
163
164/*! \brief Structure for an IP identification matching object */
166 /*! \brief Sorcery object details */
168 /*! \brief Stringfields */
170 /*! The name of the endpoint */
172 /*! If matching by request, the value to match against */
174 /*! If matching by header, the header/value to match against */
176 /*! SIP header name of the match_header string */
178 /*! SIP header value of the match_header string */
180 );
181 /*! Compiled match_header regular expression when is_header_regex is non-zero */
183 /*! Compiled match_request_uri regular expression when is_request_uri_regex is non-zero */
185 /*! \brief Networks or addresses that should match this */
187 /*! \brief Hosts to be resolved when applying configuration */
189 /*! \brief Perform SRV resolution of hostnames */
190 unsigned int srv_lookups;
191 /*! Non-zero if match_header has a regular expression (i.e., regex_header_buf is valid) */
192 unsigned int is_header_regex:1;
193 /*! Non-zero if match_header or match_request has a regular expression (i.e., regex_request_uri_buf is valid) */
194 unsigned int is_request_uri_regex:1;
195};
196
197/*! \brief Destructor function for a matching object */
198static void ip_identify_destroy(void *obj)
199{
200 struct ip_identify_match *identify = obj;
201
203 ast_free_ha(identify->matches);
204 ao2_cleanup(identify->hosts);
205 if (identify->is_header_regex) {
206 regfree(&identify->regex_header_buf);
207 }
208 if (identify->is_request_uri_regex) {
209 regfree(&identify->regex_request_uri_buf);
210 }
211}
212
213/*! \brief Allocator function for a matching object */
214static void *ip_identify_alloc(const char *name)
215{
216 struct ip_identify_match *identify = ast_sorcery_generic_alloc(sizeof(*identify), ip_identify_destroy);
217
218 if (!identify || ast_string_field_init(identify, 256)) {
219 ao2_cleanup(identify);
220 return NULL;
221 }
222
223 return identify;
224}
225
226/*! \brief Comparator function for matching an object by header */
227static int header_identify_match_check(void *obj, void *arg, int flags)
228{
229 struct ip_identify_match *identify = obj;
230 struct pjsip_rx_data *rdata = arg;
231 pjsip_hdr *header;
232 pj_str_t pj_header_name;
233 int header_present;
234
235 if (ast_strlen_zero(identify->match_header)) {
236 return 0;
237 }
238
239 pj_header_name = pj_str((void *) identify->match_header_name);
240
241 /* Check all headers of the given name for a match. */
242 header_present = 0;
243 for (header = NULL;
244 (header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &pj_header_name, header));
245 header = header->next) {
246 char *pos;
247 int len;
248 char buf[PATH_MAX];
249
250 header_present = 1;
251
252 /* Print header line to buf */
253 len = pjsip_hdr_print_on(header, buf, sizeof(buf) - 1);
254 if (len < 0) {
255 /* Buffer not large enough or no header vptr! */
256 ast_assert(0);
257 continue;
258 }
259 buf[len] = '\0';
260
261 /* Remove header name from pj_buf and trim blanks. */
262 pos = strchr(buf, ':');
263 if (!pos) {
264 /* No header name? Bug in PJPROJECT if so. */
265 ast_assert(0);
266 continue;
267 }
268 pos = ast_strip(pos + 1);
269
270 /* Does header value match what we are looking for? */
271 if (identify->is_header_regex) {
272 if (!regexec(&identify->regex_header_buf, pos, 0, NULL, 0)) {
273 return CMP_MATCH;
274 }
275 } else if (!strcmp(identify->match_header_value, pos)) {
276 return CMP_MATCH;
277 }
278
279 ast_debug(3, "Identify '%s': SIP message has '%s' header but value '%s' does not match '%s'.\n",
281 identify->match_header_name,
282 pos,
283 identify->match_header_value);
284 }
285 if (!header_present) {
286 ast_debug(3, "Identify '%s': SIP message does not have '%s' header.\n",
288 identify->match_header_name);
289 }
290 return 0;
291}
292
293/*! \brief Comparator function for matching an object by request URI */
294static int request_identify_match_check(void *obj, void *arg, int flags)
295{
296 struct ip_identify_match *identify = obj;
297 struct pjsip_rx_data *rdata = arg;
298 int len;
299 char buf[PJSIP_MAX_URL_SIZE];
300
301 if (ast_strlen_zero(identify->match_request_uri)) {
302 return 0;
303 }
304
305 /* Print request URI to req_buf */
306 len = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, buf, sizeof(buf) - 1);
307 if (len < 0) {
308 /* Buffer not large enough or no pj uri vptr! */
309 ast_assert(0);
310 } else {
311 /* Terminate the pj_str */
312 buf[len] = '\0';
313 /* Does request URI match what we are looking for? */
314 if (identify->is_request_uri_regex) {
315 if (!regexec(&identify->regex_request_uri_buf, buf, 0, NULL, 0)) {
316 return CMP_MATCH;
317 }
318 } else if (!strcmp(identify->match_request_uri, buf)) {
319 return CMP_MATCH;
320 }
321 ast_debug(3, "Identify '%s': request URI not match '%s' (value='%s').\n",
322 ast_sorcery_object_get_id(identify), identify->match_request_uri, buf);
323 }
324
325 return 0;
326}
327
328/*! \brief Comparator function for matching an object by IP address */
329static int ip_identify_match_check(void *obj, void *arg, int flags)
330{
331 struct ip_identify_match *identify = obj;
332 struct ast_sockaddr *addr = arg;
333 int sense;
334
335 sense = ast_apply_ha(identify->matches, addr);
336 if (sense != AST_SENSE_ALLOW) {
337 ast_debug(3, "Source address %s matches identify '%s'\n",
339 ast_sorcery_object_get_id(identify));
340 return CMP_MATCH;
341 } else {
342 ast_debug(3, "Source address %s does not match identify '%s'\n",
344 ast_sorcery_object_get_id(identify));
345 return 0;
346 }
347}
348
349static struct ast_sip_endpoint *common_identify(ao2_callback_fn *identify_match_cb, void *arg)
350{
351 RAII_VAR(struct ao2_container *, candidates, NULL, ao2_cleanup);
352 struct ip_identify_match *match;
353 struct ast_sip_endpoint *endpoint;
354
355 /* If no possibilities exist return early to save some time */
356 candidates = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify",
358 if (!candidates || !ao2_container_count(candidates)) {
359 ast_debug(3, "No identify sections to match against\n");
360 return NULL;
361 }
362
363 match = ao2_callback(candidates, 0, identify_match_cb, arg);
364 if (!match) {
365 return NULL;
366 }
367
368 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
369 match->endpoint_name);
370 if (endpoint) {
371 ast_debug(3, "Identify '%s' SIP message matched to endpoint %s\n",
372 ast_sorcery_object_get_id(match), match->endpoint_name);
373 } else {
374 ast_log(LOG_WARNING, "Identify '%s' points to endpoint '%s' but endpoint could not be found\n",
375 ast_sorcery_object_get_id(match), match->endpoint_name);
376 }
377
378 ao2_ref(match, -1);
379 return endpoint;
380}
381
382static struct ast_sip_endpoint *ip_identify(pjsip_rx_data *rdata)
383{
384 struct ast_sockaddr addr = { { 0, } };
385
386 ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
387 ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port);
388
390}
391
394};
395
396static struct ast_sip_endpoint *header_identify(pjsip_rx_data *rdata)
397{
399}
400
401static struct ast_sip_endpoint *request_identify(pjsip_rx_data *rdata)
402{
404}
405
408};
409
412};
413
414/*! \brief Helper function which performs a host lookup and adds result to identify match */
415static int ip_identify_match_host_lookup(struct ip_identify_match *identify, const char *host)
416{
417 struct ast_sockaddr *addrs;
418 int num_addrs = 0, error = 0, i;
419 int results = 0;
420
421 num_addrs = ast_sockaddr_resolve(&addrs, host, 0, AST_AF_UNSPEC);
422 if (!num_addrs) {
423 return -1;
424 }
425
426 for (i = 0; i < num_addrs; ++i) {
427 /* Check if the address is already in the list, if so don't add it again */
428 if (identify->matches && (ast_apply_ha(identify->matches, &addrs[i]) != AST_SENSE_ALLOW)) {
429 continue;
430 }
431
432 /* We deny what we actually want to match because there is an implicit permit all rule for ACLs */
433 identify->matches = ast_append_ha_with_port("d", ast_sockaddr_stringify(&addrs[i]), identify->matches, &error);
434
435 if (!identify->matches || error) {
436 results = -1;
437 break;
438 }
439
440 results += 1;
441 }
442
443 ast_free(addrs);
444
445 return results;
446}
447
448/*! \brief Helper function which performs an SRV lookup and then resolves the hostname */
449static int ip_identify_match_srv_lookup(struct ip_identify_match *identify, const char *prefix, const char *host, int results)
450{
451 char service[NI_MAXHOST];
452 struct srv_context *context = NULL;
453 int srv_ret;
454 const char *srvhost;
455 unsigned short srvport;
456
457 snprintf(service, sizeof(service), "%s.%s", prefix, host);
458
459 while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
460 int hosts;
461
462 /* In the case of the SRV lookup we don't care if it fails, we will output a log message
463 * when we fallback to a normal lookup.
464 */
465 hosts = ip_identify_match_host_lookup(identify, srvhost);
466 if (hosts == -1) {
467 results = -1;
468 break;
469 } else {
470 results += hosts;
471 }
472 }
473
475
476 return results;
477}
478
479/*! \brief Custom handler for match field */
480static int ip_identify_match_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
481{
482 struct ip_identify_match *identify = obj;
483 char *input_string = ast_strdupa(var->value);
484 char *current_string;
485
486 if (ast_strlen_zero(var->value)) {
487 return 0;
488 }
489
490 while ((current_string = ast_strip(strsep(&input_string, ",")))) {
491 char *mask;
492 struct ast_sockaddr address;
493 int error = 0;
494
495 if (ast_strlen_zero(current_string)) {
496 continue;
497 }
498
499 mask = strrchr(current_string, '/');
500
501 /* If it looks like a netmask is present, or we can immediately parse as an IP,
502 * hand things off to the ACL */
503 if (mask || ast_sockaddr_parse(&address, current_string, 0)) {
504 identify->matches = ast_append_ha_with_port("d", current_string, identify->matches, &error);
505
506 if (!identify->matches || error) {
507 ast_log(LOG_ERROR, "Failed to add address '%s' to ip endpoint identifier '%s'\n",
508 current_string, ast_sorcery_object_get_id(obj));
509 return -1;
510 }
511
512 continue;
513 }
514
515 if (!identify->hosts) {
517 if (!identify->hosts) {
518 ast_log(LOG_ERROR, "Failed to create container to store hosts on ip endpoint identifier '%s'\n",
520 return -1;
521 }
522 }
523
524 error = ast_str_container_add(identify->hosts, current_string);
525 if (error) {
526 ast_log(LOG_ERROR, "Failed to store host '%s' for resolution on ip endpoint identifier '%s'\n",
527 current_string, ast_sorcery_object_get_id(obj));
528 return -1;
529 }
530 }
531
532 return 0;
533}
534
535/*! \brief Apply handler for identify type */
536static int ip_identify_apply(const struct ast_sorcery *sorcery, void *obj)
537{
538 struct ip_identify_match *identify = obj;
539 char *current_string;
540 struct ao2_iterator i;
541
542 /* Validate the identify object configuration */
543 if (ast_strlen_zero(identify->endpoint_name)) {
544 ast_log(LOG_ERROR, "Identify '%s' missing required endpoint name.\n",
545 ast_sorcery_object_get_id(identify));
546 return -1;
547 }
548 if (ast_strlen_zero(identify->match_header) /* No header to match */
549 && ast_strlen_zero(identify->match_request_uri) /* and no request to match */
550 /* and no static IP addresses with a mask */
551 && !identify->matches
552 /* and no addresses to resolve */
553 && (!identify->hosts || !ao2_container_count(identify->hosts))) {
554 ast_log(LOG_ERROR, "Identify '%s' is not configured to match anything.\n",
555 ast_sorcery_object_get_id(identify));
556 return -1;
557 }
558
559 if (!ast_strlen_zero(identify->match_header)) {
560 char *c_header;
561 char *c_value;
562 int len;
563
564 /* Split the header name and value */
565 c_header = ast_strdupa(identify->match_header);
566 c_value = strchr(c_header, ':');
567 if (!c_value) {
568 ast_log(LOG_ERROR, "Identify '%s' missing ':' separator in match_header '%s'.\n",
569 ast_sorcery_object_get_id(identify), identify->match_header);
570 return -1;
571 }
572 *c_value = '\0';
573 c_value = ast_strip(c_value + 1);
574 c_header = ast_strip(c_header);
575
576 if (ast_strlen_zero(c_header)) {
577 ast_log(LOG_ERROR, "Identify '%s' has no SIP header to match in match_header '%s'.\n",
578 ast_sorcery_object_get_id(identify), identify->match_header);
579 return -1;
580 }
581
582 if (!strcmp(c_value, "//")) {
583 /* An empty regex is the same as an empty literal string. */
584 c_value = "";
585 }
586
587 if (ast_string_field_set(identify, match_header_name, c_header)
588 || ast_string_field_set(identify, match_header_value, c_value)) {
589 return -1;
590 }
591
592 len = strlen(c_value);
593 if (2 < len && c_value[0] == '/' && c_value[len - 1] == '/') {
594 /* Make "/regex/" into "regex" */
595 c_value[len - 1] = '\0';
596 ++c_value;
597
598 if (regcomp(&identify->regex_header_buf, c_value, REG_EXTENDED | REG_NOSUB)) {
599 ast_log(LOG_ERROR, "Identify '%s' failed to compile match_request_uri regex '%s'.\n",
600 ast_sorcery_object_get_id(identify), c_value);
601 return -1;
602 }
603 identify->is_header_regex = 1;
604 }
605 }
606
607 if (!ast_strlen_zero(identify->match_request_uri)) {
608 char *c_string;
609 int len;
610
611 len = strlen(identify->match_request_uri);
612 c_string = ast_strdupa(identify->match_request_uri);
613
614 if (!strcmp(c_string, "//")) {
615 /* An empty regex is the same as an empty literal string. */
616 c_string = "";
617 }
618
619 if (2 < len && c_string[0] == '/' && c_string[len - 1] == '/') {
620 /* Make "/regex/" into "regex" */
621 c_string[len - 1] = '\0';
622 ++c_string;
623
624 if (regcomp(&identify->regex_request_uri_buf, c_string, REG_EXTENDED | REG_NOSUB)) {
625 ast_log(LOG_ERROR, "Identify '%s' failed to compile match_header regex '%s'.\n",
626 ast_sorcery_object_get_id(identify), c_string);
627 return -1;
628 }
629 identify->is_request_uri_regex = 1;
630 }
631 }
632
633 if (!identify->hosts) {
634 /* No match addresses to resolve */
635 return 0;
636 }
637
638 /* Hosts can produce dynamic content, so mark the identify as such */
640
641 /* Resolve the match addresses now */
642 i = ao2_iterator_init(identify->hosts, 0);
643 while ((current_string = ao2_iterator_next(&i))) {
644 int results = 0;
645 char *colon = strrchr(current_string, ':');
646
647 /* We skip SRV lookup if a colon is present, assuming a port was specified */
648 if (!colon) {
649 /* No port, and we know this is not an IP address, so perform SRV resolution on it */
650 if (identify->srv_lookups) {
651 results = ip_identify_match_srv_lookup(identify, "_sip._udp", current_string,
652 results);
653 if (results != -1) {
654 results = ip_identify_match_srv_lookup(identify, "_sip._tcp",
655 current_string, results);
656 }
657 if (results != -1) {
658 results = ip_identify_match_srv_lookup(identify, "_sips._tcp",
659 current_string, results);
660 }
661 }
662 }
663
664 /* If SRV fails fall back to a normal lookup on the host itself */
665 if (!results) {
666 results = ip_identify_match_host_lookup(identify, current_string);
667 }
668
669 if (results == 0) {
670 ast_log(LOG_WARNING, "Identify '%s' provided address '%s' did not resolve to any address\n",
671 ast_sorcery_object_get_id(identify), current_string);
672 } else if (results == -1) {
673 ast_log(LOG_ERROR, "Identify '%s' failed when adding resolution results of '%s'\n",
674 ast_sorcery_object_get_id(identify), current_string);
675 ao2_ref(current_string, -1);
677 return -1;
678 }
679
680 ao2_ref(current_string, -1);
681 }
683
684 ao2_ref(identify->hosts, -1);
685 identify->hosts = NULL;
686
687 return 0;
688}
689
690static int match_to_str(const void *obj, const intptr_t *args, char **buf)
691{
693 const struct ip_identify_match *identify = obj;
694
695 ast_ha_join(identify->matches, &str);
697 return 0;
698}
699
700static void match_to_var_list_append(struct ast_variable **head, struct ast_ha *ha)
701{
702 char str[MAX_OBJECT_FIELD];
703 const char *addr;
704
705 if (ast_sockaddr_port(&ha->addr)) {
707 } else {
709 }
710
711 snprintf(str, MAX_OBJECT_FIELD, "%s%s/%s", ha->sense == AST_SENSE_ALLOW ? "!" : "",
713
714 ast_variable_list_append(head, ast_variable_new("match", str, ""));
715}
716
717static int match_to_var_list(const void *obj, struct ast_variable **fields)
718{
719 const struct ip_identify_match *identify = obj;
720 struct ast_variable *head = NULL;
721 struct ast_ha *ha = identify->matches;
722
723 for (; ha; ha = ha->next) {
724 match_to_var_list_append(&head, ha);
725 }
726
727 if (head) {
728 *fields = head;
729 }
730
731 return 0;
732}
733
734static int sip_identify_to_ami(const struct ip_identify_match *identify,
735 struct ast_str **buf)
736{
737 return ast_sip_sorcery_object_to_ami(identify, buf);
738}
739
740static int send_identify_ami_event(void *obj, void *arg, void *data, int flags)
741{
742 struct ip_identify_match *identify = obj;
743 const char *endpoint_name = arg;
744 struct ast_sip_ami *ami = data;
745 struct ast_str *buf;
746
747 /* Build AMI event */
748 buf = ast_sip_create_ami_event("IdentifyDetail", ami);
749 if (!buf) {
750 return CMP_STOP;
751 }
752 if (sip_identify_to_ami(identify, &buf)) {
753 ast_free(buf);
754 return CMP_STOP;
755 }
756 ast_str_append(&buf, 0, "EndpointName: %s\r\n", endpoint_name);
757
758 /* Send AMI event */
759 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
760 ++ami->count;
761
762 ast_free(buf);
763 return 0;
764}
765
766static int format_ami_endpoint_identify(const struct ast_sip_endpoint *endpoint,
767 struct ast_sip_ami *ami)
768{
769 struct ao2_container *identifies;
770 struct ast_variable fields = {
771 .name = "endpoint",
772 .value = ast_sorcery_object_get_id(endpoint),
773 };
774
775 identifies = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify",
777 if (!identifies) {
778 return -1;
779 }
780
781 /* Build and send any found identify object's AMI IdentifyDetail event. */
784 (void *) ast_sorcery_object_get_id(endpoint),
785 ami);
786
787 ao2_ref(identifies, -1);
788 return 0;
789}
790
793};
794
795static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
796{
797 const struct ast_sip_endpoint *endpoint = container;
798 struct ao2_container *identifies;
799
800 struct ast_variable fields = {
801 .name = "endpoint",
802 .value = ast_sorcery_object_get_id(endpoint),
803 .next = NULL,
804 };
805
806 identifies = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify",
808 if (!identifies) {
809 return -1;
810 }
811
812 ao2_callback(identifies, OBJ_NODATA, callback, args);
813 ao2_cleanup(identifies);
814
815 return 0;
816}
817
818static struct ao2_container *cli_get_container(const char *regex)
819{
821 struct ao2_container *s_container;
822
824 if (!container) {
825 return NULL;
826 }
827
830 if (!s_container) {
831 return NULL;
832 }
833
834 if (ao2_container_dup(s_container, container, 0)) {
835 ao2_ref(s_container, -1);
836 return NULL;
837 }
838
839 return s_container;
840}
841
842static void *cli_retrieve_by_id(const char *id)
843{
844 return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "identify", id);
845}
846
847static int cli_print_header(void *obj, void *arg, int flags)
848{
849 struct ast_sip_cli_context *context = arg;
850 int indent = CLI_INDENT_TO_SPACES(context->indent_level);
851 int filler = CLI_MAX_WIDTH - indent - 22;
852
853 ast_assert(context->output_buffer != NULL);
854
855 ast_str_append(&context->output_buffer, 0,
856 "%*s: <Identify/Endpoint%*.*s>\n",
857 indent, "Identify", filler, filler, CLI_HEADER_FILLER);
858
859 if (context->recurse) {
860 context->indent_level++;
861 indent = CLI_INDENT_TO_SPACES(context->indent_level);
862 filler = CLI_LAST_TABSTOP - indent - 24;
863
864 ast_str_append(&context->output_buffer, 0,
865 "%*s: <criteria%*.*s>\n",
866 indent, "Match", filler, filler, CLI_HEADER_FILLER);
867
868 context->indent_level--;
869 }
870
871 return 0;
872}
873
874static int cli_print_body(void *obj, void *arg, int flags)
875{
877 struct ip_identify_match *ident = obj;
878 struct ast_sip_cli_context *context = arg;
879 struct ast_ha *match;
880 int indent;
881
882 ast_assert(context->output_buffer != NULL);
883
884 ast_str_append(&context->output_buffer, 0, "%*s: %s/%s\n",
885 CLI_INDENT_TO_SPACES(context->indent_level), "Identify",
887
888 if (context->recurse) {
889 context->indent_level++;
890 indent = CLI_INDENT_TO_SPACES(context->indent_level);
891
892 for (match = ident->matches; match; match = match->next) {
893 const char *addr;
894
895 if (ast_sockaddr_port(&match->addr)) {
897 } else {
899 }
900
901 ast_str_append(&context->output_buffer, 0, "%*s: %s%s/%d\n",
902 indent,
903 "Match",
904 match->sense == AST_SENSE_ALLOW ? "!" : "",
905 addr, ast_sockaddr_cidr_bits(&match->netmask));
906 }
907
908 if (!ast_strlen_zero(ident->match_header)) {
909 ast_str_append(&context->output_buffer, 0, "%*s: %s\n",
910 indent,
911 "Header",
912 ident->match_header);
913 }
914
915 if (!ast_strlen_zero(ident->match_request_uri)) {
916 ast_str_append(&context->output_buffer, 0, "%*s: %s\n",
917 indent,
918 "RequestURI",
919 ident->match_request_uri);
920 }
921
922 context->indent_level--;
923
924 if (context->indent_level == 0) {
925 ast_str_append(&context->output_buffer, 0, "\n");
926 }
927 }
928
929 if (context->show_details
930 || (context->show_details_only_level_0 && context->indent_level == 0)) {
931 ast_str_append(&context->output_buffer, 0, "\n");
933 }
934
935 return 0;
936}
937
938/*
939 * A function pointer to callback needs to be within the
940 * module in order to avoid problems with an undefined
941 * symbol when the module is loaded.
942 */
943static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd,
944 struct ast_cli_args *a)
945{
946 return ast_sip_cli_traverse_objects(e, cmd, a);
947}
948
949static struct ast_cli_entry cli_identify[] = {
950AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Identifies",
951 .command = "pjsip list identifies",
952 .usage = "Usage: pjsip list identifies [ like <pattern> ]\n"
953 " List the configured PJSIP Identifies\n"
954 " Optional regular expression pattern is used to filter the list.\n"),
955AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Identifies",
956 .command = "pjsip show identifies",
957 .usage = "Usage: pjsip show identifies [ like <pattern> ]\n"
958 " Show the configured PJSIP Identifies\n"
959 " Optional regular expression pattern is used to filter the list.\n"),
960AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Identify",
961 .command = "pjsip show identify",
962 .usage = "Usage: pjsip show identify <id>\n"
963 " Show the configured PJSIP Identify\n"),
964};
965
967
968static int load_module(void)
969{
970 ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_endpoint_identifier_ip");
971 ast_sorcery_apply_default(ast_sip_get_sorcery(), "identify", "config", "pjsip.conf,criteria=type=identify");
972
975 }
976
977 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "type", "", OPT_NOOP_T, 0, 0);
978 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, endpoint_name));
980 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "match_header", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, match_header));
981 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "match_request_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, match_request_uri));
982 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "srv_lookups", "yes", OPT_BOOL_T, 1, FLDSET(struct ip_identify_match, srv_lookups));
984
989
991 if (!cli_formatter) {
992 ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
994 }
995 cli_formatter->name = "identify";
1002
1005
1007}
1008
1009static int reload_module(void)
1010{
1012
1013 return 0;
1014}
1015
1016static int unload_module(void)
1017{
1024
1025 return 0;
1026}
1027
1028AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP IP endpoint identifier",
1029 .support_level = AST_MODULE_SUPPORT_CORE,
1030 .load = load_module,
1032 .unload = unload_module,
1033 .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4,
1034 .requires = "res_pjsip",
Access Control of various sorts.
void ast_free_ha(struct ast_ha *ha)
Free a list of HAs.
Definition: acl.c:222
@ AST_SENSE_ALLOW
Definition: acl.h:38
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.
Definition: acl.c:807
void ast_ha_join(const struct ast_ha *ha, struct ast_str **buf)
Convert HAs to a comma separated string value.
Definition: acl.c:722
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.
Definition: acl.c:717
const char * str
Definition: app_jack.c:150
#define var
Definition: ast_expr2f.c:605
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define PATH_MAX
Definition: asterisk.h:40
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
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 ao2_iterator_next(iter)
Definition: astobj2.h:1911
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition: astobj2.h:1723
int() ao2_callback_fn(void *obj, void *arg, int flags)
Type of a generic callback function.
Definition: astobj2.h:1226
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
enum ast_cc_service_type service
Definition: ccss.c:389
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2387
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
@ OPT_NOOP_T
Type for a default handler that should do nothing.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
char * address
Definition: f2c.h:59
static const char name[]
Definition: format_mp3.c:68
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1907
static char prefix[MAX_PREFIX]
Definition: http.c:144
#define ast_variable_new(name, value, filename)
#define ast_variable_list_append(head, new_var)
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_CHANNEL_DEPEND
Definition: module.h:340
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
int ast_sockaddr_cidr_bits(const struct ast_sockaddr *sa)
Count the 1 bits in a netmask.
Definition: netsock2.c:130
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:256
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition: netsock2.h:517
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.
Definition: netsock2.c:280
@ AST_AF_UNSPEC
Definition: netsock2.h:54
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:532
static char * ast_sockaddr_stringify_addr(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
Definition: netsock2.h:286
static int reload(void)
struct ao2_container * container
Definition: res_fax.c:531
void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
Unregister a SIP endpoint identifier.
Definition: res_pjsip.c:315
void ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Register an endpoint formatter.
Definition: res_pjsip.c:481
void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Unregister an endpoint formatter.
Definition: res_pjsip.c:487
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.
int ast_sip_register_endpoint_identifier_with_name(struct ast_sip_endpoint_identifier *identifier, const char *name)
Register a SIP endpoint identifier with a name.
Definition: res_pjsip.c:233
struct ast_str * ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
Creates a string to store AMI event data in.
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
int ast_sip_unregister_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
Unregisters a CLI formatter.
Definition: pjsip_cli.c:326
#define CLI_HEADER_FILLER
Definition: res_pjsip_cli.h:24
#define CLI_MAX_WIDTH
Definition: res_pjsip_cli.h:26
int ast_sip_cli_print_sorcery_objectset(void *obj, void *arg, int flags)
Prints a sorcery object's ast_variable list.
Definition: pjsip_cli.c:36
#define CLI_LAST_TABSTOP
Definition: res_pjsip_cli.h:27
char * ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pjsip_cli.c:109
#define CLI_INDENT_TO_SPACES(x)
Definition: res_pjsip_cli.h:29
int ast_sip_register_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
Registers a CLI formatter.
Definition: pjsip_cli.c:310
static int sip_identify_to_ami(const struct ip_identify_match *identify, struct ast_str **buf)
static int request_identify_match_check(void *obj, void *arg, int flags)
Comparator function for matching an object by request URI.
static int cli_print_header(void *obj, void *arg, int flags)
static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
static void * ip_identify_alloc(const char *name)
Allocator function for a matching object.
static int ip_identify_match_check(void *obj, void *arg, int flags)
Comparator function for matching an object by IP address.
static struct ast_sip_endpoint_identifier request_identifier
static int format_ami_endpoint_identify(const struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami)
static int ip_identify_match_srv_lookup(struct ip_identify_match *identify, const char *prefix, const char *host, int results)
Helper function which performs an SRV lookup and then resolves the hostname.
static struct ast_sip_endpoint * ip_identify(pjsip_rx_data *rdata)
static int reload_module(void)
static int ip_identify_apply(const struct ast_sorcery *sorcery, void *obj)
Apply handler for identify type.
static int ip_identify_match_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Custom handler for match field.
static struct ast_sip_endpoint_identifier header_identifier
#define HOSTS_BUCKETS
The number of buckets for storing hosts for resolution.
static void * cli_retrieve_by_id(const char *id)
static int send_identify_ami_event(void *obj, void *arg, void *data, int flags)
static void ip_identify_destroy(void *obj)
Destructor function for a matching object.
static int ip_identify_match_host_lookup(struct ip_identify_match *identify, const char *host)
Helper function which performs a host lookup and adds result to identify match.
static struct ast_cli_entry cli_identify[]
static void match_to_var_list_append(struct ast_variable **head, struct ast_ha *ha)
static struct ao2_container * cli_get_container(const char *regex)
static struct ast_sip_endpoint * request_identify(pjsip_rx_data *rdata)
struct ast_sip_endpoint_formatter endpoint_identify_formatter
static int load_module(void)
static int cli_print_body(void *obj, void *arg, int flags)
static struct ast_sip_endpoint * header_identify(pjsip_rx_data *rdata)
static char * my_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int unload_module(void)
static struct ast_sip_endpoint * common_identify(ao2_callback_fn *identify_match_cb, void *arg)
static struct ast_sip_cli_formatter_entry * cli_formatter
static int header_identify_match_check(void *obj, void *arg, int flags)
Comparator function for matching an object by header.
static struct ast_sip_endpoint_identifier ip_identifier
static int match_to_str(const void *obj, const intptr_t *args, char **buf)
static int match_to_var_list(const void *obj, struct ast_variable **fields)
static struct ast_sorcery * sorcery
#define NULL
Definition: resample.c:96
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition: sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition: sorcery.h:123
void ast_sorcery_object_set_has_dynamic_contents(const void *object)
Set the dynamic contents flag on a sorcery object.
Definition: sorcery.c:2384
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
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.
Definition: sorcery.c:1954
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.
Definition: sorcery.c:1393
#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.
Definition: sorcery.h:1005
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition: sorcery.c:2464
#define ast_sorcery_apply_config(sorcery, name)
Definition: sorcery.h:455
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
Definition: sorcery.c:2440
#define MAX_OBJECT_FIELD
Maximum length of an object field name.
Definition: sorcery.h:110
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:476
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.
Definition: sorcery.c:1442
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.
Definition: sorcery.c:1897
void ast_srv_cleanup(struct srv_context **context)
Cleanup resources associated with ast_srv_lookup.
Definition: srv.c:248
int ast_srv_lookup(struct srv_context **context, const char *service, const char **host, unsigned short *port)
Retrieve set of SRV lookups, in order.
Definition: srv.c:202
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
struct ao2_container * ast_str_container_alloc_options(enum ao2_alloc_opts opts, int buckets)
Allocates a hash container for bare strings.
Definition: strings.c:200
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.
Definition: strings.c:205
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
internal representation of ACL entries In principle user applications would have no need for this,...
Definition: acl.h:51
struct ast_sockaddr addr
Definition: acl.h:53
struct ast_sockaddr netmask
Definition: acl.h:54
struct ast_ha * next
Definition: acl.h:56
enum ast_acl_sense sense
Definition: acl.h:55
AMI variable container.
Definition: res_pjsip.h:3200
struct mansession * s
Definition: res_pjsip.h:3202
CLI Formatter Context passed to all formatters.
Definition: res_pjsip_cli.h:34
CLI Formatter Registry Entry.
Definition: res_pjsip_cli.h:52
int(* iterate)(void *container, ao2_callback_fn callback, void *args)
Definition: res_pjsip_cli.h:66
ao2_callback_fn * print_header
Definition: res_pjsip_cli.h:60
void *(* retrieve_by_id)(const char *id)
Definition: res_pjsip_cli.h:68
const char *(* get_id)(const void *obj)
Definition: res_pjsip_cli.h:70
const char * name
Definition: res_pjsip_cli.h:58
ao2_callback_fn * print_body
Definition: res_pjsip_cli.h:62
struct ao2_container *(* get_container)(const char *regex)
Definition: res_pjsip_cli.h:64
An entity responsible formatting endpoint information.
Definition: res_pjsip.h:3226
int(* format_ami)(const struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami)
Callback used to format endpoint information over AMI.
Definition: res_pjsip.h:3230
An entity responsible for identifying the source of a SIP message.
Definition: res_pjsip.h:1409
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.
Definition: res_pjsip.h:1414
An entity with which Asterisk communicates.
Definition: res_pjsip.h:1051
Socket address structure.
Definition: netsock2.h:97
Full structure for sorcery.
Definition: sorcery.c:230
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
struct header * next
Structure for an IP identification matching object.
struct ao2_container * hosts
Hosts to be resolved when applying configuration.
SORCERY_OBJECT(details)
Sorcery object details.
const ast_string_field match_header
struct ast_ha * matches
Networks or addresses that should match this.
unsigned int srv_lookups
Perform SRV resolution of hostnames.
const ast_string_field match_request_uri
const ast_string_field endpoint_name
const ast_string_field match_header_value
const ast_string_field match_header_name
const char * args
static struct test_val a
int error(const char *format,...)
Definition: utils/frame.c:999
char * usage
Definition: utils/frame.c:37
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739
#define ARRAY_LEN(a)
Definition: utils.h:666