Asterisk - The Open Source Telephony Project GIT-master-70eff7f
Loading...
Searching...
No Matches
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
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
409
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, int *resolved)
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 *resolved = 1;
426
427 for (i = 0; i < num_addrs; ++i) {
428 /* Check if the address is already in the list, if so don't add it again */
429 if (identify->matches && (ast_apply_ha(identify->matches, &addrs[i]) != AST_SENSE_ALLOW)) {
430 continue;
431 }
432
433 /* We deny what we actually want to match because there is an implicit permit all rule for ACLs */
434 identify->matches = ast_append_ha_with_port("d", ast_sockaddr_stringify(&addrs[i]), identify->matches, &error);
435
436 if (!identify->matches || error) {
437 results = -1;
438 break;
439 }
440
441 results += 1;
442 }
443
444 ast_free(addrs);
445
446 return results;
447}
448
449/*! \brief Helper function which performs an SRV lookup and then resolves the hostname */
450static int ip_identify_match_srv_lookup(struct ip_identify_match *identify, const char *prefix, const char *host, int results,
451 int *resolved)
452{
453 char service[NI_MAXHOST];
454 struct srv_context *context = NULL;
455 int srv_ret;
456 const char *srvhost;
457 unsigned short srvport;
458
459 snprintf(service, sizeof(service), "%s.%s", prefix, host);
460
461 while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
462 int hosts;
463
464 /* In the case of the SRV lookup we don't care if it fails, we will output a log message
465 * when we fallback to a normal lookup.
466 */
467 hosts = ip_identify_match_host_lookup(identify, srvhost, resolved);
468 if (hosts == -1) {
469 results = -1;
470 break;
471 } else {
472 results += hosts;
473 }
474 }
475
476 ast_srv_cleanup(&context);
477
478 return results;
479}
480
481/*! \brief Custom handler for match field */
482static int ip_identify_match_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
483{
484 struct ip_identify_match *identify = obj;
485 char *input_string = ast_strdupa(var->value);
486 char *current_string;
487
488 if (ast_strlen_zero(var->value)) {
489 return 0;
490 }
491
492 while ((current_string = ast_strip(strsep(&input_string, ",")))) {
493 char *mask;
494 struct ast_sockaddr address;
495 int error = 0;
496
497 if (ast_strlen_zero(current_string)) {
498 continue;
499 }
500
501 mask = strrchr(current_string, '/');
502
503 /* If it looks like a netmask is present, or we can immediately parse as an IP,
504 * hand things off to the ACL */
505 if (mask || ast_sockaddr_parse(&address, current_string, 0)) {
506 identify->matches = ast_append_ha_with_port("d", current_string, identify->matches, &error);
507
508 if (!identify->matches || error) {
509 ast_log(LOG_ERROR, "Failed to add address '%s' to ip endpoint identifier '%s'\n",
510 current_string, ast_sorcery_object_get_id(obj));
511 return -1;
512 }
513
514 continue;
515 }
516
517 if (!identify->hosts) {
519 if (!identify->hosts) {
520 ast_log(LOG_ERROR, "Failed to create container to store hosts on ip endpoint identifier '%s'\n",
522 return -1;
523 }
524 }
525
526 error = ast_str_container_add(identify->hosts, current_string);
527 if (error) {
528 ast_log(LOG_ERROR, "Failed to store host '%s' for resolution on ip endpoint identifier '%s'\n",
529 current_string, ast_sorcery_object_get_id(obj));
530 return -1;
531 }
532 }
533
534 return 0;
535}
536
537/*! \brief Apply handler for identify type */
538static int ip_identify_apply(const struct ast_sorcery *sorcery, void *obj)
539{
540 struct ip_identify_match *identify = obj;
541 char *current_string;
542 struct ao2_iterator i;
543
544 /* Validate the identify object configuration */
545 if (ast_strlen_zero(identify->endpoint_name)) {
546 ast_log(LOG_ERROR, "Identify '%s' missing required endpoint name.\n",
547 ast_sorcery_object_get_id(identify));
548 return -1;
549 }
550 if (ast_strlen_zero(identify->match_header) /* No header to match */
551 && ast_strlen_zero(identify->match_request_uri) /* and no request to match */
552 /* and no static IP addresses with a mask */
553 && !identify->matches
554 /* and no addresses to resolve */
555 && (!identify->hosts || !ao2_container_count(identify->hosts))) {
556 ast_log(LOG_ERROR, "Identify '%s' is not configured to match anything.\n",
557 ast_sorcery_object_get_id(identify));
558 return -1;
559 }
560
561 if (!ast_strlen_zero(identify->match_header)) {
562 char *c_header;
563 char *c_value;
564 int len;
565
566 /* Split the header name and value */
567 c_header = ast_strdupa(identify->match_header);
568 c_value = strchr(c_header, ':');
569 if (!c_value) {
570 ast_log(LOG_ERROR, "Identify '%s' missing ':' separator in match_header '%s'.\n",
571 ast_sorcery_object_get_id(identify), identify->match_header);
572 return -1;
573 }
574 *c_value = '\0';
575 c_value = ast_strip(c_value + 1);
576 c_header = ast_strip(c_header);
577
578 if (ast_strlen_zero(c_header)) {
579 ast_log(LOG_ERROR, "Identify '%s' has no SIP header to match in match_header '%s'.\n",
580 ast_sorcery_object_get_id(identify), identify->match_header);
581 return -1;
582 }
583
584 if (!strcmp(c_value, "//")) {
585 /* An empty regex is the same as an empty literal string. */
586 c_value = "";
587 }
588
589 if (ast_string_field_set(identify, match_header_name, c_header)
590 || ast_string_field_set(identify, match_header_value, c_value)) {
591 return -1;
592 }
593
594 len = strlen(c_value);
595 if (2 < len && c_value[0] == '/' && c_value[len - 1] == '/') {
596 /* Make "/regex/" into "regex" */
597 c_value[len - 1] = '\0';
598 ++c_value;
599
600 if (regcomp(&identify->regex_header_buf, c_value, REG_EXTENDED | REG_NOSUB)) {
601 ast_log(LOG_ERROR, "Identify '%s' failed to compile match_request_uri regex '%s'.\n",
602 ast_sorcery_object_get_id(identify), c_value);
603 return -1;
604 }
605 identify->is_header_regex = 1;
606 }
607 }
608
609 if (!ast_strlen_zero(identify->match_request_uri)) {
610 char *c_string;
611 int len;
612
613 len = strlen(identify->match_request_uri);
614 c_string = ast_strdupa(identify->match_request_uri);
615
616 if (!strcmp(c_string, "//")) {
617 /* An empty regex is the same as an empty literal string. */
618 c_string = "";
619 }
620
621 if (2 < len && c_string[0] == '/' && c_string[len - 1] == '/') {
622 /* Make "/regex/" into "regex" */
623 c_string[len - 1] = '\0';
624 ++c_string;
625
626 if (regcomp(&identify->regex_request_uri_buf, c_string, REG_EXTENDED | REG_NOSUB)) {
627 ast_log(LOG_ERROR, "Identify '%s' failed to compile match_header regex '%s'.\n",
628 ast_sorcery_object_get_id(identify), c_string);
629 return -1;
630 }
631 identify->is_request_uri_regex = 1;
632 }
633 }
634
635 if (!identify->hosts) {
636 /* No match addresses to resolve */
637 return 0;
638 }
639
640 /* Hosts can produce dynamic content, so mark the identify as such */
642
643 /* Resolve the match addresses now */
644 i = ao2_iterator_init(identify->hosts, 0);
645 while ((current_string = ao2_iterator_next(&i))) {
646 int results = 0;
647 int resolved = 0;
648 char *colon = strrchr(current_string, ':');
649
650 /* We skip SRV lookup if a colon is present, assuming a port was specified */
651 if (!colon) {
652 /* No port, and we know this is not an IP address, so perform SRV resolution on it */
653 if (identify->srv_lookups) {
654 results = ip_identify_match_srv_lookup(identify, "_sip._udp", current_string,
655 results, &resolved);
656 if (results != -1) {
657 results = ip_identify_match_srv_lookup(identify, "_sip._tcp",
658 current_string, results, &resolved);
659 }
660 if (results != -1) {
661 results = ip_identify_match_srv_lookup(identify, "_sips._tcp",
662 current_string, results, &resolved);
663 }
664 }
665 }
666
667 /* If SRV fails fall back to a normal lookup on the host itself */
668 if (!results) {
669 results = ip_identify_match_host_lookup(identify, current_string, &resolved);
670 }
671
672 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 } else if (!results && resolved) {
679 ast_log(LOG_WARNING, "Identify '%s' provided address '%s' resolved, "
680 "but resolved addresses are already present for matching\n",
681 ast_sorcery_object_get_id(identify), current_string);
682 } else if (!results) {
683 ast_log(LOG_WARNING, "Identify '%s' provided address '%s' did not resolve to any address\n",
684 ast_sorcery_object_get_id(identify), current_string);
685 }
686
687 ao2_ref(current_string, -1);
688 }
690
691 ao2_ref(identify->hosts, -1);
692 identify->hosts = NULL;
693
694 return 0;
695}
696
697static int match_to_str(const void *obj, const intptr_t *args, char **buf)
698{
700 const struct ip_identify_match *identify = obj;
701
702 ast_ha_join(identify->matches, &str);
704 return 0;
705}
706
707static void match_to_var_list_append(struct ast_variable **head, struct ast_ha *ha)
708{
709 char str[MAX_OBJECT_FIELD];
710 const char *addr;
711
712 if (ast_sockaddr_port(&ha->addr)) {
714 } else {
716 }
717
718 snprintf(str, MAX_OBJECT_FIELD, "%s%s/%s", ha->sense == AST_SENSE_ALLOW ? "!" : "",
720
721 ast_variable_list_append(head, ast_variable_new("match", str, ""));
722}
723
724static int match_to_var_list(const void *obj, struct ast_variable **fields)
725{
726 const struct ip_identify_match *identify = obj;
727 struct ast_variable *head = NULL;
728 struct ast_ha *ha = identify->matches;
729
730 for (; ha; ha = ha->next) {
731 match_to_var_list_append(&head, ha);
732 }
733
734 if (head) {
735 *fields = head;
736 }
737
738 return 0;
739}
740
741static int sip_identify_to_ami(const struct ip_identify_match *identify,
742 struct ast_str **buf)
743{
744 return ast_sip_sorcery_object_to_ami(identify, buf);
745}
746
747static int send_identify_ami_event(void *obj, void *arg, void *data, int flags)
748{
749 struct ip_identify_match *identify = obj;
750 const char *endpoint_name = arg;
751 struct ast_sip_ami *ami = data;
752 struct ast_str *buf;
753
754 /* Build AMI event */
755 buf = ast_sip_create_ami_event("IdentifyDetail", ami);
756 if (!buf) {
757 return CMP_STOP;
758 }
759 if (sip_identify_to_ami(identify, &buf)) {
760 ast_free(buf);
761 return CMP_STOP;
762 }
763 ast_str_append(&buf, 0, "EndpointName: %s\r\n", endpoint_name);
764
765 /* Send AMI event */
766 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
767 ++ami->count;
768
769 ast_free(buf);
770 return 0;
771}
772
773static int format_ami_endpoint_identify(const struct ast_sip_endpoint *endpoint,
774 struct ast_sip_ami *ami)
775{
776 struct ao2_container *identifies;
777 struct ast_variable fields = {
778 .name = "endpoint",
779 .value = ast_sorcery_object_get_id(endpoint),
780 };
781
782 identifies = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify",
784 if (!identifies) {
785 return -1;
786 }
787
788 /* Build and send any found identify object's AMI IdentifyDetail event. */
791 (void *) ast_sorcery_object_get_id(endpoint),
792 ami);
793
794 ao2_ref(identifies, -1);
795 return 0;
796}
797
801
803{
804 const struct ast_sip_endpoint *endpoint = container;
805 struct ao2_container *identifies;
806
807 struct ast_variable fields = {
808 .name = "endpoint",
809 .value = ast_sorcery_object_get_id(endpoint),
810 .next = NULL,
811 };
812
813 identifies = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify",
815 if (!identifies) {
816 return -1;
817 }
818
819 ao2_callback(identifies, OBJ_NODATA, callback, args);
820 ao2_cleanup(identifies);
821
822 return 0;
823}
824
825static struct ao2_container *cli_get_container(const char *regex)
826{
828 struct ao2_container *s_container;
829
831 if (!container) {
832 return NULL;
833 }
834
837 if (!s_container) {
838 return NULL;
839 }
840
841 if (ao2_container_dup(s_container, container, 0)) {
842 ao2_ref(s_container, -1);
843 return NULL;
844 }
845
846 return s_container;
847}
848
849static void *cli_retrieve_by_id(const char *id)
850{
851 return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "identify", id);
852}
853
854static int cli_print_header(void *obj, void *arg, int flags)
855{
856 struct ast_sip_cli_context *context = arg;
857 int indent = CLI_INDENT_TO_SPACES(context->indent_level);
858 int filler = CLI_MAX_WIDTH - indent - 22;
859
860 ast_assert(context->output_buffer != NULL);
861
862 ast_str_append(&context->output_buffer, 0,
863 "%*s: <Identify/Endpoint%*.*s>\n",
864 indent, "Identify", filler, filler, CLI_HEADER_FILLER);
865
866 if (context->recurse) {
867 context->indent_level++;
868 indent = CLI_INDENT_TO_SPACES(context->indent_level);
869 filler = CLI_LAST_TABSTOP - indent - 24;
870
871 ast_str_append(&context->output_buffer, 0,
872 "%*s: <criteria%*.*s>\n",
873 indent, "Match", filler, filler, CLI_HEADER_FILLER);
874
875 context->indent_level--;
876 }
877
878 return 0;
879}
880
881static int cli_print_body(void *obj, void *arg, int flags)
882{
884 struct ip_identify_match *ident = obj;
885 struct ast_sip_cli_context *context = arg;
886 struct ast_ha *match;
887 int indent;
888
889 ast_assert(context->output_buffer != NULL);
890
891 ast_str_append(&context->output_buffer, 0, "%*s: %s/%s\n",
892 CLI_INDENT_TO_SPACES(context->indent_level), "Identify",
894
895 if (context->recurse) {
896 context->indent_level++;
897 indent = CLI_INDENT_TO_SPACES(context->indent_level);
898
899 for (match = ident->matches; match; match = match->next) {
900 const char *addr;
901
902 if (ast_sockaddr_port(&match->addr)) {
904 } else {
906 }
907
908 ast_str_append(&context->output_buffer, 0, "%*s: %s%s/%d\n",
909 indent,
910 "Match",
911 match->sense == AST_SENSE_ALLOW ? "!" : "",
912 addr, ast_sockaddr_cidr_bits(&match->netmask));
913 }
914
915 if (!ast_strlen_zero(ident->match_header)) {
916 ast_str_append(&context->output_buffer, 0, "%*s: %s\n",
917 indent,
918 "Header",
919 ident->match_header);
920 }
921
922 if (!ast_strlen_zero(ident->match_request_uri)) {
923 ast_str_append(&context->output_buffer, 0, "%*s: %s\n",
924 indent,
925 "RequestURI",
926 ident->match_request_uri);
927 }
928
929 context->indent_level--;
930
931 if (context->indent_level == 0) {
932 ast_str_append(&context->output_buffer, 0, "\n");
933 }
934 }
935
936 if (context->show_details
937 || (context->show_details_only_level_0 && context->indent_level == 0)) {
938 ast_str_append(&context->output_buffer, 0, "\n");
939 ast_sip_cli_print_sorcery_objectset(ident, context, 0);
940 }
941
942 return 0;
943}
944
945/*
946 * A function pointer to callback needs to be within the
947 * module in order to avoid problems with an undefined
948 * symbol when the module is loaded.
949 */
950static char *my_cli_traverse_objects(struct ast_cli_entry *e, int cmd,
951 struct ast_cli_args *a)
952{
953 return ast_sip_cli_traverse_objects(e, cmd, a);
954}
955
956static struct ast_cli_entry cli_identify[] = {
957AST_CLI_DEFINE(my_cli_traverse_objects, "List PJSIP Identifies",
958 .command = "pjsip list identifies",
959 .usage = "Usage: pjsip list identifies [ like <pattern> ]\n"
960 " List the configured PJSIP Identifies\n"
961 " Optional regular expression pattern is used to filter the list.\n"),
962AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Identifies",
963 .command = "pjsip show identifies",
964 .usage = "Usage: pjsip show identifies [ like <pattern> ]\n"
965 " Show the configured PJSIP Identifies\n"
966 " Optional regular expression pattern is used to filter the list.\n"),
967AST_CLI_DEFINE(my_cli_traverse_objects, "Show PJSIP Identify",
968 .command = "pjsip show identify",
969 .usage = "Usage: pjsip show identify <id>\n"
970 " Show the configured PJSIP Identify\n"),
971};
972
974
975static int load_module(void)
976{
977 ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_endpoint_identifier_ip");
978 ast_sorcery_apply_default(ast_sip_get_sorcery(), "identify", "config", "pjsip.conf,criteria=type=identify");
979
982 }
983
984 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "type", "", OPT_NOOP_T, 0, 0);
985 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, endpoint_name));
987 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "match_header", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, match_header));
988 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));
989 ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "srv_lookups", "yes", OPT_BOOL_T, 1, FLDSET(struct ip_identify_match, srv_lookups));
991
996
998 if (!cli_formatter) {
999 ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
1001 }
1002 cli_formatter->name = "identify";
1009
1012
1014}
1015
1016static int reload_module(void)
1017{
1019
1020 return 0;
1021}
1022
1034
1035AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP IP endpoint identifier",
1036 .support_level = AST_MODULE_SUPPORT_CORE,
1037 .load = load_module,
1039 .unload = unload_module,
1040 .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4,
1041 .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
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
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:399
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:2401
static struct ast_sorcery * sorcery
static struct ast_channel * callback(struct ast_channelstorage_instance *driver, ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags, int rdlock)
#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:1842
static char prefix[MAX_PREFIX]
Definition http.c:145
#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
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition netsock2.c:230
@ AST_AF_UNSPEC
Definition netsock2.h:54
#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:603
void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
Unregister a SIP endpoint identifier.
Definition res_pjsip.c:309
void ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Register an endpoint formatter.
Definition res_pjsip.c:479
void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Unregister an endpoint formatter.
Definition res_pjsip.c:485
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:227
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
#define CLI_MAX_WIDTH
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
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)
int ast_sip_register_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
Registers a CLI formatter.
Definition pjsip_cli.c:310
static int ip_identify_match_srv_lookup(struct ip_identify_match *identify, const char *prefix, const char *host, int results, int *resolved)
Helper function which performs an SRV lookup and then resolves the hostname.
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 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 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 int ip_identify_match_host_lookup(struct ip_identify_match *identify, const char *host, int *resolved)
Helper function which performs a host lookup and adds result to identify match.
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 @522 args
#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:2381
@ 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:2448
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:1917
#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:2018
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:1457
#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:1792
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition sorcery.c:2528
#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:2504
#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:1506
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:1961
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.
#define AST_STRING_FIELD(name)
Declare a string field.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
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
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 *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
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:3257
struct mansession * s
Definition res_pjsip.h:3259
CLI Formatter Context passed to all formatters.
CLI Formatter Registry Entry.
int(* iterate)(void *container, ao2_callback_fn callback, void *args)
ao2_callback_fn * print_header
void *(* retrieve_by_id)(const char *id)
const char *(* get_id)(const void *obj)
const char * name
ao2_callback_fn * print_body
struct ao2_container *(* get_container)(const char *regex)
An entity responsible formatting endpoint information.
Definition res_pjsip.h:3283
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:3287
An entity responsible for identifying the source of a SIP message.
Definition res_pjsip.h:1427
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:1432
An entity with which Asterisk communicates.
Definition res_pjsip.h:1067
Socket address structure.
Definition netsock2.h:97
Full structure for sorcery.
Definition sorcery.c:231
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
static struct test_val a
int error(const char *format,...)
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:981
#define ast_assert(a)
Definition utils.h:779
#define ARRAY_LEN(a)
Definition utils.h:706