Asterisk - The Open Source Telephony Project GIT-master-7e7a603
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 <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
121static int apply_acl(pjsip_rx_data *rdata, struct ast_acl_list *acl)
122{
123 struct ast_sockaddr addr;
124
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
140static 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
158static 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 */
201};
202
203static 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
215static 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
237static 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
265static 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
272static 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
279static 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
287static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
288 struct stasis_message *message)
289{
291 return;
292 }
293
295}
296
297static 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
330static int unload_module(void)
331{
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",
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:317
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_APP_DEPEND
Definition: module.h:328
@ 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
@ AST_AF_UNSPEC
Definition: netsock2.h:54
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
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:1023
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:1077
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1134
#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