Like many, I am using WiFi a lot and often on congested networks.
Without this, Wireguard strips the DSCP bits, preventing WME from
kicking in and improving the audio/video experience.
Yes, it's technically an information leak. Who cares? It's not like if
traffic analysis based on packet sizes or timings wasn't a thing.
This is the first patch of the serie, more work has to happen on ECN
Signed-off-by: Florent Daigniere <nextgens@freenetproject.org>
SetMark(value uint32) error
ReceiveIPv6(buff []byte) (int, Endpoint, error)
ReceiveIPv4(buff []byte) (int, Endpoint, error)
- Send(buff []byte, end Endpoint) error
+ Send(buff []byte, end Endpoint, tos byte) error
Close() error
}
return n, &end, err
}
-func (bind *NativeBind) Send(buff []byte, end Endpoint) error {
+func (bind *NativeBind) Send(buff []byte, end Endpoint, tos byte) error {
nend := end.(*NativeEndpoint)
if !nend.isV6 {
if bind.sock4 == -1 {
return syscall.EAFNOSUPPORT
}
- return send4(bind.sock4, nend, buff)
+ return send4(bind.sock4, nend, buff, tos)
} else {
if bind.sock6 == -1 {
return syscall.EAFNOSUPPORT
}
- return send6(bind.sock6, nend, buff)
+ return send6(bind.sock6, nend, buff, tos)
}
}
return fd, uint16(addr.Port), err
}
-func send4(sock int, end *NativeEndpoint, buff []byte) error {
+func send4(sock int, end *NativeEndpoint, buff []byte, tos byte) error {
// construct message header
+ type ipTos struct {
+ tos byte
+ }
cmsg := struct {
cmsghdr unix.Cmsghdr
pktinfo unix.Inet4Pktinfo
+ cmsghdr2 unix.Cmsghdr
+ iptos ipTos
}{
unix.Cmsghdr{
Level: unix.IPPROTO_IP,
Spec_dst: end.src4().src,
Ifindex: end.src4().ifindex,
},
+ unix.Cmsghdr{
+ Level: unix.IPPROTO_IP,
+ Type: unix.IP_TOS,
+ Len: 1 + unix.SizeofCmsghdr,
+ },
+ ipTos{
+ tos: tos,
+ },
+
}
_, err := unix.SendmsgN(sock, buff, (*[unsafe.Sizeof(cmsg)]byte)(unsafe.Pointer(&cmsg))[:], end.dst4(), 0)
return err
}
-func send6(sock int, end *NativeEndpoint, buff []byte) error {
+func send6(sock int, end *NativeEndpoint, buff []byte, tos byte) error {
// construct message header
+ type ipTos struct {
+ tos byte
+ }
cmsg := struct {
cmsghdr unix.Cmsghdr
pktinfo unix.Inet6Pktinfo
+ cmsghdr2 unix.Cmsghdr
+ tclass ipTos
}{
unix.Cmsghdr{
Level: unix.IPPROTO_IPV6,
Addr: end.src6().src,
Ifindex: end.dst6().ZoneId,
},
+ unix.Cmsghdr{
+ Level: unix.IPPROTO_IPV6,
+ Type: unix.IPV6_TCLASS,
+ Len: 1 + unix.SizeofCmsghdr,
+ },
+ ipTos{
+ tos: tos,
+ },
}
if cmsg.pktinfo.Addr == [16]byte{} {
return peer, nil
}
-func (peer *Peer) SendBuffer(buffer []byte) error {
+func (peer *Peer) SendBuffer(buffer []byte, tos byte) error {
peer.device.net.RLock()
defer peer.device.net.RUnlock()
return errors.New("no known endpoint for peer")
}
- return peer.device.net.bind.Send(buffer, peer.endpoint)
+ return peer.device.net.bind.Send(buffer, peer.endpoint, tos)
}
func (peer *Peer) String() string {
* (to allow the construction of transport messages in-place)
*/
+const (
+ HandshakeDSCP = 0x88 // AF41, plus 00 ECN
+)
+
type QueueOutboundElement struct {
dropped int32
sync.Mutex
nonce uint64 // nonce for encryption
keypair *Keypair // keypair for encryption
peer *Peer // related peer
+ tos byte // Type of Service (DSCP + ECN bits)
}
func (device *Device) NewOutboundElement() *QueueOutboundElement {
peer.timersAnyAuthenticatedPacketTraversal()
peer.timersAnyAuthenticatedPacketSent()
- err = peer.SendBuffer(packet)
+ err = peer.SendBuffer(packet, HandshakeDSCP)
if err != nil {
peer.device.log.Error.Println(peer, "- Failed to send handshake initiation", err)
}
peer.timersAnyAuthenticatedPacketTraversal()
peer.timersAnyAuthenticatedPacketSent()
- err = peer.SendBuffer(packet)
+ err = peer.SendBuffer(packet, HandshakeDSCP)
if err != nil {
peer.device.log.Error.Println(peer, "- Failed to send handshake response", err)
}
var buff [MessageCookieReplySize]byte
writer := bytes.NewBuffer(buff[:0])
binary.Write(writer, binary.LittleEndian, reply)
- device.net.bind.Send(writer.Bytes(), initiatingElem.endpoint)
+ device.net.bind.Send(writer.Bytes(), initiatingElem.endpoint, HandshakeDSCP)
if err != nil {
device.log.Error.Println("Failed to send cookie reply:", err)
}
}
dst := elem.packet[IPv4offsetDst : IPv4offsetDst+net.IPv4len]
peer = device.allowedips.LookupIPv4(dst)
-
+ elem.tos = elem.packet[1];
case ipv6.Version:
if len(elem.packet) < ipv6.HeaderLen {
continue
}
dst := elem.packet[IPv6offsetDst : IPv6offsetDst+net.IPv6len]
peer = device.allowedips.LookupIPv6(dst)
-
+ elem.tos = elem.packet[1];
default:
logDebug.Println("Received packet with unknown IP version")
}
// send message and return buffer to pool
length := uint64(len(elem.packet))
- err := peer.SendBuffer(elem.packet)
+ err := peer.SendBuffer(elem.packet, elem.tos)
device.PutMessageBuffer(elem.buffer)
device.PutOutboundElement(elem)
if err != nil {