mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 12:36:58 +00:00
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
This commit is contained in:
@@ -251,6 +251,7 @@
|
|||||||
;endpoint=mytrunk
|
;endpoint=mytrunk
|
||||||
;match=198.51.100.1
|
;match=198.51.100.1
|
||||||
;match=198.51.100.2
|
;match=198.51.100.2
|
||||||
|
;match=192.168.10.0:5061/24
|
||||||
|
|
||||||
|
|
||||||
;=============ENDPOINT CONFIGURED AS A TRUNK, INBOUND AUTH AND REGISTRATION===
|
;=============ENDPOINT CONFIGURED AS A TRUNK, INBOUND AUTH AND REGISTRATION===
|
||||||
|
@@ -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.
|
@@ -134,6 +134,29 @@ void ast_copy_ha(const struct ast_ha *from, struct ast_ha *to);
|
|||||||
*/
|
*/
|
||||||
struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error);
|
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
|
* \brief Convert HAs to a comma separated string value
|
||||||
* \param ha the starting ha head
|
* \param ha the starting ha head
|
||||||
|
49
main/acl.c
49
main/acl.c
@@ -572,7 +572,7 @@ static void debug_ha_sense_appended(struct ast_ha *ha)
|
|||||||
ha->sense);
|
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 *ha;
|
||||||
struct ast_ha *prev = NULL;
|
struct ast_ha *prev = NULL;
|
||||||
@@ -589,6 +589,8 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha
|
|||||||
}
|
}
|
||||||
|
|
||||||
while ((tmp = strsep(&list, ","))) {
|
while ((tmp = strsep(&list, ","))) {
|
||||||
|
uint16_t save_port;
|
||||||
|
|
||||||
if (!(ha = ast_calloc(1, sizeof(*ha)))) {
|
if (!(ha = ast_calloc(1, sizeof(*ha)))) {
|
||||||
if (error) {
|
if (error) {
|
||||||
*error = 1;
|
*error = 1;
|
||||||
@@ -610,7 +612,7 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha
|
|||||||
ha->sense = allowing;
|
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_log(LOG_WARNING, "Invalid IP address: %s\n", address);
|
||||||
ast_free_ha(ha);
|
ast_free_ha(ha);
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -619,6 +621,11 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha
|
|||||||
return ret;
|
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,
|
/* If someone specifies an IPv4-mapped IPv6 address,
|
||||||
* we just convert this to an IPv4 ACL
|
* we just convert this to an IPv4 ACL
|
||||||
*/
|
*/
|
||||||
@@ -667,6 +674,10 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha
|
|||||||
return ret;
|
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)) {
|
if (ast_sockaddr_apply_netmask(&ha->addr, &ha->netmask, &ha->addr)) {
|
||||||
/* This shouldn't happen because ast_sockaddr_parse would
|
/* This shouldn't happen because ast_sockaddr_parse would
|
||||||
* have failed much earlier on an unsupported address scheme
|
* have failed much earlier on an unsupported address scheme
|
||||||
@@ -681,6 +692,8 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast_sockaddr_set_port(&ha->addr, save_port);
|
||||||
|
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev->next = ha;
|
prev->next = ha;
|
||||||
} else {
|
} else {
|
||||||
@@ -696,12 +709,30 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha
|
|||||||
return ret;
|
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)
|
void ast_ha_join(const struct ast_ha *ha, struct ast_str **buf)
|
||||||
{
|
{
|
||||||
for (; ha; ha = ha->next) {
|
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/",
|
ast_str_append(buf, 0, "%s%s/",
|
||||||
ha->sense == AST_SENSE_ALLOW ? "!" : "",
|
ha->sense == AST_SENSE_ALLOW ? "!" : "",
|
||||||
ast_sockaddr_stringify_addr(&ha->addr));
|
addr);
|
||||||
/* Separated to avoid duplicating stringified addresses. */
|
/* Separated to avoid duplicating stringified addresses. */
|
||||||
ast_str_append(buf, 0, "%s", ast_sockaddr_stringify_addr(&ha->netmask));
|
ast_str_append(buf, 0, "%s", ast_sockaddr_stringify_addr(&ha->netmask));
|
||||||
if (ha->next) {
|
if (ha->next) {
|
||||||
@@ -783,6 +814,7 @@ enum ast_acl_sense ast_apply_ha(const struct ast_ha *ha, const struct ast_sockad
|
|||||||
struct ast_sockaddr result;
|
struct ast_sockaddr result;
|
||||||
struct ast_sockaddr mapped_addr;
|
struct ast_sockaddr mapped_addr;
|
||||||
const struct ast_sockaddr *addr_to_use;
|
const struct ast_sockaddr *addr_to_use;
|
||||||
|
uint16_t save_port;
|
||||||
#if 0 /* debugging code */
|
#if 0 /* debugging code */
|
||||||
char iabuf[INET_ADDRSTRLEN];
|
char iabuf[INET_ADDRSTRLEN];
|
||||||
char iabuf2[INET_ADDRSTRLEN];
|
char iabuf2[INET_ADDRSTRLEN];
|
||||||
@@ -818,13 +850,22 @@ enum ast_acl_sense ast_apply_ha(const struct ast_ha *ha, const struct ast_sockad
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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
|
/* For each rule, if this address and the netmask = the net address
|
||||||
apply the current rule */
|
apply the current rule */
|
||||||
if (ast_sockaddr_apply_netmask(addr_to_use, ¤t_ha->netmask, &result)) {
|
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 */
|
/* Unlikely to happen since we know the address to be IPv4 or IPv6 */
|
||||||
continue;
|
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;
|
res = current_ha->sense;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -63,7 +63,9 @@
|
|||||||
hostnames. IP addresses may have a subnet mask appended. The
|
hostnames. IP addresses may have a subnet mask appended. The
|
||||||
subnet mask may be written in either CIDR or dotted-decimal
|
subnet mask may be written in either CIDR or dotted-decimal
|
||||||
notation. Separate the IP address and subnet mask with a slash
|
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>
|
</para>
|
||||||
</description>
|
</description>
|
||||||
</configOption>
|
</configOption>
|
||||||
@@ -310,7 +312,7 @@ static int ip_identify_match_host_lookup(struct ip_identify_match *identify, con
|
|||||||
int num_addrs = 0, error = 0, i;
|
int num_addrs = 0, error = 0, i;
|
||||||
int results = 0;
|
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) {
|
if (!num_addrs) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -322,7 +324,7 @@ static int ip_identify_match_host_lookup(struct ip_identify_match *identify, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We deny what we actually want to match because there is an implicit permit all rule for ACLs */
|
/* 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) {
|
if (!identify->matches || error) {
|
||||||
results = -1;
|
results = -1;
|
||||||
@@ -380,15 +382,20 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va
|
|||||||
}
|
}
|
||||||
|
|
||||||
while ((current_string = ast_strip(strsep(&input_string, ",")))) {
|
while ((current_string = ast_strip(strsep(&input_string, ",")))) {
|
||||||
char *mask = strrchr(current_string, '/');
|
char *mask;
|
||||||
|
struct ast_sockaddr address;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
if (ast_strlen_zero(current_string)) {
|
if (ast_strlen_zero(current_string)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask) {
|
mask = strrchr(current_string, '/');
|
||||||
identify->matches = ast_append_ha("d", current_string, identify->matches, &error);
|
|
||||||
|
/* 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) {
|
if (!identify->matches || error) {
|
||||||
ast_log(LOG_ERROR, "Failed to add address '%s' to ip endpoint identifier '%s'\n",
|
ast_log(LOG_ERROR, "Failed to add address '%s' to ip endpoint identifier '%s'\n",
|
||||||
@@ -498,20 +505,23 @@ static int ip_identify_apply(const struct ast_sorcery *sorcery, void *obj)
|
|||||||
/* Resolve the match addresses now */
|
/* Resolve the match addresses now */
|
||||||
i = ao2_iterator_init(identify->hosts, 0);
|
i = ao2_iterator_init(identify->hosts, 0);
|
||||||
while ((current_string = ao2_iterator_next(&i))) {
|
while ((current_string = ao2_iterator_next(&i))) {
|
||||||
struct ast_sockaddr address;
|
|
||||||
int results = 0;
|
int results = 0;
|
||||||
|
char *colon = strrchr(current_string, ':');
|
||||||
|
|
||||||
/* If the provided string is not an IP address perform SRV resolution on it */
|
/* We skip SRV lookup if a colon is present, assuming a port was specified */
|
||||||
if (identify->srv_lookups && !ast_sockaddr_parse(&address, current_string, 0)) {
|
if (!colon) {
|
||||||
results = ip_identify_match_srv_lookup(identify, "_sip._udp", current_string,
|
/* No port, and we know this is not an IP address, so perform SRV resolution on it */
|
||||||
results);
|
if (identify->srv_lookups) {
|
||||||
if (results != -1) {
|
results = ip_identify_match_srv_lookup(identify, "_sip._udp", current_string,
|
||||||
results = ip_identify_match_srv_lookup(identify, "_sip._tcp",
|
results);
|
||||||
current_string, results);
|
if (results != -1) {
|
||||||
}
|
results = ip_identify_match_srv_lookup(identify, "_sip._tcp",
|
||||||
if (results != -1) {
|
current_string, results);
|
||||||
results = ip_identify_match_srv_lookup(identify, "_sips._tcp",
|
}
|
||||||
current_string, results);
|
if (results != -1) {
|
||||||
|
results = ip_identify_match_srv_lookup(identify, "_sips._tcp",
|
||||||
|
current_string, results);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,7 +564,14 @@ static int match_to_str(const void *obj, const intptr_t *args, char **buf)
|
|||||||
static void match_to_var_list_append(struct ast_variable **head, struct ast_ha *ha)
|
static void match_to_var_list_append(struct ast_variable **head, struct ast_ha *ha)
|
||||||
{
|
{
|
||||||
char str[MAX_OBJECT_FIELD];
|
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 ? "!" : "",
|
snprintf(str, MAX_OBJECT_FIELD, "%s%s/%s", ha->sense == AST_SENSE_ALLOW ? "!" : "",
|
||||||
addr, ast_sockaddr_stringify_addr(&ha->netmask));
|
addr, ast_sockaddr_stringify_addr(&ha->netmask));
|
||||||
|
|
||||||
@@ -737,7 +754,13 @@ static int cli_print_body(void *obj, void *arg, int flags)
|
|||||||
indent = CLI_INDENT_TO_SPACES(context->indent_level);
|
indent = CLI_INDENT_TO_SPACES(context->indent_level);
|
||||||
|
|
||||||
for (match = ident->matches; match; match = match->next) {
|
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",
|
ast_str_append(&context->output_buffer, 0, "%*s: %s%s/%d\n",
|
||||||
indent,
|
indent,
|
||||||
|
Reference in New Issue
Block a user