Skip to content

Commit c207898

Browse files
authored
AmneziaWG v1.5 (#84)
1 parent fe75b63 commit c207898

23 files changed

+1981
-451
lines changed

Dockerfile

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.24 as awg
1+
FROM golang:1.24.4 as awg
22
COPY . /awg
33
WORKDIR /awg
44
RUN go mod download && \
@@ -7,10 +7,24 @@ RUN go mod download && \
77

88
FROM alpine:3.19
99
ARG AWGTOOLS_RELEASE="1.0.20241018"
10+
11+
RUN apk add linux-headers build-base
12+
COPY awg-tools /awg-tools
13+
RUN pwd && ls -la / && ls -la /awg-tools
14+
WORKDIR /awg-tools/src
15+
# RUN ls -la && pwd && ls awg-tools
16+
RUN make
17+
RUN mkdir -p build && \
18+
cp wg ./build/awg && \
19+
cp wg-quick/linux.bash ./build/awg-quick
20+
21+
RUN cp build/awg /usr/bin/awg
22+
RUN cp build/awg-quick /usr/bin/awg-quick
23+
1024
RUN apk --no-cache add iproute2 iptables bash && \
1125
cd /usr/bin/ && \
12-
wget https://github.com/amnezia-vpn/amneziawg-tools/releases/download/v${AWGTOOLS_RELEASE}/alpine-3.19-amneziawg-tools.zip && \
13-
unzip -j alpine-3.19-amneziawg-tools.zip && \
26+
# wget https://github.com/amnezia-vpn/amneziawg-tools/releases/download/v${AWGTOOLS_RELEASE}/alpine-3.19-amneziawg-tools.zip && \
27+
# unzip -j alpine-3.19-amneziawg-tools.zip && \
1428
chmod +x /usr/bin/awg /usr/bin/awg-quick && \
1529
ln -s /usr/bin/awg /usr/bin/wg && \
1630
ln -s /usr/bin/awg-quick /usr/bin/wg-quick

device/awg/awg.go

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package awg
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"slices"
7+
"strconv"
8+
"strings"
9+
"sync"
10+
11+
"github.com/tevino/abool"
12+
)
13+
14+
type aSecCfgType struct {
15+
IsSet bool
16+
JunkPacketCount int
17+
JunkPacketMinSize int
18+
JunkPacketMaxSize int
19+
InitHeaderJunkSize int
20+
ResponseHeaderJunkSize int
21+
CookieReplyHeaderJunkSize int
22+
TransportHeaderJunkSize int
23+
InitPacketMagicHeader uint32
24+
ResponsePacketMagicHeader uint32
25+
UnderloadPacketMagicHeader uint32
26+
TransportPacketMagicHeader uint32
27+
// InitPacketMagicHeader Limit
28+
// ResponsePacketMagicHeader Limit
29+
// UnderloadPacketMagicHeader Limit
30+
// TransportPacketMagicHeader Limit
31+
}
32+
33+
type Limit struct {
34+
Min uint32
35+
Max uint32
36+
HeaderType uint32
37+
}
38+
39+
func NewLimit(min, max, headerType uint32) (Limit, error) {
40+
if min > max {
41+
return Limit{}, fmt.Errorf("min (%d) cannot be greater than max (%d)", min, max)
42+
}
43+
44+
return Limit{
45+
Min: min,
46+
Max: max,
47+
HeaderType: headerType,
48+
}, nil
49+
}
50+
51+
func ParseMagicHeader(key, value string, defaultHeaderType uint32) (Limit, error) {
52+
// tempAwg.ASecCfg.InitPacketMagicHeader, err = awg.NewLimit(uint32(initPacketMagicHeaderMin), uint32(initPacketMagicHeaderMax), DNewLimit(min, max, headerType)efaultMessageInitiationType)
53+
// var min, max, headerType uint32
54+
// _, err := fmt.Sscanf(value, "%d-%d:%d", &min, &max, &headerType)
55+
// if err != nil {
56+
// return Limit{}, fmt.Errorf("invalid magic header format: %s", value)
57+
// }
58+
59+
limits := strings.Split(value, "-")
60+
if len(limits) != 2 {
61+
return Limit{}, fmt.Errorf("invalid format for key: %s; %s", key, value)
62+
}
63+
64+
min, err := strconv.ParseUint(limits[0], 10, 32)
65+
if err != nil {
66+
return Limit{}, fmt.Errorf("parse min key: %s; value: ; %w", key, limits[0], err)
67+
}
68+
69+
max, err := strconv.ParseUint(limits[1], 10, 32)
70+
if err != nil {
71+
return Limit{}, fmt.Errorf("parse max key: %s; value: ; %w", key, limits[0], err)
72+
}
73+
74+
limit, err := NewLimit(uint32(min), uint32(max), defaultHeaderType)
75+
if err != nil {
76+
return Limit{}, fmt.Errorf("new lmit key: %s; value: ; %w", key, limits[0], err)
77+
}
78+
79+
return limit, nil
80+
}
81+
82+
type Limits []Limit
83+
84+
func NewLimits(limits []Limit) Limits {
85+
slices.SortFunc(limits, func(a, b Limit) int {
86+
if a.Min < b.Min {
87+
return -1
88+
} else if a.Min > b.Min {
89+
return 1
90+
}
91+
return 0
92+
})
93+
94+
return Limits(limits)
95+
}
96+
97+
type Protocol struct {
98+
IsASecOn abool.AtomicBool
99+
// TODO: revision the need of the mutex
100+
ASecMux sync.RWMutex
101+
ASecCfg aSecCfgType
102+
JunkCreator junkCreator
103+
104+
HandshakeHandler SpecialHandshakeHandler
105+
}
106+
107+
func (protocol *Protocol) CreateInitHeaderJunk() ([]byte, error) {
108+
return protocol.createHeaderJunk(protocol.ASecCfg.InitHeaderJunkSize)
109+
}
110+
111+
func (protocol *Protocol) CreateResponseHeaderJunk() ([]byte, error) {
112+
return protocol.createHeaderJunk(protocol.ASecCfg.ResponseHeaderJunkSize)
113+
}
114+
115+
func (protocol *Protocol) CreateCookieReplyHeaderJunk() ([]byte, error) {
116+
return protocol.createHeaderJunk(protocol.ASecCfg.CookieReplyHeaderJunkSize)
117+
}
118+
119+
func (protocol *Protocol) CreateTransportHeaderJunk(packetSize int) ([]byte, error) {
120+
return protocol.createHeaderJunk(protocol.ASecCfg.TransportHeaderJunkSize, packetSize)
121+
}
122+
123+
func (protocol *Protocol) createHeaderJunk(junkSize int, optExtraSize ...int) ([]byte, error) {
124+
extraSize := 0
125+
if len(optExtraSize) == 1 {
126+
extraSize = optExtraSize[0]
127+
}
128+
129+
var junk []byte
130+
protocol.ASecMux.RLock()
131+
if junkSize != 0 {
132+
buf := make([]byte, 0, junkSize+extraSize)
133+
writer := bytes.NewBuffer(buf[:0])
134+
err := protocol.JunkCreator.AppendJunk(writer, junkSize)
135+
if err != nil {
136+
protocol.ASecMux.RUnlock()
137+
return nil, err
138+
}
139+
junk = writer.Bytes()
140+
}
141+
protocol.ASecMux.RUnlock()
142+
143+
return junk, nil
144+
}

