Advanced security header layer & config

Signed-off-by: Mark Puha <marko10@inf.elte.hu>
This commit is contained in:
Mark Puha 2023-09-03 13:27:05 +02:00
parent 469159ecf7
commit 1f0f5d5b7c
16 changed files with 536 additions and 51 deletions

3
.gitignore vendored
View file

@ -1 +1,4 @@
wireguard-go
cfg/cfg_values.go
generator.exe
generator

View file

@ -29,3 +29,27 @@ clean:
rm -f wireguard-go
.PHONY: all clean test install generate-version-and-build
has_args =
# If the first argument is "cfg_gen"...
ifeq (cfg_gen,$(firstword $(MAKECMDGOALS)))
has_args = yes
endif
ifdef has_args
# use the rest as arguments for "cfg_gen"
RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
# ...and turn them into do-nothing targets
$(eval $(RUN_ARGS):;@:)
endif
ifeq ($(OS),Windows_NT)
gen_run=generator.exe
else
gen_run=./generator
endif
.PHONY: cfg_gen
cfg_gen:
go build util/cfgGenerator/generator.go && $(gen_run) $(RUN_ARGS)

View file

@ -4,6 +4,14 @@ This is an implementation of WireGuard in Go.
## Usage
### Config gen
The configs are generate from a yml file. If you want to change the config run `make cfg_gen config_name` where `config_name` is the name of the yaml file you'd like to generate from. The script will search in the `cfg/settings/` folder
### Example:
`make cfg_gen default` will generate a config from `cfg/settings/default.yml` the file will be called `cfg/cfg_values.go`
Every time you make changes to the yml you need to rerun this.
Most Linux kernel WireGuard users are used to adding an interface with `ip link add wg0 type wireguard`. With wireguard-go, instead simply run:
```

55
cfg/cfg_def.go Normal file
View file

@ -0,0 +1,55 @@
package cfg
import "log"
func init() {
if IsAdvancedSecurityOn() {
if JunkPacketMaxSize <= JunkPacketMinSize {
log.Fatalf(
"MaxSize: %d; should be greater than MinSize: %d",
JunkPacketMaxSize,
JunkPacketMinSize,
)
}
if JunkPacketCount < 0 {
log.Fatalf("JunkPacketCount should be non negative")
}
const MaxSegmentSize = 2048 - 32
if 148+InitPacketJunkSize >= MaxSegmentSize {
log.Fatalf(
"init packets should be smaller than maxSegmentSize: %d",
MaxSegmentSize,
)
}
if 92+ResponsePacketJunkSize >= MaxSegmentSize {
log.Fatalf(
"response packets should be smaller than maxSegmentSize: %d",
MaxSegmentSize,
)
}
if 64+UnderLoadPacketJunkSize >= MaxSegmentSize {
log.Fatalf(
"underload packets should be smaller than maxSegmentSize: %d",
MaxSegmentSize,
)
}
if 32+TransportPacketJunkSize >= MaxSegmentSize {
log.Fatalf(
"transport packets should be smaller than maxSegmentSize: %d",
MaxSegmentSize,
)
}
} else {
if InitPacketJunkSize != 0 ||
ResponsePacketJunkSize != 0 ||
UnderLoadPacketJunkSize != 0 ||
TransportPacketJunkSize != 0 {
log.Fatal("JunkSizes should be zero when advanced security on")
}
}
}
func IsAdvancedSecurityOn() bool {
return InitPacketMagicHeader != 1
}

View file

@ -0,0 +1,11 @@
junk_packet_count: 5
junk_packet_min_size: 10
junk_packet_max_size: 30
init_packet_junk_size: 0
response_packet_junk_size: 0
underload_packet_junk_size: 0
transport_packet_junk_size: 0
init_packet_magic_header: 1
response_packet_magic_header : 2
underload_packet_magic_header : 3
transport_packet_magic_header : 4

11
cfg/settings/default.yml Normal file
View file

@ -0,0 +1,11 @@
junk_packet_count: 5
junk_packet_min_size: 10
junk_packet_max_size: 30
init_packet_junk_size: 30
response_packet_junk_size: 50
underload_packet_junk_size: 0
transport_packet_junk_size: 0
init_packet_magic_header: 1234567
response_packet_magic_header : 7654321
underload_packet_magic_header : 12345687
transport_packet_magic_header : 146810

View file

@ -15,6 +15,7 @@ import (
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/poly1305"
"golang.zx2c4.com/wireguard/cfg"
"golang.zx2c4.com/wireguard/tai64n"
)
@ -53,10 +54,10 @@ const (
)
const (
MessageInitiationType = 1
MessageResponseType = 2
MessageCookieReplyType = 3
MessageTransportType = 4
MessageInitiationType = cfg.InitPacketMagicHeader
MessageResponseType = cfg.ResponsePacketMagicHeader
MessageCookieReplyType = cfg.UnderloadPacketMagicHeader
MessageTransportType = cfg.TransportPacketMagicHeader
)
const (
@ -75,6 +76,20 @@ const (
MessageTransportOffsetContent = 16
)
var packetSizeToMsgType = map[int]uint32{
MessageInitiationSize + cfg.InitPacketJunkSize: MessageInitiationType,
MessageResponseSize + cfg.ResponsePacketJunkSize: MessageResponseType,
MessageCookieReplySize + cfg.UnderLoadPacketJunkSize: MessageCookieReplyType,
MessageTransportSize + cfg.TransportPacketJunkSize: MessageTransportType,
}
var msgTypeToJunkSize = map[uint32]int{
MessageInitiationType: cfg.InitPacketJunkSize,
MessageResponseType: cfg.ResponsePacketJunkSize,
MessageCookieReplyType: cfg.UnderLoadPacketJunkSize,
MessageTransportType: cfg.TransportPacketJunkSize,
}
/* Type is an 8-bit field, followed by 3 nul bytes,
* by marshalling the messages in little-endian byteorder
* we can treat these as a 32-bit unsigned int (for now)
@ -174,7 +189,9 @@ func init() {
mixHash(&InitialHash, &InitialChainKey, []byte(WGIdentifier))
}
func (device *Device) CreateMessageInitiation(peer *Peer) (*MessageInitiation, error) {
func (device *Device) CreateMessageInitiation(
peer *Peer,
) (*MessageInitiation, error) {
device.staticIdentity.RLock()
defer device.staticIdentity.RUnlock()
@ -214,7 +231,12 @@ func (device *Device) CreateMessageInitiation(peer *Peer) (*MessageInitiation, e
ss[:],
)
aead, _ := chacha20poly1305.New(key[:])
aead.Seal(msg.Static[:0], ZeroNonce[:], device.staticIdentity.publicKey[:], handshake.hash[:])
aead.Seal(
msg.Static[:0],
ZeroNonce[:],
device.staticIdentity.publicKey[:],
handshake.hash[:],
)
handshake.mixHash(msg.Static[:])
// encrypt timestamp
@ -312,14 +334,23 @@ func (device *Device) ConsumeMessageInitiation(msg *MessageInitiation) *Peer {
// protect against replay & flood
replay := !timestamp.After(handshake.lastTimestamp)
flood := time.Since(handshake.lastInitiationConsumption) <= HandshakeInitationRate
flood := time.Since(
handshake.lastInitiationConsumption,
) <= HandshakeInitationRate
handshake.mutex.RUnlock()
if replay {
device.log.Verbosef("%v - ConsumeMessageInitiation: handshake replay @ %v", peer, timestamp)
device.log.Verbosef(
"%v - ConsumeMessageInitiation: handshake replay @ %v",
peer,
timestamp,
)
return nil
}
if flood {
device.log.Verbosef("%v - ConsumeMessageInitiation: handshake flood", peer)
device.log.Verbosef(
"%v - ConsumeMessageInitiation: handshake flood",
peer,
)
return nil
}
@ -348,7 +379,9 @@ func (device *Device) ConsumeMessageInitiation(msg *MessageInitiation) *Peer {
return peer
}
func (device *Device) CreateMessageResponse(peer *Peer) (*MessageResponse, error) {
func (device *Device) CreateMessageResponse(
peer *Peer,
) (*MessageResponse, error) {
handshake := &peer.handshake
handshake.mutex.Lock()
defer handshake.mutex.Unlock()
@ -361,7 +394,10 @@ func (device *Device) CreateMessageResponse(peer *Peer) (*MessageResponse, error
var err error
device.indexTable.Delete(handshake.localIndex)
handshake.localIndex, err = device.indexTable.NewIndexForHandshake(peer, handshake)
handshake.localIndex, err = device.indexTable.NewIndexForHandshake(
peer,
handshake,
)
if err != nil {
return nil, err
}
@ -551,7 +587,9 @@ func (peer *Peer) BeginSymmetricSession() error {
// zero handshake
setZero(handshake.chainKey[:])
setZero(handshake.hash[:]) // Doesn't necessarily need to be zeroed. Could be used for something interesting down the line.
setZero(
handshake.hash[:],
) // Doesn't necessarily need to be zeroed. Could be used for something interesting down the line.
setZero(handshake.localEphemeral[:])
peer.handshake.state = handshakeZeroed

View file

@ -16,6 +16,7 @@ import (
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
"golang.zx2c4.com/wireguard/cfg"
"golang.zx2c4.com/wireguard/conn"
)
@ -55,7 +56,10 @@ func (peer *Peer) keepKeyFreshReceiving() {
return
}
keypair := peer.keypairs.Current()
if keypair != nil && keypair.isInitiator && time.Since(keypair.created) > (RejectAfterTime-KeepaliveTimeout-RekeyTimeout) {
if keypair != nil && keypair.isInitiator &&
time.Since(
keypair.created,
) > (RejectAfterTime-KeepaliveTimeout-RekeyTimeout) {
peer.timers.sentLastMinuteHandshake.Store(true)
peer.SendHandshakeInitiation(false)
}
@ -66,7 +70,10 @@ func (peer *Peer) keepKeyFreshReceiving() {
* Every time the bind is updated a new routine is started for
* IPv4 and IPv6 (separately)
*/
func (device *Device) RoutineReceiveIncoming(maxBatchSize int, recv conn.ReceiveFunc) {
func (device *Device) RoutineReceiveIncoming(
maxBatchSize int,
recv conn.ReceiveFunc,
) {
recvName := recv.PrettyName()
defer func() {
device.log.Verbosef("Routine: receive incoming %s - stopped", recvName)
@ -109,7 +116,11 @@ func (device *Device) RoutineReceiveIncoming(maxBatchSize int, recv conn.Receive
if errors.Is(err, net.ErrClosed) {
return
}
device.log.Verbosef("Failed to receive %s packet: %v", recvName, err)
device.log.Verbosef(
"Failed to receive %s packet: %v",
recvName,
err,
)
if neterr, ok := err.(net.Error); ok && !neterr.Temporary() {
return
}
@ -131,8 +142,17 @@ func (device *Device) RoutineReceiveIncoming(maxBatchSize int, recv conn.Receive
// check size of packet
packet := bufsArrs[i][:size]
if cfg.IsAdvancedSecurityOn() {
var junkSize int
if mapMsgType, ok := packetSizeToMsgType[size]; ok {
junkSize = msgTypeToJunkSize[mapMsgType]
} else {
junkSize = cfg.TransportPacketJunkSize
}
// shift junk
packet = packet[junkSize:]
}
msgType := binary.LittleEndian.Uint32(packet[:4])
switch msgType {
// check if transport
@ -302,9 +322,14 @@ func (device *Device) RoutineHandshake(id int) {
// consume reply
if peer := entry.peer; peer.isRunning.Load() {
device.log.Verbosef("Receiving cookie response from %s", elem.endpoint.DstToString())
device.log.Verbosef(
"Receiving cookie response from %s",
elem.endpoint.DstToString(),
)
if !peer.cookieGenerator.ConsumeReply(&reply) {
device.log.Verbosef("Could not decrypt invalid cookie response")
device.log.Verbosef(
"Could not decrypt invalid cookie response",
)
}
}
@ -325,7 +350,10 @@ func (device *Device) RoutineHandshake(id int) {
// verify MAC2 field
if !device.cookieChecker.CheckMAC2(elem.packet, elem.endpoint.DstToBytes()) {
if !device.cookieChecker.CheckMAC2(
elem.packet,
elem.endpoint.DstToBytes(),
) {
device.SendHandshakeCookie(&elem)
goto skip
}
@ -346,9 +374,7 @@ func (device *Device) RoutineHandshake(id int) {
switch elem.msgType {
case MessageInitiationType:
// unmarshal
var msg MessageInitiation
reader := bytes.NewReader(elem.packet)
err := binary.Read(reader, binary.LittleEndian, &msg)
@ -358,10 +384,12 @@ func (device *Device) RoutineHandshake(id int) {
}
// consume initiation
peer := device.ConsumeMessageInitiation(&msg)
if peer == nil {
device.log.Verbosef("Received invalid initiation message from %s", elem.endpoint.DstToString())
device.log.Verbosef(
"Received invalid initiation message from %s",
elem.endpoint.DstToString(),
)
goto skip
}
@ -394,7 +422,10 @@ func (device *Device) RoutineHandshake(id int) {
peer := device.ConsumeMessageResponse(&msg)
if peer == nil {
device.log.Verbosef("Received invalid response message from %s", elem.endpoint.DstToString())
device.log.Verbosef(
"Received invalid response message from %s",
elem.endpoint.DstToString(),
)
goto skip
}
@ -414,7 +445,11 @@ func (device *Device) RoutineHandshake(id int) {
err = peer.BeginSymmetricSession()
if err != nil {
device.log.Errorf("%v - Failed to derive keypair: %v", peer, err)
device.log.Errorf(
"%v - Failed to derive keypair: %v",
peer,
err,
)
goto skip
}
@ -448,7 +483,10 @@ func (peer *Peer) RoutineSequentialReceiver(maxBatchSize int) {
continue
}
if !elem.keypair.replayFilter.ValidateCounter(elem.counter, RejectAfterMessages) {
if !elem.keypair.replayFilter.ValidateCounter(
elem.counter,
RejectAfterMessages,
) {
continue
}
@ -475,13 +513,17 @@ func (peer *Peer) RoutineSequentialReceiver(maxBatchSize int) {
}
field := elem.packet[IPv4offsetTotalLength : IPv4offsetTotalLength+2]
length := binary.BigEndian.Uint16(field)
if int(length) > len(elem.packet) || int(length) < ipv4.HeaderLen {
if int(length) > len(elem.packet) ||
int(length) < ipv4.HeaderLen {
continue
}
elem.packet = elem.packet[:length]
src := elem.packet[IPv4offsetSrc : IPv4offsetSrc+net.IPv4len]
if device.allowedips.Lookup(src) != peer {
device.log.Verbosef("IPv4 packet with disallowed source address from %v", peer)
device.log.Verbosef(
"IPv4 packet with disallowed source address from %v",
peer,
)
continue
}
@ -498,21 +540,36 @@ func (peer *Peer) RoutineSequentialReceiver(maxBatchSize int) {
elem.packet = elem.packet[:length]
src := elem.packet[IPv6offsetSrc : IPv6offsetSrc+net.IPv6len]
if device.allowedips.Lookup(src) != peer {
device.log.Verbosef("IPv6 packet with disallowed source address from %v", peer)
device.log.Verbosef(
"IPv6 packet with disallowed source address from %v",
peer,
)
continue
}
default:
device.log.Verbosef("Packet with invalid IP version from %v", peer)
device.log.Verbosef(
"Packet with invalid IP version from %v",
peer,
)
continue
}
bufs = append(bufs, elem.buffer[:MessageTransportOffsetContent+len(elem.packet)])
bufs = append(
bufs,
elem.buffer[:MessageTransportOffsetContent+len(elem.packet)],
)
}
if len(bufs) > 0 {
_, err := device.tun.device.Write(bufs, MessageTransportOffsetContent)
_, err := device.tun.device.Write(
bufs,
MessageTransportOffsetContent,
)
if err != nil && !device.isClosed() {
device.log.Errorf("Failed to write packets to TUN device: %v", err)
device.log.Errorf(
"Failed to write packets to TUN device: %v",
err,
)
}
}
for _, elem := range *elems {

View file

@ -9,6 +9,8 @@ import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"math/rand"
"net"
"os"
"sync"
@ -17,6 +19,7 @@ import (
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
"golang.zx2c4.com/wireguard/cfg"
"golang.zx2c4.com/wireguard/tun"
)
@ -116,22 +119,47 @@ func (peer *Peer) SendHandshakeInitiation(isRetry bool) error {
msg, err := peer.device.CreateMessageInitiation(peer)
if err != nil {
peer.device.log.Errorf("%v - Failed to create initiation message: %v", peer, err)
peer.device.log.Errorf(
"%v - Failed to create initiation message: %v",
peer,
err,
)
return err
}
// so only packet processed for cookie generation
var junkedHeader []byte
if cfg.IsAdvancedSecurityOn() {
err = peer.sendJunkPackets()
if err != nil {
peer.device.log.Errorf("%v - %v", peer, err)
return err
}
var buf [cfg.InitPacketJunkSize]byte
writer := bytes.NewBuffer(buf[:0])
err = appendJunk(writer, cfg.InitPacketJunkSize)
if err != nil {
peer.device.log.Errorf("%v - %v", peer, err)
return err
}
junkedHeader = writer.Bytes()
}
var buf [MessageInitiationSize]byte
writer := bytes.NewBuffer(buf[:0])
binary.Write(writer, binary.LittleEndian, msg)
packet := writer.Bytes()
peer.cookieGenerator.AddMacs(packet)
junkedHeader = append(junkedHeader, packet...)
peer.timersAnyAuthenticatedPacketTraversal()
peer.timersAnyAuthenticatedPacketSent()
err = peer.SendBuffers([][]byte{packet})
err = peer.SendBuffers([][]byte{junkedHeader})
if err != nil {
peer.device.log.Errorf("%v - Failed to send handshake initiation: %v", peer, err)
peer.device.log.Errorf(
"%v - Failed to send handshake initiation: %v",
peer,
err,
)
}
peer.timersHandshakeInitiated()
@ -147,15 +175,31 @@ func (peer *Peer) SendHandshakeResponse() error {
response, err := peer.device.CreateMessageResponse(peer)
if err != nil {
peer.device.log.Errorf("%v - Failed to create response message: %v", peer, err)
peer.device.log.Errorf(
"%v - Failed to create response message: %v",
peer,
err,
)
return err
}
var junkedHeader []byte
if cfg.IsAdvancedSecurityOn() {
var buf [cfg.ResponsePacketJunkSize]byte
writer := bytes.NewBuffer(buf[:0])
err = appendJunk(writer, cfg.ResponsePacketJunkSize)
if err != nil {
peer.device.log.Errorf("%v - %v", peer, err)
return err
}
junkedHeader = writer.Bytes()
}
var buf [MessageResponseSize]byte
writer := bytes.NewBuffer(buf[:0])
binary.Write(writer, binary.LittleEndian, response)
packet := writer.Bytes()
peer.cookieGenerator.AddMacs(packet)
junkedHeader = append(junkedHeader, packet...)
err = peer.BeginSymmetricSession()
if err != nil {
@ -168,18 +212,31 @@ func (peer *Peer) SendHandshakeResponse() error {
peer.timersAnyAuthenticatedPacketSent()
// TODO: allocation could be avoided
err = peer.SendBuffers([][]byte{packet})
err = peer.SendBuffers([][]byte{junkedHeader})
if err != nil {
peer.device.log.Errorf("%v - Failed to send handshake response: %v", peer, err)
peer.device.log.Errorf(
"%v - Failed to send handshake response: %v",
peer,
err,
)
}
return err
}
func (device *Device) SendHandshakeCookie(initiatingElem *QueueHandshakeElement) error {
device.log.Verbosef("Sending cookie response for denied handshake message for %v", initiatingElem.endpoint.DstToString())
func (device *Device) SendHandshakeCookie(
initiatingElem *QueueHandshakeElement,
) error {
device.log.Verbosef(
"Sending cookie response for denied handshake message for %v",
initiatingElem.endpoint.DstToString(),
)
sender := binary.LittleEndian.Uint32(initiatingElem.packet[4:8])
reply, err := device.cookieChecker.CreateReply(initiatingElem.packet, sender, initiatingElem.endpoint.DstToBytes())
reply, err := device.cookieChecker.CreateReply(
initiatingElem.packet,
sender,
initiatingElem.endpoint.DstToBytes(),
)
if err != nil {
device.log.Errorf("Failed to create cookie reply: %v", err)
return err
@ -199,7 +256,8 @@ func (peer *Peer) keepKeyFreshSending() {
return
}
nonce := keypair.sendNonce.Load()
if nonce > RekeyAfterMessages || (keypair.isInitiator && time.Since(keypair.created) > RekeyAfterTime) {
if nonce > RekeyAfterMessages ||
(keypair.isInitiator && time.Since(keypair.created) > RekeyAfterTime) {
peer.SendHandshakeInitiation(false)
}
}
@ -302,12 +360,18 @@ func (device *Device) RoutineReadFromTUN() {
// TODO: record stat for this
// This will happen if MSS is surprisingly small (< 576)
// coincident with reasonably high throughput.
device.log.Verbosef("Dropped some packets from multi-segment read: %v", readErr)
device.log.Verbosef(
"Dropped some packets from multi-segment read: %v",
readErr,
)
continue
}
if !device.isClosed() {
if !errors.Is(readErr, os.ErrClosed) {
device.log.Errorf("Failed to read packet from TUN device: %v", readErr)
device.log.Errorf(
"Failed to read packet from TUN device: %v",
readErr,
)
}
go device.Close()
}
@ -342,7 +406,8 @@ top:
}
keypair := peer.keypairs.Current()
if keypair == nil || keypair.sendNonce.Load() >= RejectAfterMessages || time.Since(keypair.created) >= RejectAfterTime {
if keypair == nil || keypair.sendNonce.Load() >= RejectAfterMessages ||
time.Since(keypair.created) >= RejectAfterTime {
peer.SendHandshakeInitiation(false)
return
}
@ -373,7 +438,9 @@ top:
*elems = (*elems)[:i]
if elemsOOO != nil {
peer.StagePackets(elemsOOO) // XXX: Out of order, but we can't front-load go chans
peer.StagePackets(
elemsOOO,
) // XXX: Out of order, but we can't front-load go chans
}
if len(*elems) == 0 {
@ -404,6 +471,31 @@ top:
}
}
func (peer *Peer) sendJunkPackets() error {
junks := make([][]byte, 0, cfg.JunkPacketCount)
for i := 0; i < cfg.JunkPacketCount; i++ {
packetSize := rand.Intn(
cfg.JunkPacketMaxSize-cfg.JunkPacketMinSize,
) + cfg.JunkPacketMinSize
junk, err := randomJunkWithSize(packetSize)
if err != nil {
peer.device.log.Errorf(
"%v - Failed to create junk packet: %v",
peer,
err,
)
return err
}
junks = append(junks, junk)
}
err := peer.SendBuffers(junks)
if err != nil {
return fmt.Errorf("failed to send junks: %v", err)
}
return nil
}
func (peer *Peer) FlushStagedPackets() {
for {
select {
@ -459,7 +551,10 @@ func (device *Device) RoutineEncryption(id int) {
binary.LittleEndian.PutUint64(fieldNonce, elem.nonce)
// pad content to multiple of 16
paddingSize := calculatePaddingSize(len(elem.packet), int(device.tun.mtu.Load()))
paddingSize := calculatePaddingSize(
len(elem.packet),
int(device.tun.mtu.Load()),
)
elem.packet = append(elem.packet, paddingZeros[:paddingSize]...)
// encrypt content and release to consumer
@ -478,7 +573,10 @@ func (device *Device) RoutineEncryption(id int) {
func (peer *Peer) RoutineSequentialSender(maxBatchSize int) {
device := peer.device
defer func() {
defer device.log.Verbosef("%v - Routine: sequential sender - stopped", peer)
defer device.log.Verbosef(
"%v - Routine: sequential sender - stopped",
peer,
)
peer.stopping.Done()
}()
device.log.Verbosef("%v - Routine: sequential sender - started", peer)

25
device/util.go Normal file
View file

@ -0,0 +1,25 @@
package device
import (
"bytes"
crand "crypto/rand"
"fmt"
)
func appendJunk(writer *bytes.Buffer, size int) error {
headerJunk, err := randomJunkWithSize(size)
if err != nil {
return fmt.Errorf("failed to create header junk: %v", err)
}
_, err = writer.Write(headerJunk)
if err != nil {
return fmt.Errorf("failed to write header junk: %v", err)
}
return nil
}
func randomJunkWithSize(size int) ([]byte, error) {
junk := make([]byte, size)
_, err := crand.Read(junk)
return junk, err
}

29
device/util_test.go Normal file
View file

@ -0,0 +1,29 @@
package device
import (
"bytes"
"fmt"
"testing"
"golang.zx2c4.com/wireguard/cfg"
)
func Test_randomJunktWithSize(t *testing.T) {
junk, err := randomJunkWithSize(30)
fmt.Println(string(junk), len(junk), err)
}
func Test_appendJunk(t *testing.T) {
t.Run("", func(t *testing.T) {
s := "apple"
buffer := bytes.NewBuffer([]byte(s))
err := appendJunk(buffer, 30)
if err != nil &&
buffer.Len() != len(s)+int(cfg.InitPacketJunkSize) {
t.Errorf("appendWithJunk() size don't match")
}
read := make([]byte, 50)
buffer.Read(read)
fmt.Println(string(read))
})
}

2
go.mod
View file

@ -3,10 +3,12 @@ module golang.zx2c4.com/wireguard
go 1.20
require (
github.com/juju/errors v1.0.0
golang.org/x/crypto v0.6.0
golang.org/x/net v0.7.0
golang.org/x/sys v0.5.1-0.20230222185716-a3b23cc77e89
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2
gopkg.in/yaml.v3 v3.0.1
gvisor.dev/gvisor v0.0.0-20221203005347-703fd9b7fbc0
)

8
go.sum
View file

@ -1,5 +1,9 @@
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/juju/errors v1.0.0 h1:yiq7kjCLll1BiaRuNY53MGI0+EQ3rF6GB+wvboZDefM=
github.com/juju/errors v1.0.0/go.mod h1:B5x9thDqx0wIMH3+aLIMP9HjItInYWObRovoCFM5Qe8=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
@ -10,5 +14,9 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqG
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gvisor.dev/gvisor v0.0.0-20221203005347-703fd9b7fbc0 h1:Wobr37noukisGxpKo5jAsLREcpj61RxrWYzD8uwveOY=
gvisor.dev/gvisor v0.0.0-20221203005347-703fd9b7fbc0/go.mod h1:Dn5idtptoW1dIos9U6A2rpebLs/MtTwFacjKb8jLdQA=

View file

@ -0,0 +1,15 @@
// THIS IS A GENERATED FILE; ANY MODIFICATION WILL BE LOST
package cfg
const JunkPacketCount int = {{.JunkPacketCount}}
const JunkPacketMinSize int = {{.JunkPacketMinSize}}
const JunkPacketMaxSize int = {{.JunkPacketMaxSize}}
const InitPacketJunkSize int = {{.InitPacketJunkSize}}
const ResponsePacketJunkSize int = {{.ResponsePacketJunkSize}}
const UnderLoadPacketJunkSize int = {{.UnderLoadPacketJunkSize}}
const TransportPacketJunkSize int = {{.TransportPacketJunkSize}}
const InitPacketMagicHeader uint32 = {{.InitPacketMagicHeader}}
const ResponsePacketMagicHeader uint32 = {{.ResponsePacketMagicHeader}}
const UnderloadPacketMagicHeader uint32 = {{.UnderloadPacketMagicHeader}}
const TransportPacketMagicHeader uint32 = {{.TransportPacketMagicHeader}}

View file

@ -0,0 +1,43 @@
package main
import (
"fmt"
"html/template"
"os"
"path/filepath"
"golang.zx2c4.com/wireguard/util/cfgGenerator/internal/config"
)
func main() {
cfgName := "default"
if len(os.Args) != 1 {
cfgName = os.Args[1]
} else {
fmt.Println("WARNING; config name omited; using default")
}
ex, err := os.Executable()
if err != nil {
panic(err)
}
mainPath := filepath.Dir(ex)
cfgPath := mainPath + "/cfg/"
cfgFilePath := cfgPath + "settings/" + cfgName + ".yml"
cfgTmpl, err := template.ParseFiles(
mainPath + "/util/cfgGenerator/cfg_values.txt",
)
if err != nil {
panic(err)
}
cfg, err := config.NewFromFilename(cfgFilePath)
if err != nil {
panic(err)
}
f, _ := os.Create(cfgPath + "cfg_values.go")
defer f.Close()
cfgTmpl.Execute(f, *cfg)
f.Sync()
}

View file

@ -0,0 +1,58 @@
package config
import (
"io/ioutil"
"github.com/juju/errors"
"gopkg.in/yaml.v3"
)
type config struct {
JunkPacketCount int `yaml:"junk_packet_count"`
JunkPacketMinSize int `yaml:"junk_packet_min_size"`
JunkPacketMaxSize int `yaml:"junk_packet_max_size"`
InitPacketJunkSize int `yaml:"init_packet_junk_size"`
ResponsePacketJunkSize int `yaml:"response_packet_junk_size"`
UnderLoadPacketJunkSize int `yaml:"underload_packet_junk_size"`
TransportPacketJunkSize int `yaml:"transport_packet_junk_size"`
InitPacketMagicHeader uint32 `yaml:"init_packet_magic_header"`
ResponsePacketMagicHeader uint32 `yaml:"response_packet_magic_header"`
UnderloadPacketMagicHeader uint32 `yaml:"underload_packet_magic_header"`
TransportPacketMagicHeader uint32 `yaml:"transport_packet_magic_header"`
}
// New creates a new CW from a file by the given name
func New(name string) (*config, error) {
return NewFromFilename(name)
}
// NewFromFilename creates a new CW from a file by the given filename
func NewFromFilename(filename string) (*config, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, errors.Trace(err)
}
return NewFromRaw(data)
}
// NewFromRaw creates a new CW by unmarshaling the given raw data
func NewFromRaw(raw []byte) (*config, error) {
cfg := &config{}
if err := yaml.Unmarshal(raw, cfg); err != nil {
return nil, errors.Trace(err)
}
return cfg, nil
}
// TODO
// String can't be defined on a value receiver here because of the mutex
func (c *config) String() string {
raw, err := yaml.Marshal(c)
if err != nil {
return err.Error()
}
return string(raw)
}