func (this *RegexpDomainMatcher) Apply(dest v2net.Destination) bool { if !dest.Address().IsDomain() { return false } domain := serial.StringLiteral(dest.Address().Domain()) return this.pattern.MatchString(domain.ToLower().String()) }
func Dial(dest v2net.Destination) (net.Conn, error) { if dest.Address().IsDomain() { dialer := &net.Dialer{ Timeout: time.Second * 60, DualStack: true, } network := "tcp" if dest.IsUDP() { network = "udp" } return dialer.Dial(network, dest.NetAddr()) } ip := dest.Address().IP() if dest.IsTCP() { return net.DialTCP("tcp", nil, &net.TCPAddr{ IP: ip, Port: int(dest.Port()), }) } else { return net.DialUDP("udp", nil, &net.UDPAddr{ IP: ip, Port: int(dest.Port()), }) } }
func (this *VMessOutboundHandler) handleCommand(dest v2net.Destination, cmdId byte, data []byte) { if len(data) < 4 { return } fnv1hash := fnv.New32a() fnv1hash.Write(data[4:]) actualHashValue := fnv1hash.Sum32() expectedHashValue := serial.BytesLiteral(data[:4]).Uint32Value() if actualHashValue != expectedHashValue { return } data = data[4:] cmd, err := command.CreateResponseCommand(cmdId) if err != nil { log.Warning("VMessOut: Unknown response command (", cmdId, "): ", err) return } if err := cmd.Unmarshal(data); err != nil { log.Warning("VMessOut: Failed to parse response command: ", err) return } switch typedCommand := cmd.(type) { case *command.SwitchAccount: if typedCommand.Host == nil { typedCommand.Host = dest.Address() } this.handleSwitchAccount(typedCommand) default: } }
func startCommunicate(request *protocol.VMessRequest, dest *v2net.Destination, ray core.OutboundRay) error { input := ray.OutboundInput() output := ray.OutboundOutput() conn, err := net.DialTCP(dest.Network(), nil, &net.TCPAddr{dest.Address().IP(), int(dest.Address().Port()), ""}) if err != nil { log.Error("Failed to open tcp (%s): %v", dest.String(), err) close(output) return err } log.Info("VMessOut: Tunneling request for %s", request.Address.String()) defer conn.Close() requestFinish := make(chan bool) responseFinish := make(chan bool) go handleRequest(conn, request, input, requestFinish) go handleResponse(conn, request, output, responseFinish) <-requestFinish conn.CloseWrite() <-responseFinish return nil }
func Dial(src v2net.Address, dest v2net.Destination, settings *StreamSettings) (Connection, error) { var connection Connection var err error if dest.IsTCP() { switch { case settings.IsCapableOf(StreamConnectionTypeTCP): connection, err = TCPDialer(src, dest) case settings.IsCapableOf(StreamConnectionTypeKCP): connection, err = KCPDialer(src, dest) case settings.IsCapableOf(StreamConnectionTypeRawTCP): connection, err = RawTCPDialer(src, dest) default: return nil, ErrUnsupportedStreamType } if err != nil { return nil, err } if settings.Security == StreamSecurityTypeNone { return connection, nil } config := settings.TLSSettings.GetTLSConfig() if dest.Address().IsDomain() { config.ServerName = dest.Address().Domain() } tlsConn := tls.Client(connection, config) return v2tls.NewConnection(tlsConn), nil } return UDPDialer(src, dest) }
func (this *RegexpDomainMatcher) Apply(dest v2net.Destination) bool { if !dest.Address().IsDomain() { return false } domain := dest.Address().Domain() return this.pattern.MatchString(strings.ToLower(domain)) }
func (this *PlainDomainMatcher) Apply(dest v2net.Destination) bool { if !dest.Address().IsDomain() { return false } domain := dest.Address().Domain() return strings.Contains(domain, this.pattern) }
func (this *PlainDomainMatcher) Apply(dest v2net.Destination) bool { if !dest.Address().IsDomain() { return false } domain := serial.StringLiteral(dest.Address().Domain()) return domain.Contains(this.pattern) }
func startCommunicate(request *protocol.VMessRequest, dest v2net.Destination, ray core.OutboundRay, firstPacket v2net.Packet) error { conn, err := net.Dial(dest.Network(), dest.Address().String()) if err != nil { log.Error("Failed to open %s: %v", dest.String(), err) if ray != nil { close(ray.OutboundOutput()) } return err } log.Info("VMessOut: Tunneling request to %s via %s", request.Address.String(), dest.String()) defer conn.Close() input := ray.OutboundInput() output := ray.OutboundOutput() var requestFinish, responseFinish sync.Mutex requestFinish.Lock() responseFinish.Lock() go handleRequest(conn, request, firstPacket, input, &requestFinish) go handleResponse(conn, request, output, &responseFinish, dest.IsUDP()) requestFinish.Lock() if tcpConn, ok := conn.(*net.TCPConn); ok { tcpConn.CloseWrite() } responseFinish.Lock() return nil }
func (this *VMessOutboundHandler) Dispatch(target v2net.Destination, payload *alloc.Buffer, ray ray.OutboundRay) error { defer ray.OutboundInput().Release() defer ray.OutboundOutput().Close() var rec *protocol.ServerSpec var conn internet.Connection err := retry.Timed(5, 100).On(func() error { rec = this.serverPicker.PickServer() rawConn, err := internet.Dial(this.meta.Address, rec.Destination(), this.meta.StreamSettings) if err != nil { return err } conn = rawConn return nil }) if err != nil { log.Error("VMess|Outbound: Failed to find an available destination:", err) return err } log.Info("VMess|Outbound: Tunneling request to ", target, " via ", rec.Destination) command := protocol.RequestCommandTCP if target.IsUDP() { command = protocol.RequestCommandUDP } request := &protocol.RequestHeader{ Version: encoding.Version, User: rec.PickUser(), Command: command, Address: target.Address(), Port: target.Port(), Option: protocol.RequestOptionChunkStream, } defer conn.Close() conn.SetReusable(true) if conn.Reusable() { // Conn reuse may be disabled on transportation layer request.Option.Set(protocol.RequestOptionConnectionReuse) } input := ray.OutboundInput() output := ray.OutboundOutput() var requestFinish, responseFinish sync.Mutex requestFinish.Lock() responseFinish.Lock() session := encoding.NewClientSession(protocol.DefaultIDHash) go this.handleRequest(session, conn, request, payload, input, &requestFinish) go this.handleResponse(session, conn, request, rec.Destination(), output, &responseFinish) requestFinish.Lock() responseFinish.Lock() return nil }
func socks5UDPRequest(address v2net.Destination, payload []byte) []byte { request := make([]byte, 0, 1024) request = append(request, 0, 0, 0) request = appendAddress(request, address.Address()) request = address.Port().Bytes(request) request = append(request, payload...) return request }
func (this *VMessOutboundHandler) handleCommand(dest v2net.Destination, cmd protocol.ResponseCommand) { switch typedCommand := cmd.(type) { case *protocol.CommandSwitchAccount: if typedCommand.Host == nil { typedCommand.Host = dest.Address() } this.handleSwitchAccount(typedCommand) default: } }
func (this *ChinaSitesRule) Apply(dest v2net.Destination) bool { address := dest.Address() if !address.IsDomain() { return false } domain := strings.ToLower(address.Domain()) for _, matcher := range compiledMatchers { if matcher.Match(domain) { return true } } return false }
func Dial(dest v2net.Destination) (net.Conn, error) { var ip net.IP if dest.Address().IsIPv4() || dest.Address().IsIPv6() { ip = dest.Address().IP() } else { ips, err := net.LookupIP(dest.Address().Domain()) if err != nil { return nil, err } if len(ips) == 0 { return nil, ErrInvalidHost } ip = ips[dice.Roll(len(ips))] } if dest.IsTCP() { return net.DialTCP("tcp", nil, &net.TCPAddr{ IP: ip, Port: int(dest.Port()), }) } else { return net.DialUDP("udp", nil, &net.UDPAddr{ IP: ip, Port: int(dest.Port()), }) } }
func (this *FieldRule) Apply(dest v2net.Destination) bool { address := dest.Address() if len(this.Domain) > 0 { if !address.IsDomain() { return false } foundMatch := false for _, domain := range this.Domain { if domain.Match(address.Domain()) { foundMatch = true break } } if !foundMatch { return false } } if this.IP != nil && len(this.IP) > 0 { if !(address.IsIPv4() || address.IsIPv6()) { return false } foundMatch := false for _, ipnet := range this.IP { if ipnet.Contains(address.IP()) { foundMatch = true break } } if !foundMatch { return false } } if this.Port != nil { port := dest.Port() if port.Value() < this.Port.From().Value() || port.Value() > this.Port.To().Value() { return false } } if this.Network != nil { if !this.Network.HasNetwork(v2net.Network(dest.Network())) { return false } } return true }
// @Private func (this *Router) ResolveIP(dest v2net.Destination) []v2net.Destination { ips := this.dnsServer.Get(dest.Address().Domain()) if len(ips) == 0 { return nil } dests := make([]v2net.Destination, len(ips)) for idx, ip := range ips { if dest.IsTCP() { dests[idx] = v2net.TCPDestination(v2net.IPAddress(ip), dest.Port()) } else { dests[idx] = v2net.UDPDestination(v2net.IPAddress(ip), dest.Port()) } } return dests }
func DialKCP(src v2net.Address, dest v2net.Destination) (internet.Connection, error) { udpDest := v2net.UDPDestination(dest.Address(), dest.Port()) log.Info("Dialling KCP to ", udpDest) conn, err := internet.DialToDest(src, udpDest) if err != nil { return nil, err } cpip := NewSimpleAuthenticator() conv := uint16(atomic.AddUint32(&globalConv, 1)) session := NewConnection(conv, conn, conn.LocalAddr().(*net.UDPAddr), conn.RemoteAddr().(*net.UDPAddr), cpip) session.FetchInputFrom(conn) return session, nil }
func (this *Listener) OnReceive(payload *alloc.Buffer, src v2net.Destination) { defer payload.Release() if valid := this.block.Open(payload); !valid { log.Info("KCP|Listener: discarding invalid payload from ", src) return } if !this.running { return } this.Lock() defer this.Unlock() if !this.running { return } if payload.Len() < 4 { return } conv := serial.BytesToUint16(payload.Value) cmd := Command(payload.Value[2]) sourceId := src.NetAddr() + "|" + serial.Uint16ToString(conv) conn, found := this.sessions[sourceId] if !found { if cmd == CommandTerminate { return } log.Debug("KCP|Listener: Creating session with id(", sourceId, ") from ", src) writer := &Writer{ id: sourceId, hub: this.hub, dest: src, listener: this, } srcAddr := &net.UDPAddr{ IP: src.Address().IP(), Port: int(src.Port()), } conn = NewConnection(conv, writer, this.localAddr, srcAddr, this.block) select { case this.awaitingConns <- conn: case <-time.After(time.Second * 5): conn.Close() return } this.sessions[sourceId] = conn } conn.Input(payload.Value) }
// @Private func (this *FreedomConnection) ResolveIP(destination v2net.Destination) v2net.Destination { if !destination.Address().IsDomain() { return destination } ips := this.dns.Get(destination.Address().Domain()) if len(ips) == 0 { log.Info("Freedom: DNS returns nil answer. Keep domain as is.") return destination } ip := ips[dice.Roll(len(ips))] var newDest v2net.Destination if destination.IsTCP() { newDest = v2net.TCPDestination(v2net.IPAddress(ip), destination.Port()) } else { newDest = v2net.UDPDestination(v2net.IPAddress(ip), destination.Port()) } log.Info("Freedom: Changing destination from ", destination, " to ", newDest) return newDest }
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()), ""}) if err != nil { log.Error("Failed to open tcp (%s): %v", dest.String(), err) if ray != nil { close(ray.OutboundOutput()) } return err } log.Info("VMessOut: Tunneling request for %s", request.Address.String()) defer conn.Close() if chunk := firstPacket.Chunk(); chunk != nil { conn.Write(chunk) } if !firstPacket.MoreChunks() { if ray != nil { close(ray.OutboundOutput()) } return nil } input := ray.OutboundInput() output := ray.OutboundOutput() var requestFinish, responseFinish sync.Mutex requestFinish.Lock() responseFinish.Lock() go handleRequest(conn, request, input, &requestFinish) go handleResponse(conn, request, output, &responseFinish) requestFinish.Lock() conn.CloseWrite() responseFinish.Lock() return nil }
func (this *Router) takeDetourWithoutCache(dest v2net.Destination) (string, error) { for _, rule := range this.config.Rules { if rule.Apply(dest) { return rule.Tag, nil } } if this.config.DomainStrategy == UseIPIfNonMatch && dest.Address().IsDomain() { log.Info("Router: Looking up IP for ", dest) ipDests := this.ResolveIP(dest) if ipDests != nil { for _, ipDest := range ipDests { log.Info("Router: Trying IP ", ipDest) for _, rule := range this.config.Rules { if rule.Apply(ipDest) { return rule.Tag, nil } } } } } return "", ErrNoRuleApplicable }
func (this *VMessOutboundHandler) startCommunicate(request *proto.RequestHeader, dest v2net.Destination, ray ray.OutboundRay, firstPacket v2net.Packet) error { var destIP net.IP if dest.Address().IsIPv4() || dest.Address().IsIPv6() { destIP = dest.Address().IP() } else { ips, err := net.LookupIP(dest.Address().Domain()) if err != nil { return err } destIP = ips[0] } conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{ IP: destIP, Port: int(dest.Port()), }) if err != nil { log.Error("Failed to open ", dest, ": ", err) if ray != nil { close(ray.OutboundOutput()) } return err } log.Info("VMessOut: Tunneling request to ", request.Address, " via ", dest) defer conn.Close() input := ray.OutboundInput() output := ray.OutboundOutput() var requestFinish, responseFinish sync.Mutex requestFinish.Lock() responseFinish.Lock() session := raw.NewClientSession(proto.DefaultIDHash) go this.handleRequest(session, conn, request, firstPacket, input, &requestFinish) go this.handleResponse(session, conn, request, dest, output, &responseFinish) requestFinish.Lock() conn.CloseWrite() responseFinish.Lock() return nil }
func startCommunicate(request *protocol.VMessRequest, dest v2net.Destination, ray ray.OutboundRay, firstPacket v2net.Packet) error { var destIp net.IP if dest.Address().IsIPv4() || dest.Address().IsIPv6() { destIp = dest.Address().IP() } else { ips, err := net.LookupIP(dest.Address().Domain()) if err != nil { return err } destIp = ips[0] } conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{ IP: destIp, Port: int(dest.Port()), }) if err != nil { log.Error("Failed to open ", dest, ": ", err) if ray != nil { close(ray.OutboundOutput()) } return err } log.Info("VMessOut: Tunneling request to ", request.Address, " via ", dest) defer conn.Close() input := ray.OutboundInput() output := ray.OutboundOutput() var requestFinish, responseFinish sync.Mutex requestFinish.Lock() responseFinish.Lock() go handleRequest(conn, request, firstPacket, input, &requestFinish) go handleResponse(conn, request, output, &responseFinish, (request.Command == protocol.CmdUDP)) requestFinish.Lock() conn.CloseWrite() responseFinish.Lock() return nil }
func socks5Request(command byte, address v2net.Destination) []byte { request := []byte{socks5Version, command, 0} request = appendAddress(request, address.Address()) request = address.Port().Bytes(request) return request }
func (this *UDPHub) WriteTo(payload []byte, dest v2net.Destination) (int, error) { return this.conn.WriteToUDP(payload, &net.UDPAddr{ IP: dest.Address().IP(), Port: int(dest.Port()), }) }
func (this *CIDRMatcher) Apply(dest v2net.Destination) bool { if !dest.Address().IsIPv4() && !dest.Address().IsIPv6() { return false } return this.cidr.Contains(dest.Address().IP()) }
func (this *FreedomConnection) Dispatch(destination v2net.Destination, payload *alloc.Buffer, ray ray.OutboundRay) error { log.Info("Freedom: Opening connection to ", destination) defer payload.Release() defer ray.OutboundInput().Release() defer ray.OutboundOutput().Close() var conn internet.Connection if this.domainStrategy == DomainStrategyUseIP && destination.Address().IsDomain() { destination = this.ResolveIP(destination) } err := retry.Timed(5, 100).On(func() error { rawConn, err := internet.Dial(this.meta.Address, destination, this.meta.StreamSettings) if err != nil { return err } conn = rawConn return nil }) if err != nil { log.Warning("Freedom: Failed to open connection to ", destination, ": ", err) return err } defer conn.Close() input := ray.OutboundInput() output := ray.OutboundOutput() var readMutex, writeMutex sync.Mutex readMutex.Lock() writeMutex.Lock() conn.Write(payload.Value) go func() { v2writer := v2io.NewAdaptiveWriter(conn) defer v2writer.Release() v2io.Pipe(input, v2writer) writeMutex.Unlock() }() go func() { defer readMutex.Unlock() var reader io.Reader = conn timeout := this.timeout if destination.IsUDP() { timeout = 16 } if timeout > 0 { reader = v2net.NewTimeOutReader(int(timeout) /* seconds */, conn) } v2reader := v2io.NewAdaptiveReader(reader) defer v2reader.Release() v2io.Pipe(v2reader, output) ray.OutboundOutput().Close() }() writeMutex.Lock() if tcpConn, ok := conn.(*tcp.RawConnection); ok { tcpConn.CloseWrite() } readMutex.Lock() return nil }
func (this *IPv4Matcher) Apply(dest v2net.Destination) bool { if !dest.Address().IsIPv4() { return false } return this.ipv4net.Contains(dest.Address().IP()) }