device/awg/internal/mock.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package internal
2+
3+
type mockGenerator struct {
4+
size int
5+
}
6+
7+
func NewMockGenerator(size int) mockGenerator {
8+
return mockGenerator{size: size}
9+
}
10+
11+
func (m mockGenerator) Generate() []byte {
12+
return make([]byte, m.size)
13+
}
14+
15+
func (m mockGenerator) Size() int {
16+
return m.size
17+
}
18+
19+
func (m mockGenerator) Name() string {
20+
return "mock"
21+
}
22+
23+
type mockByteGenerator struct {
24+
data []byte
25+
}
26+
27+
func NewMockByteGenerator(data []byte) mockByteGenerator {
28+
return mockByteGenerator{data: data}
29+
}
30+
31+
func (bg mockByteGenerator) Generate() []byte {
32+
return bg.data
33+
}
34+
35+
func (bg mockByteGenerator) Size() int {
36+
return len(bg.data)
37+
}

device/junk_creator.go renamed to device/awg/junk_creator.go

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package device
1+
package awg
22

33
import (
44
"bytes"
@@ -8,61 +8,62 @@ import (
88
)
99

1010
type junkCreator struct {
11-
device *Device
11+
aSecCfg aSecCfgType
1212
cha8Rand *v2.ChaCha8
1313
}
1414

15-
func NewJunkCreator(d *Device) (junkCreator, error) {
15+
// TODO: refactor param to only pass the junk related params
16+
func NewJunkCreator(aSecCfg aSecCfgType) (junkCreator, error) {
1617
buf := make([]byte, 32)
1718
_, err := crand.Read(buf)
1819
if err != nil {
1920
return junkCreator{}, err
2021
}
21-
return junkCreator{device: d, cha8Rand: v2.NewChaCha8([32]byte(buf))}, nil
22+
return junkCreator{aSecCfg: aSecCfg, cha8Rand: v2.NewChaCha8([32]byte(buf))}, nil
2223
}
2324

2425
// Should be called with aSecMux RLocked
25-
func (jc *junkCreator) createJunkPackets() ([][]byte, error) {
26-
if jc.device.aSecCfg.junkPacketCount == 0 {
27-
return nil, nil
26+
func (jc *junkCreator) CreateJunkPackets(junks *[][]byte) error {
27+
if jc.aSecCfg.JunkPacketCount == 0 {
28+
return nil
2829
}
2930

30-
junks := make([][]byte, 0, jc.device.aSecCfg.junkPacketCount)
31-
for i := 0; i < jc.device.aSecCfg.junkPacketCount; i++ {
31+
for range jc.aSecCfg.JunkPacketCount {
3232
packetSize := jc.randomPacketSize()
3333
junk, err := jc.randomJunkWithSize(packetSize)
3434
if err != nil {
35-
return nil, fmt.Errorf("Failed to create junk packet: %v", err)
35+
return fmt.Errorf("create junk packet: %v", err)
3636
}
37-
junks = append(junks, junk)
37+
*junks = append(*junks, junk)
3838
}
39-
return junks, nil
39+
return nil
4040
}
4141

4242
// Should be called with aSecMux RLocked
4343
func (jc *junkCreator) randomPacketSize() int {
4444
return int(
4545
jc.cha8Rand.Uint64()%uint64(
46-
jc.device.aSecCfg.junkPacketMaxSize-jc.device.aSecCfg.junkPacketMinSize,
46+
jc.aSecCfg.JunkPacketMaxSize-jc.aSecCfg.JunkPacketMinSize,
4747
),
48-
) + jc.device.aSecCfg.junkPacketMinSize
48+
) + jc.aSecCfg.JunkPacketMinSize
4949
}
5050

5151
// Should be called with aSecMux RLocked
52-
func (jc *junkCreator) appendJunk(writer *bytes.Buffer, size int) error {
52+
func (jc *junkCreator) AppendJunk(writer *bytes.Buffer, size int) error {
5353
headerJunk, err := jc.randomJunkWithSize(size)
5454
if err != nil {
55-
return fmt.Errorf("failed to create header junk: %v", err)
55+
return fmt.Errorf("create header junk: %v", err)
5656
}
5757
_, err = writer.Write(headerJunk)
5858
if err != nil {
59-
return fmt.Errorf("failed to write header junk: %v", err)
59+
return fmt.Errorf("write header junk: %v", err)
6060
}
6161
return nil
6262
}
6363

6464
// Should be called with aSecMux RLocked
6565
func (jc *junkCreator) randomJunkWithSize(size int) ([]byte, error) {
66+
// TODO: use a memory pool to allocate
6667
junk := make([]byte, size)
6768
_, err := jc.cha8Rand.Read(junk)
6869
return junk, err

0 commit comments

Comments
 (0)