[Asterisk-code-review] res_pjsip_endpoint_identifier_ip.c: Add port matching support (asterisk[13])
Joshua Colp
asteriskteam at digium.com
Thu Jan 9 15:07:49 CST 2020
Joshua Colp has submitted this change. ( https://gerrit.asterisk.org/c/asterisk/+/13312 )
Change subject: res_pjsip_endpoint_identifier_ip.c: Add port matching support
......................................................................
res_pjsip_endpoint_identifier_ip.c: Add port matching support
Adds source port matching support when IP matching is used:
[example]
type = identify
match = 1.2.3.4:5060/32, 1.2.3.4:6000/32, asterisk.org:4444
If the IP matches but the source port does not, we reject and search for
alternatives. SRV lookups are still performed if enabled (srv_lookups = yes),
unless the configured FQDN includes a port number in which case just a host
lookup is performed.
ASTERISK-28639 #close
Reported by: Mitch Claborn
Change-Id: I256d5bd5d478b95f526e2f80ace31b690eebba92
---
M configs/samples/pjsip.conf.sample
A doc/CHANGES-staging/res_pjsip_endpoint_identifier_ip_match_port.txt
M include/asterisk/acl.h
M main/acl.c
M res/res_pjsip_endpoint_identifier_ip.c
5 files changed, 120 insertions(+), 24 deletions(-)
Approvals:
Joshua Colp: Looks good to me, but someone else must approve; Approved for Submit
Benjamin Keith Ford: Looks good to me, but someone else must approve
George Joseph: Looks good to me, approved
diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample
index 9e6365e..fd2d742 100644
--- a/configs/samples/pjsip.conf.sample
+++ b/configs/samples/pjsip.conf.sample
@@ -251,6 +251,7 @@
;endpoint=mytrunk
;match=198.51.100.1
;match=198.51.100.2
+;match=192.168.10.0:5061/24
;=============ENDPOINT CONFIGURED AS A TRUNK, INBOUND AUTH AND REGISTRATION===
diff --git a/doc/CHANGES-staging/res_pjsip_endpoint_identifier_ip_match_port.txt b/doc/CHANGES-staging/res_pjsip_endpoint_identifier_ip_match_port.txt
new file mode 100644
index 0000000..3881d64
--- /dev/null
+++ b/doc/CHANGES-staging/res_pjsip_endpoint_identifier_ip_match_port.txt
@@ -0,0 +1,8 @@
+Subject: res_pjsip_endpoint_identifier_ip
+
+In 'type = identify' sections, the addresses specified for the 'match'
+clause can now include a port number. For IP addresses, the port is
+provided by including a colon after the address, followed by the
+desired port number. If supplied, the netmask should follow the port
+number. To specify a port for IPv6 addresses, the address itself must
+be enclosed in brackets to be parsed correctly.
diff --git a/include/asterisk/acl.h b/include/asterisk/acl.h
index b8a4f72..fe49a5b 100644
--- a/include/asterisk/acl.h
+++ b/include/asterisk/acl.h
@@ -135,6 +135,29 @@
struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error);
/*!
+ * \brief Add a new rule with optional port to a list of HAs
+ * \since 13.31.0, 16.8.0, 17.2.0
+ *
+ * \details
+ * This adds the new host access rule to the end of the list
+ * whose head is specified by the path parameter. Rules are
+ * evaluated in a way such that if multiple rules apply to
+ * a single IP address/subnet mask, then the rule latest
+ * in the list will be used.
+ *
+ * \param sense Either "permit" or "deny" (Actually any 'p' word will result
+ * in permission, and any other word will result in denial)
+ * \param stuff The IP address and subnet mask, separated with a '/'. The subnet
+ * mask can either be in dotted-decimal format or in CIDR notation (i.e. 0-32). A
+ * port can be provided by placing it after the IP address, separated with a ':'.
+ * \param path The head of the HA list to which we wish to append our new rule. If
+ * NULL is passed, then the new rule will become the head of the list
+ * \param[out] error The integer error points to will be set non-zero if an error occurs
+ * \return The head of the HA list
+ */
+struct ast_ha *ast_append_ha_with_port(const char *sense, const char *stuff, struct ast_ha *path, int *error);
+
+/*!
* \brief Convert HAs to a comma separated string value
* \param ha the starting ha head
* \param buf string buffer to convert data to
diff --git a/main/acl.c b/main/acl.c
index 5028587..9179753 100644
--- a/main/acl.c
+++ b/main/acl.c
@@ -574,7 +574,7 @@
ha->sense);
}
-struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error)
+static struct ast_ha *append_ha_core(const char *sense, const char *stuff, struct ast_ha *path, int *error, int port_flags)
{
struct ast_ha *ha;
struct ast_ha *prev = NULL;
@@ -591,6 +591,8 @@
}
while ((tmp = strsep(&list, ","))) {
+ uint16_t save_port;
+
if (!(ha = ast_calloc(1, sizeof(*ha)))) {
if (error) {
*error = 1;
@@ -612,7 +614,7 @@
ha->sense = allowing;
}
- if (!ast_sockaddr_parse(&ha->addr, address, PARSE_PORT_FORBID)) {
+ if (!ast_sockaddr_parse(&ha->addr, address, port_flags)) {
ast_log(LOG_WARNING, "Invalid IP address: %s\n", address);
ast_free_ha(ha);
if (error) {
@@ -621,6 +623,11 @@
return ret;
}
+ /* Be pedantic and zero out the port if we don't want it */
+ if ((port_flags & PARSE_PORT_MASK) == PARSE_PORT_FORBID) {
+ ast_sockaddr_set_port(&ha->addr, 0);
+ }
+
/* If someone specifies an IPv4-mapped IPv6 address,
* we just convert this to an IPv4 ACL
*/
@@ -669,6 +676,10 @@
return ret;
}
+ /* ast_sockaddr_apply_netmask() does not preserve the port, so we need to save and
+ * restore it */
+ save_port = ast_sockaddr_port(&ha->addr);
+
if (ast_sockaddr_apply_netmask(&ha->addr, &ha->netmask, &ha->addr)) {
/* This shouldn't happen because ast_sockaddr_parse would
* have failed much earlier on an unsupported address scheme
@@ -683,6 +694,8 @@
return ret;
}
+ ast_sockaddr_set_port(&ha->addr, save_port);
+
if (prev) {
prev->next = ha;
} else {
@@ -698,12 +711,30 @@
return ret;
}
+struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error)
+{
+ return append_ha_core(sense, stuff, path, error, PARSE_PORT_FORBID);
+}
+
+struct ast_ha *ast_append_ha_with_port(const char *sense, const char *stuff, struct ast_ha *path, int *error)
+{
+ return append_ha_core(sense, stuff, path, error, 0);
+}
+
void ast_ha_join(const struct ast_ha *ha, struct ast_str **buf)
{
for (; ha; ha = ha->next) {
+ const char *addr;
+
+ if (ast_sockaddr_port(&ha->addr)) {
+ addr = ast_sockaddr_stringify(&ha->addr);
+ } else {
+ addr = ast_sockaddr_stringify_addr(&ha->addr);
+ }
+
ast_str_append(buf, 0, "%s%s/",
ha->sense == AST_SENSE_ALLOW ? "!" : "",
- ast_sockaddr_stringify_addr(&ha->addr));
+ addr);
/* Separated to avoid duplicating stringified addresses. */
ast_str_append(buf, 0, "%s", ast_sockaddr_stringify_addr(&ha->netmask));
if (ha->next) {
@@ -785,6 +816,7 @@
struct ast_sockaddr result;
struct ast_sockaddr mapped_addr;
const struct ast_sockaddr *addr_to_use;
+ uint16_t save_port;
#if 0 /* debugging code */
char iabuf[INET_ADDRSTRLEN];
char iabuf2[INET_ADDRSTRLEN];
@@ -820,13 +852,22 @@
}
}
+ /* ast_sockaddr_apply_netmask() does not preserve the port, so we need to save and
+ * restore it */
+ save_port = ast_sockaddr_port(addr_to_use);
+
/* For each rule, if this address and the netmask = the net address
apply the current rule */
if (ast_sockaddr_apply_netmask(addr_to_use, ¤t_ha->netmask, &result)) {
/* Unlikely to happen since we know the address to be IPv4 or IPv6 */
continue;
}
- if (!ast_sockaddr_cmp_addr(&result, ¤t_ha->addr)) {
+
+ ast_sockaddr_set_port(&result, save_port);
+
+ if (!ast_sockaddr_cmp_addr(&result, ¤t_ha->addr)
+ && (!ast_sockaddr_port(¤t_ha->addr)
+ || ast_sockaddr_port(¤t_ha->addr) == ast_sockaddr_port(&result))) {
res = current_ha->sense;
}
}
diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c
index ac4057b..f8d5c70 100644
--- a/res/res_pjsip_endpoint_identifier_ip.c
+++ b/res/res_pjsip_endpoint_identifier_ip.c
@@ -63,7 +63,9 @@
hostnames. IP addresses may have a subnet mask appended. The
subnet mask may be written in either CIDR or dotted-decimal
notation. Separate the IP address and subnet mask with a slash
- ('/').
+ ('/'). A source port can also be specified by adding a colon (':')
+ after the address but before the subnet mask, e.g.
+ 3.2.1.0:5061/24.
</para>
</description>
</configOption>
@@ -310,7 +312,7 @@
int num_addrs = 0, error = 0, i;
int results = 0;
- num_addrs = ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC);
+ num_addrs = ast_sockaddr_resolve(&addrs, host, 0, AST_AF_UNSPEC);
if (!num_addrs) {
return -1;
}
@@ -322,7 +324,7 @@
}
/* We deny what we actually want to match because there is an implicit permit all rule for ACLs */
- identify->matches = ast_append_ha("d", ast_sockaddr_stringify_addr(&addrs[i]), identify->matches, &error);
+ identify->matches = ast_append_ha_with_port("d", ast_sockaddr_stringify(&addrs[i]), identify->matches, &error);
if (!identify->matches || error) {
results = -1;
@@ -380,15 +382,20 @@
}
while ((current_string = ast_strip(strsep(&input_string, ",")))) {
- char *mask = strrchr(current_string, '/');
+ char *mask;
+ struct ast_sockaddr address;
int error = 0;
if (ast_strlen_zero(current_string)) {
continue;
}
- if (mask) {
- identify->matches = ast_append_ha("d", current_string, identify->matches, &error);
+ mask = strrchr(current_string, '/');
+
+ /* If it looks like a netmask is present, or we can immediately parse as an IP,
+ * hand things off to the ACL */
+ if (mask || ast_sockaddr_parse(&address, current_string, 0)) {
+ identify->matches = ast_append_ha_with_port("d", current_string, identify->matches, &error);
if (!identify->matches || error) {
ast_log(LOG_ERROR, "Failed to add address '%s' to ip endpoint identifier '%s'\n",
@@ -498,20 +505,23 @@
/* Resolve the match addresses now */
i = ao2_iterator_init(identify->hosts, 0);
while ((current_string = ao2_iterator_next(&i))) {
- struct ast_sockaddr address;
int results = 0;
+ char *colon = strrchr(current_string, ':');
- /* If the provided string is not an IP address perform SRV resolution on it */
- if (identify->srv_lookups && !ast_sockaddr_parse(&address, current_string, 0)) {
- results = ip_identify_match_srv_lookup(identify, "_sip._udp", current_string,
- results);
- if (results != -1) {
- results = ip_identify_match_srv_lookup(identify, "_sip._tcp",
- current_string, results);
- }
- if (results != -1) {
- results = ip_identify_match_srv_lookup(identify, "_sips._tcp",
- current_string, results);
+ /* We skip SRV lookup if a colon is present, assuming a port was specified */
+ if (!colon) {
+ /* No port, and we know this is not an IP address, so perform SRV resolution on it */
+ if (identify->srv_lookups) {
+ results = ip_identify_match_srv_lookup(identify, "_sip._udp", current_string,
+ results);
+ if (results != -1) {
+ results = ip_identify_match_srv_lookup(identify, "_sip._tcp",
+ current_string, results);
+ }
+ if (results != -1) {
+ results = ip_identify_match_srv_lookup(identify, "_sips._tcp",
+ current_string, results);
+ }
}
}
@@ -554,7 +564,14 @@
static void match_to_var_list_append(struct ast_variable **head, struct ast_ha *ha)
{
char str[MAX_OBJECT_FIELD];
- const char *addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr));
+ const char *addr;
+
+ if (ast_sockaddr_port(&ha->addr)) {
+ addr = ast_strdupa(ast_sockaddr_stringify(&ha->addr));
+ } else {
+ addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr));
+ }
+
snprintf(str, MAX_OBJECT_FIELD, "%s%s/%s", ha->sense == AST_SENSE_ALLOW ? "!" : "",
addr, ast_sockaddr_stringify_addr(&ha->netmask));
@@ -737,7 +754,13 @@
indent = CLI_INDENT_TO_SPACES(context->indent_level);
for (match = ident->matches; match; match = match->next) {
- const char *addr = ast_sockaddr_stringify_addr(&match->addr);
+ const char *addr;
+
+ if (ast_sockaddr_port(&match->addr)) {
+ addr = ast_sockaddr_stringify(&match->addr);
+ } else {
+ addr = ast_sockaddr_stringify_addr(&match->addr);
+ }
ast_str_append(&context->output_buffer, 0, "%*s: %s%s/%d\n",
indent,
--
To view, visit https://gerrit.asterisk.org/c/asterisk/+/13312
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings
Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-Change-Id: I256d5bd5d478b95f526e2f80ace31b690eebba92
Gerrit-Change-Number: 13312
Gerrit-PatchSet: 11
Gerrit-Owner: Sean Bright <sean.bright at gmail.com>
Gerrit-Reviewer: Benjamin Keith Ford <bford at digium.com>
Gerrit-Reviewer: Friendly Automation
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at sangoma.com>
Gerrit-Reviewer: Sean Bright <sean.bright at gmail.com>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20200109/55b377ef/attachment-0001.html>
More information about the asterisk-code-review
mailing list