Skip to content

Commit

Permalink
[core] Fix alignment issues in cmsg header management (#2844).
Browse files Browse the repository at this point in the history
  • Loading branch information
yomnes0 authored Jan 12, 2024
1 parent 88c6214 commit bff0712
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 29 deletions.
8 changes: 5 additions & 3 deletions srtcore/channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -761,9 +761,10 @@ int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet, const socka

// Note that even if PKTINFO is desired, the first caller's packet will be sent
// without ancillary info anyway because there's no "peer" yet to know where to send it.
char mh_crtl_buf[sizeof(CMSGNodeIPv4) + sizeof(CMSGNodeIPv6)];
if (m_bBindMasked && source_addr.family() != AF_UNSPEC && !source_addr.isany())
{
if (!setSourceAddress(mh, source_addr))
if (!setSourceAddress(mh, mh_crtl_buf, source_addr))
{
LOGC(kslog.Error, log << "CChannel::setSourceAddress: source address invalid family #" << source_addr.family() << ", NOT setting.");
}
Expand Down Expand Up @@ -862,14 +863,15 @@ srt::EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet
#ifdef SRT_ENABLE_PKTINFO
// Without m_bBindMasked, we don't need ancillary data - the source
// address will always be the bound address.
char mh_crtl_buf[sizeof(CMSGNodeIPv4) + sizeof(CMSGNodeIPv6)];
if (m_bBindMasked)
{
// Extract the destination IP address from the ancillary
// data. This might be interesting for the connection to
// know to which address the packet should be sent back during
// the handshake and then addressed when sending during connection.
mh.msg_control = (m_acCmsgRecvBuffer);
mh.msg_controllen = sizeof m_acCmsgRecvBuffer;
mh.msg_control = (mh_crtl_buf);
mh.msg_controllen = sizeof mh_crtl_buf;
}
#endif

Expand Down
47 changes: 21 additions & 26 deletions srtcore/channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,19 +215,10 @@ class CChannel
cmsghdr hdr;
};

// This is 'mutable' because it's a utility buffer defined here
// to avoid unnecessary re-allocations.
SRT_ATR_ALIGNAS(8) mutable char m_acCmsgRecvBuffer [sizeof (CMSGNodeIPv4) + sizeof (CMSGNodeIPv6)]; // Reserved space for ancillary data with pktinfo
SRT_ATR_ALIGNAS(8) mutable char m_acCmsgSendBuffer [sizeof (CMSGNodeIPv4) + sizeof (CMSGNodeIPv6)]; // Reserved space for ancillary data with pktinfo

// IMPORTANT!!! This function shall be called EXCLUSIVELY just after
// calling ::recvmsg function. It uses a static buffer to supply data
// for the call, and it's stated that only one thread is trying to
// use a CChannel object in receiving mode.
sockaddr_any getTargetAddress(const msghdr& msg) const
{
// Loop through IP header messages
cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
cmsghdr* cmsg;
for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg != NULL;
cmsg = CMSG_NXTHDR(((msghdr*)&msg), cmsg))
Expand All @@ -236,14 +227,16 @@ class CChannel
// IPv4 headers or IPv6 headers.
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO)
{
in_pktinfo *dest_ip_ptr = (in_pktinfo*)CMSG_DATA(cmsg);
return sockaddr_any(dest_ip_ptr->ipi_addr, 0);
in_pktinfo dest_ip;
memcpy(&dest_ip, CMSG_DATA(cmsg), sizeof(struct in_pktinfo));
return sockaddr_any(dest_ip.ipi_addr, 0);
}

if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO)
{
in6_pktinfo* dest_ip_ptr = (in6_pktinfo*)CMSG_DATA(cmsg);
return sockaddr_any(dest_ip_ptr->ipi6_addr, 0);
in6_pktinfo dest_ip;
memcpy(&dest_ip, CMSG_DATA(cmsg), sizeof(struct in6_pktinfo));
return sockaddr_any(dest_ip.ipi6_addr, 0);
}
}

Expand All @@ -255,7 +248,7 @@ class CChannel
// calling ::sendmsg function. It uses a static buffer to supply data
// for the call, and it's stated that only one thread is trying to
// use a CChannel object in sending mode.
bool setSourceAddress(msghdr& mh, const sockaddr_any& adr) const
bool setSourceAddress(msghdr& mh, char *buf, const sockaddr_any& adr) const
{
// In contrast to an advice followed on the net, there's no case of putting
// both IPv4 and IPv6 ancillary data, case we could have them. Only one
Expand All @@ -264,30 +257,32 @@ class CChannel

if (adr.family() == AF_INET)
{
mh.msg_control = m_acCmsgSendBuffer;
mh.msg_controllen = CMSG_SPACE(sizeof(in_pktinfo));
cmsghdr* cmsg_send = CMSG_FIRSTHDR(&mh);
mh.msg_control = (void *) buf;
mh.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));

// after initializing msghdr & control data to CMSG_SPACE(sizeof(struct in_pktinfo))
cmsghdr* cmsg_send = CMSG_FIRSTHDR(&mh);
cmsg_send->cmsg_level = IPPROTO_IP;
cmsg_send->cmsg_type = IP_PKTINFO;
cmsg_send->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
in_pktinfo* pktinfo = (in_pktinfo*) CMSG_DATA(cmsg_send);
pktinfo->ipi_ifindex = 0;
pktinfo->ipi_spec_dst = adr.sin.sin_addr;

in_pktinfo pktinfo;
pktinfo.ipi_ifindex = 0;
pktinfo.ipi_spec_dst = adr.sin.sin_addr;
memcpy(CMSG_DATA(cmsg_send), &pktinfo, sizeof(in_pktinfo));

return true;
}

if (adr.family() == AF_INET6)
{
mh.msg_control = m_acCmsgSendBuffer;
mh.msg_controllen = CMSG_SPACE(sizeof(in6_pktinfo));
cmsghdr* cmsg_send = CMSG_FIRSTHDR(&mh);
mh.msg_control = buf;
mh.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));

cmsghdr* cmsg_send = CMSG_FIRSTHDR(&mh);
cmsg_send->cmsg_level = IPPROTO_IPV6;
cmsg_send->cmsg_type = IPV6_PKTINFO;
cmsg_send->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));

in6_pktinfo* pktinfo = (in6_pktinfo*) CMSG_DATA(cmsg_send);
pktinfo->ipi6_ifindex = 0;
pktinfo->ipi6_addr = adr.sin6.sin6_addr;
Expand All @@ -298,7 +293,7 @@ class CChannel
return false;
}

#endif // SRT_ENABLE_PKTINFO
#endif //SRT_ENABLE_PKTINFO

};

Expand Down

0 comments on commit bff0712

Please sign in to comment.