typelevel / typelevel/fs2

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

Open
#3,653 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Scala
Stars
2.5k
Forks
636
Avg merge
2d 4h
Merged PRs (30d)
7

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by examining Socket's getOption API and the Scala Native socket implementation. Compare exposing the native file descriptor with adding SO_ORIGINAL_DST support, including the stated JVM UnsupportedException behavior. Done means the chosen approach retrieves the original IPv4 or IPv6 destination for transparent proxies and handles unsupported socket options.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
networking
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.