Skip to content

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

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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