Index: src/OFSocket.m ================================================================== --- src/OFSocket.m +++ src/OFSocket.m @@ -430,10 +430,38 @@ if (number > UINT16_MAX) @throw [OFInvalidFormatException exception]; return (uint16_t)number; } + +static OFString * +transformEmbeddedIPv4(OFString *IPv6) +{ + size_t lastColon = [IPv6 + rangeOfString: @":" + options: OFStringSearchBackwards].location; + OFString *IPv4; + OFSocketAddress address; + const struct sockaddr_in *addrIn; + uint32_t addr; + + if (lastColon == OFNotFound) + @throw [OFInvalidFormatException exception]; + + IPv4 = [IPv6 substringWithRange: + OFMakeRange(lastColon + 1, IPv6.length - lastColon - 1)]; + IPv6 = [IPv6 substringWithRange: OFMakeRange(0, lastColon + 1)]; + + address = OFSocketAddressParseIPv4(IPv4, 0); + addrIn = &address.sockaddr.in; + addr = OFFromBigEndian32(addrIn->sin_addr.s_addr); + + return [IPv6 stringByAppendingString: + [OFString stringWithFormat: @"%x%02x:%x%02x", + (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, + (addr & 0x0000FF00) >> 8, addr & 0x000000FF]]; +} OFSocketAddress OFSocketAddressParseIPv6(OFString *IPv6, uint16_t port) { void *pool = objc_autoreleasePoolPush(); @@ -467,10 +495,13 @@ } if (addrIn6->sin6_scope_id == 0) @throw [OFInvalidArgumentException exception]; } + + if ([IPv6 rangeOfString: @"."].location != OFNotFound) + IPv6 = transformEmbeddedIPv4(IPv6); doubleColon = [IPv6 rangeOfString: @"::"].location; if (doubleColon != OFNotFound) { OFString *left = [IPv6 substringToIndex: doubleColon]; OFString *right = [IPv6 substringFromIndex: doubleColon + 2]; Index: tests/OFSocketTests.m ================================================================== --- tests/OFSocketTests.m +++ tests/OFSocketTests.m @@ -119,10 +119,20 @@ R(addr = OFSocketAddressParseIP(@"fd00::1%123", 1234)) && COMPARE_V6(addr, 0xFD00, 0, 0, 0, 0, 0, 0, 1) && OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234 && addr.sockaddr.in6.sin6_scope_id == 123) + TEST(@"Parsing an IPv6 #7", + R(addr = OFSocketAddressParseIP(@"::ffff:127.0.0.1", 1234)) && + COMPARE_V6(addr, 0, 0, 0, 0, 0, 0xFFFF, 0x7F00, 1) && + OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + + TEST(@"Parsing an IPv6 #8", + R(addr = OFSocketAddressParseIP(@"64:ff9b::127.0.0.1", 1234)) && + COMPARE_V6(addr, 0x64, 0xFF9B, 0, 0, 0, 0, 0x7F00, 1) && + OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #1", OFInvalidFormatException, OFSocketAddressParseIP(@"1:::2", 1234)) EXPECT_EXCEPTION(@"Refusing invalid IPv6 #2", OFInvalidFormatException, OFSocketAddressParseIP(@"1: ::2", 1234))