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_acl.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"
30#include "asterisk/module.h"
31#include "asterisk/logger.h"
32#include "asterisk/sorcery.h"
33#include "asterisk/acl.h"
34#include "asterisk/stasis.h"
36
37/*** DOCUMENTATION
38 <configInfo name="res_pjsip_acl" language="en_US">
39 <synopsis>SIP ACL module</synopsis>
40 <description><para>
41 <emphasis>ACL</emphasis>
42 </para><para>
43 The ACL module used by <literal>res_pjsip</literal>. This module is
44 independent of <literal>endpoints</literal> and operates on all inbound
45 SIP communication using res_pjsip.
46 </para><para>
47 There are two main ways of defining your ACL with the options
48 provided. You can use the <literal>permit</literal> and <literal>deny</literal> options
49 which act on <emphasis>IP</emphasis> addresses, or the <literal>contactpermit</literal>
50 and <literal>contactdeny</literal> options which act on <emphasis>Contact header</emphasis>
51 addresses in incoming REGISTER requests. You can combine the various options to
52 create a mixed ACL.
53 </para><para>
54 Additionally, instead of defining an ACL with options, you can reference IP or
55 Contact header ACLs from the file <filename>acl.conf</filename> by using the <literal>acl</literal>
56 or <literal>contactacl</literal> options.
57 </para></description>
58 <configFile name="pjsip.conf">
59 <configObject name="acl">
60 <since>
61 <version>12.0.0</version>
62 </since>
63 <synopsis>Access Control List</synopsis>
64 <configOption name="acl">
65 <since>
66 <version>12.2.0</version>
67 </since>
68 <synopsis>List of IP ACL section names in acl.conf</synopsis>
69 <description><para>
70 This matches sections configured in <literal>acl.conf</literal>. The value is
71 defined as a list of comma-delimited section names.
72 </para></description>
73 </configOption>
74 <configOption name="contact_acl">
75 <since>
76 <version>12.2.0</version>
77 </since>
78 <synopsis>List of Contact ACL section names in acl.conf</synopsis>
79 <description><para>
80 This matches sections configured in <literal>acl.conf</literal>. The value is
81 defined as a list of comma-delimited section names.
82 </para></description>
83 </configOption>
84 <configOption name="contact_deny">
85 <since>
86 <version>12.2.0</version>
87 </since>
88 <synopsis>List of Contact header addresses to deny</synopsis>
89 <description><para>
90 The value is a comma-delimited list of IP addresses. IP addresses may
91 have a subnet mask appended. The subnet mask may be written in either
92 CIDR or dotted-decimal notation. Separate the IP address and subnet
93 mask with a slash ('/')
94 </para></description>
95 </configOption>
96 <configOption name="contact_permit">
97 <since>
98 <version>12.2.0</version>
99 </since>
100 <synopsis>List of Contact header addresses to permit</synopsis>
101 <description><para>
102 The value is a comma-delimited list of IP addresses. IP addresses may
103 have a subnet mask appended. The subnet mask may be written in either
104 CIDR or dotted-decimal notation. Separate the IP address and subnet
105 mask with a slash ('/')
106 </para></description>
107 </configOption>
108 <configOption name="deny">
109 <since>
110 <version>12.2.0</version>
111 </since>
112 <synopsis>List of IP addresses to deny access from</synopsis>
113 <description><para>
114 The value is a comma-delimited list of IP addresses. IP addresses may
115 have a subnet mask appended. The subnet mask may be written in either
116 CIDR or dotted-decimal notation. Separate the IP address and subnet
117 mask with a slash ('/')
118 </para></description>
119 </configOption>
120 <configOption name="permit">
121 <since>
122 <version>12.2.0</version>
123 </since>
124 <synopsis>List of IP addresses to permit access from</synopsis>
125 <description><para>
126 The value is a comma-delimited list of IP addresses. IP addresses may
127 have a subnet mask appended. The subnet mask may be written in either
128 CIDR or dotted-decimal notation. Separate the IP address and subnet
129 mask with a slash ('/')
130 </para></description>
131 </configOption>
132 <configOption name="type">
133 <since>
134 <version>12.0.0</version>
135 </since>
136 <synopsis>Must be of type 'acl'.</synopsis>
137 </configOption>
138 </configObject>
139 </configFile>
140 </configInfo>
141 ***/
142
144
145static int apply_acl(pjsip_rx_data *rdata, struct ast_acl_list *acl)
146{
147 struct ast_sockaddr addr;
148
150 return 0;
151 }
152
153 memset(&addr, 0, sizeof(addr));
154 ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
155 ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port);
156
157 if (ast_apply_acl(acl, &addr, "SIP ACL: ") != AST_SENSE_ALLOW) {
158 ast_log(LOG_WARNING, "Incoming SIP message from %s did not pass ACL test\n", ast_sockaddr_stringify(&addr));
159 return 1;
160 }
161 return 0;
162}
163
164static int extract_contact_addr(pjsip_contact_hdr *contact, struct ast_sockaddr **addrs)
165{
166 pjsip_sip_uri *sip_uri;
167 char host[256];
168
169 if (!contact || contact->star) {
170 *addrs = NULL;
171 return 0;
172 }
173 if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
174 *addrs = NULL;
175 return 0;
176 }
177 sip_uri = pjsip_uri_get_uri(contact->uri);
178 ast_copy_pj_str(host, &sip_uri->host, sizeof(host));
180}
181
182static int apply_contact_acl(pjsip_rx_data *rdata, struct ast_acl_list *contact_acl)
183{
184 int num_contact_addrs;
185 int forbidden = 0;
186 struct ast_sockaddr *contact_addrs;
187 int i;
188 pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
189
190 if (ast_acl_list_is_empty(contact_acl)) {
191 return 0;
192 }
193
194 while ((contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
195 num_contact_addrs = extract_contact_addr(contact, &contact_addrs);
196 if (num_contact_addrs <= 0) {
197 continue;
198 }
199 for (i = 0; i < num_contact_addrs; ++i) {
200 if (ast_apply_acl(contact_acl, &contact_addrs[i], "SIP Contact ACL: ") != AST_SENSE_ALLOW) {
201 ast_log(LOG_WARNING, "Incoming SIP message from %s did not pass ACL test\n", ast_sockaddr_stringify(&contact_addrs[i]));
202 forbidden = 1;
203 break;
204 }
205 }
206 ast_free(contact_addrs);
207 if (forbidden) {
208 /* No use checking other contacts if we already have failed ACL check */
209 break;
210 }
211 }
212
213 return forbidden;
214}
215
216#define SIP_SORCERY_ACL_TYPE "acl"
217
218/*!
219 * \brief SIP ACL details and configuration.
220 */
225};
226
227static int check_acls(void *obj, void *arg, int flags)
228{
229 struct ast_sip_acl *sip_acl = obj;
230 pjsip_rx_data *rdata = arg;
231
232 if (apply_acl(rdata, sip_acl->acl) ||
233 apply_contact_acl(rdata, sip_acl->contact_acl)) {
234 return CMP_MATCH | CMP_STOP;
235 }
236 return 0;
237}
238
239static pj_bool_t acl_on_rx_msg(pjsip_rx_data *rdata)
240{
244 RAII_VAR(struct ast_sip_acl *, matched_acl, NULL, ao2_cleanup);
245
246 if (!acls) {
247 ast_log(LOG_ERROR, "Unable to retrieve ACL sorcery data\n");
248 return PJ_FALSE;
249 }
250
251 if ((matched_acl = ao2_callback(acls, 0, check_acls, rdata))) {
252 if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
253 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
254 }
255 return PJ_TRUE;
256 }
257
258 return PJ_FALSE;
259}
260
261static int acl_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
262{
263 struct ast_sip_acl *sip_acl = obj;
264 int error = 0;
265 int ignore;
266
267 if (!strncmp(var->name, "contact_", 8)) {
268 ast_append_acl(var->name + 8, var->value, &sip_acl->contact_acl, &error, &ignore);
269 if (error) {
270 ast_log(LOG_ERROR, "Bad contact ACL '%s' at line '%d' of pjsip.conf\n",
271 var->value, var->lineno);
272 }
273 } else {
274 ast_append_acl(var->name, var->value, &sip_acl->acl, &error, &ignore);
275 if (error) {
276 ast_log(LOG_ERROR, "Bad ACL '%s' at line '%d' of pjsip.conf\n",
277 var->value, var->lineno);
278 }
279 }
280
281 if (error) {
282 ast_log(LOG_ERROR, "There is an error in ACL configuration. Blocking ALL SIP traffic.\n");
283 ast_append_acl("deny", "0.0.0.0/0.0.0.0", &sip_acl->acl, NULL, &ignore);
284 }
285
286 return error;
287}
288
289static pjsip_module acl_module = {
290 .name = { "ACL Module", 14 },
291 /* This should run after a logger but before anything else */
292 .priority = 1,
293 .on_rx_request = acl_on_rx_msg,
294};
295
296static void acl_destroy(void *obj)
297{
298 struct ast_sip_acl *sip_acl = obj;
299 sip_acl->acl = ast_free_acl_list(sip_acl->acl);
300 sip_acl->contact_acl = ast_free_acl_list(sip_acl->contact_acl);
301}
302
303static void *acl_alloc(const char *name)
304{
305 struct ast_sip_acl *sip_acl =
306 ast_sorcery_generic_alloc(sizeof(*sip_acl), acl_destroy);
307
308 return sip_acl;
309}
310
311static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
312 struct stasis_message *message)
313{
315 return;
316 }
317
319}
320
321static int load_module(void)
322{
325 "config", "pjsip.conf,criteria=type=acl");
326
328 acl_alloc, NULL, NULL)) {
329
330 ast_log(LOG_ERROR, "Failed to register SIP %s object with sorcery\n",
333 }
334
342
344
348
350
352}
353
354static int unload_module(void)
355{
358 return 0;
359}
360
362 .support_level = AST_MODULE_SUPPORT_CORE,
363 .load = load_module,
364 .unload = unload_module,
365 .load_pri = AST_MODPRI_APP_DEPEND,
366 .requires = "res_pjsip",
Access Control of various sorts.
enum ast_acl_sense ast_apply_acl(struct ast_acl_list *acl_list, const struct ast_sockaddr *addr, const char *purpose)
Apply a set of rules to a given IP address.
Definition: acl.c:799
struct stasis_message_type * ast_named_acl_change_type(void)
a stasis_message_type for changes against a named ACL or the set of all named ACLs
void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list **path, int *error, int *named_acl_flag)
Add a rule to an ACL struct.
Definition: acl.c:429
@ AST_SENSE_ALLOW
Definition: acl.h:38
int ast_acl_list_is_empty(struct ast_acl_list *acl_list)
Determines if an ACL is empty or if it contains entries.
Definition: acl.c:540
struct ast_acl_list * ast_free_acl_list(struct ast_acl_list *acl)
Free a list of ACLs.
Definition: acl.c:233
#define var
Definition: ast_expr2f.c:605
if(!yyg->yy_init)
Definition: ast_expr2f.c:854
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_log
Definition: astobj2.c:42
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
#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
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
@ OPT_NOOP_T
Type for a default handler that should do nothing.
static const char name[]
Definition: format_mp3.c:68
Support for logging to various files, console and syslog Configuration in file logger....
#define LOG_ERROR
#define LOG_WARNING
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_APP_DEPEND
Definition: module.h:342
@ 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
def ignore(key=None, val=None, section=None, pjsip=None, nmapped=None, type='endpoint')
Definition: sip_to_pjsip.py:48
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:256
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
struct stasis_forward * sub
Definition: res_corosync.c:240
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:133
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:117
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:2201
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
static int check_acls(void *obj, void *arg, int flags)
static int acl_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static void acl_destroy(void *obj)
static struct stasis_subscription * acl_change_sub
static int extract_contact_addr(pjsip_contact_hdr *contact, struct ast_sockaddr **addrs)
#define SIP_SORCERY_ACL_TYPE
static pj_bool_t acl_on_rx_msg(pjsip_rx_data *rdata)
static pjsip_module acl_module
static int apply_acl(pjsip_rx_data *rdata, struct ast_acl_list *acl)
static void * acl_alloc(const char *name)
static int load_module(void)
static int unload_module(void)
static int apply_contact_acl(pjsip_rx_data *rdata, struct ast_acl_list *contact_acl)
static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
#define NULL
Definition: resample.c:96
Security Event Reporting API.
struct stasis_topic * ast_security_topic(void)
A stasis_topic which publishes messages for security related issues.
Sorcery Data Access Layer API.
@ 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
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
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
#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
void ast_sorcery_force_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects even if no changes determin...
Definition: sorcery.c:1457
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:476
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
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition: stasis.h:297
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1050
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1104
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1161
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:649
Definition: test_acl.c:111
Generic container type.
Wrapper for an ast_acl linked list.
Definition: acl.h:76
SIP ACL details and configuration.
SORCERY_OBJECT(details)
struct ast_acl_list * contact_acl
struct ast_acl_list * acl
Socket address structure.
Definition: netsock2.h:97
Structure for variables, used for configurations and for channel variables.
int error(const char *format,...)
Definition: utils/frame.c:999
#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