tap: Pass source address to protocol handler functions

The tap code passes the IPv4 or IPv6 destination address of packets it
receives to the protocol specific code.  Currently that protocol code
doesn't use the source address, but we want it to in future.  So, in
preparation, pass the IPv4/IPv6 source address of tap packets to those
functions as well.

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 2023-08-22 15:29:53 +10:00 committed by Stefano Brivio
parent 673bde1f21
commit cee4a2da48
7 changed files with 48 additions and 32 deletions

12
icmp.c
View file

@ -154,17 +154,21 @@ void icmpv6_sock_handler(const struct ctx *c, union epoll_ref ref)
* icmp_tap_handler() - Handle packets from tap * icmp_tap_handler() - Handle packets from tap
* @c: Execution context * @c: Execution context
* @af: Address family, AF_INET or AF_INET6 * @af: Address family, AF_INET or AF_INET6
* @addr: Destination address * @saddr: Source address
* @daddr: Destination address
* @p: Packet pool, single packet with ICMP/ICMPv6 header * @p: Packet pool, single packet with ICMP/ICMPv6 header
* @now: Current timestamp * @now: Current timestamp
* *
* Return: count of consumed packets (always 1, even if malformed) * Return: count of consumed packets (always 1, even if malformed)
*/ */
int icmp_tap_handler(const struct ctx *c, int af, const void *addr, int icmp_tap_handler(const struct ctx *c, int af,
const void *saddr, const void *daddr,
const struct pool *p, const struct timespec *now) const struct pool *p, const struct timespec *now)
{ {
size_t plen; size_t plen;
(void)saddr;
if (af == AF_INET) { if (af == AF_INET) {
struct sockaddr_in sa = { struct sockaddr_in sa = {
.sin_family = AF_INET, .sin_family = AF_INET,
@ -210,7 +214,7 @@ int icmp_tap_handler(const struct ctx *c, int af, const void *addr,
icmp_id_map[V4][id].ts = now->tv_sec; icmp_id_map[V4][id].ts = now->tv_sec;
bitmap_set(icmp_act[V4], id); bitmap_set(icmp_act[V4], id);
sa.sin_addr = *(struct in_addr *)addr; sa.sin_addr = *(struct in_addr *)daddr;
if (sendto(s, ih, sizeof(*ih) + plen, MSG_NOSIGNAL, if (sendto(s, ih, sizeof(*ih) + plen, MSG_NOSIGNAL,
(struct sockaddr *)&sa, sizeof(sa)) < 0) { (struct sockaddr *)&sa, sizeof(sa)) < 0) {
debug("ICMP: failed to relay request to socket"); debug("ICMP: failed to relay request to socket");
@ -264,7 +268,7 @@ int icmp_tap_handler(const struct ctx *c, int af, const void *addr,
icmp_id_map[V6][id].ts = now->tv_sec; icmp_id_map[V6][id].ts = now->tv_sec;
bitmap_set(icmp_act[V6], id); bitmap_set(icmp_act[V6], id);
sa.sin6_addr = *(struct in6_addr *)addr; sa.sin6_addr = *(struct in6_addr *)daddr;
if (sendto(s, ih, sizeof(*ih) + plen, MSG_NOSIGNAL, if (sendto(s, ih, sizeof(*ih) + plen, MSG_NOSIGNAL,
(struct sockaddr *)&sa, sizeof(sa)) < 1) { (struct sockaddr *)&sa, sizeof(sa)) < 1) {
debug("ICMPv6: failed to relay request to socket"); debug("ICMPv6: failed to relay request to socket");

3
icmp.h
View file

@ -12,7 +12,8 @@ struct ctx;
void icmp_sock_handler(const struct ctx *c, union epoll_ref ref); void icmp_sock_handler(const struct ctx *c, union epoll_ref ref);
void icmpv6_sock_handler(const struct ctx *c, union epoll_ref ref); void icmpv6_sock_handler(const struct ctx *c, union epoll_ref ref);
int icmp_tap_handler(const struct ctx *c, int af, const void *addr, int icmp_tap_handler(const struct ctx *c,
int af, const void *saddr, const void *daddr,
const struct pool *p, const struct timespec *now); const struct pool *p, const struct timespec *now);
void icmp_timer(const struct ctx *c, const struct timespec *ts); void icmp_timer(const struct ctx *c, const struct timespec *ts);
void icmp_init(void); void icmp_init(void);

19
tap.c
View file

@ -643,7 +643,8 @@ resume:
tap_packet_debug(iph, NULL, NULL, 0, NULL, 1); tap_packet_debug(iph, NULL, NULL, 0, NULL, 1);
packet_add(pkt, l4_len, l4h); packet_add(pkt, l4_len, l4h);
icmp_tap_handler(c, AF_INET, &iph->daddr, pkt, now); icmp_tap_handler(c, AF_INET, &iph->saddr, &iph->daddr,
pkt, now);
continue; continue;
} }
@ -708,7 +709,6 @@ append:
for (j = 0, seq = tap4_l4; j < seq_count; j++, seq++) { for (j = 0, seq = tap4_l4; j < seq_count; j++, seq++) {
struct pool *p = (struct pool *)&seq->p; struct pool *p = (struct pool *)&seq->p;
struct in_addr *da = &seq->daddr;
size_t n = p->count; size_t n = p->count;
tap_packet_debug(NULL, NULL, seq, 0, NULL, n); tap_packet_debug(NULL, NULL, seq, 0, NULL, n);
@ -716,11 +716,13 @@ append:
if (seq->protocol == IPPROTO_TCP) { if (seq->protocol == IPPROTO_TCP) {
if (c->no_tcp) if (c->no_tcp)
continue; continue;
while ((n -= tcp_tap_handler(c, AF_INET, da, p, now))); while ((n -= tcp_tap_handler(c, AF_INET, &seq->saddr,
&seq->daddr, p, now)));
} else if (seq->protocol == IPPROTO_UDP) { } else if (seq->protocol == IPPROTO_UDP) {
if (c->no_udp) if (c->no_udp)
continue; continue;
while ((n -= udp_tap_handler(c, AF_INET, da, p, now))); while ((n -= udp_tap_handler(c, AF_INET, &seq->saddr,
&seq->daddr, p, now)));
} }
} }
@ -801,7 +803,7 @@ resume:
tap_packet_debug(NULL, ip6h, NULL, proto, NULL, 1); tap_packet_debug(NULL, ip6h, NULL, proto, NULL, 1);
packet_add(pkt, l4_len, l4h); packet_add(pkt, l4_len, l4h);
icmp_tap_handler(c, AF_INET6, daddr, pkt, now); icmp_tap_handler(c, AF_INET6, saddr, daddr, pkt, now);
continue; continue;
} }
@ -868,7 +870,6 @@ append:
for (j = 0, seq = tap6_l4; j < seq_count; j++, seq++) { for (j = 0, seq = tap6_l4; j < seq_count; j++, seq++) {
struct pool *p = (struct pool *)&seq->p; struct pool *p = (struct pool *)&seq->p;
struct in6_addr *da = &seq->daddr;
size_t n = p->count; size_t n = p->count;
tap_packet_debug(NULL, NULL, NULL, seq->protocol, seq, n); tap_packet_debug(NULL, NULL, NULL, seq->protocol, seq, n);
@ -876,11 +877,13 @@ append:
if (seq->protocol == IPPROTO_TCP) { if (seq->protocol == IPPROTO_TCP) {
if (c->no_tcp) if (c->no_tcp)
continue; continue;
while ((n -= tcp_tap_handler(c, AF_INET6, da, p, now))); while ((n -= tcp_tap_handler(c, AF_INET6, &seq->saddr,
&seq->daddr, p, now)));
} else if (seq->protocol == IPPROTO_UDP) { } else if (seq->protocol == IPPROTO_UDP) {
if (c->no_udp) if (c->no_udp)
continue; continue;
while ((n -= udp_tap_handler(c, AF_INET6, da, p, now))); while ((n -= udp_tap_handler(c, AF_INET6, &seq->saddr,
&seq->daddr, p, now)));
} }
} }

28
tcp.c
View file

@ -2005,13 +2005,15 @@ static void tcp_bind_outbound(const struct ctx *c, int s, sa_family_t af)
* tcp_conn_from_tap() - Handle connection request (SYN segment) from tap * tcp_conn_from_tap() - Handle connection request (SYN segment) from tap
* @c: Execution context * @c: Execution context
* @af: Address family, AF_INET or AF_INET6 * @af: Address family, AF_INET or AF_INET6
* @addr: Remote address, pointer to in_addr or in6_addr * @saddr: Source address, pointer to in_addr or in6_addr
* @daddr: Destination address, pointer to in_addr or in6_addr
* @th: TCP header from tap: caller MUST ensure it's there * @th: TCP header from tap: caller MUST ensure it's there
* @opts: Pointer to start of options * @opts: Pointer to start of options
* @optlen: Bytes in options: caller MUST ensure available length * @optlen: Bytes in options: caller MUST ensure available length
* @now: Current timestamp * @now: Current timestamp
*/ */
static void tcp_conn_from_tap(struct ctx *c, int af, const void *addr, static void tcp_conn_from_tap(struct ctx *c,
int af, const void *saddr, const void *daddr,
const struct tcphdr *th, const char *opts, const struct tcphdr *th, const char *opts,
size_t optlen, const struct timespec *now) size_t optlen, const struct timespec *now)
{ {
@ -2019,18 +2021,20 @@ static void tcp_conn_from_tap(struct ctx *c, int af, const void *addr,
struct sockaddr_in addr4 = { struct sockaddr_in addr4 = {
.sin_family = AF_INET, .sin_family = AF_INET,
.sin_port = th->dest, .sin_port = th->dest,
.sin_addr = *(struct in_addr *)addr, .sin_addr = *(struct in_addr *)daddr,
}; };
struct sockaddr_in6 addr6 = { struct sockaddr_in6 addr6 = {
.sin6_family = AF_INET6, .sin6_family = AF_INET6,
.sin6_port = th->dest, .sin6_port = th->dest,
.sin6_addr = *(struct in6_addr *)addr, .sin6_addr = *(struct in6_addr *)daddr,
}; };
const struct sockaddr *sa; const struct sockaddr *sa;
struct tcp_tap_conn *conn; struct tcp_tap_conn *conn;
socklen_t sl; socklen_t sl;
int s, mss; int s, mss;
(void)saddr;
if (c->tcp.conn_count >= TCP_MAX_CONNS) if (c->tcp.conn_count >= TCP_MAX_CONNS)
return; return;
@ -2039,9 +2043,9 @@ static void tcp_conn_from_tap(struct ctx *c, int af, const void *addr,
return; return;
if (!c->no_map_gw) { if (!c->no_map_gw) {
if (af == AF_INET && IN4_ARE_ADDR_EQUAL(addr, &c->ip4.gw)) if (af == AF_INET && IN4_ARE_ADDR_EQUAL(daddr, &c->ip4.gw))
addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (af == AF_INET6 && IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw)) if (af == AF_INET6 && IN6_ARE_ADDR_EQUAL(daddr, &c->ip6.gw))
addr6.sin6_addr = in6addr_loopback; addr6.sin6_addr = in6addr_loopback;
} }
@ -2078,7 +2082,7 @@ static void tcp_conn_from_tap(struct ctx *c, int af, const void *addr,
if (!(conn->wnd_from_tap = (htons(th->window) >> conn->ws_from_tap))) if (!(conn->wnd_from_tap = (htons(th->window) >> conn->ws_from_tap)))
conn->wnd_from_tap = 1; conn->wnd_from_tap = 1;
inany_from_af(&conn->addr, af, addr); inany_from_af(&conn->addr, af, daddr);
if (af == AF_INET) { if (af == AF_INET) {
sa = (struct sockaddr *)&addr4; sa = (struct sockaddr *)&addr4;
@ -2556,13 +2560,14 @@ static void tcp_conn_from_sock_finish(struct ctx *c, struct tcp_tap_conn *conn,
* tcp_tap_handler() - Handle packets from tap and state transitions * tcp_tap_handler() - Handle packets from tap and state transitions
* @c: Execution context * @c: Execution context
* @af: Address family, AF_INET or AF_INET6 * @af: Address family, AF_INET or AF_INET6
* @addr: Destination address * @saddr: Source address
* @daddr: Destination address
* @p: Pool of TCP packets, with TCP headers * @p: Pool of TCP packets, with TCP headers
* @now: Current timestamp * @now: Current timestamp
* *
* Return: count of consumed packets * Return: count of consumed packets
*/ */
int tcp_tap_handler(struct ctx *c, int af, const void *addr, int tcp_tap_handler(struct ctx *c, int af, const void *saddr, const void *daddr,
const struct pool *p, const struct timespec *now) const struct pool *p, const struct timespec *now)
{ {
struct tcp_tap_conn *conn; struct tcp_tap_conn *conn;
@ -2583,12 +2588,13 @@ int tcp_tap_handler(struct ctx *c, int af, const void *addr,
optlen = MIN(optlen, ((1UL << 4) /* from doff width */ - 6) * 4UL); optlen = MIN(optlen, ((1UL << 4) /* from doff width */ - 6) * 4UL);
opts = packet_get(p, 0, sizeof(*th), optlen, NULL); opts = packet_get(p, 0, sizeof(*th), optlen, NULL);
conn = tcp_hash_lookup(c, af, addr, htons(th->source), htons(th->dest)); conn = tcp_hash_lookup(c, af, daddr, htons(th->source), htons(th->dest));
/* New connection from tap */ /* New connection from tap */
if (!conn) { if (!conn) {
if (opts && th->syn && !th->ack) if (opts && th->syn && !th->ack)
tcp_conn_from_tap(c, af, addr, th, opts, optlen, now); tcp_conn_from_tap(c, af, saddr, daddr, th,
opts, optlen, now);
return 1; return 1;
} }

2
tcp.h
View file

@ -17,7 +17,7 @@ void tcp_timer_handler(struct ctx *c, union epoll_ref ref);
void tcp_listen_handler(struct ctx *c, union epoll_ref ref, void tcp_listen_handler(struct ctx *c, union epoll_ref ref,
const struct timespec *now); const struct timespec *now);
void tcp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events); void tcp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events);
int tcp_tap_handler(struct ctx *c, int af, const void *addr, int tcp_tap_handler(struct ctx *c, int af, const void *saddr, const void *daddr,
const struct pool *p, const struct timespec *now); const struct pool *p, const struct timespec *now);
int tcp_sock_init(const struct ctx *c, sa_family_t af, const void *addr, int tcp_sock_init(const struct ctx *c, sa_family_t af, const void *addr,
const char *ifname, in_port_t port); const char *ifname, in_port_t port);

14
udp.c
View file

@ -799,7 +799,8 @@ void udp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
* udp_tap_handler() - Handle packets from tap * udp_tap_handler() - Handle packets from tap
* @c: Execution context * @c: Execution context
* @af: Address family, AF_INET or AF_INET6 * @af: Address family, AF_INET or AF_INET6
* @addr: Destination address * @saddr: Source address
* @daddr: Destination address
* @p: Pool of UDP packets, with UDP headers * @p: Pool of UDP packets, with UDP headers
* @now: Current timestamp * @now: Current timestamp
* *
@ -807,7 +808,7 @@ void udp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
* *
* #syscalls sendmmsg * #syscalls sendmmsg
*/ */
int udp_tap_handler(struct ctx *c, int af, const void *addr, int udp_tap_handler(struct ctx *c, int af, const void *saddr, const void *daddr,
const struct pool *p, const struct timespec *now) const struct pool *p, const struct timespec *now)
{ {
struct mmsghdr mm[UIO_MAXIOV]; struct mmsghdr mm[UIO_MAXIOV];
@ -821,6 +822,7 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
socklen_t sl; socklen_t sl;
(void)c; (void)c;
(void)saddr;
uh = packet_get(p, 0, 0, sizeof(*uh), NULL); uh = packet_get(p, 0, 0, sizeof(*uh), NULL);
if (!uh) if (!uh)
@ -836,7 +838,7 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
s_in = (struct sockaddr_in) { s_in = (struct sockaddr_in) {
.sin_family = AF_INET, .sin_family = AF_INET,
.sin_port = uh->dest, .sin_port = uh->dest,
.sin_addr = *(struct in_addr *)addr, .sin_addr = *(struct in_addr *)daddr,
}; };
sa = (struct sockaddr *)&s_in; sa = (struct sockaddr *)&s_in;
@ -881,17 +883,17 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
s_in6 = (struct sockaddr_in6) { s_in6 = (struct sockaddr_in6) {
.sin6_family = AF_INET6, .sin6_family = AF_INET6,
.sin6_port = uh->dest, .sin6_port = uh->dest,
.sin6_addr = *(struct in6_addr *)addr, .sin6_addr = *(struct in6_addr *)daddr,
}; };
const struct in6_addr *bind_addr = &in6addr_any; const struct in6_addr *bind_addr = &in6addr_any;
sa = (struct sockaddr *)&s_in6; sa = (struct sockaddr *)&s_in6;
sl = sizeof(s_in6); sl = sizeof(s_in6);
if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.dns_match) && if (IN6_ARE_ADDR_EQUAL(daddr, &c->ip6.dns_match) &&
ntohs(s_in6.sin6_port) == 53) { ntohs(s_in6.sin6_port) == 53) {
s_in6.sin6_addr = c->ip6.dns_host; s_in6.sin6_addr = c->ip6.dns_host;
} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw) && } else if (IN6_ARE_ADDR_EQUAL(daddr, &c->ip6.gw) &&
!c->no_map_gw) { !c->no_map_gw) {
if (!(udp_tap_map[V6][dst].flags & PORT_LOCAL) || if (!(udp_tap_map[V6][dst].flags & PORT_LOCAL) ||
(udp_tap_map[V6][dst].flags & PORT_LOOPBACK)) (udp_tap_map[V6][dst].flags & PORT_LOOPBACK))

2
udp.h
View file

@ -10,7 +10,7 @@
void udp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events, void udp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
const struct timespec *now); const struct timespec *now);
int udp_tap_handler(struct ctx *c, int af, const void *addr, int udp_tap_handler(struct ctx *c, int af, const void *saddr, const void *daddr,
const struct pool *p, const struct timespec *now); const struct pool *p, const struct timespec *now);
int udp_sock_init(const struct ctx *c, int ns, sa_family_t af, int udp_sock_init(const struct ctx *c, int ns, sa_family_t af,
const void *addr, const char *ifname, in_port_t port); const void *addr, const char *ifname, in_port_t port);