mirror of
https://github.com/xjasonlyu/tun2socks.git
synced 2025-10-29 11:12:33 +08:00
update core
This commit is contained in:
134
core/core_test.go
Executable file
134
core/core_test.go
Executable file
@@ -0,0 +1,134 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"net"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
ipv4Header = 20 // Length of the IPv4 header in bytes.
|
||||
udpHeader = 8 // Length of the UDP header in bytes.
|
||||
// A small NTP query packet (UDP)
|
||||
ntpHex = "45b8004c72e94000401125a2646a4100d8ef2304007b007b0038a1a7230209e8000003620000072ed8ef230ce10ff888c730e992e10ffbdbc742a583e10ffbdbcaa4151ae10ffde6c3cf01e3"
|
||||
// Two fragments of a large UDP packet.
|
||||
frag1Hex = "450003fc0001200040117bab646a41005db8d8220afa00000774af62691c476d4d1f5bd3b2d5f17b926562b91de7ab5ee5bea9fe13ed6223891668ab17e4236a4ec1bed53fb9db397f2885e0fd418dbe2f29416b3e01dfa633bd72d1486e6aa39d568a4b9906834ba06d0c39f9696cbbe96c13638c4cef0fedab2f17d9aa3eb87b6fcf7a3e614cbf7cc7141fbf174d97ef220f17d7e669752bad3965785ec1355b19a3adea31a6c148a0b77ade200962dc4f02ad302e1f927c537627dc1f56f613e1a9d69847a8adc5b965059e973312c013f3916f6c54ddedb96605590f9d81e39e3649d007a44e1b57d9086487c073b511da5b868a44ad043e013feb23903eade049bcac0c0486c6e832aabce435a054159242a27784260bdbe8318f677dc58cbcc90f5ec7a065504b8ddd66c5a53480e634deed9b075a9d23dbabd37c97a825e2c6d17b179bbe83a35b09c852db9aa8d04ee23f285d83c68ae808c1a16cb2ed7c93e1d9724c1e0f4e413dfd50814f12d648201bc3352dd87640609937db0eef31c335b182e6969b32a50cd7af1116013caeeccc9417d0918bbfb1320cdb6e215b6a0c70654bb196e99636b70c503d9d1837f1a33f4a43913390f2585b361c33912cf16ccbb0a5cfbba90be9c3a360cf11193b9738b1a1459860e0bb99418df9368174a9184aac6f9ecb1299876ce62ab5028f48cf6c93b58b4fb1ced3199d36ae9dfa4b4eb9109ca62f8b186c912939018a8257b79a93cec689223b04a62de256019d56dbe54ba989b1f22aa00ea81e50b0895b152d7841416e9f5ed209d99cb38534820c82b4298a8d93afdc134aa41a2e3cd62d43419873ac8d17487de28b15e186eefe538c2019023086923b3f9aec506589fb5504f483dd820993f6950262231cb0f914415d37a929a77c435ba3ecdab90a817d683abd4dc8028c3294770d4ee28ea71eb09fc027b9dc9afedc00fbe414eef5756d409909786c82186fce59f4305ad3ca47d72d59d2bff2224f5a2115f01bee7b71552160fefd14587f150a67ffc08e92c73f40d8ad7b6b900324ae56ea84eccdbb2872f644cea1b2e011e862f2dba10dbac8452f53a2c6c9ac9d5b33ab03fa16a1f146197d1c649ee2c65636f4973b916190107b1977fb55f4157ff57e62251d3a3e0fcc3357665c13287009a3f11fc0cfe4495a4b9bb981b0893fd06c938c5d99e3b7e68d6ad16326ea54314d5c6a428cf105bf95aea4e8374bd7ff81ecc5b6b9f050dc6482aa123c470d7c068a2f171949cb5dee61ddf3c40ec97099c527926dddb84b0ffa3f69564bb3b9632da0fc6914a80e2044793ac302e3763d762f42abc07b0ed52968f09e96ce3e5fa83822a5d35548973fdda478610fa39355db82bb4c743479743c32a93521082a131cd21439bca3735c8b01d295c67b8dfe8a0071487d8472"
|
||||
frag2Hex = "450003a00001007d40119b8a646a41005db8d822c726296a575ed8996bdad7392375d166d9894a6f0c0c08e4ae1ae9e55ae13a9f206b15cf74a43bff8f579f85344b972e7298f8c56d6a23081c19a369488a1b680af5f2e96e7d650261ac937ac709b74f45d15aa053b734cea3f5cbf400379a0e30e49bf696640a61a86076d867834cb79e7bcb798d129a28a8d81f47448ddc38b6040bd45607013d839c9198daabf8ae2f2994908e8b5d04f3194fe2def74e95e52aaf313119b9cef0bde9232fb7a95003e5fdcb9d8b759cf52d570c75f885333b600348b93fe8d0ccaa113465e37f20ce72b432ecc9c8a25809c2b2ed201a88d39b7f47023651ed6841e50b8fb298ef703888d603cd02438ac2ca563ae1ee273da555c3929a6221467f122a60bdb6484bd99d22fd4f4f3bfc41fd39e49c090acf33f46544c0705dbeb03b7249d90a398eacfbf239bcbb279e2596b06d25cfb9c6e247c34a57d55a272797f27df4fd2fc0fb23623f7c4890e05133ab2fa4f02cdd44eecabb3a49d7abae7dcb95f1429c82a685c4f69901cf22e355e31916bd20d038efc66dc37387d63a4330c516d03b6a2dd23bb9228d94c225723487792ae62888282a41e8c1c834d68ae58b4db92243671fd171157439282cfbab316439224dfb522f304a788f91c52715dc6588f0e1055455f159a28865d97292a7af670ec78afb229fcfa7cb97590d51d7fc8eb40edef005b19c8fb235f41b3bb5f6f7923b7534bf8ca8437ef93f40fabeb49b9eb9c5e8de9ad27ad8de282cea26adf3ddbd5b3ea4537535e2ddb864b125e73d330bf25d923e3df41be562b8de3bb3ce969defb159bc77cacb2337b07ac5204d8f1a39520089932ca6649a742f63c7e5e2ab25dc4bbed75faf68796dd5d521aee6452fbecc6af63623a1c55ad02de7c727c265ef8a4cdd109d41a7be9a5597dc69c3803e77340f2dff5608817b9c6d7c340c351e451401599a6ede93a0a897bd9bfe2dba1bfc7b61683ee9ff266a8a49fbec63ea60e4a58473c3705404cd3b3ff96415fcc92672a045555f48418a7125f0f4bda7b2df2d367af6d0e9d27a1f3895148c002b1503c6b83efa2a1e93def67fa07937d355b04a193465094e16128f33017e892d0bd154b9b87985eb6571d074d6011863b5af1395972d9415b21bd83d971cf5f3f67cc73dc0ab057aad3c83af4f6b10d5a6d8102ee3fe9f25929a14306871bf579e56dfd69cf45dd1472bbfcb1f0ab7fbb3972e27e2aba98273383b50700872d73f5c2ecf6ce3ea384ec08c4818fcfe0ed86513d617025f52"
|
||||
)
|
||||
|
||||
var ntp, ntpPayload, frag1, frag2, fragPayload []byte
|
||||
|
||||
func decode(s string) []byte {
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// This is a trivial UDP handler that sends each received packet to a channel for inspection.
|
||||
type fakeUDPHandler struct {
|
||||
UDPConnHandler
|
||||
packets chan []byte
|
||||
}
|
||||
|
||||
func (h *fakeUDPHandler) Connect(conn UDPConn, target *net.UDPAddr) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *fakeUDPHandler) ReceiveTo(conn UDPConn, data []byte, addr *net.UDPAddr) error {
|
||||
h.packets <- data
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupUDP(t *testing.T) (LWIPStack, *fakeUDPHandler) {
|
||||
// Reinitialize source data before each test to avoid interference.
|
||||
ntp = decode(ntpHex)
|
||||
ntpPayload = ntp[ipv4Header+udpHeader:]
|
||||
frag1 = decode(frag1Hex)
|
||||
frag2 = decode(frag2Hex)
|
||||
fragPayload = append([]byte(nil), frag1[ipv4Header+udpHeader:]...)
|
||||
fragPayload = append(fragPayload, frag2[ipv4Header:]...)
|
||||
|
||||
// Reset the set of known UDP connections to empty before each test. Otherwise, the
|
||||
// tests will interfere with each other.
|
||||
udpConns = sync.Map{}
|
||||
|
||||
s := NewLWIPStack()
|
||||
// This channel is buffered because the first Write->ReceiveTo can either be synchronous or
|
||||
// asynchronous, depending on the results of a race during "connection".
|
||||
h := &fakeUDPHandler{packets: make(chan []byte, 1)}
|
||||
RegisterUDPConnHandler(h)
|
||||
return s, h
|
||||
}
|
||||
|
||||
func write(s LWIPStack, b []byte, t *testing.T) {
|
||||
if _, err := s.Write(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func checkedCopy(dst, src []byte, t *testing.T) {
|
||||
if copy(dst, src) != len(src) {
|
||||
t.Fatal("Copy failed due to test misconfiguration")
|
||||
}
|
||||
}
|
||||
|
||||
func assertEqual(actual, expected []byte, t *testing.T) {
|
||||
if !bytes.Equal(actual, expected) {
|
||||
t.Error("Payloads are not equal")
|
||||
}
|
||||
}
|
||||
|
||||
// Basic test for sending a single UDP packet.
|
||||
func TestUDP(t *testing.T) {
|
||||
s, h := setupUDP(t)
|
||||
write(s, ntp, t)
|
||||
assertEqual(<-h.packets, ntpPayload, t)
|
||||
}
|
||||
|
||||
// Send a fragmented UDP packet.
|
||||
func TestUDPFragmentation(t *testing.T) {
|
||||
s, h := setupUDP(t)
|
||||
write(s, frag1, t)
|
||||
write(s, frag2, t)
|
||||
assertEqual(<-h.packets, fragPayload, t)
|
||||
}
|
||||
|
||||
// Write UDP fragments out of order.
|
||||
func TestUDPFragmentReordering(t *testing.T) {
|
||||
s, h := setupUDP(t)
|
||||
write(s, frag2, t)
|
||||
write(s, frag1, t)
|
||||
assertEqual(<-h.packets, fragPayload, t)
|
||||
}
|
||||
|
||||
// Send a fragmented UDP packet where fragments reuse the same buffer.
|
||||
func TestUDPFragmentationMemory(t *testing.T) {
|
||||
s, h := setupUDP(t)
|
||||
buf := make([]byte, len(frag1))
|
||||
|
||||
checkedCopy(buf, frag1, t)
|
||||
write(s, buf[:len(frag1)], t)
|
||||
|
||||
checkedCopy(buf, frag2, t)
|
||||
write(s, buf[:len(frag2)], t)
|
||||
|
||||
assertEqual(<-h.packets, fragPayload, t)
|
||||
}
|
||||
|
||||
// Regression test for a segmentation fault.
|
||||
func TestUDPFragmentationMemoryAndReordering(t *testing.T) {
|
||||
s, h := setupUDP(t)
|
||||
buf := make([]byte, len(frag1))
|
||||
|
||||
checkedCopy(buf, frag2, t)
|
||||
write(s, buf[:len(frag2)], t)
|
||||
|
||||
checkedCopy(buf, frag1, t)
|
||||
write(s, buf[:len(frag1)], t)
|
||||
|
||||
assertEqual(<-h.packets, fragPayload, t)
|
||||
}
|
||||
2
core/input.go
Normal file → Executable file
2
core/input.go
Normal file → Executable file
@@ -104,7 +104,7 @@ func Input(pkt []byte) (int, error) {
|
||||
|
||||
var buf *C.struct_pbuf
|
||||
|
||||
if nextProto == proto_udp && (!moreFrags(ipv, pkt) || fragOffset(ipv, pkt) > 0) {
|
||||
if nextProto == proto_udp && !(moreFrags(ipv, pkt) || fragOffset(ipv, pkt) > 0) {
|
||||
// Copying data is not necessary for unfragmented UDP packets, and we would like to
|
||||
// have all data in one pbuf.
|
||||
buf = C.pbuf_alloc_reference(unsafe.Pointer(&pkt[0]), C.u16_t(len(pkt)), C.PBUF_REF)
|
||||
|
||||
31
core/udp_conn.go
Normal file → Executable file
31
core/udp_conn.go
Normal file → Executable file
@@ -16,8 +16,7 @@ import (
|
||||
type udpConnState uint
|
||||
|
||||
const (
|
||||
udpNewConn udpConnState = iota
|
||||
udpConnecting
|
||||
udpConnecting udpConnState = iota
|
||||
udpConnected
|
||||
udpClosed
|
||||
)
|
||||
@@ -46,13 +45,10 @@ func newUDPConn(pcb *C.struct_udp_pcb, handler UDPConnHandler, localIP C.ip_addr
|
||||
localAddr: localAddr,
|
||||
localIP: localIP,
|
||||
localPort: localPort,
|
||||
state: udpNewConn,
|
||||
pending: make(chan *udpPacket, 1), // For DNS request payload.
|
||||
state: udpConnecting,
|
||||
pending: make(chan *udpPacket, 1), // To hold the first packet on the connection
|
||||
}
|
||||
|
||||
conn.Lock()
|
||||
conn.state = udpConnecting
|
||||
conn.Unlock()
|
||||
go func() {
|
||||
err := handler.Connect(conn, remoteAddr)
|
||||
if err != nil {
|
||||
@@ -94,28 +90,33 @@ func (conn *udpConn) checkState() error {
|
||||
return errors.New("connection closed")
|
||||
case udpConnected:
|
||||
return nil
|
||||
case udpNewConn, udpConnecting:
|
||||
case udpConnecting:
|
||||
return errors.New("not connected")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (conn *udpConn) isConnecting() bool {
|
||||
// If the connection isn't ready yet, and there is room in the queue, make a copy
|
||||
// and hold onto it until the connection is ready.
|
||||
func (conn *udpConn) enqueueEarlyPacket(data []byte, addr *net.UDPAddr) bool {
|
||||
conn.Lock()
|
||||
defer conn.Unlock()
|
||||
return conn.state == udpConnecting
|
||||
}
|
||||
|
||||
func (conn *udpConn) ReceiveTo(data []byte, addr *net.UDPAddr) error {
|
||||
if conn.isConnecting() {
|
||||
if conn.state == udpConnecting {
|
||||
pkt := &udpPacket{data: append([]byte(nil), data...), addr: addr}
|
||||
select {
|
||||
// Data will be dropped if pending is full.
|
||||
case conn.pending <- pkt:
|
||||
return nil
|
||||
return true
|
||||
default:
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (conn *udpConn) ReceiveTo(data []byte, addr *net.UDPAddr) error {
|
||||
if conn.enqueueEarlyPacket(data, addr) {
|
||||
return nil
|
||||
}
|
||||
if err := conn.checkState(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user