mirror of
https://github.com/v2fly/v2ray-core.git
synced 2025-01-01 23:16:23 -05:00
UDP support
This commit is contained in:
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…
Reference in New Issue
Block a user