pion / dtls

DTLS 1.2 Server/Client implementation for Go
https://pion.ly/
MIT License
585 stars 154 forks source link

Support for setting Out-Of-Band (OOB) data on packets #641

Open RyanGordon opened 3 months ago

RyanGordon commented 3 months ago

Summary

This feature request suggests adding a new function to the dtls package:

Proposed format could be something like the following with an argument format similar to the UDPConn WriteMsgUDP function

(c *Conn) WriteWithOOB(b, oob []byte) (n, oobn int, err error)

This would be optionally available and accessible from the underlying Conn package

Example: Set the DSCP IP field on a linux based system

// Define the desired DSCP value. For example, 46 (EF class) for expedited forwarding.
// Shift it left by 2 bits to fit into the ToS field correctly.
dscpValue := byte(46 << 2)

// Create a single-byte slice with the DSCP value for the ToS field.
optionData := []byte{dscpValue}

// Update the Cmsghdr to set the Type of Service (ToS).
cmsgHeader := syscall.Cmsghdr{
    Level: unix.IPPROTO_IP, // IP level
    Type:  unix.IP_TOS,     // Type of Service
}

// Serialize the control message with the updated DiffServ value.
cmsg := SerializeCmsg(cmsgHeader, optionData)

// Print the serialized control message for debugging purposes.
fmt.Printf("%X\n", cmsg)

// The connection can write data to the desired address with the updated DiffServ header.
_, _, err = conn.WriteWithOOB([]byte("data"), cmsg)
if err != nil {
    log.Fatal(err)
}

func SerializeCmsg(h syscall.Cmsghdr, data []byte) []byte {
    cmsg := make([]byte, 0, unix.SizeofCmsghdr+len(data))
    cmsg = binary.LittleEndian.AppendUint64(cmsg, unix.SizeofCmsghdr+uint64(len(data)))
    cmsg = binary.LittleEndian.AppendUint32(cmsg, uint32(h.Level))
    cmsg = binary.LittleEndian.AppendUint32(cmsg, uint32(h.Type))
    return append(cmsg, data...)
}

Motivation

As a lower-level protocol library, this provides the ability to extensibly cover use cases that OOB can allow for, such as:

OOB as a general function allows us to make changes to the IP-header without having to construct the IP header ourselves.

Describe alternatives you've considered

It would be possible to implement specific DiffServ and ECN setting and getting helper functions on top of OOB, but limits the extensibility of providing an abstract OOB capability. This library is low-level enough that it should be possible to expose this lower-level extensibility without sacrificing the default and traditional net.Conn interface.

Additional context

Conn.Write

Below is the current flow for Conn.Write:

Conn.Write
  -> Conn.writePackets
    -> Conn.WriteToContext
      -> pion/transport/v3/netctx.PacketConn.WriteToContext
        -> net.WriteTo

Below is a potential proposed flow for Conn.WriteWithOOB

Conn.WriteWithOOB(pkt, oob)
  -> Conn.writePackets(ctx, []{pkt}, oob)
    -> pion/transport/v3/netctx.PacketConn.WriteToContext(ctx, compactedRawPacket, addr) <-- oob is added to ctx
     -> net.WriteMsgUDP <-- used if oob key is set in ctx
     -> net.WriteTo <- used if oob key is not set in ctx (default)

Here is an example implementation: https://github.com/pion/dtls/compare/ryang/conn_write_with_oob

Sean-Der commented 1 month ago

Hey @RyanGordon I released v3.0.0!

Want to start landing this?