UDP support

pull/40/head
V2Ray 9 years ago
parent cd42e5551c
commit 5c4b149d48

@ -13,6 +13,7 @@ type SocksConfig struct {
AuthMethod string `json:"auth"` AuthMethod string `json:"auth"`
Username string `json:"user"` Username string `json:"user"`
Password string `json:"pass"` Password string `json:"pass"`
UDPEnabled bool `json:"udp"`
} }
func (config SocksConfig) IsNoAuth() bool { func (config SocksConfig) IsNoAuth() bool {

@ -26,6 +26,7 @@ func (u *VMessUser) ToUser() (user.User, error) {
// VMessInboundConfig is // VMessInboundConfig is
type VMessInboundConfig struct { type VMessInboundConfig struct {
AllowedClients []VMessUser `json:"clients"` AllowedClients []VMessUser `json:"clients"`
UDPEnabled bool `json:"udp"`
} }
func loadInboundConfig(rawConfig []byte) (VMessInboundConfig, error) { func loadInboundConfig(rawConfig []byte) (VMessInboundConfig, error) {

@ -73,3 +73,67 @@ func TestVMessInAndOut(t *testing.T) {
assert.Bytes([]byte(data2Send)).Equals(och.Data2Send.Bytes()) assert.Bytes([]byte(data2Send)).Equals(och.Data2Send.Bytes())
assert.Bytes(ich.DataReturned.Bytes()).Equals(och.Data2Return) assert.Bytes(ich.DataReturned.Bytes()).Equals(och.Data2Return)
} }
func TestVMessInAndOutUDP(t *testing.T) {
assert := unit.Assert(t)
data2Send := "The data to be send to outbound server."
portA := uint16(17394)
ich := &mocks.InboundConnectionHandler{
Data2Send: []byte(data2Send),
DataReturned: bytes.NewBuffer(make([]byte, 0, 1024)),
}
core.RegisterInboundConnectionHandlerFactory("mock_ich", ich)
configA := mocks.Config{
PortValue: portA,
InboundConfigValue: &mocks.ConnectionConfig{
ProtocolValue: "mock_ich",
ContentValue: nil,
},
OutboundConfigValue: &mocks.ConnectionConfig{
ProtocolValue: "vmess",
ContentValue: []byte("{\"vnext\":[{\"address\": \"127.0.0.1\", \"network\": \"udp\", \"port\": 13841, \"users\":[{\"id\": \"ad937d9d-6e23-4a5a-ba23-bce5092a7c51\"}]}]}"),
},
}
pointA, err := core.NewPoint(&configA)
assert.Error(err).IsNil()
err = pointA.Start()
assert.Error(err).IsNil()
portB := uint16(13841)
och := &mocks.OutboundConnectionHandler{
Data2Send: bytes.NewBuffer(make([]byte, 0, 1024)),
Data2Return: []byte("The data to be returned to inbound server."),
}
core.RegisterOutboundConnectionHandlerFactory("mock_och", och)
configB := mocks.Config{
PortValue: portB,
InboundConfigValue: &mocks.ConnectionConfig{
ProtocolValue: "vmess",
ContentValue: []byte("{\"clients\": [{\"id\": \"ad937d9d-6e23-4a5a-ba23-bce5092a7c51\"}], \"udp\": true}"),
},
OutboundConfigValue: &mocks.ConnectionConfig{
ProtocolValue: "mock_och",
ContentValue: nil,
},
}
pointB, err := core.NewPoint(&configB)
assert.Error(err).IsNil()
err = pointB.Start()
assert.Error(err).IsNil()
dest := v2net.NewUDPDestination(v2net.IPAddress([]byte{1, 2, 3, 4}, 80))
ich.Communicate(v2net.NewPacket(dest, []byte(data2Send), false))
assert.Bytes([]byte(data2Send)).Equals(och.Data2Send.Bytes())
assert.Bytes(ich.DataReturned.Bytes()).Equals(och.Data2Return)
}

@ -25,15 +25,17 @@ var (
) )
type VMessInboundHandler struct { type VMessInboundHandler struct {
vPoint *core.Point vPoint *core.Point
clients user.UserSet clients user.UserSet
accepting bool accepting bool
udpEnabled bool
} }
func NewVMessInboundHandler(vp *core.Point, clients user.UserSet) *VMessInboundHandler { func NewVMessInboundHandler(vp *core.Point, clients user.UserSet, udpEnabled bool) *VMessInboundHandler {
return &VMessInboundHandler{ return &VMessInboundHandler{
vPoint: vp, vPoint: vp,
clients: clients, clients: clients,
udpEnabled: udpEnabled,
} }
} }
@ -45,6 +47,10 @@ func (handler *VMessInboundHandler) Listen(port uint16) error {
handler.accepting = true handler.accepting = true
go handler.AcceptConnections(listener) go handler.AcceptConnections(listener)
if handler.udpEnabled {
handler.ListenUDP(port)
}
return nil return nil
} }
@ -143,7 +149,8 @@ func (factory *VMessInboundHandlerFactory) Create(vp *core.Point, rawConfig []by
} }
allowedClients.AddUser(user) allowedClients.AddUser(user)
} }
return NewVMessInboundHandler(vp, allowedClients), nil
return NewVMessInboundHandler(vp, allowedClients, config.UDPEnabled), nil
} }
func init() { func init() {

@ -31,13 +31,13 @@ func (handler *VMessInboundHandler) ListenUDP(port uint16) error {
return nil return nil
} }
func (handler *VMessInboundHandler) AcceptPackets(conn *net.UDPConn) error { func (handler *VMessInboundHandler) AcceptPackets(conn *net.UDPConn) {
for { for {
buffer := make([]byte, 0, bufferSize) buffer := make([]byte, bufferSize)
nBytes, addr, err := conn.ReadFromUDP(buffer) nBytes, addr, err := conn.ReadFromUDP(buffer)
if err != nil { if err != nil {
log.Error("VMessIn failed to read UDP packets: %v", err) log.Error("VMessIn failed to read UDP packets: %v", err)
return err continue
} }
reader := bytes.NewReader(buffer[:nBytes]) reader := bytes.NewReader(buffer[:nBytes])
@ -46,23 +46,23 @@ func (handler *VMessInboundHandler) AcceptPackets(conn *net.UDPConn) error {
request, err := requestReader.Read(reader) request, err := requestReader.Read(reader)
if err != nil { if err != nil {
log.Warning("VMessIn: Invalid request from (%s): %v", addr.String(), err) log.Warning("VMessIn: Invalid request from (%s): %v", addr.String(), err)
return err continue
} }
cryptReader, err := v2io.NewAesDecryptReader(request.RequestKey[:], request.RequestIV[:], reader) cryptReader, err := v2io.NewAesDecryptReader(request.RequestKey[:], request.RequestIV[:], reader)
if err != nil { if err != nil {
log.Error("VMessIn: Failed to create decrypt reader: %v", err) log.Error("VMessIn: Failed to create decrypt reader: %v", err)
return err continue
} }
data := make([]byte, bufferSize) data := make([]byte, bufferSize)
nBytes, err = cryptReader.Read(data) nBytes, err = cryptReader.Read(data)
if err != nil { if err != nil {
log.Warning("VMessIn: Unable to decrypt data: %v", err) log.Warning("VMessIn: Unable to decrypt data: %v", err)
return err continue
} }
packet := v2net.NewPacket(request.Destination(), data, false) packet := v2net.NewPacket(request.Destination(), data[:nBytes], false)
go handler.handlePacket(conn, request, packet, addr) go handler.handlePacket(conn, request, packet, addr)
} }
} }

@ -35,9 +35,10 @@ type VMessOutboundHandler struct {
func NewVMessOutboundHandler(vp *core.Point, vNextList, vNextListUDP []VNextServer, firstPacket v2net.Packet) *VMessOutboundHandler { func NewVMessOutboundHandler(vp *core.Point, vNextList, vNextListUDP []VNextServer, firstPacket v2net.Packet) *VMessOutboundHandler {
return &VMessOutboundHandler{ return &VMessOutboundHandler{
vPoint: vp, vPoint: vp,
packet: firstPacket, packet: firstPacket,
vNextList: vNextList, vNextList: vNextList,
vNextListUDP: vNextListUDP,
} }
} }
@ -65,7 +66,11 @@ func pickVNext(serverList []VNextServer) (v2net.Destination, user.User) {
} }
func (handler *VMessOutboundHandler) Start(ray core.OutboundRay) error { func (handler *VMessOutboundHandler) Start(ray core.OutboundRay) error {
vNextAddress, vNextUser := pickVNext(handler.vNextList) vNextList := handler.vNextList
if handler.packet.Destination().IsUDP() {
vNextList = handler.vNextListUDP
}
vNextAddress, vNextUser := pickVNext(vNextList)
command := protocol.CmdTCP command := protocol.CmdTCP
if handler.packet.Destination().IsUDP() { if handler.packet.Destination().IsUDP() {
@ -86,9 +91,9 @@ func (handler *VMessOutboundHandler) Start(ray core.OutboundRay) error {
} }
func startCommunicate(request *protocol.VMessRequest, dest v2net.Destination, ray core.OutboundRay, firstPacket v2net.Packet) error { func startCommunicate(request *protocol.VMessRequest, dest v2net.Destination, ray core.OutboundRay, firstPacket v2net.Packet) error {
conn, err := net.DialTCP(dest.Network(), nil, &net.TCPAddr{dest.Address().IP(), int(dest.Address().Port()), ""}) conn, err := net.Dial(dest.Network(), dest.Address().String())
if err != nil { if err != nil {
log.Error("Failed to open tcp (%s): %v", dest.String(), err) log.Error("Failed to open %s: %v", dest.String(), err)
if ray != nil { if ray != nil {
close(ray.OutboundOutput()) close(ray.OutboundOutput())
} }
@ -105,15 +110,17 @@ func startCommunicate(request *protocol.VMessRequest, dest v2net.Destination, ra
responseFinish.Lock() responseFinish.Lock()
go handleRequest(conn, request, firstPacket, input, &requestFinish) go handleRequest(conn, request, firstPacket, input, &requestFinish)
go handleResponse(conn, request, output, &responseFinish) go handleResponse(conn, request, output, &responseFinish, dest.IsUDP())
requestFinish.Lock() requestFinish.Lock()
conn.CloseWrite() if tcpConn, ok := conn.(*net.TCPConn); ok {
tcpConn.CloseWrite()
}
responseFinish.Lock() responseFinish.Lock()
return nil return nil
} }
func handleRequest(conn *net.TCPConn, request *protocol.VMessRequest, firstPacket v2net.Packet, input <-chan []byte, finish *sync.Mutex) { func handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2net.Packet, input <-chan []byte, finish *sync.Mutex) {
defer finish.Unlock() defer finish.Unlock()
encryptRequestWriter, err := v2io.NewAesEncryptWriter(request.RequestKey[:], request.RequestIV[:], conn) encryptRequestWriter, err := v2io.NewAesEncryptWriter(request.RequestKey[:], request.RequestIV[:], conn)
if err != nil { if err != nil {
@ -153,7 +160,7 @@ func handleRequest(conn *net.TCPConn, request *protocol.VMessRequest, firstPacke
return return
} }
func handleResponse(conn *net.TCPConn, request *protocol.VMessRequest, output chan<- []byte, finish *sync.Mutex) { func handleResponse(conn net.Conn, request *protocol.VMessRequest, output chan<- []byte, finish *sync.Mutex, isUDP bool) {
defer finish.Unlock() defer finish.Unlock()
defer close(output) defer close(output)
responseKey := md5.Sum(request.RequestKey[:]) responseKey := md5.Sum(request.RequestKey[:])
@ -165,18 +172,24 @@ func handleResponse(conn *net.TCPConn, request *protocol.VMessRequest, output ch
return return
} }
response := protocol.VMessResponse{} buffer := make([]byte, 2*1024)
_, err = decryptResponseReader.Read(response[:])
nBytes, err := decryptResponseReader.Read(buffer)
if err != nil { if err != nil {
//log.Error("VMessOut: Failed to read VMess response (%d bytes): %v", nBytes, err) //log.Error("VMessOut: Failed to read VMess response (%d bytes): %v", nBytes, err)
return return
} }
if !bytes.Equal(response[:], request.ResponseHeader[:]) { if !bytes.Equal(buffer[:4], request.ResponseHeader[:]) {
log.Warning("VMessOut: unexepcted response header. The connection is probably hijacked.") log.Warning("VMessOut: unexepcted response header. The connection is probably hijacked.")
return return
} }
v2net.ReaderToChan(output, decryptResponseReader) output <- buffer[4:nBytes]
if !isUDP {
v2net.ReaderToChan(output, decryptResponseReader)
}
return return
} }

@ -1,3 +1,4 @@
{ {
"auth": "noauth" "auth": "noauth",
"udp": false
} }

@ -1,5 +1,6 @@
{ {
"clients": [ "clients": [
{"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"} {"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"}
] ],
"udp": false
} }

@ -25,7 +25,9 @@ func (handler *OutboundConnectionHandler) Start(ray core.OutboundRay) error {
} }
handler.Data2Send.Write(data) handler.Data2Send.Write(data)
} }
output <- handler.Data2Return dataCopy := make([]byte, len(handler.Data2Return))
copy(dataCopy, handler.Data2Return)
output <- dataCopy
close(output) close(output)
}() }()
@ -38,5 +40,9 @@ func (handler *OutboundConnectionHandler) Initialize(config []byte) error {
func (handler *OutboundConnectionHandler) Create(point *core.Point, packet v2net.Packet) (core.OutboundConnectionHandler, error) { func (handler *OutboundConnectionHandler) Create(point *core.Point, packet v2net.Packet) (core.OutboundConnectionHandler, error) {
handler.Destination = packet.Destination() handler.Destination = packet.Destination()
if packet.Chunk() != nil {
handler.Data2Send.Write(packet.Chunk())
}
return handler, nil return handler, nil
} }

Loading…
Cancel
Save