3809: Compress IPv6 string representations according to RFC5952 r=def- a=heinrich5991

https://tools.ietf.org/html/rfc5952#section-4

Also add some tests.

<!-- What is the motivation for the changes of this pull request -->

## Checklist

- [x] 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 if it works standalone, system.c especially
- [ ] 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] 2021-05-05 22:16:02 +00:00 committed by GitHub
commit 4f974effa0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 122 additions and 11 deletions

View file

@ -1089,6 +1089,73 @@ int net_addr_comp_noport(const NETADDR *a, const NETADDR *b)
return net_addr_comp(&ta, &tb);
}
void net_addr_str_v6(const unsigned short ip[8], int port, char *buffer, int buffer_size)
{
int longest_seq_len = 0;
int longest_seq_start = -1;
int w = 0;
int i;
{
int seq_len = 0;
int seq_start = -1;
// Determine longest sequence of zeros.
for(i = 0; i < 8 + 1; i++)
{
if(seq_start != -1)
{
if(i == 8 || ip[i] != 0)
{
if(longest_seq_len < seq_len)
{
longest_seq_len = seq_len;
longest_seq_start = seq_start;
}
seq_len = 0;
seq_start = -1;
}
else
{
seq_len += 1;
}
}
else
{
if(i != 8 && ip[i] == 0)
{
seq_start = i;
seq_len = 1;
}
}
}
}
if(longest_seq_len <= 1)
{
longest_seq_len = 0;
longest_seq_start = -1;
}
w += str_format(buffer + w, buffer_size - w, "[");
for(i = 0; i < 8; i++)
{
if(longest_seq_start <= i && i < longest_seq_start + longest_seq_len)
{
if(i == longest_seq_start)
{
w += str_format(buffer + w, buffer_size - w, "::");
}
}
else
{
char *colon = i == 0 || i == longest_seq_start + longest_seq_len ? "" : ":";
w += str_format(buffer + w, buffer_size - w, "%s%x", colon, ip[i]);
}
}
w += str_format(buffer + w, buffer_size - w, "]");
if(port >= 0)
{
str_format(buffer + w, buffer_size - w, ":%d", port);
}
}
void net_addr_str(const NETADDR *addr, char *string, int max_length, int add_port)
{
if(addr->type == NETTYPE_IPV4 || addr->type == NETTYPE_WEBSOCKET_IPV4)
@ -1100,15 +1167,18 @@ void net_addr_str(const NETADDR *addr, char *string, int max_length, int add_por
}
else if(addr->type == NETTYPE_IPV6)
{
if(add_port != 0)
str_format(string, max_length, "[%x:%x:%x:%x:%x:%x:%x:%x]:%d",
(addr->ip[0] << 8) | addr->ip[1], (addr->ip[2] << 8) | addr->ip[3], (addr->ip[4] << 8) | addr->ip[5], (addr->ip[6] << 8) | addr->ip[7],
(addr->ip[8] << 8) | addr->ip[9], (addr->ip[10] << 8) | addr->ip[11], (addr->ip[12] << 8) | addr->ip[13], (addr->ip[14] << 8) | addr->ip[15],
addr->port);
else
str_format(string, max_length, "[%x:%x:%x:%x:%x:%x:%x:%x]",
(addr->ip[0] << 8) | addr->ip[1], (addr->ip[2] << 8) | addr->ip[3], (addr->ip[4] << 8) | addr->ip[5], (addr->ip[6] << 8) | addr->ip[7],
(addr->ip[8] << 8) | addr->ip[9], (addr->ip[10] << 8) | addr->ip[11], (addr->ip[12] << 8) | addr->ip[13], (addr->ip[14] << 8) | addr->ip[15]);
int port = -1;
unsigned short ip[8];
int i;
if(add_port)
{
port = addr->port;
}
for(i = 0; i < 8; i++)
{
ip[i] = (addr->ip[i * 2] << 8) | (addr->ip[i * 2 + 1]);
}
net_addr_str_v6(ip, port, string, max_length);
}
else
str_format(string, max_length, "unknown type %d", addr->type);

View file

@ -23,8 +23,8 @@ TEST(NetAddr, FromStr)
EXPECT_FALSE(net_addr_from_str(&Addr, "[::1]"));
net_addr_str(&Addr, aBuf1, sizeof(aBuf1), true);
net_addr_str(&Addr, aBuf2, sizeof(aBuf2), false);
EXPECT_STREQ(aBuf1, "[0:0:0:0:0:0:0:1]:0");
EXPECT_STREQ(aBuf2, "[0:0:0:0:0:0:0:1]");
EXPECT_STREQ(aBuf1, "[::1]:0");
EXPECT_STREQ(aBuf2, "[::1]");
EXPECT_FALSE(net_addr_from_str(&Addr, "[0123:4567:89ab:cdef:1:2:3:4]:5678"));
net_addr_str(&Addr, aBuf1, sizeof(aBuf1), true);
@ -33,6 +33,47 @@ TEST(NetAddr, FromStr)
EXPECT_STREQ(aBuf2, "[123:4567:89ab:cdef:1:2:3:4]");
}
TEST(NetAddr, StrV6)
{
NETADDR Addr;
char aBuf1[NETADDR_MAXSTRSIZE];
char aBuf2[NETADDR_MAXSTRSIZE];
// Test vectors from RFC 5952 section 4:
// https://tools.ietf.org/html/rfc5952#section-4
// 4.1 Handling Leading Zeros in a 16-Bit Field
EXPECT_FALSE(net_addr_from_str(&Addr, "[2001:0db8::0001]:1"));
net_addr_str(&Addr, aBuf1, sizeof(aBuf1), true);
net_addr_str(&Addr, aBuf2, sizeof(aBuf2), false);
EXPECT_STREQ(aBuf1, "[2001:db8::1]:1");
EXPECT_STREQ(aBuf2, "[2001:db8::1]");
// 4.2.1 Shorten as Much as Possible
EXPECT_FALSE(net_addr_from_str(&Addr, "[2001:db8:0:0:0:0:2:1]"));
net_addr_str(&Addr, aBuf1, sizeof(aBuf1), true);
net_addr_str(&Addr, aBuf2, sizeof(aBuf2), false);
EXPECT_STREQ(aBuf1, "[2001:db8::2:1]:0");
EXPECT_STREQ(aBuf2, "[2001:db8::2:1]");
EXPECT_FALSE(net_addr_from_str(&Addr, "[2001:db8::0:1]"));
net_addr_str(&Addr, aBuf2, sizeof(aBuf2), false);
EXPECT_STREQ(aBuf2, "[2001:db8::1]");
// 4.2.2 Handling One 16-Bit 0 Field
EXPECT_FALSE(net_addr_from_str(&Addr, "[2001:db8::1:1:1:1:1]"));
net_addr_str(&Addr, aBuf2, sizeof(aBuf2), false);
EXPECT_STREQ(aBuf2, "[2001:db8:0:1:1:1:1:1]");
// 4.2.3 Choice in Placement of "::"
EXPECT_FALSE(net_addr_from_str(&Addr, "[2001:0:0:1:0:0:0:1]"));
net_addr_str(&Addr, aBuf2, sizeof(aBuf2), false);
EXPECT_STREQ(aBuf2, "[2001:0:0:1::1]");
EXPECT_FALSE(net_addr_from_str(&Addr, "[2001:db8:0:0:1:0:0:1]"));
net_addr_str(&Addr, aBuf2, sizeof(aBuf2), false);
EXPECT_STREQ(aBuf2, "[2001:db8::1:0:0:1]");
}
TEST(NetAddr, FromStrInvalid)
{
NETADDR Addr;