1
0
Fork 0
mirror of https://passt.top/passt synced 2025-05-23 01:35:35 +02:00

udp: support traceroute in direction tap-socket

Now that ICMP pass-through from socket-to-tap is in place, it is
easy to support UDP based traceroute functionality in direction
tap-to-socket.

We fix that in this commit.

Link: https://bugs.passt.top/show_bug.cgi?id=64
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
Jon Maloy 2025-04-05 15:21:26 -04:00 committed by Stefano Brivio
parent 06784d7fc6
commit a7775e9550
5 changed files with 40 additions and 7 deletions

17
tap.c
View file

@ -559,6 +559,7 @@ PACKET_POOL_DECL(pool_l4, UIO_MAXIOV, pkt_buf);
* struct l4_seq4_t - Message sequence for one protocol handler call, IPv4
* @msgs: Count of messages in sequence
* @protocol: Protocol number
* @ttl: Time to live
* @source: Source port
* @dest: Destination port
* @saddr: Source address
@ -567,6 +568,7 @@ PACKET_POOL_DECL(pool_l4, UIO_MAXIOV, pkt_buf);
*/
static struct tap4_l4_t {
uint8_t protocol;
uint8_t ttl;
uint16_t source;
uint16_t dest;
@ -586,6 +588,7 @@ static struct tap4_l4_t {
* @dest: Destination port
* @saddr: Source address
* @daddr: Destination address
* @hop_limit: Hop limit
* @msg: Array of messages that can be handled in a single call
*/
static struct tap6_l4_t {
@ -598,6 +601,8 @@ static struct tap6_l4_t {
struct in6_addr saddr;
struct in6_addr daddr;
uint8_t hop_limit;
struct pool_l4_t p;
} tap6_l4[TAP_SEQS /* Arbitrary: TAP_MSGS in theory, so limit in users */];
@ -786,7 +791,8 @@ resume:
#define L4_MATCH(iph, uh, seq) \
((seq)->protocol == (iph)->protocol && \
(seq)->source == (uh)->source && (seq)->dest == (uh)->dest && \
(seq)->saddr.s_addr == (iph)->saddr && (seq)->daddr.s_addr == (iph)->daddr)
(seq)->saddr.s_addr == (iph)->saddr && \
(seq)->daddr.s_addr == (iph)->daddr && (seq)->ttl == (iph)->ttl)
#define L4_SET(iph, uh, seq) \
do { \
@ -795,6 +801,7 @@ resume:
(seq)->dest = (uh)->dest; \
(seq)->saddr.s_addr = (iph)->saddr; \
(seq)->daddr.s_addr = (iph)->daddr; \
(seq)->ttl = (iph)->ttl; \
} while (0)
if (seq && L4_MATCH(iph, uh, seq) && seq->p.count < UIO_MAXIOV)
@ -843,7 +850,7 @@ append:
for (k = 0; k < p->count; )
k += udp_tap_handler(c, PIF_TAP, AF_INET,
&seq->saddr, &seq->daddr,
p, k, now);
seq->ttl, p, k, now);
}
}
@ -966,7 +973,8 @@ resume:
(seq)->dest == (uh)->dest && \
(seq)->flow_lbl == ip6_get_flow_lbl(ip6h) && \
IN6_ARE_ADDR_EQUAL(&(seq)->saddr, saddr) && \
IN6_ARE_ADDR_EQUAL(&(seq)->daddr, daddr))
IN6_ARE_ADDR_EQUAL(&(seq)->daddr, daddr) && \
(seq)->hop_limit == (ip6h)->hop_limit)
#define L4_SET(ip6h, proto, uh, seq) \
do { \
@ -976,6 +984,7 @@ resume:
(seq)->flow_lbl = ip6_get_flow_lbl(ip6h); \
(seq)->saddr = *saddr; \
(seq)->daddr = *daddr; \
(seq)->hop_limit = (ip6h)->hop_limit; \
} while (0)
if (seq && L4_MATCH(ip6h, proto, uh, seq) &&
@ -1026,7 +1035,7 @@ append:
for (k = 0; k < p->count; )
k += udp_tap_handler(c, PIF_TAP, AF_INET6,
&seq->saddr, &seq->daddr,
p, k, now);
seq->hop_limit, p, k, now);
}
}

