Skip to content

Get access to the socket file descriptor or generalise getOption to gain access to SO_ORIGINAL_DST in scala native #3653

@rreckel

Description

@rreckel

Hi,

I would be nice to gain access to the SO_ORIGINAL_DST option using the socket.
I wrote a transparent proxy to be used on a linux machine, and therefore need the destination address.

I patched fs2 to get this option, but I think it would be useful for other projects.

There are two possible solutions:

  1. Grant access to the native FD in Socket. (should return an UnsupportedException on the JVM)
  2. Include the SO_ORIGINAL_DST option in the getOption method (only in scala-native...)

The code would be something like:

  def getOptOriginalDest[F[_]](fd: CInt)(implicit F: Sync[F]): F[Option[SocketAddress[IpAddress]]] = {
    F.delay {
      val SOL_IP = 0
      val SO_ORIGINAL_DST = 80
      val size = sizeOf[sockaddr_storage]
      val ptr = stackalloc[Byte](size)
      val szPtr = stackalloc[UInt]()
      !szPtr = size.toUInt
      val ret = guardMask(
        getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, ptr, szPtr)
        )(_ == ENOPROTOOPT)
      if (ret == ENOPROTOOPT) None else {
        val sockaddr = ptr.asInstanceOf[Ptr[sockaddr_storage]]
        if(sockaddr._1 == AF_INET) {
          val dstStr = stackalloc[Byte](INET_ADDRSTRLEN)
          val addr = ptr.asInstanceOf[Ptr[sockaddr_in]]
          val addr_in = addr.sin_addr
          val port = htons(addr.sin_port).toInt
          inet_ntop(AF_INET, addr_in.toPtr.asInstanceOf[CVoidPtr], dstStr, INET_ADDRSTRLEN.toUInt)
          SocketAddress.fromString4(s"${fromCString(dstStr)}:$port")
        } else if(sockaddr._1 == AF_INET6) {
          val dstStr = stackalloc[Byte](INET6_ADDRSTRLEN)
          val addr = ptr.asInstanceOf[Ptr[sockaddr_in6]]
          val addr_in = addr.sin6_addr
          val port = htons(addr.sin6_port).toInt
          inet_ntop(AF_INET6, addr_in.toPtr.asInstanceOf[CVoidPtr], dstStr, INET6_ADDRSTRLEN.toUInt)
          SocketAddress.fromString6(s"${fromCString(dstStr)}:$port")
        } else {
          println("Something went wrong during getsockopt")
          None
        }
      }
    }
  }

What do you think?
I could help making a PR if needed

Thanks for this great library

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions