title: How to set ToS field in IP header for a TCP connection using Golang
body: <p>I am trying to create a TCP server and client using Golang where I am able to set the Type of Service field in the IP header in order to prioritise different traffic flows.</p>
  
  <p>The client and servers are able to communicate but I can not figure out how to set the ToS field.</p>
  
  <p>I have tried using the ipv4 Golang package with the method described here: <a href="https://godoc.org/golang.org/x/net/ipv4#NewConn" rel="nofollow noreferrer">https://godoc.org/golang.org/x/net/ipv4#NewConn</a></p>
  
  <p>A simplified server example:</p>
  
  <pre><code>func main () {
  ln, err := net.Listen("tcp4", "192.168.0.20:1024")
  if err != nil {
      // error handling
  }
  defer ln.Close()
  for {
      c, err := ln.Accept()
      if err != nil {
          // error handling
      }
      go func(c net.Conn) {
          defer c.Close()
  
          if err := ipv4.NewConn(c).SetTOS(0x28); err != nil {
              fmt.Println("Error: ", err.Error())
          }
      }(c)
  }
  </code></pre>
  
  <p>And the corresponding client (also simplified) </p>
  
  <pre><code>func main () {
  
      conn, err := net.Dial("tcp4", "192.168.0.20:1024")
      if err != nil {
          fmt.Println(err)
      }
  
      for {
  
              writer := bufio.NewWriter(conn)
              // Create "packet"
              Data := make([]byte, 1200)
              endLine := "\r\n"
  
  
  
              //Set packetLength
              length := strconv.FormatInt(int64(1200), 10)
              copy(Data[0:], length)
  
              //Set ID
              idString := strconv.FormatInt(int64(1), 10)
              if strings.Contains(idString, "\r") || strings.Contains(idString, "\n") || strings.Contains(idString, "\r\n") {
                  fmt.Println("This is gonna result in an error in the id string.")
              }
              idbuf := []byte(idString)
              copy(Data[15:], idbuf)
  
              //Set timestamp
              timestamp0 := time.Now().UnixNano()
              timestampString := strconv.FormatInt(timestamp0, 10)
              if strings.Contains(timestampString, "\r") || strings.Contains(timestampString, "\n") || strings.Contains(timestampString, "\r\n") {
                  fmt.Println("This is gonna result in an error in the timestamp string.")
              }
              buf := []byte(timestampString)
              copy(Data[50:], buf)
  
              copy(Data[int(1200)-2:], endLine)
  
              if len(Data) != int(1200) {
                  fmt.Println("This is also gonna be an error. Length is: ", len(Data))
              }
              //Send the data and flush the writer
              writer.Write(Data)
              writer.Flush()
          }
          //time.Sleep(1*time.Nanosecond)
      }
  
  </code></pre>
  
  <p>I have also tried creating my own dialer with a control function that passes a syscall in order to set the socket like this:</p>
  
  <pre><code>    dialer := &amp;net.Dialer{
          Timeout:       5 * time.Second,
          Deadline:      time.Time{},
          LocalAddr:     tcpAddr,
          DualStack:     false,
          FallbackDelay: 0,
          KeepAlive:     0,
          Resolver:      nil,
          Control:       highPrio,
      }
  
      func highPrio(network, address string, c syscall.RawConn) error {
      return c.Control(func(fd uintptr) {
          // set the socket options
          err := syscall.SetsockoptInt(syscall.Handle(fd), syscall.IPPROTO_IP, syscall.IP_TOS, 128)
          if err != nil {
              log.Println("setsocketopt: ", err)
          }
      })
  </code></pre>
  
  <p>I am verifying that it does not work by inspecting the traffic with Wireshark and am using Windows 10 Pro as my OS.</p>