inany_from_sockaddr() expects a socket address of family AF_INET or
AF_INET6 and ASSERT()s if it gets anything else. In many of the callers we
can handle an unexpected family more gracefully, though, e.g. by failing
a single flow rather than killing passt.
Change inany_from_sockaddr() to return an error instead of ASSERT()ing,
and handle those errors in the callers. Improve the reporting of any such
errors while we're at it.
With this greater robustness, allow inany_from_sockaddr() to take a void *
rather than specifically a union sockaddr_inany *.
Signed-off-by: David Gibson
---
flow.c | 16 ++++++++++++++--
inany.h | 22 ++++++++++++++--------
tcp.c | 10 ++++------
udp_flow.c | 6 +++---
4 files changed, 35 insertions(+), 19 deletions(-)
diff --git a/flow.c b/flow.c
index 3c81cb42..447c0211 100644
--- a/flow.c
+++ b/flow.c
@@ -408,7 +408,12 @@ struct flowside *flow_initiate_sa(union flow *flow, uint8_t pif,
{
struct flowside *ini = &flow->f.side[INISIDE];
- inany_from_sockaddr(&ini->eaddr, &ini->eport, ssa);
+ if (inany_from_sockaddr(&ini->eaddr, &ini->eport, ssa) < 0) {
+ char str[SOCKADDR_STRLEN];
+
+ ASSERT_WITH_MSG(0, "Bad socket address %s",
+ sockaddr_ntop(ssa, str, sizeof(str)));
+ }
if (daddr)
ini->oaddr = *daddr;
else if (inany_v4(&ini->eaddr))
@@ -768,7 +773,14 @@ flow_sidx_t flow_lookup_sa(const struct ctx *c, uint8_t proto, uint8_t pif,
.oport = oport,
};
- inany_from_sockaddr(&side.eaddr, &side.eport, esa);
+ if (inany_from_sockaddr(&side.eaddr, &side.eport, esa) < 0) {
+ char str[SOCKADDR_STRLEN];
+
+ warn("Flow lookup on bad socket address %s",
+ sockaddr_ntop(esa, str, sizeof(str)));
+ return FLOW_SIDX_NONE;
+ }
+
if (oaddr)
side.oaddr = *oaddr;
else if (inany_v4(&side.eaddr))
diff --git a/inany.h b/inany.h
index 1c247e1e..f5c618bf 100644
--- a/inany.h
+++ b/inany.h
@@ -239,22 +239,28 @@ static inline void inany_from_af(union inany_addr *aa,
/** inany_from_sockaddr - Extract IPv[46] address and port number from sockaddr
* @aa: Pointer to store IPv[46] address
* @port: Pointer to store port number, host order
- * @addr: AF_INET or AF_INET6 socket address
+ * @addr: Socket address
+ *
+ * Return: 0 on success, -1 on error (bad address family)
*/
-static inline void inany_from_sockaddr(union inany_addr *aa, in_port_t *port,
- const union sockaddr_inany *sa)
+static inline int inany_from_sockaddr(union inany_addr *aa, in_port_t *port,
+ const void *sa_)
{
+ const union sockaddr_inany *sa = (const union sockaddr_inany *)sa_;
+
if (sa->sa_family == AF_INET6) {
inany_from_af(aa, AF_INET6, &sa->sa6.sin6_addr);
*port = ntohs(sa->sa6.sin6_port);
- } else if (sa->sa_family == AF_INET) {
+ return 0;
+ }
+
+ if (sa->sa_family == AF_INET) {
inany_from_af(aa, AF_INET, &sa->sa4.sin_addr);
*port = ntohs(sa->sa4.sin_port);
- } else {
- /* Not valid to call with other address families */
- ASSERT_WITH_MSG(0, "Unexpected sockaddr family: %u",
- sa->sa_family);
+ return 0;
}
+
+ return -1;
}
/** inany_siphash_feed- Fold IPv[46] address into an in-progress siphash
diff --git a/tcp.c b/tcp.c
index 9c6bc529..0ac298a7 100644
--- a/tcp.c
+++ b/tcp.c
@@ -1546,9 +1546,8 @@ static void tcp_conn_from_tap(const struct ctx *c, sa_family_t af,
if (c->mode == MODE_VU) { /* To rebind to same oport after migration */
sl = sizeof(sa);
- if (!getsockname(s, &sa.sa, &sl))
- inany_from_sockaddr(&tgt->oaddr, &tgt->oport, &sa);
- else
+ if (getsockname(s, &sa.sa, &sl) ||
+ inany_from_sockaddr(&tgt->oaddr, &tgt->oport, &sa) < 0)
err_perror("Can't get local address for socket %i", s);
}
@@ -2204,9 +2203,8 @@ void tcp_listen_handler(const struct ctx *c, union epoll_ref ref,
NULL, ref.tcp_listen.port);
if (c->mode == MODE_VU) { /* Rebind to same address after migration */
- if (!getsockname(s, &sa.sa, &sl))
- inany_from_sockaddr(&ini->oaddr, &ini->oport, &sa);
- else
+ if (getsockname(s, &sa.sa, &sl) ||
+ inany_from_sockaddr(&ini->oaddr, &ini->oport, &sa) < 0)
err_perror("Can't get local address for socket %i", s);
}
diff --git a/udp_flow.c b/udp_flow.c
index ef2cbb06..fea1cf3c 100644
--- a/udp_flow.c
+++ b/udp_flow.c
@@ -158,12 +158,12 @@ static flow_sidx_t udp_flow_new(const struct ctx *c, union flow *flow,
socklen_t sl = sizeof(sa);
in_port_t port;
- if (getsockname(uflow->s[TGTSIDE], &sa.sa, &sl) < 0) {
+ if (getsockname(uflow->s[TGTSIDE], &sa.sa, &sl) < 0 ||
+ inany_from_sockaddr(&uflow->f.side[TGTSIDE].oaddr,
+ &port, &sa) < 0) {
flow_perror(uflow, "Unable to determine local address");
goto cancel;
}
- inany_from_sockaddr(&uflow->f.side[TGTSIDE].oaddr,
- &port, &sa);
if (port != tgt->oport) {
flow_err(uflow, "Unexpected local port");
goto cancel;
--
2.49.0