22
udp.c
View file

@ -844,6 +844,7 @@ fail:
* @af: Address family, AF_INET or AF_INET6
* @saddr: Source address
* @daddr: Destination address
* @ttl: TTL or hop limit for packets to be sent in this call
* @p: Pool of UDP packets, with UDP headers
* @idx: Index of first packet to process
* @now: Current timestamp
@ -854,7 +855,8 @@ fail:
*/
int udp_tap_handler(const struct ctx *c, uint8_t pif,
sa_family_t af, const void *saddr, const void *daddr,
const struct pool *p, int idx, const struct timespec *now)
uint8_t ttl, const struct pool *p, int idx,
const struct timespec *now)
{
const struct flowside *toside;
struct mmsghdr mm[UIO_MAXIOV];
@ -933,6 +935,24 @@ int udp_tap_handler(const struct ctx *c, uint8_t pif,
mm[i].msg_hdr.msg_controllen = 0;
mm[i].msg_hdr.msg_flags = 0;
if (ttl != uflow->ttl[tosidx.sidei]) {
uflow->ttl[tosidx.sidei] = ttl;
if (af == AF_INET) {
if (setsockopt(s, IPPROTO_IP, IP_TTL,
&ttl, sizeof(ttl)) < 0)
flow_perror(uflow,
"setsockopt IP_TTL");
} else {
/* IPv6 hop_limit cannot be only 1 byte */
int hop_limit = ttl;
if (setsockopt(s, SOL_IPV6, IPV6_UNICAST_HOPS,
&hop_limit, sizeof(hop_limit)) < 0)
flow_perror(uflow,
"setsockopt IPV6_UNICAST_HOPS");
}
}
count++;
}

3
udp.h
View file

@ -15,7 +15,8 @@ void udp_reply_sock_handler(const struct ctx *c, union epoll_ref ref,
uint32_t events, const struct timespec *now);
int udp_tap_handler(const struct ctx *c, uint8_t pif,
sa_family_t af, const void *saddr, const void *daddr,
const struct pool *p, int idx, const struct timespec *now);
uint8_t ttl, const struct pool *p, int idx,
const struct timespec *now);
int udp_sock_init(const struct ctx *c, int ns, const union inany_addr *addr,
const char *ifname, in_port_t port);
int udp_init(struct ctx *c);

View file

@ -137,6 +137,7 @@ static flow_sidx_t udp_flow_new(const struct ctx *c, union flow *flow,
uflow = FLOW_SET_TYPE(flow, FLOW_UDP, udp);
uflow->ts = now->tv_sec;
uflow->s[INISIDE] = uflow->s[TGTSIDE] = -1;
uflow->ttl[INISIDE] = uflow->ttl[TGTSIDE] = 0;
if (s_ini >= 0) {
/* When using auto port-scanning the listening port could go

View file

@ -8,11 +8,12 @@
#define UDP_FLOW_H
/**
* struct udp - Descriptor for a flow of UDP packets
* struct udp_flow - Descriptor for a flow of UDP packets
* @f: Generic flow information
* @closed: Flow is already closed
* @ts: Activity timestamp
* @s: Socket fd (or -1) for each side of the flow
* @ttl: TTL or hop_limit for both sides
*/
struct udp_flow {
/* Must be first element */
@ -21,6 +22,7 @@ struct udp_flow {
bool closed :1;
time_t ts;
int s[SIDES];
uint8_t ttl[SIDES];
};
struct udp_flow *udp_at_sidx(flow_sidx_t sidx);