icmp: Manage outbound socket address via flow table

For now when we forward a ping to the host we leave the host side
forwarding address and port blank since we don't necessarily know what
source address and id will be used by the kernel.  When the outbound
address option is active, though, we do know the address at least, so we
can record it in the flowside.

Having done that, use it as the primary source of truth, binding the
outgoing socket based on the information in there.  This allows the
possibility of more complex rules for what outbound address and/or id
we use in future.

To implement this we create a new helper which sets up a new socket based
on information in a flowside, which will also have future uses.  It
behaves slightly differently from the existing ICMP code, in that it
doesn't bind to a specific interface if given a loopback address.  This is
logically correct - the loopback address means we need to operate through
the host's loopback interface, not ifname_out.  We didn't need it in ICMP
because ICMP will never generate a loopback address at this point, however
we intend to change that in future.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
David Gibson 2024-07-18 15:26:42 +10:00 committed by Stefano Brivio
parent 781164e25b
commit 4cd753e65c
2 changed files with 10 additions and 14 deletions

1
flow.c
View file

@ -194,7 +194,6 @@ static int flowside_sock_splice(void *arg)
* Return: socket fd of protocol @proto bound to the forwarding address and port
* from @tgt (if specified).
*/
/* cppcheck-suppress unusedFunction */
int flowside_sock_l4(const struct ctx *c, enum epoll_type type, uint8_t pif,
const struct flowside *tgt, uint32_t data)
{

23
icmp.c
View file

@ -173,30 +173,27 @@ static struct icmp_ping_flow *icmp_ping_new(const struct ctx *c,
union epoll_ref ref = { .type = EPOLL_TYPE_PING };
union flow *flow = flow_alloc();
struct icmp_ping_flow *pingf;
const struct flowside *tgt;
const void *bind_addr;
const char *bind_if;
if (!flow)
return NULL;
flow_initiate_af(flow, PIF_TAP, af, saddr, id, daddr, id);
/* FIXME: Record outbound source address when known */
flow_target_af(flow, PIF_HOST, af, NULL, 0, daddr, 0);
if (af == AF_INET)
bind_addr = &c->ip4.addr_out;
else if (af == AF_INET6)
bind_addr = &c->ip6.addr_out;
tgt = flow_target_af(flow, PIF_HOST, af, bind_addr, 0, daddr, 0);
pingf = FLOW_SET_TYPE(flow, flowtype, ping);
pingf->seq = -1;
if (af == AF_INET) {
bind_addr = &c->ip4.addr_out;
bind_if = c->ip4.ifname_out;
} else {
bind_addr = &c->ip6.addr_out;
bind_if = c->ip6.ifname_out;
}
ref.flowside = FLOW_SIDX(flow, TGTSIDE);
pingf->sock = sock_l4(c, af, EPOLL_TYPE_PING, bind_addr, bind_if,
0, ref.data);
pingf->sock = flowside_sock_l4(c, EPOLL_TYPE_PING, PIF_HOST,
tgt, ref.data);
if (pingf->sock < 0) {
warn("Cannot open \"ping\" socket. You might need to:");