mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-31 18:41:39 +00:00
MEDIUM: quic-sock: fix udp source address for send on listener socket
When receiving a QUIC datagram, destination address is retrieved via recvmsg() and stored in quic-conn as qc.local_addr. This address is then reused when using the quic-conn owned socket. When listener socket mode is preferred, send operation did not specify the source address of the emitted datagram. If listener socket is bound on a wildcard address, the kernel is free to choose any address assigned to the local machine. This may be different from the address selected by the client on its first datagram which will prevent the client to emit next replies. To address this, this patch fixes the UDP source address via sendmsg(). This process is similar to the reception and relies on ancillary message, so the socket is left untouched after the operation. This is heavily platform specific and may not be supported by some kernels. This change has only an impact if listener socket only is used for QUIC communications. This is the default behavior for 2.7 branch but not anymore on 2.8. Use tune.quic.socket-owner set to listener to ensure set it. This should be backported up to 2.7.
This commit is contained in:
parent
d18025eeef
commit
2d380926ba
@ -516,6 +516,91 @@ int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t sz,
|
||||
ret = send(qc->fd, b_peek(buf, b_head_ofs(buf)), sz,
|
||||
MSG_DONTWAIT | MSG_NOSIGNAL);
|
||||
}
|
||||
#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) || defined(IPV6_RECVPKTINFO)
|
||||
else if (is_addr(&qc->local_addr)) {
|
||||
struct msghdr msg = { 0 };
|
||||
struct iovec vec;
|
||||
struct cmsghdr *cmsg;
|
||||
#ifdef IP_PKTINFO
|
||||
struct in_pktinfo in;
|
||||
#endif /* IP_PKTINFO */
|
||||
#ifdef IPV6_RECVPKTINFO
|
||||
struct in6_pktinfo in6;
|
||||
#endif /* IPV6_RECVPKTINFO */
|
||||
union {
|
||||
#ifdef IP_PKTINFO
|
||||
char buf[CMSG_SPACE(sizeof(in))];
|
||||
#endif /* IP_PKTINFO */
|
||||
#ifdef IPV6_RECVPKTINFO
|
||||
char buf6[CMSG_SPACE(sizeof(in6))];
|
||||
#endif /* IPV6_RECVPKTINFO */
|
||||
char bufaddr[CMSG_SPACE(sizeof(struct in_addr))];
|
||||
struct cmsghdr align;
|
||||
} u;
|
||||
|
||||
vec.iov_base = b_peek(buf, b_head_ofs(buf));
|
||||
vec.iov_len = sz;
|
||||
msg.msg_name = &qc->peer_addr;
|
||||
msg.msg_namelen = get_addr_len(&qc->peer_addr);
|
||||
msg.msg_iov = &vec;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
switch (qc->local_addr.ss_family) {
|
||||
case AF_INET:
|
||||
#if defined(IP_PKTINFO)
|
||||
memset(&in, 0, sizeof(in));
|
||||
memcpy(&in.ipi_spec_dst,
|
||||
&((struct sockaddr_in *)&qc->local_addr)->sin_addr,
|
||||
sizeof(struct in_addr));
|
||||
|
||||
msg.msg_control = u.buf;
|
||||
msg.msg_controllen = sizeof(u.buf);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_level = IPPROTO_IP;
|
||||
cmsg->cmsg_type = IP_PKTINFO;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||
memcpy(CMSG_DATA(cmsg), &in, sizeof(in));
|
||||
#elif defined(IP_RECVDSTADDR)
|
||||
msg.msg_control = u.bufaddr;
|
||||
msg.msg_controllen = sizeof(u.bufaddr);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_level = IPPROTO_IP;
|
||||
cmsg->cmsg_type = IP_SENDSRCADDR;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
|
||||
memcpy(CMSG_DATA(cmsg),
|
||||
&((struct sockaddr_in *)&qc->local_addr)->sin_addr,
|
||||
sizeof(struct in_addr));
|
||||
#endif /* IP_PKTINFO || IP_RECVDSTADDR */
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
#ifdef IPV6_RECVPKTINFO
|
||||
memset(&in6, 0, sizeof(in6));
|
||||
memcpy(&in6.ipi6_addr,
|
||||
&((struct sockaddr_in6 *)&qc->local_addr)->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
|
||||
msg.msg_control = u.buf6;
|
||||
msg.msg_controllen = sizeof(u.buf6);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_level = IPPROTO_IPV6;
|
||||
cmsg->cmsg_type = IPV6_PKTINFO;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||
memcpy(CMSG_DATA(cmsg), &in6, sizeof(in6));
|
||||
#endif /* IPV6_RECVPKTINFO */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = sendmsg(qc->li->rx.fd, &msg,
|
||||
MSG_DONTWAIT|MSG_NOSIGNAL);
|
||||
}
|
||||
#endif /* IP_PKTINFO || IP_RECVDSTADDR || IPV6_RECVPKTINFO */
|
||||
else {
|
||||
ret = sendto(qc->li->rx.fd, b_peek(buf, b_head_ofs(buf)), sz,
|
||||
MSG_DONTWAIT|MSG_NOSIGNAL,
|
||||
|
Loading…
Reference in New Issue
Block a user