aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
authortilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2008-09-12 20:37:18 +0000
committertilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2008-09-12 20:37:18 +0000
commit3d74fe145cd118d1e92a9306dc15f32da3b91401 (patch)
tree2f1e7e04964e16dc1ca328f9113917b28345b23a /channels
parentd7fe1556d7d7afb6918941cc7c2f2d66887ecedf (diff)
Create rules for disallowing contacts at certain addresses, which may
improve the security of various installations. As this does not change any default behavior, it is not classified as a direct security fix for anything within Asterisk, but may help PBX admins better secure their SIP servers. (closes issue #11776) Reported by: ibc Patches: 20080829__bug11776.diff.txt uploaded by Corydon76 (license 14) Tested by: Corydon76, blitzrage git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@142865 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_sip.c44
1 files changed, 37 insertions, 7 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 6f205a381..0ff45af6a 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -574,6 +574,10 @@ static int global_matchexterniplocally; /*!< Match externip/externhost setting a
/*! \brief Codecs that we support by default: */
static int global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263;
+/*! \brief Global list of addresses dynamic peers are not allowed to use */
+static struct ast_ha *global_contact_ha = NULL;
+static int global_dynamic_exclude_static = 0;
+
/* Object counters */
static int suserobjs = 0; /*!< Static users */
static int ruserobjs = 0; /*!< Realtime users */
@@ -1132,6 +1136,7 @@ struct sip_peer {
struct sockaddr_in defaddr; /*!< Default IP address, used until registration */
struct ast_ha *ha; /*!< Access control list */
+ struct ast_ha *contactha; /*!< Restrict what IPs are allowed in the Contact header (for registration) */
struct ast_variable *chanvars; /*!< Variables to set for channel created by user */
struct sip_pvt *mwipvt; /*!< Subscription for MWI */
int lastmsg;
@@ -8174,7 +8179,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
const char *useragent;
struct hostent *hp;
struct ast_hostent ahp;
- struct sockaddr_in oldsin;
+ struct sockaddr_in oldsin, testsin;
ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact));
@@ -8255,13 +8260,26 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
} else
port = STANDARD_SIP_PORT;
oldsin = peer->addr;
+
+ /* Check that they're allowed to register at this IP */
+ /* XXX This could block for a long time XXX */
+ hp = ast_gethostbyname(n, &ahp);
+ if (!hp) {
+ ast_log(LOG_WARNING, "Invalid host '%s'\n", n);
+ *peer->fullcontact = '\0';
+ ast_string_field_set(pvt, our_contact, "");
+ return PARSE_REGISTER_FAILED;
+ }
+ memcpy(&testsin.sin_addr, hp->h_addr, sizeof(testsin.sin_addr));
+ if ( ast_apply_ha(global_contact_ha, &testsin) != AST_SENSE_ALLOW ||
+ ast_apply_ha(peer->contactha, &testsin) != AST_SENSE_ALLOW) {
+ ast_log(LOG_WARNING, "Host '%s' disallowed by rule\n", n);
+ *peer->fullcontact = '\0';
+ ast_string_field_set(pvt, our_contact, "");
+ return PARSE_REGISTER_FAILED;
+ }
+
if (!ast_test_flag(&peer->flags[0], SIP_NAT_ROUTE)) {
- /* XXX This could block for a long time XXX */
- hp = ast_gethostbyname(n, &ahp);
- if (!hp) {
- ast_log(LOG_WARNING, "Invalid host '%s'\n", n);
- return PARSE_REGISTER_FAILED;
- }
peer->addr.sin_family = AF_INET;
memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr));
peer->addr.sin_port = htons(port);
@@ -17158,6 +17176,9 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
if (!peer->addr.sin_port)
peer->addr.sin_port = htons(STANDARD_SIP_PORT);
}
+ if (global_dynamic_exclude_static) {
+ global_contact_ha = ast_append_ha("deny", (char *)ast_inet_ntoa(peer->addr.sin_addr), global_contact_ha);
+ }
}
} else if (!strcasecmp(v->name, "defaultip")) {
if (ast_get_ip(&peer->defaddr, v->value)) {
@@ -17166,6 +17187,8 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
}
} else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
peer->ha = ast_append_ha(v->name, v->value, peer->ha);
+ } else if (!strcasecmp(v->name, "contactpermit") || !strcasecmp(v->name, "contactdeny")) {
+ peer->contactha = ast_append_ha(v->name + 7, v->value, peer->contactha);
} else if (!strcasecmp(v->name, "port")) {
if (!realtime && ast_test_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC))
peer->defaddr.sin_port = htons(atoi(v->value));
@@ -17333,6 +17356,9 @@ static int reload_config(enum channelreloadreason reason)
clear_sip_domains();
authl = NULL;
+ ast_free_ha(global_contact_ha);
+ global_contact_ha = NULL;
+
/* First, destroy all outstanding registry calls */
/* This is needed, since otherwise active registry entries will not be destroyed */
ASTOBJ_CONTAINER_TRAVERSE(&regl, 1, do {
@@ -17483,6 +17509,10 @@ static int reload_config(enum channelreloadreason reason)
ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_IGNOREREGEXPIRE);
} else if (!strcasecmp(v->name, "t1min")) {
global_t1min = atoi(v->value);
+ } else if (!strcasecmp(v->name, "dynamic_exclude_static") || !strcasecmp(v->name, "dynamic_excludes_static")) {
+ global_dynamic_exclude_static = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "contactpermit") || !strcasecmp(v->name, "contactdeny")) {
+ global_contact_ha = ast_append_ha(v->name + 7, v->value, global_contact_ha);
} else if (!strcasecmp(v->name, "rtautoclear")) {
int i = atoi(v->value);
if (i > 0)