docs: add comprehensive README.md for RelayDNS project
This commit introduces a new README.md file that provides an overview of the RelayDNS secure relay service, including features, architecture diagrams, security aspects, and usage instructions. This documentation helps users understand the project's purpose of enabling end-to-end encrypted communication through a central server.
lemon-mint committed
Oct 27, 2025 at 14:59 UTC
4c6f5a1f59835c18c3f12a9766ff01bba4b82648
2 files changed
+494
-525
README.md
new
+494
@@ -0,0 +1,494 @@
1
+# RelayDNS
2
+
3
+RelayDNS is a secure, encrypted relay service that enables end-to-end encrypted communication between clients through a central relay server. It provides mutual authentication, forward secrecy, and secure connection management with cryptographic identity verification.
4
+
5
+## Table of Contents
6
+
7
+- [Overview](#overview)
8
+- [Features](#features)
9
+- [Architecture](#architecture)
10
+- [Security](#security)
11
+- [Installation](#installation)
12
+- [Usage](#usage)
13
+- [API Reference](#api-reference)
14
+- [Protocol Specification](#protocol-specification)
15
+- [Development](#development)
16
+- [Contributing](#contributing)
17
+- [License](#license)
18
+
19
+## Overview
20
+
21
+RelayDNS implements a secure relay protocol that allows clients to register leases and establish encrypted connections through a central server. The system uses modern cryptographic primitives to ensure:
22
+
23
+- **End-to-end encryption**: All communication is encrypted using ChaCha20-Poly1305 AEAD
24
+- **Mutual authentication**: Ed25519 signatures verify client identities
25
+- **Forward secrecy**: Ephemeral X25519 key exchange per connection
26
+- **Secure relay**: The relay server cannot decrypt client communications
27
+
28
+## Features
29
+
30
+- 🔐 **End-to-End Encryption**: Client-to-client communication is fully encrypted
31
+- 🔑 **Cryptographic Identity**: Ed25519-based identity system with verifiable signatures
32
+- 🔄 **Connection Relay**: Secure connection forwarding through central server
33
+- ⏰ **Lease Management**: Time-based lease system with automatic cleanup
34
+- 🌐 **Protocol Support**: Application-Layer Protocol Negotiation (ALPN)
35
+- 🚀 **High Performance**: Multiplexed connections using yamux
36
+- 🐳 **Docker Support**: Containerized deployment ready
37
+
38
+## Architecture
39
+
40
+### System Architecture
41
+
42
+```mermaid
43
+graph TB
44
+ subgraph "Client A"
45
+ CA[Client A]
46
+ CA --> CA_ID[Identity: Ed25519]
47
+ CA --> CA_LEASE[Lease Manager]
48
+ end
49
+
50
+ subgraph "Client B"
51
+ CB[Client B]
52
+ CB --> CB_ID[Identity: Ed25519]
53
+ CB --> CB_LEASE[Lease Manager]
54
+ end
55
+
56
+ subgraph "Relay Server"
57
+ RS[Relay Server]
58
+ RS --> RS_ID[Server Identity]
59
+ RS --> LM[Lease Manager]
60
+ RS --> CM[Connection Manager]
61
+ RS --> FH[Forwarding Handler]
62
+ end
63
+
64
+ CA -.->|1. Register Lease| RS
65
+ CB -.->|2. Register Lease| RS
66
+ CB -.->|3. Request Connection| RS
67
+ RS -.->|4. Forward Request| CA
68
+ CA -.->|5. Accept Connection| RS
69
+ RS -.->|6. Establish E2EE| CB
70
+
71
+ CA <-->|7. Encrypted Data| CB
72
+```
73
+
74
+### Component Architecture
75
+
76
+```mermaid
77
+graph LR
78
+ subgraph "Client Components"
79
+ C[RelayClient]
80
+ C --> H[Handshaker]
81
+ C --> LM[LeaseManager]
82
+ C --> SC[SecureConnection]
83
+ end
84
+
85
+ subgraph "Server Components"
86
+ S[RelayServer]
87
+ S --> LH[LeaseHandler]
88
+ S --> CH[ConnectionHandler]
89
+ S --> FH[ForwardingHandler]
90
+ S --> LM2[LeaseManager]
91
+ end
92
+
93
+ subgraph "Crypto Operations"
94
+ CO[CryptoOps]
95
+ CO --> CRED[Credential]
96
+ CO --> SIG[Signature]
97
+ CO --> E2EE[End-to-End Encryption]
98
+ end
99
+
100
+ C <-->|Protocol Messages| S
101
+ H --> CO
102
+ SC --> CO
103
+ LH --> LM2
104
+ CH --> FH
105
+```
106
+
107
+### Connection Flow
108
+
109
+```mermaid
110
+sequenceDiagram
111
+ participant C1 as Client 1
112
+ participant RS as Relay Server
113
+ participant C2 as Client 2
114
+
115
+ Note over C1,C2: Lease Registration Phase
116
+ C1->>RS: Register Lease (Identity, ALPN)
117
+ RS->>C1: Lease Confirmation
118
+
119
+ C2->>RS: Register Lease (Identity, ALPN)
120
+ RS->>C2: Lease Confirmation
121
+
122
+ Note over C1,C2: Connection Establishment Phase
123
+ C2->>RS: Request Connection (to Client 1)
124
+ RS->>C1: Forward Connection Request
125
+ C1->>RS: Accept Connection
126
+ RS->>C2: Connection Accepted
127
+
128
+ Note over C1,C2: Secure Handshake Phase
129
+ C2->>C1: X25519 Handshake (via relay)
130
+ C1->>C2: X25519 Response (via relay)
131
+
132
+ Note over C1,C2: End-to-End Encrypted Communication
133
+ C2->>C1: Encrypted Data (ChaCha20-Poly1305)
134
+ C1->>C2: Encrypted Data (ChaCha20-Poly1305)
135
+```
136
+
137
+### Cryptographic Handshake Flow
138
+
139
+```mermaid
140
+sequenceDiagram
141
+ participant C as Client
142
+ participant S as Server
143
+
144
+ Note over C,S: Phase 1: Client Init
145
+ C->>C: Generate X25519 Ephemeral Key
146
+ C->>C: Create ClientInitPayload
147
+ C->>C: Sign with Ed25519 Private Key
148
+ C->>S: Signed ClientInitPayload
149
+
150
+ Note over C,S: Phase 2: Server Response
151
+ S->>S: Validate Client Signature
152
+ S->>S: Generate X25519 Ephemeral Key
153
+ S->>S: Create ServerInitPayload
154
+ S->>S: Sign with Ed25519 Private Key
155
+ S->>C: Signed ServerInitPayload
156
+
157
+ Note over C,S: Phase 3: Key Derivation
158
+ C->>C: Derive Shared Secret (X25519)
159
+ C->>C: Derive Directional Keys (HKDF-SHA256)
160
+ S->>S: Derive Shared Secret (X25519)
161
+ S->>S: Derive Directional Keys (HKDF-SHA256)
162
+
163
+ Note over C,S: Phase 4: Secure Communication
164
+ C->>S: Encrypted Message (ChaCha20-Poly1305)
165
+ S->>C: Encrypted Message (ChaCha20-Poly1305)
166
+```
167
+
168
+## Security
169
+
170
+### Cryptographic Primitives
171
+
172
+- **Ed25519**: Digital signatures for identity verification
173
+- **X25519**: Ephemeral key exchange for forward secrecy
174
+- **ChaCha20-Poly1305**: Authenticated encryption for data confidentiality
175
+- **HKDF-SHA256**: Key derivation for session keys
176
+- **HMAC-SHA256**: Identity derivation from public keys
177
+
178
+### Security Properties
179
+
180
+- **Mutual Authentication**: Both parties verify each other's identities
181
+- **Forward Secrecy**: Compromise of long-term keys doesn't compromise past sessions
182
+- **Replay Protection**: Timestamps and random nonces prevent replay attacks
183
+- **Integrity**: AEAD authentication tags prevent tampering
184
+- **Confidentiality**: End-to-end encryption prevents relay server access
185
+
186
+### Threat Mitigation
187
+
188
+- **Man-in-the-Middle**: Prevented by Ed25519 signature verification
189
+- **Replay Attacks**: Mitigated by timestamp validation and unique nonces
190
+- **Downgrade Attacks**: Protocol version validation prevents downgrade
191
+- **Denial of Service**: Packet size limits and silent failure on invalid handshakes
192
+
193
+## Installation
194
+
195
+### Prerequisites
196
+
197
+- Go 1.25.3 or later
198
+- Docker (for containerized deployment)
199
+
200
+### Build from Source
201
+
202
+```bash
203
+# Clone the repository
204
+git clone https://github.com/gosuda/relaydns.git
205
+cd relaydns
206
+
207
+# Note: The main entry point appears to be in development
208
+# You can build individual packages for testing:
209
+go build ./relaydns
210
+```
211
+
212
+### Docker Deployment
213
+
214
+```bash
215
+# Build and run with Docker Compose
216
+docker-compose up -d
217
+
218
+# Or build manually
219
+docker build -t relaydns .
220
+docker run -p 8080:8080 relaydns
221
+```
222
+
223
+## Usage
224
+
225
+### Server Setup
226
+
227
+```go
228
+package main
229
+
230
+import (
231
+ "github.com/gosuda/relaydns/relaydns"
232
+ "github.com/gosuda/relaydns/relaydns/core/cryptoops"
233
+)
234
+
235
+func main() {
236
+ // Create server credential
237
+ cred, err := cryptoops.NewCredential()
238
+ if err != nil {
239
+ panic(err)
240
+ }
241
+
242
+ // Create relay server
243
+ server := relaydns.NewRelayServer(cred, []string{"localhost:8080"})
244
+
245
+ // Start the server
246
+ server.Start()
247
+ defer server.Stop()
248
+
249
+ // Handle connections (implementation depends on your transport)
250
+ // For example, with HTTP/WebSocket:
251
+ // http.HandleFunc("/relay", handleRelayConnection)
252
+ // http.ListenAndServe(":8080", nil)
253
+}
254
+```
255
+
256
+### Client Usage
257
+
258
+```go
259
+package main
260
+
261
+import (
262
+ "context"
263
+ "github.com/gosuda/relaydns/relaydns"
264
+ "github.com/gosuda/relaydns/relaydns/core/cryptoops"
265
+)
266
+
267
+func main() {
268
+ // Create client credential
269
+ cred, err := cryptoops.NewCredential()
270
+ if err != nil {
271
+ panic(err)
272
+ }
273
+
274
+ // Connect to relay server (implementation depends on your transport)
275
+ // This is a conceptual example - actual connection method may vary
276
+ // conn, err := net.Dial("tcp", "localhost:8080")
277
+ // if err != nil {
278
+ // panic(err)
279
+ // }
280
+
281
+ // Create relay client
282
+ client := relaydns.NewRelayClient(conn)
283
+ defer client.Close()
284
+
285
+ // Register lease
286
+ err = client.RegisterLease(cred, "my-service", []string{"relay-v1"})
287
+ if err != nil {
288
+ panic(err)
289
+ }
290
+
291
+ // Get relay info
292
+ info, err := client.GetRelayInfo(context.Background())
293
+ if err != nil {
294
+ panic(err)
295
+ }
296
+
297
+ // fmt.Printf("Relay Info: %+v\n", info)
298
+
299
+ // Listen for incoming connections
300
+ go func() {
301
+ for incoming := range client.IncommingConnection() {
302
+ handleIncomingConnection(incoming)
303
+ }
304
+ }()
305
+
306
+ // Request connection to another client
307
+ targetLeaseID := "target-client-id"
308
+ _, secureConn, err := client.RequestConnection(targetLeaseID, "relay-v1", cred)
309
+ if err != nil {
310
+ panic(err)
311
+ }
312
+
313
+ // Use the secure connection
314
+ data := []byte("Hello, secure world!")
315
+ _, err = secureConn.Write(data)
316
+ if err != nil {
317
+ panic(err)
318
+ }
319
+}
320
+```
321
+
322
+## API Reference
323
+
324
+### RelayServer
325
+
326
+#### Methods
327
+
328
+- `NewRelayServer(credential *cryptoops.Credential, address []string) *RelayServer`
329
+- `HandleConnection(conn io.ReadWriteCloser) error`
330
+- `Start()`
331
+- `Stop()`
332
+
333
+### RelayClient
334
+
335
+#### Methods
336
+
337
+- `NewRelayClient(conn io.ReadWriteCloser) *RelayClient`
338
+- `Close() error`
339
+- `GetRelayInfo(ctx context.Context) (*rdverb.RelayInfo, error)`
340
+- `RegisterLease(cred *cryptoops.Credential, name string, alpns []string) error`
341
+- `DeregisterLease(cred *cryptoops.Credential) error`
342
+- `RequestConnection(leaseID string, alpn string, clientCred *cryptoops.Credential) (rdverb.ResponseCode, io.ReadWriteCloser, error)`
343
+- `IncommingConnection() <-chan *IncommingConn`
344
+
345
+### CryptoOps
346
+
347
+#### Credential Methods
348
+
349
+- `NewCredential() (*Credential, error)`
350
+- `NewCredentialFromPrivateKey(privateKey ed25519.PrivateKey) (*Credential, error)`
351
+- `ID() string`
352
+- `Sign(data []byte) []byte`
353
+- `Verify(data, sig []byte) bool`
354
+- `PublicKey() ed25519.PublicKey`
355
+- `PrivateKey() ed25519.PrivateKey`
356
+
357
+## Protocol Specification
358
+
359
+### Packet Types
360
+
361
+```protobuf
362
+enum PacketType {
363
+ PACKET_TYPE_RELAY_INFO_REQUEST = 0;
364
+ PACKET_TYPE_RELAY_INFO_RESPONSE = 1;
365
+ PACKET_TYPE_LEASE_UPDATE_REQUEST = 2;
366
+ PACKET_TYPE_LEASE_UPDATE_RESPONSE = 3;
367
+ PACKET_TYPE_LEASE_DELETE_REQUEST = 4;
368
+ PACKET_TYPE_LEASE_DELETE_RESPONSE = 5;
369
+ PACKET_TYPE_CONNECTION_REQUEST = 6;
370
+ PACKET_TYPE_CONNECTION_RESPONSE = 7;
371
+}
372
+```
373
+
374
+### Message Format
375
+
376
+All messages follow a length-prefixed protobuf format:
377
+
378
+```
379
++-------------------+-------------------+
380
+| Length (4 bytes) | Protobuf Payload |
381
+| Big Endian Uint32 | (variable length) |
382
++-------------------+-------------------+
383
+```
384
+
385
+### Encrypted Messages
386
+
387
+End-to-end encrypted messages use the following format:
388
+
389
+```
390
++-------------------+-------------------+-------------------+-------------------+
391
+| Length (4 bytes) | Nonce (12 bytes) | Ciphertext | Tag (16 bytes) |
392
+| Big Endian Uint32 | Random | (variable length) | Poly1305 MAC |
393
++-------------------+-------------------+-------------------+-------------------+
394
+```
395
+
396
+## Development
397
+
398
+### Project Structure
399
+
400
+```
401
+relaydns/
402
+├── relaydns/ # Main package
403
+│ ├── client.go # Client implementation
404
+│ ├── relay.go # Server implementation
405
+│ ├── handlers.go # Request handlers
406
+│ ├── lease.go # Lease management
407
+│ └── helper.go # Utility functions
408
+├── relaydns/core/ # Core components
409
+│ ├── cryptoops/ # Cryptographic operations
410
+│ │ ├── handshaker.go # E2EE handshake
411
+│ │ ├── identity.go # Identity management
412
+│ │ └── sig.go # Signature operations
413
+│ └── proto/ # Protocol definitions
414
+│ ├── rdsec/ # Security protocol
415
+│ └── rdverb/ # Relay protocol
416
+├── relaydns/internal/ # Internal utilities
417
+│ ├── randpool/ # CSPRNG implementation
418
+│ └── wsstream/ # WebSocket stream adapter
419
+└── sdk/ # Client SDKs
420
+ └── go/ # Go SDK
421
+```
422
+
423
+### Building
424
+
425
+```bash
426
+# Build all components
427
+go build ./...
428
+
429
+# Run tests
430
+go test ./...
431
+
432
+# Generate protobuf files
433
+buf generate
434
+
435
+# Build Docker image
436
+docker build -t relaydns .
437
+```
438
+
439
+### Testing
440
+
441
+```bash
442
+# Run unit tests
443
+go test ./relaydns/...
444
+
445
+# Run integration tests
446
+go test -tags=integration ./...
447
+
448
+# Run with coverage
449
+go test -cover ./...
450
+```
451
+
452
+## Contributing
453
+
454
+1. Fork the repository
455
+2. Create a feature branch (`git checkout -b feature/amazing-feature`)
456
+3. Commit your changes (`git commit -m 'Add amazing feature'`)
457
+4. Push to the branch (`git push origin feature/amazing-feature`)
458
+5. Open a Pull Request
459
+
460
+### Development Guidelines
461
+
462
+- Follow Go best practices and idioms
463
+- Ensure all cryptographic operations use constant-time implementations
464
+- Add comprehensive tests for new features
465
+- Update documentation for API changes
466
+- Use the provided memory pools for sensitive data
467
+
468
+## License
469
+
470
+This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
471
+
472
+## Security Considerations
473
+
474
+- **Never** use `math/rand` for cryptographic operations
475
+- **Always** validate timestamps within reasonable bounds
476
+- **Always** verify signatures before trusting identity claims
477
+- **Always** wipe sensitive data from memory after use
478
+- **Never** reuse nonces with the same encryption key
479
+- **Always** use the provided memory pools for sensitive data
480
+
481
+## Performance Considerations
482
+
483
+- Connection multiplexing using yamux for efficient resource usage
484
+- Memory pooling to reduce GC pressure
485
+- Fragmentation for large messages (32MB chunks)
486
+- Efficient buffer management with aligned allocations
487
+- Constant-time cryptographic operations
488
+
489
+## Compatibility
490
+
491
+- **Go**: 1.25.3 or later
492
+- **Protocol**: Version 1 (current)
493
+- **Ciphers**: ChaCha20-Poly1305, X25519, Ed25519
494
+- **Transport**: TCP, WebSocket (via adapter)
\ No newline at end of file
README_RELAY.md
deleted
-525
@@ -1,525 +0,0 @@
1
-# RelayServer 상세 동작 문서
2
-
3
-## 개요
4
-
5
-RelayServer는 DNS 기반 P2P 프록시 레이어로, libp2p 위에 구축된 경량 서비스입니다. 이 서버는 클라이언트 간의 안전한 연결을 중개하고, 리스(lease) 관리, 암호화된 통신, 다양한 프로토콜 지원 등의 기능을 제공합니다.
6
-
7
-## 핵심 구성 요소
8
-
9
-### 1. RelayServer 구조체
10
-
11
-RelayServer는 시스템의 핵심 구조체로, 다음과 같은 주요 필드를 포함합니다:
12
-
13
-```go
14
-type RelayServer struct {
15
- credential *cryptoops.Credential // 암호화 자격 증명
16
- identity *rdsec.Identity // 서버 신원 정보
17
- address []string // 서버 주소 목록
18
-
19
- connidCounter int64 // 연결 ID 카운터
20
- connections map[int64]*Connection // 활성 연결 맵
21
- connectionsLock sync.RWMutex // 연결 맵 락
22
-
23
- leaseConnections map[string]*Connection // 리스-연결 맵
24
- leaseConnectionsLock sync.RWMutex // 리스-연결 맵 락
25
-
26
- relayedConnections map[string][]*yamux.Stream // 릴레이된 연결 맵
27
- relayedConnectionsLock sync.RWMutex // 릴레이된 연결 맵 락
28
-
29
- leaseManager *LeaseManager // 리스 관리자
30
-
31
- stopch chan struct{} // 종료 신호 채널
32
- waitgroup sync.WaitGroup // 대기 그룹
33
-}
34
-```
35
-
36
-### 2. Connection 구조체
37
-
38
-각 클라이언트 연결을 나타내는 구조체입니다:
39
-
40
-```go
41
-type Connection struct {
42
- conn io.ReadWriteCloser // 기본 연결
43
- sess *yamux.Session // 다중화 세션
44
-
45
- streams map[uint32]*yamux.Stream // 스트림 맵
46
- streamsLock sync.Mutex // 스트림 맵 락
47
-}
48
-```
49
-
50
-### 3. LeaseManager
51
-
52
-리스(임대) 정보를 관리하는 컴포넌트로, 만료된 리스를 정리하고 리스 수명을 관리합니다:
53
-
54
-```go
55
-type LeaseManager struct {
56
- leases map[string]*LeaseEntry // 리스 맵 (키: 신원 ID)
57
- leasesLock sync.RWMutex // 리스 맵 락
58
- stopCh chan struct{} // 종료 신호 채널
59
- ttlInterval time.Duration // TTL 확인 간격
60
-}
61
-```
62
-
63
-## 주요 동작
64
-
65
-### 1. 서버 초기화
66
-
67
-서버는 `NewRelayServer` 함수로 초기화됩니다:
68
-
69
-```go
70
-func NewRelayServer(credential *cryptoops.Credential, address []string) *RelayServer
71
-```
72
-
73
-- 암호화 자격 증명과 주소 목록을 받아 RelayServer 인스턴스를 생성
74
-- 내부 맵들과 리스 관리자를 초기화
75
-- 30초 간격의 TTL 확인을 위한 리스 관리자 생성
76
-
77
-### 2. 연결 처리
78
-
79
-#### 2.1 새 연결 수락
80
-
81
-`HandleConnection` 메서드는 새로운 클라이언트 연결을 처리합니다:
82
-
83
-1. yamux 서버 세션을 생성
84
-2. 고유 연결 ID를 할당하고 연결 맵에 저장
85
-3. `handleConn` 고루틴을 시작하여 연결을 비동기적으로 처리
86
-
87
-#### 2.2 연결 관리
88
-
89
-`handleConn` 메서드는 연결의 수명 주기를 관리합니다:
90
-
91
-1. 세션에서 들어오는 스트림을 계속해서 수락
92
-2. 각 스트림에 대해 `handleStream` 고루틴을 시작
93
-3. 연결이 종료될 때 관련 리스를 정리하고 자원을 해제
94
-
95
-### 3. 스트림 처리
96
-
97
-`handleStream` 메서드는 개별 스트림의 요청을 처리합니다:
98
-
99
-1. 스트림에서 패킷을 읽음
100
-2. 패킷 타입에 따라 적절한 핸들러로 분기:
101
- - `PACKET_TYPE_RELAY_INFO_REQUEST`: `handleRelayInfoRequest`
102
- - `PACKET_TYPE_LEASE_UPDATE_REQUEST`: `handleLeaseUpdateRequest`
103
- - `PACKET_TYPE_LEASE_DELETE_REQUEST`: `handleLeaseDeleteRequest`
104
- - `PACKET_TYPE_CONNECTION_REQUEST`: `handleConnectionRequest`
105
-
106
-### 4. 리스 관리
107
-
108
-#### 4.1 리스 업데이트
109
-
110
-`handleLeaseUpdateRequest` 메서드는 리스 업데이트 요청을 처리합니다:
111
-
112
-1. 서명된 페이로드를 검증
113
-2. 리스 만료 시간을 확인
114
-3. 유효한 경우 리스를 업데이트하고 연결 맵에 등록
115
-4. 응답 코드를 반환
116
-
117
-#### 4.2 리스 삭제
118
-
119
-`handleLeaseDeleteRequest` 메서드는 리스 삭제 요청을 처리합니다:
120
-
121
-1. 서명된 페이로드를 검증
122
-2. 해당 리스를 리스 관리자에서 삭제
123
-3. 리스-연결 맵에서도 제거
124
-4. 응답 코드를 반환
125
-
126
-#### 4.3 리스 만료 관리
127
-
128
-LeaseManager는 백그라운드에서 만료된 리스를 정리합니다:
129
-
130
-1. `ttlWorker` 고루틴이 주기적으로 실행
131
-2. 만료된 리스를 자동으로 제거
132
-3. 특정 연결 ID와 관련된 모든 리스를 정리하는 기능 제공
133
-
134
-### 5. 연결 릴레이
135
-
136
-#### 5.1 연결 요청 처리
137
-
138
-`handleConnectionRequest` 메서드는 클라이언트 간의 연결 요청을 처리합니다:
139
-
140
-1. 대상 클라이언트의 리스가 존재하는지 확인
141
-2. 리스 소유자에게 연결 요청을 전달
142
-3. 요청이 수락되면 양방향 포워딩을 설정
143
-
144
-#### 5.2 양방향 포워딩 설정
145
-
146
-`setupBidirectionalForwarding` 메서드는 클라이언트 간의 데이터 포워딩을 설정합니다:
147
-
148
-1. 리스 소유자에게 새 데이터 스트림을 열고 초기화
149
-2. 클라이언트와 리스 소유자 간의 양방향 데이터 복사를 설정
150
-3. 연결이 종료될 때 관련 자원을 정리
151
-
152
-### 6. 암호화 및 보안
153
-
154
-#### 6.1 핸드셰이크 프로토콜
155
-
156
-X25519-ChaCha20Poly1305 기반의 핸드셰이크 프로토콜을 사용합니다:
157
-
158
-1. 클라이언트와 서버가 각각 임시 키 쌍 생성
159
-2. Ed25519로 서명된 초기화 메시지 교환
160
-3. 공유 비밀을 계산하고 세션 키를 파생
161
-4. ChaCha20Poly1305 AEAD 암호화 설정
162
-
163
-#### 6.2 서명 검증
164
-
165
-모든 인증된 요청은 Ed25519 서명을 통해 검증됩니다:
166
-
167
-1. `VerifySignedPayload` 함수로 서명 검증
168
-2. 신원 정보의 유효성 확인
169
-3. 타임스탬프 검증으로 리플레이 공격 방지
170
-
171
-### 7. 프로토콜 메시지
172
-
173
-#### 7.1 패킷 구조
174
-
175
-모든 통신은 다음과 같은 패킷 구조를 사용합니다:
176
-
177
-```protobuf
178
-message Packet {
179
- PacketType type = 1; // 패킷 타입
180
- bytes payload = 2; // 페이로드
181
-}
182
-```
183
-
184
-#### 7.2 패킷 타입
185
-
186
-- `PACKET_TYPE_RELAY_INFO_REQUEST/RESPONSE`: 릴레이 서버 정보 요청
187
-- `PACKET_TYPE_LEASE_UPDATE_REQUEST/RESPONSE`: 리스 업데이트 요청
188
-- `PACKET_TYPE_LEASE_DELETE_REQUEST/RESPONSE`: 리스 삭제 요청
189
-- `PACKET_TYPE_CONNECTION_REQUEST/RESPONSE`: 연결 요청
190
-
191
-#### 7.3 응답 코드
192
-
193
-- `RESPONSE_CODE_ACCEPTED`: 요청 수락
194
-- `RESPONSE_CODE_INVALID_EXPIRES`: 유효하지 않은 만료 시간
195
-- `RESPONSE_CODE_INVALID_IDENTITY`: 유효하지 않은 신원
196
-- `RESPONSE_CODE_INVALID_NAME`: 유효하지 않은 이름
197
-- `RESPONSE_CODE_INVALID_ALPN`: 유효하지 않은 ALPN
198
-- `RESPONSE_CODE_REJECTED`: 요청 거부
199
-
200
-### 8. HTTP 관리 인터페이스
201
-
202
-#### 8.1 관리 UI
203
-
204
-웹 기반 관리 인터페이스를 제공합니다:
205
-
206
-1. `/`: 서버 상태와 연결된 클라이언트 목록 표시
207
-2. `/peer/{peerID}/`: 특정 피어로의 HTTP 프록시
208
-3. `/hosts`: 연결된 호스트 목록 (JSON)
209
-4. `/health`: 서버 상태 확인 (JSON)
210
-
211
-#### 8.2 TCP 프록시
212
-
213
-선택적으로 원시 TCP 연결을 지원합니다:
214
-
215
-1. 지정된 포트에서 수신 대기
216
-2. 들어오는 연결을 선택된 피어로 프록시
217
-3. SSH 등의 TCP 기반 프로토콜 지원
218
-
219
-### 9. 서버 수명 주기
220
-
221
-#### 9.1 시작
222
-
223
-1. `Start` 메서드로 리스 관리자 시작
224
-2. 백그라운드 TTL 확인 고루틴 시작
225
-
226
-#### 9.2 종료
227
-
228
-1. `Stop` 메서드로 종료 신호 전송
229
-2. 리스 관리자 중지
230
-3. 모든 백그라운드 고루틴이 완료될 때까지 대기
231
-
232
-## 동작 흐름 예시
233
-
234
-### 1. 클라이언트 연결 및 리스 등록
235
-
236
-1. 클라이언트가 RelayServer에 연결
237
-2. yamux 세션이 설정되고 연결이 등록됨
238
-3. 클라이언트가 리스 업데이트 요청을 보냄
239
-4. 서버가 서명을 검증하고 리스를 등록
240
-5. 리스-연결 맵이 업데이트됨
241
-
242
-### 2. 클라이언트 간 연결 설정
243
-
244
-1. 클라이언트 A가 클라이언트 B로의 연결을 요청
245
-2. 서버가 클라이언트 B의 리스를 확인
246
-3. 서버가 클라이언트 B에게 연결 요청을 전달
247
-4. 클라이언트 B가 요청을 수락
248
-5. 서버가 양방향 포워딩을 설정
249
-6. 클라이언트 A와 B가 데이터를 교환
250
-
251
-### 3. 연결 종료 및 정리
252
-
253
-1. 클라이언트 연결이 종료됨
254
-2. 관련 리스가 자동으로 정리됨
255
-3. 릴레이된 연결이 모두 닫힘
256
-4. 연결 맵에서 항목이 제거됨
257
-
258
-## 보안 고려사항
259
-
260
-1. **암호화**: 모든 통신은 X25519-ChaCha20Poly1305로 암호화됨
261
-2. **인증**: Ed25519 서명으로 모든 요청의 출처를 검증
262
-3. **리플레이 방지**: 타임스탬프 검증으로 오래된 메시지 거부
263
-4. **신원 검증**: 공개 키에서 파생된 ID와 제공된 ID 일치 확인
264
-5. **세션 키**: 각 연결마다 고유한 세션 키를 사용
265
-
266
-## 암호화 상세
267
-
268
-### 1. 자격 증명(Credential) 시스템
269
-
270
-#### 1.1 자격 증명 생성
271
-
272
-```go
273
-type Credential struct {
274
- privateKey ed25519.PrivateKey // Ed25519 개인 키
275
- publicKey ed25519.PublicKey // Ed25519 공개 키
276
- id string // 파생된 ID
277
-}
278
-```
279
-
280
-- `NewCredential()`: 새로운 Ed25519 키 쌍을 생성하고 자격 증명을 반환
281
-- `NewCredentialFromPrivateKey()`: 기존 개인 키로부터 자격 증명 생성
282
-
283
-#### 1.2 ID 파생
284
-
285
-```go
286
-func DeriveID(publickey ed25519.PublicKey) string
287
-```
288
-
289
-- HMAC-SHA256을 사용하여 공개 키로부터 고유 ID를 파생
290
-- 매직 문자열 "RDVERB_PROTOCOL_VER_01_SHA256_ID" 사용
291
-- Base32 인코딩으로 최종 ID 생성
292
-
293
-#### 1.3 서명 및 검증
294
-
295
-- `Sign(data []byte)`: Ed25519로 데이터에 서명
296
-- `Verify(data, sig []byte)`: Ed25519 서명 검증
297
-- 모든 인증된 메시지는 이 서명 메커니즘을 통해 검증됨
298
-
299
-### 2. 핸드셰이크 프로토콜 상세
300
-
301
-#### 2.1 클라이언트 핸드셰이크
302
-
303
-1. **임시 키 생성**: X25519 임시 키 쌍 생성
304
-2. **ClientInitPayload 생성**:
305
- - 프로토콜 버전, nonce, 타임스탬프
306
- - 클라이언트 신원 정보
307
- - ALPN(Application-Layer Protocol Negotiation) 문자열
308
- - 임시 공개 키
309
-3. **서명 및 전송**: 페이로드를 서명하여 서버로 전송
310
-4. **서버 응답 수신**: ServerInitPayload 수신 및 검증
311
-5. **세션 키 파생**: 클라이언트 암호화/복호화 키 파생
312
-6. **SecureConnection 생성**: 암호화된 연결 설정
313
-
314
-#### 2.2 서버 핸드셰이크
315
-
316
-1. **클라이언트 요청 수신**: ClientInitPayload 수신
317
-2. **클라이언트 검증**:
318
- - 프로토콜 버전 확인
319
- - 타임스탬프 유효성 검증 (30초 이내)
320
- - ALPN 일치 확인
321
- - 신원 정보 유효성 검증
322
- - Ed25519 서명 검증
323
-3. **임시 키 생성**: X25519 임시 키 쌍 생성
324
-4. **ServerInitPayload 생성**: 클라이언트와 유사한 구조로 서버 정보 생성
325
-5. **세션 키 파생**: 서버 암호화/복호화 키 파생
326
-6. **응답 전송 및 SecureConnection 생성**
327
-
328
-#### 2.3 세션 키 파생
329
-
330
-```go
331
-// 클라이언트 측
332
-clientEncryptKey, clientDecryptKey, err := h.deriveClientSessionKeys(
333
- clientPriv, clientPub, serverPub, clientNonce, serverNonce)
334
-
335
-// 서버 측
336
-serverEncryptKey, serverDecryptKey, err := h.deriveServerSessionKeys(
337
- serverPriv, serverPub, clientPub, clientNonce, serverNonce)
338
-```
339
-
340
-- X25519를 사용하여 공유 비밀 계산
341
-- HKDF-SHA256을 사용하여 세션 키 파생
342
-- 클라이언트 암호화 키 = 서버 복호화 키
343
-- 서버 암호화 키 = 클라이언트 복호화 키
344
-- 솔트(salt)로 nonce 조합 사용:
345
- - 클라이언트 암호화: `clientNonce + serverNonce`
346
- - 서버 암호화: `serverNonce + clientNonce`
347
-- 정보 문자열(info): "RDSEC_KEY_CLIENT" / "RDSEC_KEY_SERVER"
348
-
349
-#### 2.4 암호화된 통신
350
-
351
-```go
352
-type SecureConnection struct {
353
- conn io.ReadWriteCloser // 기본 연결
354
- encryptor cipher.AEAD // 암호화기 (ChaCha20Poly1305)
355
- decryptor cipher.AEAD // 복호화기 (ChaCha20Poly1305)
356
- encryptNonce []byte // 암호화용 nonce
357
- decryptNonce []byte // 복호화용 nonce
358
-}
359
-```
360
-
361
-- 각 메시지마다 nonce 증가 (간단한 바이트 단위 증가)
362
-- 길이 접두사가 있는 메시지 형식 사용:
363
- ```
364
- [4바이트 길이][데이터]
365
- ```
366
-- 최대 패킷 크기: 64MB
367
-- EncryptedData protobuf 메시지로 암호화된 데이터 전송:
368
- ```protobuf
369
- message EncryptedData {
370
- bytes nonce = 1; // 12바이트 nonce
371
- bytes payload = 2; // 암호화된 페이로드
372
- }
373
- ```
374
-
375
-#### 2.5 길이 접두사 메시지 처리
376
-
377
-핸드셰이크와 암호화된 통신에서 사용되는 공통 메시지 형식:
378
-
379
-```go
380
-// 쓰기: [4바이트 길이][데이터]
381
-func writeLengthPrefixed(conn io.Writer, data []byte) error
382
-
383
-// 읽기: [4바이트 길이][데이터]
384
-func readLengthPrefixed(conn io.Reader) ([]byte, error)
385
-```
386
-
387
-- 빅 엔디안 형식으로 길이 인코딩
388
-- 패킷 크기 제한으로 메모리 과사용 방지
389
-- 전송 계층에서의 메시지 경계 명확화
390
-
391
-### 3. WebSocket 스트림 지원
392
-
393
-#### 3.1 wsStream 구조체
394
-
395
-```go
396
-type wsStream struct {
397
- c *websocket.Conn // WebSocket 연결
398
- currentReader io.Reader // 현재 읽기 리더
399
-}
400
-```
401
-
402
-#### 3.2 WebSocket 스트림 동작
403
-
404
-1. **읽기 동작**:
405
- - WebSocket 메시지 리더를 가져옴
406
- - 데이터를 버퍼로 읽음
407
- - EOF 발생 시 다음 메시지를 위해 리더 재설정
408
-
409
-2. **쓰기 동작**:
410
- - 바이너리 메시지 타입으로 데이터 전송
411
- - WebSocket 프레이밍 자동 처리
412
-
413
-3. **닫기 동작**:
414
- - WebSocket 연결 종료
415
-
416
-## 프로토콜 상세
417
-
418
-### 1. 패킷 형식
419
-
420
-모든 통신은 다음과 같은 구조를 따릅니다:
421
-
422
-```
423
-[4바이트 길이][패킷 데이터]
424
-```
425
-
426
-패킷 데이터는 protobuf로 직렬화된 `Packet` 메시지:
427
-
428
-```protobuf
429
-message Packet {
430
- PacketType type = 1; // 패킷 타입
431
- bytes payload = 2; // 페이로드
432
-}
433
-```
434
-
435
-### 2. 메시지 타입별 상세
436
-
437
-#### 2.1 릴레이 정보 요청/응답
438
-
439
-- **요청**: `RelayInfoRequest` (빈 메시지)
440
-- **응답**: `RelayInfoResponse`
441
- ```protobuf
442
- message RelayInfo {
443
- rdsec.Identity identity = 1; // 서버 신원
444
- repeated string address = 2; // 서버 주소 목록
445
- repeated string leases = 3; // 활성 리스 ID 목록
446
- }
447
- ```
448
-
449
-#### 2.2 리스 업데이트 요청/응답
450
-
451
-- **요청**: `LeaseUpdateRequest` (SignedPayload로 래핑)
452
- ```protobuf
453
- message LeaseUpdateRequest {
454
- Lease lease = 1; // 리스 정보
455
- bytes nonce = 2; // nonce
456
- int64 timestamp = 3; // 타임스탬프
457
- }
458
-
459
- message Lease {
460
- rdsec.Identity identity = 1; // 클라이언트 신원
461
- int64 expires = 2; // 만료 시간 (Unix 타임스탬프)
462
- string name = 3; // 리스 이름
463
- repeated string alpn = 4; // 지원 ALPN 목록
464
- }
465
- ```
466
-
467
-- **응답**: `LeaseUpdateResponse`
468
- ```protobuf
469
- message LeaseUpdateResponse {
470
- ResponseCode code = 1; // 응답 코드
471
- }
472
- ```
473
-
474
-#### 2.3 리스 삭제 요청/응답
475
-
476
-- **요청**: `LeaseDeleteRequest` (SignedPayload로 래핑)
477
- ```protobuf
478
- message LeaseDeleteRequest {
479
- rdsec.Identity identity = 1; // 삭제할 신원
480
- bytes nonce = 2; // nonce
481
- int64 timestamp = 3; // 타임스탬프
482
- }
483
- ```
484
-
485
-- **응답**: `LeaseDeleteResponse`
486
- ```protobuf
487
- message LeaseDeleteResponse {
488
- ResponseCode code = 1; // 응답 코드
489
- }
490
- ```
491
-
492
-#### 2.4 연결 요청/응답
493
-
494
-- **요청**: `ConnectionRequest`
495
- ```protobuf
496
- message ConnectionRequest {
497
- string lease_id = 1; // 대상 리스 ID
498
- rdsec.Identity client_identity = 2; // 클라이언트 신원
499
- }
500
- ```
501
-
502
-- **응답**: `ConnectionResponse`
503
- ```protobuf
504
- message ConnectionResponse {
505
- ResponseCode code = 1; // 응답 코드
506
- }
507
- ```
508
-
509
-## 성능 최적화
510
-
511
-1. **다중화**: yamux를 사용한 단일 연결 위의 다중 스트림
512
-2. **동시성**: 각 스트림과 연결을 독립적인 고루틴으로 처리
513
-3. **버퍼 풀**: bytebufferpool을 사용한 메모리 할당 최적화
514
-4. **락 최적화**: 읽기/쓰기 락을 사용한 동시 접근 최적화
515
-5. **암호화 최적화**: ChaCha20Poly1305를 사용한 고성능 암호화
516
-6. **네트워크 최적화**: 길이 접두사가 있는 바이너리 프로토콜 사용
517
-
518
-## 확장성 고려사항
519
-
520
-1. **프로토콜 버전 관리**: protobuf를 사용한 안전한 프로토콜 진화
521
-2. **ALPN 지원**: 다양한 애플리케이션 프로토콜 지원
522
-3. **플러그인 아키텍처**: 핸들러 기반의 확장 가능한 요청 처리
523
-4. **모듈형 설계**: 암호화, 리스 관리, 연결 관리의 분리
524
-
525
-이 문서는 RelayServer의 핵심 동작과 구조를 상세하게 설명하며, 시스템의 이해와 유지보수에 도움을 제공합니다.
\ No newline at end of file