Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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  <synopsis>Access Control List</synopsis>
61  <configOption name="acl">
62  <synopsis>List of IP ACL section names in acl.conf</synopsis>
63  <description><para>
64  This matches sections configured in <literal>acl.conf</literal>. The value is
65  defined as a list of comma-delimited section names.
66  </para></description>
67  </configOption>
68  <configOption name="contact_acl">
69  <synopsis>List of Contact ACL section names in acl.conf</synopsis>
70  <description><para>
71  This matches sections configured in <literal>acl.conf</literal>. The value is
72  defined as a list of comma-delimited section names.
73  </para></description>
74  </configOption>
75  <configOption name="contact_deny">
76  <synopsis>List of Contact header addresses to deny</synopsis>
77  <description><para>
78  The value is a comma-delimited list of IP addresses. IP addresses may
79  have a subnet mask appended. The subnet mask may be written in either
80  CIDR or dotted-decimal notation. Separate the IP address and subnet
81  mask with a slash ('/')
82  </para></description>
83  </configOption>
84  <configOption name="contact_permit">
85  <synopsis>List of Contact header addresses to permit</synopsis>
86  <description><para>
87  The value is a comma-delimited list of IP addresses. IP addresses may
88  have a subnet mask appended. The subnet mask may be written in either
89  CIDR or dotted-decimal notation. Separate the IP address and subnet
90  mask with a slash ('/')
91  </para></description>
92  </configOption>
93  <configOption name="deny">
94  <synopsis>List of IP addresses to deny access from</synopsis>
95  <description><para>
96  The value is a comma-delimited list of IP addresses. IP addresses may
97  have a subnet mask appended. The subnet mask may be written in either
98  CIDR or dotted-decimal notation. Separate the IP address and subnet
99  mask with a slash ('/')
100  </para></description>
101  </configOption>
102  <configOption name="permit">
103  <synopsis>List of IP addresses to permit access from</synopsis>
104  <description><para>
105  The value is a comma-delimited list of IP addresses. IP addresses may
106  have a subnet mask appended. The subnet mask may be written in either
107  CIDR or dotted-decimal notation. Separate the IP address and subnet
108  mask with a slash ('/')
109  </para></description>
110  </configOption>
111  <configOption name="type">
112  <synopsis>Must be of type 'acl'.</synopsis>
113  </configOption>
114  </configObject>
115  </configFile>
116  </configInfo>
117  ***/
118 
120 
121 static int apply_acl(pjsip_rx_data *rdata, struct ast_acl_list *acl)
122 {
123  struct ast_sockaddr addr;
124 
125  if (ast_acl_list_is_empty(acl)) {
126  return 0;
127  }
128 
129  memset(&addr, 0, sizeof(addr));
130  ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
131  ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port);
132 
133  if (ast_apply_acl(acl, &addr, "SIP ACL: ") != AST_SENSE_ALLOW) {
134  ast_log(LOG_WARNING, "Incoming SIP message from %s did not pass ACL test\n", ast_sockaddr_stringify(&addr));
135  return 1;
136  }
137  return 0;
138 }
139 
140 static int extract_contact_addr(pjsip_contact_hdr *contact, struct ast_sockaddr **addrs)
141 {
142  pjsip_sip_uri *sip_uri;
143  char host[256];
144 
145  if (!contact || contact->star) {
146  *addrs = NULL;
147  return 0;
148  }
149  if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
150  *addrs = NULL;
151  return 0;
152  }
153  sip_uri = pjsip_uri_get_uri(contact->uri);
154  ast_copy_pj_str(host, &sip_uri->host, sizeof(host));
156 }
157 
158 static int apply_contact_acl(pjsip_rx_data *rdata, struct ast_acl_list *contact_acl)
159 {
160  int num_contact_addrs;
161  int forbidden = 0;
162  struct ast_sockaddr *contact_addrs;
163  int i;
164  pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
165 
166  if (ast_acl_list_is_empty(contact_acl)) {
167  return 0;
168  }
169 
170  while ((contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
171  num_contact_addrs = extract_contact_addr(contact, &contact_addrs);
172  if (num_contact_addrs <= 0) {
173  continue;
174  }
175  for (i = 0; i < num_contact_addrs; ++i) {
176  if (ast_apply_acl(contact_acl, &contact_addrs[i], "SIP Contact ACL: ") != AST_SENSE_ALLOW) {
177  ast_log(LOG_WARNING, "Incoming SIP message from %s did not pass ACL test\n", ast_sockaddr_stringify(&contact_addrs[i]));
178  forbidden = 1;
179  break;
180  }
181  }
182  ast_free(contact_addrs);
183  if (forbidden) {
184  /* No use checking other contacts if we already have failed ACL check */
185  break;
186  }
187  }
188 
189  return forbidden;
190 }
191 
192 #define SIP_SORCERY_ACL_TYPE "acl"
193 
194 /*!
195  * \brief SIP ACL details and configuration.
196  */
197 struct ast_sip_acl {
198  SORCERY_OBJECT(details);
199  struct ast_acl_list *acl;
201 };
202 
203 static int check_acls(void *obj, void *arg, int flags)
204 {
205  struct ast_sip_acl *sip_acl = obj;
206  pjsip_rx_data *rdata = arg;
207 
208  if (apply_acl(rdata, sip_acl->acl) ||
209  apply_contact_acl(rdata, sip_acl->contact_acl)) {
210  return CMP_MATCH | CMP_STOP;
211  }
212  return 0;
213 }
214 
215 static pj_bool_t acl_on_rx_msg(pjsip_rx_data *rdata)
216 {
220  RAII_VAR(struct ast_sip_acl *, matched_acl, NULL, ao2_cleanup);
221 
222  if (!acls) {
223  ast_log(LOG_ERROR, "Unable to retrieve ACL sorcery data\n");
224  return PJ_FALSE;
225  }
226 
227  if ((matched_acl = ao2_callback(acls, 0, check_acls, rdata))) {
228  if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
229  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
230  }
231  return PJ_TRUE;
232  }
233 
234  return PJ_FALSE;
235 }
236 
237 static int acl_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
238 {
239  struct ast_sip_acl *sip_acl = obj;
240  int error = 0;
241  int ignore;
242 
243  if (!strncmp(var->name, "contact_", 8)) {
244  ast_append_acl(var->name + 8, var->value, &sip_acl->contact_acl, &error, &ignore);
245  if (error) {
246  ast_log(LOG_ERROR, "Bad contact ACL '%s' at line '%d' of pjsip.conf\n",
247  var->value, var->lineno);
248  }
249  } else {
250  ast_append_acl(var->name, var->value, &sip_acl->acl, &error, &ignore);
251  if (error) {
252  ast_log(LOG_ERROR, "Bad ACL '%s' at line '%d' of pjsip.conf\n",
253  var->value, var->lineno);
254  }
255  }
256 
257  if (error) {
258  ast_log(LOG_ERROR, "There is an error in ACL configuration. Blocking ALL SIP traffic.\n");
259  ast_append_acl("deny", "0.0.0.0/0.0.0.0", &sip_acl->acl, NULL, &ignore);
260  }
261 
262  return error;
263 }
264 
265 static pjsip_module acl_module = {
266  .name = { "ACL Module", 14 },
267  /* This should run after a logger but before anything else */
268  .priority = 1,
269  .on_rx_request = acl_on_rx_msg,
270 };
271 
272 static void acl_destroy(void *obj)
273 {
274  struct ast_sip_acl *sip_acl = obj;
275  sip_acl->acl = ast_free_acl_list(sip_acl->acl);
276  sip_acl->contact_acl = ast_free_acl_list(sip_acl->contact_acl);
277 }
278 
279 static void *acl_alloc(const char *name)
280 {
281  struct ast_sip_acl *sip_acl =
282  ast_sorcery_generic_alloc(sizeof(*sip_acl), acl_destroy);
283 
284  return sip_acl;
285 }
286 
287 static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
288  struct stasis_message *message)
289 {
291  return;
292  }
293 
295 }
296 
297 static int load_module(void)
298 {
301  "config", "pjsip.conf,criteria=type=acl");
302 
304  acl_alloc, NULL, NULL)) {
305 
306  ast_log(LOG_ERROR, "Failed to register SIP %s object with sorcery\n",
309  }
310 
318 
320 
324 
326 
328 }
329 
330 static int unload_module(void)
331 {
332  acl_change_sub = stasis_unsubscribe_and_join(acl_change_sub);
334  return 0;
335 }
336 
338  .support_level = AST_MODULE_SUPPORT_CORE,
339  .load = load_module,
340  .unload = unload_module,
341  .load_pri = AST_MODPRI_APP_DEPEND,
342  .requires = "res_pjsip",
343 );
static void acl_destroy(void *obj)
Asterisk main include file. File version handling, generic pbx functions.
Security Event Reporting API.
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
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
struct stasis_topic * ast_security_topic(void)
A stasis_topic which publishes messages for security related issues.
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
static int apply_acl(pjsip_rx_data *rdata, struct ast_acl_list *acl)
#define LOG_WARNING
Definition: logger.h:274
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
static int apply_contact_acl(pjsip_rx_data *rdata, struct ast_acl_list *contact_acl)
Perform no matching, return all objects.
Definition: sorcery.h:123
if(!yyg->yy_init)
Definition: ast_expr2f.c:868
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
Type for a default handler that should do nothing.
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:1079
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 ...
#define ast_sorcery_apply_config(sorcery, name)
Definition: sorcery.h:456
Return all matching objects.
Definition: sorcery.h:120
Wrapper for an ast_acl linked list.
Definition: acl.h:76
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:5240
#define NULL
Definition: resample.c:96
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
Socket address structure.
Definition: netsock2.h:97
SORCERY_OBJECT(details)
static pjsip_module acl_module
#define ast_log
Definition: astobj2.c:42
#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
static char host[256]
Definition: muted.c:77
#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:911
Access Control of various sorts.
static int extract_contact_addr(pjsip_contact_hdr *contact, struct ast_sockaddr **addrs)
static struct stasis_subscription * acl_change_sub
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:838
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:3315
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:800
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:541
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:652
static int check_acls(void *obj, void *arg, int flags)
#define LOG_ERROR
Definition: logger.h:285
static int load_module(void)
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:537
struct ast_acl_list * ast_free_acl_list(struct ast_acl_list *acl)
Free a list of ACLs.
Definition: acl.c:233
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:477
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:260
def ignore(key=None, val=None, section=None, pjsip=None, nmapped=None, type='endpoint')
Definition: sip_to_pjsip.py:48
#define SIP_SORCERY_ACL_TYPE
Definition: test_acl.c:111
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
static void * acl_alloc(const char *name)
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1136
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static pj_bool_t acl_on_rx_msg(pjsip_rx_data *rdata)
Support for logging to various files, console and syslog Configuration in file logger.conf.
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
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
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
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:430
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:3331
static int unload_module(void)
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:1025
struct stasis_forward * sub
Definition: res_corosync.c:240
struct ast_acl_list * contact_acl
static int acl_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
struct ast_acl_list * acl
int error(const char *format,...)
Definition: utils/frame.c:999
Generic container type.
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
SIP ACL details and configuration.
Sorcery Data Access Layer API.
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