0

The following code is used to convert a sockaddr to a sockaddr_in6 to get the IPv6 address:

extension sockaddr {
  private var addressV6: String {
    var me = self
    var buffer = [Int8](repeating: 0, count: Int(INET6_ADDRSTRLEN))

    withUnsafePointer(to: &me) {
      $0.withMemoryRebound(to: sockaddr_in6.self, capacity: 1) {
        var addrV6 = $0.pointee.sin6_addr
        inet_ntop(AF_INET6, &addrV6, &buffer, socklen_t(INET6_ADDRSTRLEN))
      }
    }

    return String(cString: buffer)
  }
}

When I run the code in Xcode 9 beta with the Address Sanitizer, execution stops on this line:

var addrV6 = $0.pointee.sin6_addr

With the following message (plus a lot of memory info):

AddressSanitizer: stack-buffer-overflow on address 0x000131810077 at pc 0x00010a3c06d5 bp 0x7fff55ded010 sp 0x7fff55ded008 READ of size 16 at 0x000131810077 thread T0

I can understand that the ASAN is concerned that I'm reading past the boundaries of the sockaddr to get the full sockaddr_in6 (the sockaddr is 16 bytes, the sockaddr_in6 is 28 bytes).

But I can't seem to test the rest of my app with the ASAN because of this. It seems a bit weird that any use of withMemoryRebound would trip the ASAN.

I've tried to write it in different ways, even using Data as a vessle for the bytes. But I always seem to end up with a solution that triggers the ASAN.

Is there something wrong with my code?
Or can I somehow ignore this function in the ASAN?

Yvo
  • 18,681
  • 11
  • 71
  • 90
  • What do you expect? `struct sockaddr` *cannot* hold an IPv6 address. – Have a look at "Socket API Helper" in https://swift.org/migration-guide/se-0107-migrate.html. – Martin R Jun 08 '17 at 06:42
  • I believe `sockaddr` is a struct that points to the same structure of a IPv4 or IPv6 address. The `sa_family` field defines if it is AF_INET (v4) or AF_INET (v6). When you know which one it is, you can cast the memory to a `sockaddr_in` or a `sockaddr_in6`. My code starts with the `getifaddrs` function that returns the network interfaces of the current device. Each interface has a `ifa_addr` which is a `sockaddr` and can be either a v4 or v6 address. – Yvo Jun 09 '17 at 02:18
  • In this piece of C code you can see how the `ifa_addr` is interpreted as either a `sockaddr_in` or a `sockaddr_in6` (line 28 and 35). I can't think of a way to do that in Swift without tripping the ASAN: http://codegists.com/snippet/c/getifaddrsc_fgken_c – Yvo Jun 09 '17 at 03:34
  • That C code casts *pointers.* `sockaddr_in` is the struct itself, not a pointer. – Martin R Jun 09 '17 at 03:44
  • How does that translate to the Swift code? Thank you for your help. – Yvo Jun 09 '17 at 04:22
  • That depends on what you are trying to do. Did you have a look at the migration guide (link in my first comment)? They use `sockaddr_storage` which is large enough to hold all kind of addresses. – If you "only" need a list of all interface addresses then this https://stackoverflow.com/a/25627545/1187415 might help. – Martin R Jun 09 '17 at 05:13
  • @MartinR thanks I have it working now using the `getnameinfo` function. I've tried that function before but would always get a FAIL (return code 4). Not really sure what I'm doing different now. – Yvo Jun 10 '17 at 20:04
  • @MartinR yikes, it seems that the order of my swift statements seems relevant for the `getnameinfo` function to work for IPv6. I've opened a new question about it: https://stackoverflow.com/questions/44478074/swift-getnameinfo-unreliable-results-for-ipv6 – Yvo Jun 10 '17 at 21:05

1 Answers1

0

The pointer returned by the getifaddrs function looks like a sockaddr pointer but is actually a pointer to sockaddr_in or sockaddr_in6. By moving the addressV6 function to an extension on sockaddr, the memory was copied and cut to the size of a sockaddr struct. In case of IPv6 valuable address information would get lost.

The new (trimmed) sockaddr could never be converted to a sockaddr_in6 triggering the SAN.

For more information see: Swift getnameinfo unreliable results for IPv6

Thank you @MartinR for helping me with this!

Yvo
  • 18,681
  • 11
  • 71
  • 90