5856: Fix receiving IPv6 packets after IPv4 ones on Linux r=def- a=heinrich5991

Previously, the socket addresses were truncated as the `msg_namelen` field is both input **and** output: After receiving an IPv4 packet, the socket address field would be too short for an IPv6 address.

## Checklist

- [ ] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [x] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: heinrich5991 <heinrich5991@gmail.com>
This commit is contained in:
bors[bot] 2022-09-19 23:30:52 +00:00 committed by GitHub
commit bc8ec8c1d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 0 deletions

View file

@ -2519,6 +2519,7 @@ if(GTEST_FOUND OR DOWNLOAD_GTEST)
json.cpp json.cpp
mapbugs.cpp mapbugs.cpp
name_ban.cpp name_ban.cpp
net.cpp
netaddr.cpp netaddr.cpp
os.cpp os.cpp
packer.cpp packer.cpp

View file

@ -149,6 +149,7 @@ typedef struct
} NETSOCKET_BUFFER; } NETSOCKET_BUFFER;
void net_buffer_init(NETSOCKET_BUFFER *buffer); void net_buffer_init(NETSOCKET_BUFFER *buffer);
void net_buffer_reinit(NETSOCKET_BUFFER *buffer);
void net_buffer_simple(NETSOCKET_BUFFER *buffer, char **buf, int *size); void net_buffer_simple(NETSOCKET_BUFFER *buffer, char **buf, int *size);
struct NETSOCKET_INTERNAL struct NETSOCKET_INTERNAL
@ -1698,6 +1699,16 @@ void net_buffer_init(NETSOCKET_BUFFER *buffer)
#endif #endif
} }
void net_buffer_reinit(NETSOCKET_BUFFER *buffer)
{
#if defined(CONF_PLATFORM_LINUX)
for(int i = 0; i < VLEN; i++)
{
buffer->msgs[i].msg_hdr.msg_namelen = sizeof(buffer->sockaddrs[i]);
}
#endif
}
void net_buffer_simple(NETSOCKET_BUFFER *buffer, char **buf, int *size) void net_buffer_simple(NETSOCKET_BUFFER *buffer, char **buf, int *size)
{ {
#if defined(CONF_PLATFORM_LINUX) #if defined(CONF_PLATFORM_LINUX)
@ -1719,6 +1730,7 @@ int net_udp_recv(NETSOCKET sock, NETADDR *addr, unsigned char **data)
{ {
if(sock->buffer.pos >= sock->buffer.size) if(sock->buffer.pos >= sock->buffer.size)
{ {
net_buffer_reinit(&sock->buffer);
sock->buffer.size = recvmmsg(sock->ipv4sock, sock->buffer.msgs, VLEN, 0, NULL); sock->buffer.size = recvmmsg(sock->ipv4sock, sock->buffer.msgs, VLEN, 0, NULL);
sock->buffer.pos = 0; sock->buffer.pos = 0;
} }
@ -1728,6 +1740,7 @@ int net_udp_recv(NETSOCKET sock, NETADDR *addr, unsigned char **data)
{ {
if(sock->buffer.pos >= sock->buffer.size) if(sock->buffer.pos >= sock->buffer.size)
{ {
net_buffer_reinit(&sock->buffer);
sock->buffer.size = recvmmsg(sock->ipv6sock, sock->buffer.msgs, VLEN, 0, NULL); sock->buffer.size = recvmmsg(sock->ipv6sock, sock->buffer.msgs, VLEN, 0, NULL);
sock->buffer.pos = 0; sock->buffer.pos = 0;
} }

47
src/test/net.cpp Normal file
View file

@ -0,0 +1,47 @@
#include <gtest/gtest.h>
#include <base/system.h>
TEST(Net, Ipv4AndIpv6Work)
{
NETADDR Bindaddr = {};
NETSOCKET Socket1;
NETSOCKET Socket2;
Bindaddr.type = NETTYPE_IPV4 | NETTYPE_IPV6;
Socket2 = net_udp_create(Bindaddr);
do
{
Bindaddr.port = secure_rand() % 64511 + 1024;
} while(!(Socket1 = net_udp_create(Bindaddr)));
NETADDR LocalhostV4;
NETADDR LocalhostV6;
NETADDR TargetV4;
NETADDR TargetV6;
ASSERT_FALSE(net_addr_from_str(&LocalhostV4, "127.0.0.1"));
ASSERT_FALSE(net_addr_from_str(&LocalhostV6, "[::1]"));
TargetV4 = LocalhostV4;
TargetV6 = LocalhostV6;
TargetV4.port = Bindaddr.port;
TargetV6.port = Bindaddr.port;
NETADDR Addr;
unsigned char *pData;
EXPECT_EQ(net_udp_send(Socket2, &TargetV4, "abc", 3), 3);
EXPECT_EQ(net_socket_read_wait(Socket1, 10000000), 1);
ASSERT_EQ(net_udp_recv(Socket1, &Addr, &pData), 3);
Addr.port = 0;
EXPECT_EQ(Addr, LocalhostV4);
EXPECT_EQ(mem_comp(pData, "abc", 3), 0);
EXPECT_EQ(net_udp_send(Socket2, &TargetV6, "def", 3), 3);
EXPECT_EQ(net_socket_read_wait(Socket1, 10000000), 1);
ASSERT_EQ(net_udp_recv(Socket1, &Addr, &pData), 3);
Addr.port = 0;
EXPECT_EQ(Addr, LocalhostV6);
EXPECT_EQ(mem_comp(pData, "def", 3), 0);
}