diff options
author | Pau Espin Pedrol <pespin@sysmocom.de> | 2020-08-21 16:46:06 +0200 |
---|---|---|
committer | Pau Espin Pedrol <pespin@sysmocom.de> | 2020-08-24 10:34:54 +0200 |
commit | ce88150c057fa92d6342ca677aa55735912996e5 (patch) | |
tree | 871afd8fafcac1f5f0435366ca6a3e10c1f5e239 | |
parent | 0b39f2cf7bab5cf3924d8b0b753f41b5b0cabd25 (diff) |
Fix finding ASP on IPv6 connections
Change-Id: I09226a5cecc37dd4676acd61c2051befe5234cb3
-rw-r--r-- | src/osmo_ss7.c | 43 |
1 files changed, 36 insertions, 7 deletions
diff --git a/src/osmo_ss7.c b/src/osmo_ss7.c index cdac27a..bae9904 100644 --- a/src/osmo_ss7.c +++ b/src/osmo_ss7.c @@ -1198,6 +1198,26 @@ static uint16_t get_in_port(struct sockaddr *sa) } } +/* Converts string representation of v4-mappend-on-v6 IP addr to a pure IPv4 address. + * Example: ::ffff:172.18.19.200 => 172.18.19.200 + */ +static void chop_v4_mapped_on_v6_prefix(char* buf) +{ + char *last_colon; + size_t len; + char *first_dot = strchr(buf, '.'); + + if (!first_dot) + return; /* Not an IPv4-mappend-on-v6 string representation, nothing to do */ + last_colon = strrchr(buf, ':'); + if (!last_colon) + return; /* pure IPv4 address, nothing to do */ + + len = strlen(last_colon + 1); + memmove(buf, last_colon + 1, len); + buf[len] = '\0'; +} + /*! \brief Find an ASP definition matching the local+remote IP/PORT of given fd * \param[in] fd socket descriptor of given socket * \returns SS7 ASP in case a matching one is found; NULL otherwise */ @@ -1205,7 +1225,7 @@ static struct osmo_ss7_asp * osmo_ss7_asp_find_by_socket_addr(int fd) { struct osmo_ss7_instance *inst; - struct sockaddr sa_l, sa_r; + struct sockaddr_storage sa_l, sa_r; socklen_t sa_len_l = sizeof(sa_l); socklen_t sa_len_r = sizeof(sa_r); char hostbuf_l[64], hostbuf_r[64]; @@ -1215,23 +1235,32 @@ osmo_ss7_asp_find_by_socket_addr(int fd) OSMO_ASSERT(ss7_initialized); /* convert local and remote IP to string */ - rc = getsockname(fd, &sa_l, &sa_len_l); + rc = getsockname(fd, (struct sockaddr*)&sa_l, &sa_len_l); if (rc < 0) return NULL; - rc = getnameinfo(&sa_l, sa_len_l, hostbuf_l, sizeof(hostbuf_l), + rc = getnameinfo((struct sockaddr*)&sa_l, sa_len_l, + hostbuf_l, sizeof(hostbuf_l), NULL, 0, NI_NUMERICHOST); if (rc < 0) return NULL; - local_port = ntohs(get_in_port(&sa_l)); + local_port = ntohs(get_in_port((struct sockaddr*)&sa_l)); - rc = getpeername(fd, &sa_r, &sa_len_r); + rc = getpeername(fd, (struct sockaddr*)&sa_r, &sa_len_r); if (rc < 0) return NULL; - rc = getnameinfo(&sa_r, sa_len_r, hostbuf_r, sizeof(hostbuf_r), + rc = getnameinfo((struct sockaddr*)&sa_r, sa_len_r, + hostbuf_r, sizeof(hostbuf_r), NULL, 0, NI_NUMERICHOST); if (rc < 0) return NULL; - remote_port = ntohs(get_in_port(&sa_r)); + remote_port = ntohs(get_in_port((struct sockaddr*)&sa_r)); + + /* If multi-home is used with both IPv4 and IPv6, then the socket is + * AF_INET6, and then returned IPv4 addresses are actually v6mapped ones. + * We need to convert them to IPv4 before matching. + */ + chop_v4_mapped_on_v6_prefix(hostbuf_l); + chop_v4_mapped_on_v6_prefix(hostbuf_r); /* check all instances for any ASP definition matching the * address combination of local/remote ip/port */ |