1
0
mirror of https://git.zx2c4.com/wireguard-go synced 2024-11-15 01:05:15 +01:00

send: propagate DSCP bits to the outer tunnel

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>
This commit is contained in:
Florent Daigniere 2019-02-23 14:14:09 +01:00
parent 42c6d0e261
commit 9e686cd714
No known key found for this signature in database
GPG Key ID: EAC5EBF07AA9C2A3
4 changed files with 46 additions and 14 deletions

View File

@ -22,7 +22,7 @@ type Bind interface {
SetMark(value uint32) error SetMark(value uint32) error
ReceiveIPv6(buff []byte) (int, Endpoint, error) ReceiveIPv6(buff []byte) (int, Endpoint, error)
ReceiveIPv4(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 Close() error
} }

View File

@ -258,18 +258,18 @@ func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
return n, &end, err 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) nend := end.(*NativeEndpoint)
if !nend.isV6 { if !nend.isV6 {
if bind.sock4 == -1 { if bind.sock4 == -1 {
return syscall.EAFNOSUPPORT return syscall.EAFNOSUPPORT
} }
return send4(bind.sock4, nend, buff) return send4(bind.sock4, nend, buff, tos)
} else { } else {
if bind.sock6 == -1 { if bind.sock6 == -1 {
return syscall.EAFNOSUPPORT return syscall.EAFNOSUPPORT
} }
return send6(bind.sock6, nend, buff) return send6(bind.sock6, nend, buff, tos)
} }
} }
@ -452,13 +452,18 @@ func create6(port uint16) (int, uint16, error) {
return fd, uint16(addr.Port), err 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 // construct message header
type ipTos struct {
tos byte
}
cmsg := struct { cmsg := struct {
cmsghdr unix.Cmsghdr cmsghdr unix.Cmsghdr
pktinfo unix.Inet4Pktinfo pktinfo unix.Inet4Pktinfo
cmsghdr2 unix.Cmsghdr
iptos ipTos
}{ }{
unix.Cmsghdr{ unix.Cmsghdr{
Level: unix.IPPROTO_IP, Level: unix.IPPROTO_IP,
@ -469,6 +474,15 @@ func send4(sock int, end *NativeEndpoint, buff []byte) error {
Spec_dst: end.src4().src, Spec_dst: end.src4().src,
Ifindex: end.src4().ifindex, 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) _, err := unix.SendmsgN(sock, buff, (*[unsafe.Sizeof(cmsg)]byte)(unsafe.Pointer(&cmsg))[:], end.dst4(), 0)
@ -488,13 +502,18 @@ func send4(sock int, end *NativeEndpoint, buff []byte) error {
return err 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 // construct message header
type ipTos struct {
tos byte
}
cmsg := struct { cmsg := struct {
cmsghdr unix.Cmsghdr cmsghdr unix.Cmsghdr
pktinfo unix.Inet6Pktinfo pktinfo unix.Inet6Pktinfo
cmsghdr2 unix.Cmsghdr
tclass ipTos
}{ }{
unix.Cmsghdr{ unix.Cmsghdr{
Level: unix.IPPROTO_IPV6, Level: unix.IPPROTO_IPV6,
@ -505,6 +524,14 @@ func send6(sock int, end *NativeEndpoint, buff []byte) error {
Addr: end.src6().src, Addr: end.src6().src,
Ifindex: end.dst6().ZoneId, 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{} { if cmsg.pktinfo.Addr == [16]byte{} {

View File

@ -125,7 +125,7 @@ func (device *Device) NewPeer(pk NoisePublicKey) (*Peer, error) {
return peer, nil return peer, nil
} }
func (peer *Peer) SendBuffer(buffer []byte) error { func (peer *Peer) SendBuffer(buffer []byte, tos byte) error {
peer.device.net.RLock() peer.device.net.RLock()
defer peer.device.net.RUnlock() defer peer.device.net.RUnlock()
@ -140,7 +140,7 @@ func (peer *Peer) SendBuffer(buffer []byte) error {
return errors.New("no known endpoint for peer") 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 { func (peer *Peer) String() string {

17
send.go
View File

@ -41,6 +41,10 @@ import (
* (to allow the construction of transport messages in-place) * (to allow the construction of transport messages in-place)
*/ */
const (
HandshakeDSCP = 0x88 // AF41, plus 00 ECN
)
type QueueOutboundElement struct { type QueueOutboundElement struct {
dropped int32 dropped int32
sync.Mutex sync.Mutex
@ -49,6 +53,7 @@ type QueueOutboundElement struct {
nonce uint64 // nonce for encryption nonce uint64 // nonce for encryption
keypair *Keypair // keypair for encryption keypair *Keypair // keypair for encryption
peer *Peer // related peer peer *Peer // related peer
tos byte // Type of Service (DSCP + ECN bits)
} }
func (device *Device) NewOutboundElement() *QueueOutboundElement { func (device *Device) NewOutboundElement() *QueueOutboundElement {
@ -159,7 +164,7 @@ func (peer *Peer) SendHandshakeInitiation(isRetry bool) error {
peer.timersAnyAuthenticatedPacketTraversal() peer.timersAnyAuthenticatedPacketTraversal()
peer.timersAnyAuthenticatedPacketSent() peer.timersAnyAuthenticatedPacketSent()
err = peer.SendBuffer(packet) err = peer.SendBuffer(packet, HandshakeDSCP)
if err != nil { if err != nil {
peer.device.log.Error.Println(peer, "- Failed to send handshake initiation", err) peer.device.log.Error.Println(peer, "- Failed to send handshake initiation", err)
} }
@ -197,7 +202,7 @@ func (peer *Peer) SendHandshakeResponse() error {
peer.timersAnyAuthenticatedPacketTraversal() peer.timersAnyAuthenticatedPacketTraversal()
peer.timersAnyAuthenticatedPacketSent() peer.timersAnyAuthenticatedPacketSent()
err = peer.SendBuffer(packet) err = peer.SendBuffer(packet, HandshakeDSCP)
if err != nil { if err != nil {
peer.device.log.Error.Println(peer, "- Failed to send handshake response", err) peer.device.log.Error.Println(peer, "- Failed to send handshake response", err)
} }
@ -218,7 +223,7 @@ func (device *Device) SendHandshakeCookie(initiatingElem *QueueHandshakeElement)
var buff [MessageCookieReplySize]byte var buff [MessageCookieReplySize]byte
writer := bytes.NewBuffer(buff[:0]) writer := bytes.NewBuffer(buff[:0])
binary.Write(writer, binary.LittleEndian, reply) 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 { if err != nil {
device.log.Error.Println("Failed to send cookie reply:", err) device.log.Error.Println("Failed to send cookie reply:", err)
} }
@ -294,14 +299,14 @@ func (device *Device) RoutineReadFromTUN() {
} }
dst := elem.packet[IPv4offsetDst : IPv4offsetDst+net.IPv4len] dst := elem.packet[IPv4offsetDst : IPv4offsetDst+net.IPv4len]
peer = device.allowedips.LookupIPv4(dst) peer = device.allowedips.LookupIPv4(dst)
elem.tos = elem.packet[1];
case ipv6.Version: case ipv6.Version:
if len(elem.packet) < ipv6.HeaderLen { if len(elem.packet) < ipv6.HeaderLen {
continue continue
} }
dst := elem.packet[IPv6offsetDst : IPv6offsetDst+net.IPv6len] dst := elem.packet[IPv6offsetDst : IPv6offsetDst+net.IPv6len]
peer = device.allowedips.LookupIPv6(dst) peer = device.allowedips.LookupIPv6(dst)
elem.tos = elem.packet[1];
default: default:
logDebug.Println("Received packet with unknown IP version") logDebug.Println("Received packet with unknown IP version")
} }
@ -600,7 +605,7 @@ func (peer *Peer) RoutineSequentialSender() {
// send message and return buffer to pool // send message and return buffer to pool
length := uint64(len(elem.packet)) length := uint64(len(elem.packet))
err := peer.SendBuffer(elem.packet) err := peer.SendBuffer(elem.packet, elem.tos)
device.PutMessageBuffer(elem.buffer) device.PutMessageBuffer(elem.buffer)
device.PutOutboundElement(elem) device.PutOutboundElement(elem)
if err != nil { if err != nil {