├── .github └── workflows │ └── test.yml ├── .gitignore ├── LICENSE ├── client.go ├── common ├── buf │ ├── buffer.go │ ├── multi.go │ └── pool.go ├── cond.go ├── const.go ├── exceptions │ └── error.go ├── list │ ├── cond.go │ └── list.go ├── rw │ ├── read.go │ └── write.go └── socksaddr │ ├── addr.go │ ├── exception.go │ ├── family.go │ └── serializer.go ├── go.mod ├── go.sum ├── resolver.go ├── server.go ├── uot.go └── uot_test.go /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - '**.md' 9 | - '.github/**' 10 | - '!.github/workflows/test.yml' 11 | pull_request: 12 | branches: 13 | - main 14 | 15 | jobs: 16 | build: 17 | name: Test 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v2 22 | - name: Install Golang 23 | uses: actions/setup-go@v2 24 | with: 25 | stable: false 26 | go-version: 1.18.0 27 | - name: Get project dependencies 28 | run: go mod download -x 29 | - name: Run test 30 | run: go test -v ./... -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 nekohasekai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /client.go: -------------------------------------------------------------------------------- 1 | package uot 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | "net" 7 | 8 | "github.com/sagernet/uot/common/socksaddr" 9 | ) 10 | 11 | type ClientConn struct { 12 | net.Conn 13 | } 14 | 15 | func NewClientConn(conn net.Conn) net.PacketConn { 16 | return &ClientConn{conn} 17 | } 18 | 19 | func (c *ClientConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { 20 | address, port, err := AddrParser.ReadAddressAndPort(c) 21 | if err != nil { 22 | return 0, nil, err 23 | } 24 | var length uint16 25 | err = binary.Read(c, binary.BigEndian, &length) 26 | if err != nil { 27 | return 0, nil, err 28 | } 29 | if len(p) < int(length) { 30 | return 0, nil, io.ErrShortBuffer 31 | } 32 | n, err = io.ReadAtLeast(c, p, int(length)) 33 | if err != nil { 34 | return 0, nil, err 35 | } 36 | addr = &net.UDPAddr{ 37 | IP: address.Addr().AsSlice(), 38 | Port: int(port), 39 | } 40 | return 41 | } 42 | 43 | func (c *ClientConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { 44 | address, port := socksaddr.AddressFromNetAddr(addr) 45 | err = AddrParser.WriteAddressAndPort(c, address, port) 46 | if err != nil { 47 | return 48 | } 49 | err = binary.Write(c, binary.BigEndian, uint16(len(p))) 50 | if err != nil { 51 | return 52 | } 53 | return c.Write(p) 54 | } 55 | -------------------------------------------------------------------------------- /common/buf/buffer.go: -------------------------------------------------------------------------------- 1 | package buf 2 | 3 | import ( 4 | "crypto/rand" 5 | "fmt" 6 | "io" 7 | "net" 8 | 9 | "github.com/sagernet/uot/common" 10 | "github.com/sagernet/uot/common/list" 11 | ) 12 | 13 | type Buffer struct { 14 | data []byte 15 | start int 16 | end int 17 | managed bool 18 | } 19 | 20 | func New() *Buffer { 21 | return &Buffer{ 22 | data: GetBytes(), 23 | start: ReversedHeader, 24 | end: ReversedHeader, 25 | managed: true, 26 | } 27 | } 28 | 29 | func FullNew() *Buffer { 30 | return &Buffer{ 31 | data: GetBytes(), 32 | managed: true, 33 | } 34 | } 35 | 36 | func StackNew() Buffer { 37 | return Buffer{ 38 | data: GetBytes(), 39 | managed: true, 40 | } 41 | } 42 | 43 | func From(data []byte) *Buffer { 44 | buffer := New() 45 | buffer.Write(data) 46 | return buffer 47 | } 48 | 49 | func As(data []byte) *Buffer { 50 | size := len(data) 51 | max := cap(data) 52 | if size != max { 53 | data = data[:max] 54 | } 55 | return &Buffer{ 56 | data: data, 57 | end: size, 58 | } 59 | } 60 | 61 | func With(data []byte) *Buffer { 62 | return &Buffer{ 63 | data: data, 64 | } 65 | } 66 | 67 | func (b *Buffer) Byte(index int) byte { 68 | return b.data[b.start+index] 69 | } 70 | 71 | func (b *Buffer) SetByte(index int, value byte) { 72 | b.data[b.start+index] = value 73 | } 74 | 75 | func (b *Buffer) Extend(n int) []byte { 76 | if b.start == b.end { 77 | b.start = 0 78 | b.end = n 79 | return b.data[:n] 80 | } 81 | end := b.end + n 82 | ext := b.data[b.end:end] 83 | b.end = end 84 | return ext 85 | } 86 | 87 | func (b *Buffer) Advance(from int) { 88 | b.start += from 89 | } 90 | 91 | func (b *Buffer) Truncate(to int) { 92 | b.end = b.start + to 93 | } 94 | 95 | func (b *Buffer) Write(data []byte) (n int, err error) { 96 | if b.IsFull() { 97 | return 0, io.ErrShortBuffer 98 | } 99 | n = copy(b.data[b.end:], data) 100 | b.end += n 101 | return 102 | } 103 | 104 | func (b *Buffer) WriteAtFirst(data []byte) (n int, err error) { 105 | size := len(data) 106 | if b.start >= size { 107 | n = copy(b.data[b.start-size:b.start], data) 108 | b.start -= n 109 | return 110 | } 111 | 112 | offset := size - b.start 113 | copy(b.data[offset:], b.data[b.start:b.end]) 114 | n = copy(b.data[:offset], data) 115 | b.end += offset 116 | return 117 | } 118 | 119 | func (b *Buffer) WriteRandom(size int) { 120 | common.Must1(io.ReadFull(rand.Reader, b.Extend(size))) 121 | } 122 | 123 | func (b *Buffer) WriteByte(byte byte) error { 124 | if b.IsFull() { 125 | return io.ErrShortBuffer 126 | } 127 | b.data[b.end] = byte 128 | b.end++ 129 | return nil 130 | } 131 | 132 | func (b *Buffer) ReadFrom(r io.Reader) (int64, error) { 133 | if b.IsFull() { 134 | return 0, io.ErrShortBuffer 135 | } 136 | n, err := r.Read(b.FreeBytes()) 137 | if err != nil { 138 | return 0, err 139 | } 140 | b.end += n 141 | return int64(n), nil 142 | } 143 | 144 | func (b *Buffer) ReadPacketFrom(r net.PacketConn) (int64, net.Addr, error) { 145 | if b.IsFull() { 146 | return 0, nil, io.ErrShortBuffer 147 | } 148 | n, addr, err := r.ReadFrom(b.FreeBytes()) 149 | if err != nil { 150 | return 0, nil, err 151 | } 152 | b.end += n 153 | return int64(n), addr, nil 154 | } 155 | 156 | func (b *Buffer) ReadFullFrom(r io.Reader, size int) (n int, err error) { 157 | if b.IsFull() { 158 | return 0, io.ErrShortBuffer 159 | } 160 | end := b.end + size 161 | n, err = io.ReadFull(r, b.data[b.start:end]) 162 | if err != nil { 163 | return 0, err 164 | } 165 | b.end += n 166 | return 167 | } 168 | 169 | func (b *Buffer) WriteRune(s rune) (int, error) { 170 | return b.Write([]byte{byte(s)}) 171 | } 172 | 173 | func (b *Buffer) WriteString(s string) (int, error) { 174 | return b.Write([]byte(s)) 175 | } 176 | 177 | func (b *Buffer) WriteSprint(s ...any) (int, error) { 178 | return b.WriteString(fmt.Sprint(s...)) 179 | } 180 | 181 | func (b *Buffer) WriteZero() error { 182 | if b.IsFull() { 183 | return io.ErrShortBuffer 184 | } 185 | b.end++ 186 | b.data[b.end] = 0 187 | return nil 188 | } 189 | 190 | func (b *Buffer) WriteZeroN(n int) error { 191 | if b.end+n > b.Cap() { 192 | return io.ErrShortBuffer 193 | } 194 | for i := b.end; i <= b.end+n; i++ { 195 | b.data[i] = 0 196 | } 197 | b.end += n 198 | return nil 199 | } 200 | 201 | func (b *Buffer) ReadByte() (byte, error) { 202 | if b.IsEmpty() { 203 | return 0, io.EOF 204 | } 205 | 206 | nb := b.data[b.start] 207 | b.start++ 208 | return nb, nil 209 | } 210 | 211 | func (b *Buffer) ReadBytes(n int) ([]byte, error) { 212 | if b.end-b.start < n { 213 | return nil, io.EOF 214 | } 215 | 216 | nb := b.data[b.start : b.start+n] 217 | b.start += n 218 | return nb, nil 219 | } 220 | 221 | func (b *Buffer) Read(data []byte) (n int, err error) { 222 | if b.Len() == 0 { 223 | return 0, io.EOF 224 | } 225 | n = copy(data, b.data[b.start:b.end]) 226 | if n == b.Len() { 227 | b.Reset() 228 | } else { 229 | b.start += n 230 | } 231 | return n, nil 232 | } 233 | 234 | func (b *Buffer) WriteTo(w io.Writer) (int64, error) { 235 | n, err := w.Write(b.Bytes()) 236 | return int64(n), err 237 | } 238 | 239 | func (b *Buffer) Resize(start, end int) { 240 | b.start = start 241 | b.end = b.start + end 242 | } 243 | 244 | func (b *Buffer) Reset() { 245 | b.start = ReversedHeader 246 | b.end = ReversedHeader 247 | } 248 | 249 | func (b *Buffer) FullReset() { 250 | b.start = 0 251 | b.end = 0 252 | } 253 | 254 | func (b *Buffer) Release() { 255 | if b == nil || b.data == nil || !b.managed { 256 | return 257 | } 258 | PutBytes(b.data) 259 | *b = Buffer{} 260 | } 261 | 262 | func (b Buffer) Len() int { 263 | return b.end - b.start 264 | } 265 | 266 | func (b Buffer) Cap() int { 267 | return cap(b.data) 268 | } 269 | 270 | func (b Buffer) Bytes() []byte { 271 | return b.data[b.start:b.end] 272 | } 273 | 274 | func (b Buffer) Slice() []byte { 275 | return b.data 276 | } 277 | 278 | func (b Buffer) From(n int) []byte { 279 | return b.data[b.start+n : b.end] 280 | } 281 | 282 | func (b Buffer) To(n int) []byte { 283 | return b.data[b.start : b.start+n] 284 | } 285 | 286 | func (b Buffer) Index(start int) []byte { 287 | return b.data[b.start+start : b.start+start] 288 | } 289 | 290 | func (b Buffer) FreeLen() int { 291 | return b.Cap() - b.end 292 | } 293 | 294 | func (b Buffer) FreeBytes() []byte { 295 | return b.data[b.end:b.Cap()] 296 | } 297 | 298 | func (b Buffer) IsEmpty() bool { 299 | return b.end-b.start == 0 300 | } 301 | 302 | func (b Buffer) IsFull() bool { 303 | return b.end == b.Cap() 304 | } 305 | 306 | func (b Buffer) ToOwned() *Buffer { 307 | var buffer *Buffer 308 | if b.Len() > BufferSize { 309 | buffer = As(make([]byte, b.Len())) 310 | copy(buffer.data, b.Bytes()) 311 | } else { 312 | buffer = New() 313 | buffer.Write(b.Bytes()) 314 | } 315 | return buffer 316 | } 317 | 318 | func (b Buffer) Copy() []byte { 319 | buffer := make([]byte, b.Len()) 320 | copy(buffer, b.Bytes()) 321 | return buffer 322 | } 323 | 324 | func ReleaseMulti(mb *list.List[*Buffer]) { 325 | for entry := mb.Front(); entry != nil; entry = entry.Next() { 326 | // TODO: remove cast 327 | var buffer *Buffer = entry.Value 328 | buffer.Release() 329 | } 330 | } 331 | 332 | func ForeachN(b []byte, size int) [][]byte { 333 | total := len(b) 334 | var index int 335 | var retArr [][]byte 336 | for { 337 | nextIndex := index + size 338 | if nextIndex < total { 339 | retArr = append(retArr, b[index:nextIndex]) 340 | index = nextIndex 341 | } else { 342 | retArr = append(retArr, b[index:]) 343 | break 344 | } 345 | } 346 | return retArr 347 | } 348 | -------------------------------------------------------------------------------- /common/buf/multi.go: -------------------------------------------------------------------------------- 1 | package buf 2 | 3 | type MultiBuffer struct { 4 | buffers []*Buffer 5 | index int 6 | } 7 | 8 | func (b MultiBuffer) Size() int { 9 | return len(b.buffers) 10 | } 11 | 12 | func (b MultiBuffer) Len() int { 13 | var length int 14 | for _, buffer := range b.buffers { 15 | length += buffer.Len() 16 | } 17 | return length 18 | } 19 | 20 | func (b *MultiBuffer) Release() { 21 | for _, buffer := range b.buffers { 22 | buffer.Release() 23 | } 24 | b.buffers = nil 25 | b.index = 0 26 | } 27 | 28 | func (b MultiBuffer) From(n int) MultiBuffer { 29 | var newBuffer MultiBuffer 30 | for _, buffer := range b.buffers { 31 | if n == 0 { 32 | newBuffer.buffers = append(newBuffer.buffers, buffer) 33 | } else if buffer.Len() < n { 34 | n -= buffer.Len() 35 | } else { 36 | newBuffer.buffers = append(newBuffer.buffers, As(buffer.From(n))) 37 | n = 0 38 | } 39 | } 40 | return newBuffer 41 | } 42 | 43 | func (b *MultiBuffer) BufferForWrite() *Buffer { 44 | var buffer *Buffer 45 | if b.Size() > 0 && !b.buffers[b.index].IsFull() { 46 | buffer = b.buffers[b.index] 47 | } else { 48 | buffer = New() 49 | b.buffers = append(b.buffers, buffer) 50 | b.index++ 51 | } 52 | return buffer 53 | } 54 | 55 | func (b *MultiBuffer) Write(data []byte) (n int, err error) { 56 | size := len(data) 57 | var wn int 58 | for wn < size { 59 | n, err = b.BufferForWrite().Write(data) 60 | if err != nil { 61 | return 0, err 62 | } 63 | wn += n 64 | } 65 | return wn, nil 66 | } 67 | 68 | func (b *MultiBuffer) WriteAtFirst(data []byte) (n int, err error) { 69 | length := len(data) 70 | if b.Size() > 0 { 71 | buffer := b.buffers[0] 72 | if buffer.start > 0 { 73 | n = copy(buffer.data[:buffer.start], data[length-buffer.start:length]) 74 | buffer.start -= n 75 | } 76 | } 77 | if n < length { 78 | b.buffers = append([]*Buffer{As(data[n:length])}, b.buffers...) 79 | b.index++ 80 | } 81 | return 82 | } 83 | 84 | func (b *MultiBuffer) WriteMulti(data *MultiBuffer) (n int, err error) { 85 | defer data.Release() 86 | for _, buffer := range data.buffers { 87 | writeN, err := b.Write(buffer.Bytes()) 88 | if err != nil { 89 | return 0, err 90 | } 91 | n += writeN 92 | } 93 | return 94 | } 95 | 96 | func (b *MultiBuffer) WriteString(str string) (n int, err error) { 97 | return b.Write([]byte(str)) 98 | } 99 | -------------------------------------------------------------------------------- /common/buf/pool.go: -------------------------------------------------------------------------------- 1 | package buf 2 | 3 | import "sync" 4 | 5 | const ( 6 | ReversedHeader = 1024 7 | BufferSize = 20 * 1024 8 | UDPBufferSize = 16 * 1024 9 | ) 10 | 11 | var pool = sync.Pool{ 12 | New: func() any { 13 | var buffer [BufferSize]byte 14 | return buffer[:] 15 | }, 16 | } 17 | 18 | func GetBytes() []byte { 19 | return pool.Get().([]byte) 20 | } 21 | 22 | func PutBytes(buffer []byte) { 23 | pool.Put(buffer) 24 | } 25 | -------------------------------------------------------------------------------- /common/cond.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "strings" 7 | ) 8 | 9 | func Any[T any](array []T, block func(it T) bool) bool { 10 | for _, it := range array { 11 | if block(it) { 12 | return true 13 | } 14 | } 15 | return true 16 | } 17 | 18 | func Contains[T comparable](arr []T, target T) bool { 19 | for i := range arr { 20 | if target == arr[i] { 21 | return true 22 | } 23 | } 24 | return false 25 | } 26 | 27 | func Map[T any, N any](arr []T, block func(it T) N) []N { 28 | var retArr []N 29 | for index := range arr { 30 | retArr = append(retArr, block(arr[index])) 31 | } 32 | return retArr 33 | } 34 | 35 | func Filter[T any](arr []T, block func(it T) bool) []T { 36 | var retArr []T 37 | for _, it := range arr { 38 | if block(it) { 39 | retArr = append(retArr, it) 40 | } 41 | } 42 | return retArr 43 | } 44 | 45 | func Done(ctx context.Context) bool { 46 | select { 47 | case <-ctx.Done(): 48 | return true 49 | default: 50 | return false 51 | } 52 | } 53 | 54 | func IsEmpty[T any](array []T) bool { 55 | return len(array) == 0 56 | } 57 | 58 | func IsNotEmpty[T any](array []T) bool { 59 | return len(array) >= 0 60 | } 61 | 62 | func IsBlank(str string) bool { 63 | return strings.TrimSpace(str) == EmptyString 64 | } 65 | 66 | func IsNotBlank(str string) bool { 67 | return strings.TrimSpace(str) != EmptyString 68 | } 69 | 70 | func Error(_ any, err error) error { 71 | return err 72 | } 73 | 74 | func Must(err error) { 75 | if err != nil { 76 | log.Fatalln(err) 77 | } 78 | } 79 | 80 | func Must1(_ any, err error) { 81 | if err != nil { 82 | log.Fatalln(err) 83 | } 84 | } 85 | 86 | func Must2(_ any, _ any, err error) { 87 | if err != nil { 88 | log.Fatalln(err) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /common/const.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | const EmptyString = "" 4 | 5 | type DummyAddr struct{} 6 | 7 | func (d *DummyAddr) Network() string { 8 | return "dummy" 9 | } 10 | 11 | func (d *DummyAddr) String() string { 12 | return "dummy" 13 | } 14 | -------------------------------------------------------------------------------- /common/exceptions/error.go: -------------------------------------------------------------------------------- 1 | package exceptions 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | type Exception interface { 9 | error 10 | Cause() error 11 | } 12 | 13 | type SuppressedException interface { 14 | error 15 | Suppressed() error 16 | } 17 | 18 | type exception struct { 19 | message string 20 | cause error 21 | } 22 | 23 | func (e exception) Error() string { 24 | if e.cause == nil { 25 | return e.message 26 | } 27 | return e.message + ":" + e.cause.Error() 28 | } 29 | 30 | func (e exception) Cause() error { 31 | return e.cause 32 | } 33 | 34 | func New(message ...any) error { 35 | return errors.New(fmt.Sprint(message...)) 36 | } 37 | 38 | func Cause(cause error, message ...any) Exception { 39 | return &exception{fmt.Sprint(message...), cause} 40 | } 41 | -------------------------------------------------------------------------------- /common/list/cond.go: -------------------------------------------------------------------------------- 1 | package list 2 | 3 | func (l List[T]) IsEmpty() bool { 4 | return l.len == 0 5 | } 6 | 7 | func (l *List[T]) PopBack() T { 8 | if l.len == 0 { 9 | var defaultValue T 10 | return defaultValue 11 | } 12 | entry := l.root.prev 13 | l.remove(entry) 14 | return entry.Value 15 | } 16 | 17 | func (l *List[T]) PopFront() T { 18 | if l.len == 0 { 19 | var defaultValue T 20 | return defaultValue 21 | } 22 | entry := l.root.next 23 | l.remove(entry) 24 | return entry.Value 25 | } 26 | 27 | func (l *List[T]) Array() []T { 28 | if l.len == 0 { 29 | return nil 30 | } 31 | array := make([]T, 0, l.len) 32 | for element := l.Front(); element != nil; element = element.Next() { 33 | array = append(array, element.Value) 34 | } 35 | return array 36 | } 37 | -------------------------------------------------------------------------------- /common/list/list.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package list implements a doubly linked list. 6 | // 7 | // To iterate over a list (where l is a *List[T]): 8 | // for e := l.Front(); e != nil; e = e.Next() { 9 | // // do something with e.Value 10 | // } 11 | // 12 | package list 13 | 14 | // Element is an element of a linked list. 15 | type Element[T any] struct { 16 | // Next and previous pointers in the doubly-linked list of elements. 17 | // To simplify the implementation, internally a list l is implemented 18 | // as a ring, such that &l.root is both the next element of the last 19 | // list element (l.Back()) and the previous element of the first list 20 | // element (l.Front()). 21 | next, prev *Element[T] 22 | 23 | // The list to which this element belongs. 24 | list *List[T] 25 | 26 | // The value stored with this element. 27 | Value T 28 | } 29 | 30 | // Next returns the next list element or nil. 31 | func (e *Element[T]) Next() *Element[T] { 32 | if p := e.next; e.list != nil && p != &e.list.root { 33 | return p 34 | } 35 | return nil 36 | } 37 | 38 | // Prev returns the previous list element or nil. 39 | func (e *Element[T]) Prev() *Element[T] { 40 | if p := e.prev; e.list != nil && p != &e.list.root { 41 | return p 42 | } 43 | return nil 44 | } 45 | 46 | // List represents a doubly linked list. 47 | // The zero value for List is an empty list ready to use. 48 | type List[T any] struct { 49 | root Element[T] // sentinel list element, only &root, root.prev, and root.next are used 50 | len int // current list length excluding (this) sentinel element 51 | } 52 | 53 | // Init initializes or clears list l. 54 | func (l *List[T]) Init() *List[T] { 55 | l.root.next = &l.root 56 | l.root.prev = &l.root 57 | l.len = 0 58 | return l 59 | } 60 | 61 | // Len returns the number of elements of list l. 62 | // The complexity is O(1). 63 | func (l *List[T]) Len() int { return l.len } 64 | 65 | // Front returns the first element of list l or nil if the list is empty. 66 | func (l *List[T]) Front() *Element[T] { 67 | if l.len == 0 { 68 | return nil 69 | } 70 | return l.root.next 71 | } 72 | 73 | // Back returns the last element of list l or nil if the list is empty. 74 | func (l *List[T]) Back() *Element[T] { 75 | if l.len == 0 { 76 | return nil 77 | } 78 | return l.root.prev 79 | } 80 | 81 | // lazyInit lazily initializes a zero List value. 82 | func (l *List[T]) lazyInit() { 83 | if l.root.next == nil { 84 | l.Init() 85 | } 86 | } 87 | 88 | // insert inserts e after at, increments l.len, and returns e. 89 | func (l *List[T]) insert(e, at *Element[T]) *Element[T] { 90 | e.prev = at 91 | e.next = at.next 92 | e.prev.next = e 93 | e.next.prev = e 94 | e.list = l 95 | l.len++ 96 | return e 97 | } 98 | 99 | // insertValue is a convenience wrapper for insert(&Element{Value: v}, at). 100 | func (l *List[T]) insertValue(v any, at *Element[T]) *Element[T] { 101 | e := new(Element[T]) 102 | e.Value = v.(T) 103 | return l.insert(e, at) 104 | } 105 | 106 | // remove removes e from its list, decrements l.len 107 | func (l *List[T]) remove(e *Element[T]) { 108 | e.prev.next = e.next 109 | e.next.prev = e.prev 110 | e.next = nil // avoid memory leaks 111 | e.prev = nil // avoid memory leaks 112 | e.list = nil 113 | l.len-- 114 | } 115 | 116 | // move moves e to next to at. 117 | func (l *List[T]) move(e, at *Element[T]) { 118 | if e == at { 119 | return 120 | } 121 | e.prev.next = e.next 122 | e.next.prev = e.prev 123 | 124 | e.prev = at 125 | e.next = at.next 126 | e.prev.next = e 127 | e.next.prev = e 128 | } 129 | 130 | // Remove removes e from l if e is an element of list l. 131 | // It returns the element value e.Value. 132 | // The element must not be nil. 133 | func (l *List[T]) Remove(e *Element[T]) any { 134 | if e.list == l { 135 | // if e.list == l, l must have been initialized when e was inserted 136 | // in l or l == nil (e is a zero Element) and l.remove will crash 137 | l.remove(e) 138 | } 139 | return e.Value 140 | } 141 | 142 | // PushFront inserts a new element e with value v at the front of list l and returns e. 143 | func (l *List[T]) PushFront(v T) *Element[T] { 144 | l.lazyInit() 145 | return l.insertValue(v, &l.root) 146 | } 147 | 148 | // PushBack inserts a new element e with value v at the back of list l and returns e. 149 | func (l *List[T]) PushBack(v T) *Element[T] { 150 | l.lazyInit() 151 | return l.insertValue(v, l.root.prev) 152 | } 153 | 154 | // InsertBefore inserts a new element e with value v immediately before mark and returns e. 155 | // If mark is not an element of l, the list is not modified. 156 | // The mark must not be nil. 157 | func (l *List[T]) InsertBefore(v T, mark *Element[T]) *Element[T] { 158 | if mark.list != l { 159 | return nil 160 | } 161 | // see comment in List.Remove about initialization of l 162 | return l.insertValue(v, mark.prev) 163 | } 164 | 165 | // InsertAfter inserts a new element e with value v immediately after mark and returns e. 166 | // If mark is not an element of l, the list is not modified. 167 | // The mark must not be nil. 168 | func (l *List[T]) InsertAfter(v T, mark *Element[T]) *Element[T] { 169 | if mark.list != l { 170 | return nil 171 | } 172 | // see comment in List.Remove about initialization of l 173 | return l.insertValue(v, mark) 174 | } 175 | 176 | // MoveToFront moves element e to the front of list l. 177 | // If e is not an element of l, the list is not modified. 178 | // The element must not be nil. 179 | func (l *List[T]) MoveToFront(e *Element[T]) { 180 | if e.list != l || l.root.next == e { 181 | return 182 | } 183 | // see comment in List.Remove about initialization of l 184 | l.move(e, &l.root) 185 | } 186 | 187 | // MoveToBack moves element e to the back of list l. 188 | // If e is not an element of l, the list is not modified. 189 | // The element must not be nil. 190 | func (l *List[T]) MoveToBack(e *Element[T]) { 191 | if e.list != l || l.root.prev == e { 192 | return 193 | } 194 | // see comment in List.Remove about initialization of l 195 | l.move(e, l.root.prev) 196 | } 197 | 198 | // MoveBefore moves element e to its new position before mark. 199 | // If e or mark is not an element of l, or e == mark, the list is not modified. 200 | // The element and mark must not be nil. 201 | func (l *List[T]) MoveBefore(e, mark *Element[T]) { 202 | if e.list != l || e == mark || mark.list != l { 203 | return 204 | } 205 | l.move(e, mark.prev) 206 | } 207 | 208 | // MoveAfter moves element e to its new position after mark. 209 | // If e or mark is not an element of l, or e == mark, the list is not modified. 210 | // The element and mark must not be nil. 211 | func (l *List[T]) MoveAfter(e, mark *Element[T]) { 212 | if e.list != l || e == mark || mark.list != l { 213 | return 214 | } 215 | l.move(e, mark) 216 | } 217 | 218 | // PushBackList inserts a copy of another list at the back of list l. 219 | // The lists l and other may be the same. They must not be nil. 220 | func (l *List[T]) PushBackList(other *List[T]) { 221 | l.lazyInit() 222 | for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { 223 | l.insertValue(e.Value, l.root.prev) 224 | } 225 | } 226 | 227 | // PushFrontList inserts a copy of another list at the front of list l. 228 | // The lists l and other may be the same. They must not be nil. 229 | func (l *List[T]) PushFrontList(other *List[T]) { 230 | l.lazyInit() 231 | for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { 232 | l.insertValue(e.Value, &l.root) 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /common/rw/read.go: -------------------------------------------------------------------------------- 1 | package rw 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/sagernet/uot/common" 7 | ) 8 | 9 | func Skip(reader io.Reader) error { 10 | return SkipN(reader, 1) 11 | } 12 | 13 | func SkipN(reader io.Reader, size int) error { 14 | return common.Error(ReadBytes(reader, size)) 15 | } 16 | 17 | func ReadByte(reader io.Reader) (byte, error) { 18 | var b [1]byte 19 | if err := common.Error(io.ReadFull(reader, b[:])); err != nil { 20 | return 0, err 21 | } 22 | return b[0], nil 23 | } 24 | 25 | func ReadBytes(reader io.Reader, size int) ([]byte, error) { 26 | b := make([]byte, size) 27 | if err := common.Error(io.ReadFull(reader, b[:])); err != nil { 28 | return nil, err 29 | } 30 | return b, nil 31 | } 32 | 33 | func ReadString(reader io.Reader, size int) (string, error) { 34 | b, err := ReadBytes(reader, size) 35 | if err != nil { 36 | return common.EmptyString, err 37 | } 38 | return string(b), nil 39 | } 40 | -------------------------------------------------------------------------------- /common/rw/write.go: -------------------------------------------------------------------------------- 1 | package rw 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/sagernet/uot/common" 7 | ) 8 | 9 | var ZeroBytes = make([]byte, 1024) 10 | 11 | func WriteByte(writer io.Writer, b byte) error { 12 | return common.Error(writer.Write([]byte{b})) 13 | } 14 | 15 | func WriteBytes(writer io.Writer, b []byte) error { 16 | return common.Error(writer.Write(b)) 17 | } 18 | 19 | func WriteZero(writer io.Writer) error { 20 | return WriteByte(writer, 0) 21 | } 22 | 23 | func WriteZeroN(writer io.Writer, size int) error { 24 | var index int 25 | for index < size { 26 | next := index + 1024 27 | if next < size { 28 | _, err := writer.Write(ZeroBytes) 29 | if err != nil { 30 | return err 31 | } 32 | index = next 33 | } else { 34 | _, err := writer.Write(ZeroBytes[:size-index]) 35 | return err 36 | } 37 | } 38 | return nil 39 | } 40 | 41 | func WriteString(writer io.Writer, str string) error { 42 | return WriteBytes(writer, []byte(str)) 43 | } 44 | -------------------------------------------------------------------------------- /common/socksaddr/addr.go: -------------------------------------------------------------------------------- 1 | package socksaddr 2 | 3 | import ( 4 | "net" 5 | 6 | "net/netip" 7 | ) 8 | 9 | type Addr interface { 10 | Family() Family 11 | Addr() netip.Addr 12 | Fqdn() string 13 | String() string 14 | } 15 | 16 | func AddrFromIP(ip net.IP) Addr { 17 | addr, _ := netip.AddrFromSlice(ip) 18 | if addr.Is4() { 19 | return Addr4(addr.As4()) 20 | } else { 21 | return Addr16(addr.As16()) 22 | } 23 | } 24 | 25 | func AddressFromNetAddr(netAddr net.Addr) (addr Addr, port uint16) { 26 | var ip net.IP 27 | switch addr := netAddr.(type) { 28 | case *net.TCPAddr: 29 | ip = addr.IP 30 | port = uint16(addr.Port) 31 | case *net.UDPAddr: 32 | ip = addr.IP 33 | port = uint16(addr.Port) 34 | } 35 | return AddrFromIP(ip), port 36 | } 37 | 38 | func AddrFromFqdn(fqdn string) Addr { 39 | return AddrFqdn(fqdn) 40 | } 41 | 42 | type Addr4 [4]byte 43 | 44 | func (a Addr4) Family() Family { 45 | return AddressFamilyIPv4 46 | } 47 | 48 | func (a Addr4) Addr() netip.Addr { 49 | return netip.AddrFrom4(a) 50 | } 51 | 52 | func (a Addr4) Fqdn() string { 53 | return "" 54 | } 55 | 56 | func (a Addr4) String() string { 57 | return net.IP(a[:]).String() 58 | } 59 | 60 | type Addr16 [16]byte 61 | 62 | func (a Addr16) Family() Family { 63 | return AddressFamilyIPv6 64 | } 65 | 66 | func (a Addr16) Addr() netip.Addr { 67 | return netip.AddrFrom16(a) 68 | } 69 | 70 | func (a Addr16) Fqdn() string { 71 | return "" 72 | } 73 | 74 | func (a Addr16) String() string { 75 | return net.IP(a[:]).String() 76 | } 77 | 78 | type AddrFqdn string 79 | 80 | func (f AddrFqdn) Family() Family { 81 | return AddressFamilyFqdn 82 | } 83 | 84 | func (f AddrFqdn) Addr() netip.Addr { 85 | return netip.Addr{} 86 | } 87 | 88 | func (f AddrFqdn) Fqdn() string { 89 | return string(f) 90 | } 91 | 92 | func (f AddrFqdn) String() string { 93 | return string(f) 94 | } 95 | -------------------------------------------------------------------------------- /common/socksaddr/exception.go: -------------------------------------------------------------------------------- 1 | package socksaddr 2 | 3 | import "fmt" 4 | 5 | type StringTooLongException struct { 6 | Op string 7 | Len int 8 | } 9 | 10 | func (e StringTooLongException) Error() string { 11 | return fmt.Sprint(e.Op, " too long: length ", e.Len, ", max 255") 12 | } 13 | -------------------------------------------------------------------------------- /common/socksaddr/family.go: -------------------------------------------------------------------------------- 1 | package socksaddr 2 | 3 | type Family byte 4 | 5 | const ( 6 | AddressFamilyIPv4 Family = iota 7 | AddressFamilyIPv6 8 | AddressFamilyFqdn 9 | ) 10 | 11 | func (af Family) IsIPv4() bool { 12 | return af == AddressFamilyIPv4 13 | } 14 | 15 | func (af Family) IsIPv6() bool { 16 | return af == AddressFamilyIPv6 17 | } 18 | 19 | func (af Family) IsIP() bool { 20 | return af != AddressFamilyFqdn 21 | } 22 | 23 | func (af Family) IsFqdn() bool { 24 | return af == AddressFamilyFqdn 25 | } 26 | 27 | type FamilyParser func(byte) byte 28 | -------------------------------------------------------------------------------- /common/socksaddr/serializer.go: -------------------------------------------------------------------------------- 1 | package socksaddr 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | 7 | "github.com/sagernet/uot/common" 8 | "github.com/sagernet/uot/common/exceptions" 9 | "github.com/sagernet/uot/common/rw" 10 | ) 11 | 12 | type SerializerOption func(*Serializer) 13 | 14 | func AddressFamilyByte(b byte, f Family) SerializerOption { 15 | return func(s *Serializer) { 16 | s.familyMap[b] = f 17 | s.familyByteMap[f] = b 18 | } 19 | } 20 | 21 | func PortThenAddress() SerializerOption { 22 | return func(s *Serializer) { 23 | s.portFirst = true 24 | } 25 | } 26 | 27 | func WithFamilyParser(fp FamilyParser) SerializerOption { 28 | return func(s *Serializer) { 29 | s.familyParser = fp 30 | } 31 | } 32 | 33 | type Serializer struct { 34 | familyMap map[byte]Family 35 | familyByteMap map[Family]byte 36 | familyParser FamilyParser 37 | portFirst bool 38 | } 39 | 40 | func NewSerializer(options ...SerializerOption) *Serializer { 41 | s := &Serializer{ 42 | familyMap: make(map[byte]Family), 43 | familyByteMap: make(map[Family]byte), 44 | } 45 | for _, option := range options { 46 | option(s) 47 | } 48 | return s 49 | } 50 | 51 | func (s *Serializer) WriteAddress(writer io.Writer, addr Addr) error { 52 | err := rw.WriteByte(writer, s.familyByteMap[addr.Family()]) 53 | if err != nil { 54 | return err 55 | } 56 | if addr.Family().IsIP() { 57 | err = rw.WriteBytes(writer, addr.Addr().AsSlice()) 58 | } else { 59 | domain := addr.Fqdn() 60 | err = WriteString(writer, "fqdn", domain) 61 | } 62 | return err 63 | } 64 | 65 | func (s *Serializer) WritePort(writer io.Writer, port uint16) error { 66 | return binary.Write(writer, binary.BigEndian, port) 67 | } 68 | 69 | func (s *Serializer) WriteAddressAndPort(writer io.Writer, addr Addr, port uint16) error { 70 | var err error 71 | if !s.portFirst { 72 | err = s.WriteAddress(writer, addr) 73 | } else { 74 | err = s.WritePort(writer, port) 75 | } 76 | if err != nil { 77 | return err 78 | } 79 | if s.portFirst { 80 | err = s.WriteAddress(writer, addr) 81 | } else { 82 | err = s.WritePort(writer, port) 83 | } 84 | return err 85 | } 86 | 87 | func (s *Serializer) ReadAddress(reader io.Reader) (Addr, error) { 88 | af, err := rw.ReadByte(reader) 89 | if err != nil { 90 | return nil, err 91 | } 92 | if s.familyParser != nil { 93 | af = s.familyParser(af) 94 | } 95 | family := s.familyMap[af] 96 | switch family { 97 | case AddressFamilyFqdn: 98 | fqdn, err := ReadString(reader) 99 | if err != nil { 100 | return nil, exceptions.Cause(err, "read fqdn") 101 | } 102 | return AddrFqdn(fqdn), nil 103 | default: 104 | switch family { 105 | case AddressFamilyIPv4: 106 | var addr [4]byte 107 | err = common.Error(reader.Read(addr[:])) 108 | if err != nil { 109 | return nil, exceptions.Cause(err, "read ipv4 address") 110 | } 111 | return Addr4(addr), nil 112 | case AddressFamilyIPv6: 113 | var addr [16]byte 114 | err = common.Error(reader.Read(addr[:])) 115 | if err != nil { 116 | return nil, exceptions.Cause(err, "read ipv6 address") 117 | } 118 | return Addr16(addr), nil 119 | default: 120 | return nil, exceptions.New("unknown address family: ", af) 121 | } 122 | } 123 | } 124 | 125 | func (s *Serializer) ReadPort(reader io.Reader) (uint16, error) { 126 | port, err := rw.ReadBytes(reader, 2) 127 | if err != nil { 128 | return 0, exceptions.Cause(err, "read port") 129 | } 130 | return binary.BigEndian.Uint16(port), nil 131 | } 132 | 133 | func (s *Serializer) ReadAddressAndPort(reader io.Reader) (addr Addr, port uint16, err error) { 134 | if !s.portFirst { 135 | addr, err = s.ReadAddress(reader) 136 | } else { 137 | port, err = s.ReadPort(reader) 138 | } 139 | if err != nil { 140 | return 141 | } 142 | if s.portFirst { 143 | addr, err = s.ReadAddress(reader) 144 | } else { 145 | port, err = s.ReadPort(reader) 146 | } 147 | return 148 | } 149 | 150 | func ReadString(reader io.Reader) (string, error) { 151 | strLen, err := rw.ReadByte(reader) 152 | if err != nil { 153 | return common.EmptyString, err 154 | } 155 | return rw.ReadString(reader, int(strLen)) 156 | } 157 | 158 | func WriteString(writer io.Writer, op string, str string) error { 159 | strLen := len(str) 160 | if strLen > 255 { 161 | return &StringTooLongException{op, strLen} 162 | } 163 | err := rw.WriteByte(writer, byte(strLen)) 164 | if err != nil { 165 | return err 166 | } 167 | return rw.WriteString(writer, str) 168 | } 169 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/sagernet/uot 2 | 3 | go 1.18 4 | 5 | require golang.org/x/net v0.0.0-20220403103023-749bd193bc2b 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0= 2 | golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 3 | -------------------------------------------------------------------------------- /resolver.go: -------------------------------------------------------------------------------- 1 | package uot 2 | 3 | import ( 4 | "context" 5 | "net" 6 | "time" 7 | ) 8 | 9 | var LookupAddress func(domain string) (net.IP, error) 10 | 11 | func init() { 12 | LookupAddress = func(domain string) (net.IP, error) { 13 | ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) 14 | ips, err := net.DefaultResolver.LookupIP(ctx, "ip", domain) 15 | cancel() 16 | if err != nil { 17 | return nil, err 18 | } 19 | return ips[0], nil 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /server.go: -------------------------------------------------------------------------------- 1 | package uot 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | "net" 7 | 8 | "github.com/sagernet/uot/common" 9 | "github.com/sagernet/uot/common/buf" 10 | "github.com/sagernet/uot/common/socksaddr" 11 | ) 12 | 13 | type ServerConn struct { 14 | net.PacketConn 15 | inputReader, outputReader *io.PipeReader 16 | inputWriter, outputWriter *io.PipeWriter 17 | } 18 | 19 | func NewServerConn(packetConn net.PacketConn) net.Conn { 20 | c := &ServerConn{ 21 | PacketConn: packetConn, 22 | } 23 | c.inputReader, c.inputWriter = io.Pipe() 24 | c.outputReader, c.outputWriter = io.Pipe() 25 | go c.loopInput() 26 | go c.loopOutput() 27 | return c 28 | } 29 | 30 | func (c *ServerConn) Read(b []byte) (n int, err error) { 31 | return c.outputReader.Read(b) 32 | } 33 | 34 | func (c *ServerConn) Write(b []byte) (n int, err error) { 35 | return c.inputWriter.Write(b) 36 | } 37 | 38 | func (c *ServerConn) RemoteAddr() net.Addr { 39 | return &common.DummyAddr{} 40 | } 41 | 42 | func (c *ServerConn) loopInput() { 43 | buffer := buf.New() 44 | defer buffer.Release() 45 | for { 46 | address, port, err := AddrParser.ReadAddressAndPort(c.inputReader) 47 | if err != nil { 48 | break 49 | } 50 | var ip net.IP 51 | if address.Family().IsFqdn() { 52 | ip, err = LookupAddress(address.Fqdn()) 53 | if err != nil { 54 | break 55 | } 56 | } else { 57 | ip = address.Addr().AsSlice() 58 | } 59 | udpAddr := &net.UDPAddr{ 60 | IP: ip, 61 | Port: int(port), 62 | } 63 | var length uint16 64 | err = binary.Read(c.inputReader, binary.BigEndian, &length) 65 | if err != nil { 66 | break 67 | } 68 | buffer.FullReset() 69 | _, err = buffer.ReadFullFrom(c.inputReader, int(length)) 70 | if err != nil { 71 | break 72 | } 73 | _, err = c.WriteTo(buffer.Bytes(), udpAddr) 74 | if err != nil { 75 | break 76 | } 77 | } 78 | c.Close() 79 | } 80 | 81 | func (c *ServerConn) loopOutput() { 82 | buffer := buf.New() 83 | defer buffer.Release() 84 | for { 85 | buffer.FullReset() 86 | n, addr, err := buffer.ReadPacketFrom(c) 87 | if err != nil { 88 | break 89 | } 90 | address, port := socksaddr.AddressFromNetAddr(addr) 91 | err = AddrParser.WriteAddressAndPort(c.outputWriter, address, port) 92 | if err != nil { 93 | break 94 | } 95 | err = binary.Write(c.outputWriter, binary.BigEndian, uint16(n)) 96 | if err != nil { 97 | break 98 | } 99 | _, err = buffer.WriteTo(c.outputWriter) 100 | if err != nil { 101 | break 102 | } 103 | } 104 | c.Close() 105 | } 106 | 107 | func (c *ServerConn) Close() error { 108 | c.inputReader.Close() 109 | c.inputWriter.Close() 110 | c.outputReader.Close() 111 | c.outputWriter.Close() 112 | c.PacketConn.Close() 113 | return nil 114 | } 115 | -------------------------------------------------------------------------------- /uot.go: -------------------------------------------------------------------------------- 1 | package uot 2 | 3 | import ( 4 | "github.com/sagernet/uot/common/socksaddr" 5 | ) 6 | 7 | const UOTMagicAddress = "sp.udp-over-tcp.arpa" 8 | 9 | var AddrParser = socksaddr.NewSerializer( 10 | socksaddr.AddressFamilyByte(0x00, socksaddr.AddressFamilyIPv4), 11 | socksaddr.AddressFamilyByte(0x01, socksaddr.AddressFamilyIPv6), 12 | socksaddr.AddressFamilyByte(0x02, socksaddr.AddressFamilyFqdn), 13 | ) 14 | -------------------------------------------------------------------------------- /uot_test.go: -------------------------------------------------------------------------------- 1 | package uot 2 | 3 | import ( 4 | "net" 5 | "testing" 6 | 7 | "github.com/sagernet/uot/common" 8 | "github.com/sagernet/uot/common/buf" 9 | "golang.org/x/net/dns/dnsmessage" 10 | ) 11 | 12 | func TestServerConn(t *testing.T) { 13 | udpConn, err := net.ListenUDP("udp", nil) 14 | common.Must(err) 15 | serverConn := NewServerConn(udpConn) 16 | defer serverConn.Close() 17 | clientConn := NewClientConn(serverConn) 18 | message := new(dnsmessage.Message) 19 | message.Header.ID = 1 20 | message.Header.RecursionDesired = true 21 | message.Questions = append(message.Questions, dnsmessage.Question{ 22 | Name: dnsmessage.MustNewName("google.com."), 23 | Type: dnsmessage.TypeA, 24 | Class: dnsmessage.ClassINET, 25 | }) 26 | packet, err := message.Pack() 27 | common.Must(err) 28 | common.Must1(clientConn.WriteTo(packet, &net.UDPAddr{ 29 | IP: net.IPv4(8, 8, 8, 8), 30 | Port: 53, 31 | })) 32 | buffer := buf.New() 33 | defer buffer.Release() 34 | common.Must2(buffer.ReadPacketFrom(clientConn)) 35 | common.Must(message.Unpack(buffer.Bytes())) 36 | for _, answer := range message.Answers { 37 | t.Log("got answer :", answer.Body) 38 | } 39 | } 40 | --------------------------------------------------------------------------------