func New(ctx context.Context, config *Config) (*VMessInboundHandler, error) { space := app.SpaceFromContext(ctx) if space == nil { return nil, errors.New("VMess|Inbound: No space in context.") } allowedClients := vmess.NewTimedUserValidator(protocol.DefaultIDHash) for _, user := range config.User { allowedClients.Add(user) } handler := &VMessInboundHandler{ clients: allowedClients, detours: config.Detour, usersByEmail: NewUserByEmail(config.User, config.GetDefaultValue()), } space.OnInitialize(func() error { handler.packetDispatcher = dispatcher.FromSpace(space) if handler.packetDispatcher == nil { return errors.New("VMess|Inbound: Dispatcher is not found in space.") } handler.inboundHandlerManager = proxyman.InboundHandlerManagerFromSpace(space) if handler.inboundHandlerManager == nil { return errors.New("VMess|Inbound: InboundHandlerManager is not found is space.") } return nil }) return handler, nil }
func Dial(ctx context.Context, dest v2net.Destination) (Connection, error) { if dest.Network == v2net.Network_TCP { streamSettings, _ := StreamSettingsFromContext(ctx) protocol := streamSettings.GetEffectiveProtocol() transportSettings, err := streamSettings.GetEffectiveTransportSettings() if err != nil { return nil, err } ctx = ContextWithTransportSettings(ctx, transportSettings) if streamSettings != nil && streamSettings.HasSecuritySettings() { securitySettings, err := streamSettings.GetEffectiveSecuritySettings() if err != nil { return nil, err } ctx = ContextWithSecuritySettings(ctx, securitySettings) } dialer := transportDialerCache[protocol] if dialer == nil { return nil, errors.New("Internet|Dialer: ", protocol, " dialer not registered.") } return dialer(ctx, dest) } udpDialer := transportDialerCache[TransportProtocol_UDP] if udpDialer == nil { return nil, errors.New("Internet|Dialer: UDP dialer not registered.") } return udpDialer(ctx, dest) }
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) { space := app.SpaceFromContext(ctx) if space == nil { return nil, errors.New("Shadowsocks|Server: No space in context.") } if config.GetUser() == nil { return nil, protocol.ErrUserMissing } rawAccount, err := config.User.GetTypedAccount() if err != nil { return nil, errors.Base(err).Message("Shadowsocks|Server: Failed to get user account.") } account := rawAccount.(*ShadowsocksAccount) s := &Server{ config: config, user: config.GetUser(), account: account, } space.OnInitialize(func() error { s.packetDispatcher = dispatcher.FromSpace(space) if s.packetDispatcher == nil { return errors.New("Shadowsocks|Server: Dispatcher is not found in space.") } return nil }) return s, nil }
func NewRouter(ctx context.Context, config *Config) (*Router, error) { space := app.SpaceFromContext(ctx) if space == nil { return nil, errors.New("Router: No space in context.") } r := &Router{ domainStrategy: config.DomainStrategy, rules: make([]Rule, len(config.Rule)), } space.OnInitialize(func() error { for idx, rule := range config.Rule { r.rules[idx].Tag = rule.Tag cond, err := rule.BuildCondition() if err != nil { return err } r.rules[idx].Condition = cond } r.dnsServer = dns.FromSpace(space) if r.dnsServer == nil { return errors.New("Router: DNS is not found in the space.") } return nil }) return r, nil }
func (v *ShadowsocksClientConfig) Build() (*serial.TypedMessage, error) { config := new(shadowsocks.ClientConfig) if len(v.Servers) == 0 { return nil, errors.New("0 Shadowsocks server configured.") } serverSpecs := make([]*protocol.ServerEndpoint, len(v.Servers)) for idx, server := range v.Servers { if server.Address == nil { return nil, errors.New("Shadowsocks server address is not set.") } if server.Port == 0 { return nil, errors.New("Invalid Shadowsocks port.") } if len(server.Password) == 0 { return nil, errors.New("Shadowsocks password is not specified.") } account := &shadowsocks.Account{ Password: server.Password, Ota: shadowsocks.Account_Enabled, } if !server.Ota { account.Ota = shadowsocks.Account_Disabled } cipher := strings.ToLower(server.Cipher) switch cipher { case "aes-256-cfb": account.CipherType = shadowsocks.CipherType_AES_256_CFB case "aes-128-cfb": account.CipherType = shadowsocks.CipherType_AES_128_CFB case "chacha20": account.CipherType = shadowsocks.CipherType_CHACHA20 case "chacha20-ietf": account.CipherType = shadowsocks.CipherType_CHACHA20_IEFT default: return nil, errors.New("Unknown cipher method: " + cipher) } ss := &protocol.ServerEndpoint{ Address: server.Address.Build(), Port: uint32(server.Port), User: []*protocol.User{ { Email: server.Email, Account: serial.ToTypedMessage(account), }, }, } serverSpecs[idx] = ss } config.Server = serverSpecs return serial.ToTypedMessage(config), nil }
func ReadUDPRequest(packet []byte) (*Socks5UDPRequest, error) { if len(packet) < 5 { return nil, errors.New("Socks|UDP: Insufficient length of packet.") } request := new(Socks5UDPRequest) // packet[0] and packet[1] are reserved request.Fragment = packet[2] addrType := packet[3] var dataBegin int switch addrType { case AddrTypeIPv4: if len(packet) < 10 { return nil, errors.New("Socks|UDP: Insufficient length of packet.") } ip := packet[4:8] request.Port = v2net.PortFromBytes(packet[8:10]) request.Address = v2net.IPAddress(ip) dataBegin = 10 case AddrTypeIPv6: if len(packet) < 22 { return nil, errors.New("Socks|UDP: Insufficient length of packet.") } ip := packet[4:20] request.Port = v2net.PortFromBytes(packet[20:22]) request.Address = v2net.IPAddress(ip) dataBegin = 22 case AddrTypeDomain: domainLength := int(packet[4]) if len(packet) < 5+domainLength+2 { return nil, errors.New("Socks|UDP: Insufficient length of packet.") } domain := string(packet[5 : 5+domainLength]) request.Port = v2net.PortFromBytes(packet[5+domainLength : 5+domainLength+2]) request.Address = v2net.ParseAddress(domain) dataBegin = 5 + domainLength + 2 default: return nil, errors.Format("Socks|UDP: Unknown address type %d", addrType) } if len(packet) > dataBegin { b := buf.NewSmall() b.Append(packet[dataBegin:]) request.Data = b } return request, nil }
func (v *InboundDetourConfig) Build() (*proxyman.InboundHandlerConfig, error) { receiverSettings := &proxyman.ReceiverConfig{ AllowPassiveConnection: v.AllowPassive, } if v.PortRange == nil { return nil, errors.New("Port range not specified in InboundDetour.") } receiverSettings.PortRange = v.PortRange.Build() if v.ListenOn != nil { if v.ListenOn.Family().IsDomain() { return nil, errors.New("Unable to listen on domain address: ", v.ListenOn.Domain()) } receiverSettings.Listen = v.ListenOn.Build() } if v.Allocation != nil { as, err := v.Allocation.Build() if err != nil { return nil, err } receiverSettings.AllocationStrategy = as } if v.StreamSetting != nil { ss, err := v.StreamSetting.Build() if err != nil { return nil, err } receiverSettings.StreamSettings = ss } rawConfig, err := inboundConfigLoader.LoadWithID(v.Settings, v.Protocol) if err != nil { return nil, errors.Base(err).Message("Failed to load inbound detour config.") } if dokodemoConfig, ok := rawConfig.(*DokodemoConfig); ok { receiverSettings.ReceiveOriginalDestination = dokodemoConfig.Redirect } ts, err := rawConfig.(Buildable).Build() if err != nil { return nil, err } return &proxyman.InboundHandlerConfig{ Tag: v.Tag, ReceiverSettings: serial.ToTypedMessage(receiverSettings), ProxySettings: ts, }, nil }
func (m *DefaultInboundHandlerManager) GetHandler(ctx context.Context, tag string) (proxyman.InboundHandler, error) { handler, found := m.taggedHandlers[tag] if !found { return nil, errors.New("Proxymand|DefaultInboundHandlerManager: Handler not found: ", tag) } return handler, nil }
func RegisterTransportDialer(protocol TransportProtocol, dialer Dialer) error { if _, found := transportDialerCache[protocol]; found { return errors.New("Internet|Dialer: ", protocol, " dialer already registered.") } transportDialerCache[protocol] = dialer return nil }
func NewCacheServer(space app.Space, config *dns.Config) *CacheServer { server := &CacheServer{ records: make(map[string]*DomainRecord), servers: make([]NameServer, len(config.NameServers)), hosts: config.GetInternalHosts(), } space.InitializeApplication(func() error { if !space.HasApp(dispatcher.APP_ID) { return errors.New("DNS: Dispatcher is not found in the space.") } dispatcher := space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher) for idx, destPB := range config.NameServers { address := destPB.Address.AsAddress() if address.Family().IsDomain() && address.Domain() == "localhost" { server.servers[idx] = &LocalNameServer{} } else { dest := destPB.AsDestination() if dest.Network == v2net.Network_Unknown { dest.Network = v2net.Network_UDP } if dest.Network == v2net.Network_UDP { server.servers[idx] = NewUDPNameServer(dest, dispatcher) } } } if len(config.NameServers) == 0 { server.servers = append(server.servers, &LocalNameServer{}) } return nil }) return server }
func NewRouter(config *Config, space app.Space) *Router { r := &Router{ domainStrategy: config.DomainStrategy, //cache: NewRoutingTable(), rules: make([]Rule, len(config.Rule)), } space.InitializeApplication(func() error { for idx, rule := range config.Rule { r.rules[idx].Tag = rule.Tag cond, err := rule.BuildCondition() if err != nil { return err } r.rules[idx].Condition = cond } if !space.HasApp(dns.APP_ID) { return errors.New("Router: DNS is not found in the space.") } r.dnsServer = space.GetApp(dns.APP_ID).(dns.Server) return nil }) return r }
func (v *ChunkReader) Read() (*buf.Buffer, error) { buffer := buf.New() if err := buffer.AppendSupplier(buf.ReadFullFrom(v.reader, 2)); err != nil { buffer.Release() return nil, err } // There is a potential buffer overflow here. Large buffer is 64K bytes, // while uin16 + 10 will be more than that length := serial.BytesToUint16(buffer.BytesTo(2)) + AuthSize if length > buf.Size { // Theoretically the size of a chunk is 64K, but most Shadowsocks implementations used <4K buffer. buffer.Release() buffer = buf.NewLocal(int(length) + 128) } buffer.Clear() if err := buffer.AppendSupplier(buf.ReadFullFrom(v.reader, int(length))); err != nil { buffer.Release() return nil, err } authBytes := buffer.BytesTo(AuthSize) payload := buffer.BytesFrom(AuthSize) actualAuthBytes := make([]byte, AuthSize) v.auth.Authenticate(payload)(actualAuthBytes) if !bytes.Equal(authBytes, actualAuthBytes) { buffer.Release() return nil, errors.New("Shadowsocks|AuthenticationReader: Invalid auth.") } buffer.SliceFrom(AuthSize) return buffer, nil }
func CreateTransportConfig(protocol TransportProtocol) (interface{}, error) { creator, ok := globalTransportConfigCreatorCache[protocol] if !ok { return nil, errors.New("Internet: Unknown transport protocol: ", protocol) } return creator(), nil }
func (v *SocksServerConfig) Build() (*serial.TypedMessage, error) { config := new(socks.ServerConfig) if v.AuthMethod == AuthMethodNoAuth { config.AuthType = socks.AuthType_NO_AUTH } else if v.AuthMethod == AuthMethodUserPass { config.AuthType = socks.AuthType_PASSWORD } else { return nil, errors.New("Unknown socks auth method: " + v.AuthMethod) } if len(v.Accounts) > 0 { config.Accounts = make(map[string]string, len(v.Accounts)) for _, account := range v.Accounts { config.Accounts[account.Username] = account.Password } } config.UdpEnabled = v.UDP if v.Host != nil { config.Address = v.Host.Build() } config.Timeout = v.Timeout return serial.ToTypedMessage(config), nil }
func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandlerMeta) (*Server, error) { if config.GetUser() == nil { return nil, protocol.ErrUserMissing } rawAccount, err := config.User.GetTypedAccount() if err != nil { return nil, errors.Base(err).Message("Shadowsocks|Server: Failed to get user account.") } account := rawAccount.(*ShadowsocksAccount) s := &Server{ config: config, meta: meta, user: config.GetUser(), account: account, } space.InitializeApplication(func() error { if !space.HasApp(dispatcher.APP_ID) { return errors.New("Shadowsocks|Server: Dispatcher is not found in space.") } s.packetDispatcher = space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher) return nil }) return s, nil }
func NewDefaultDispatcher(ctx context.Context, config *dispatcher.Config) (*DefaultDispatcher, error) { space := app.SpaceFromContext(ctx) if space == nil { return nil, errors.New("DefaultDispatcher: No space in context.") } d := &DefaultDispatcher{} space.OnInitialize(func() error { d.ohm = proxyman.OutboundHandlerManagerFromSpace(space) if d.ohm == nil { return errors.New("DefaultDispatcher: OutboundHandlerManager is not found in the space.") } d.router = router.FromSpace(space) return nil }) return d, nil }
func (v *InboundConnectionConfig) Build() (*core.InboundConnectionConfig, error) { config := new(core.InboundConnectionConfig) config.PortRange = &v2net.PortRange{ From: uint32(v.Port), To: uint32(v.Port), } if v.Listen != nil { if v.Listen.Family().IsDomain() { return nil, errors.New("Point: Unable to listen on domain address: " + v.Listen.Domain()) } config.ListenOn = v.Listen.Build() } if v.StreamSetting != nil { ts, err := v.StreamSetting.Build() if err != nil { return nil, err } config.StreamSettings = ts } config.AllowPassiveConnection = v.AllowPassive jsonConfig, err := inboundConfigLoader.LoadWithID(v.Settings, v.Protocol) if err != nil { return nil, errors.Base(err).Message("Failed to load inbound config.") } ts, err := jsonConfig.(Buildable).Build() if err != nil { return nil, err } config.Settings = ts if len(v.Tag) > 0 { config.Tag = v.Tag } return config, nil }
func RegisterTransportListener(protocol TransportProtocol, listener ListenFunc) error { if _, found := transportListenerCache[protocol]; found { return errors.New("Internet|TCPHub: ", protocol, " listener already registered.") } transportListenerCache[protocol] = listener return nil }
func (v *InboundDetourAllocationConfig) Build() (*core.AllocationStrategy, error) { config := new(core.AllocationStrategy) switch strings.ToLower(v.Strategy) { case "always": config.Type = core.AllocationStrategy_Always case "random": config.Type = core.AllocationStrategy_Random case "external": config.Type = core.AllocationStrategy_External default: return nil, errors.New("Unknown allocation strategy: ", v.Strategy) } if v.Concurrency != nil { config.Concurrency = &core.AllocationStrategyConcurrency{ Value: *v.Concurrency, } } if v.RefreshMin != nil { config.Refresh = &core.AllocationStrategyRefresh{ Value: *v.RefreshMin, } } return config, nil }
// ParseString converts an UUID in string form to object. func ParseString(str string) (*UUID, error) { text := []byte(str) if len(text) < 32 { return nil, errors.New("Invalid UUID: ", str) } uuid := new(UUID) b := uuid.Bytes() for _, byteGroup := range byteGroups { if text[0] == '-' { text = text[1:] } _, err := hex.Decode(b[:byteGroup/2], text[:byteGroup]) if err != nil { return nil, err } text = text[byteGroup:] b = b[byteGroup/2:] } return uuid, nil }
func (v *ProxyConfig) Build() (*internet.ProxyConfig, error) { if len(v.Tag) == 0 { return nil, errors.New("Proxy tag is not set.") } return &internet.ProxyConfig{ Tag: v.Tag, }, nil }
func waitForData(wdi *waitDataInspector) func() error { return func() error { if wdi.WaitForData() { return nil } return errors.New("DefaultDispatcher: No data.") } }
// NewServer creates a new HTTP inbound handler. func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) { space := app.SpaceFromContext(ctx) if space == nil { return nil, errors.New("HTTP|Server: No space in context.") } s := &Server{ config: config, } space.OnInitialize(func() error { s.packetDispatcher = dispatcher.FromSpace(space) if s.packetDispatcher == nil { return errors.New("HTTP|Server: Dispatcher not found in space.") } return nil }) return s, nil }
// PraseBytes converts an UUID in byte form to object. func ParseBytes(b []byte) (*UUID, error) { if len(b) != 16 { return nil, errors.New("Invalid UUID: ", b) } uuid := new(UUID) copy(uuid[:], b) return uuid, nil }
func CreateOutboundHandler(name string, space app.Space, config interface{}, meta *OutboundHandlerMeta) (OutboundHandler, error) { creator, found := outboundFactories[name] if !found { return nil, errors.New("Proxy: Unknown outbound name: " + name) } if meta.StreamSettings == nil { meta.StreamSettings = &internet.StreamConfig{ Network: creator.StreamCapability().Get(0), } } else { if !creator.StreamCapability().HasNetwork(meta.StreamSettings.Network) { return nil, errors.New("Proxy: Invalid network: " + meta.StreamSettings.Network.String()) } } return creator.Create(space, config, meta) }
func (v *spaceImpl) AddApplication(app Application) error { if v == nil { return errors.New("App: Nil space.") } appType := reflect.TypeOf(app.Interface()) v.cache[appType] = app return nil }
func (v *HTTPAuthenticatorResponse) Build() (*http.ResponseConfig, error) { config := &http.ResponseConfig{ Header: []*http.Header{ { Name: "Content-Type", Value: []string{"application/octet-stream", "video/mpeg"}, }, { Name: "Transfer-Encoding", Value: []string{"chunked"}, }, { Name: "Connection", Value: []string{"keep-alive"}, }, { Name: "Pragma", Value: []string{"no-cache"}, }, { Name: "Cache-Control", Value: []string{"private", "no-cache"}, }, }, } if len(v.Version) > 0 { config.Version = &http.Version{Value: v.Version} } if len(v.Status) > 0 || len(v.Reason) > 0 { config.Status = &http.Status{ Code: "200", Reason: "OK", } if len(v.Status) > 0 { config.Status.Code = v.Status } if len(v.Reason) > 0 { config.Status.Reason = v.Reason } } if len(v.Headers) > 0 { config.Header = make([]*http.Header, 0, len(v.Headers)) for key, value := range v.Headers { if value == nil { return nil, errors.New("Empty HTTP header value: " + key) } config.Header = append(config.Header, &http.Header{ Name: key, Value: append([]string(nil), (*value)...), }) } } return config, nil }
func (v *HTTPAuthenticatorRequest) Build() (*http.RequestConfig, error) { config := &http.RequestConfig{ Uri: []string{"/"}, Header: []*http.Header{ { Name: "Host", Value: []string{"www.baidu.com", "www.bing.com"}, }, { Name: "User-Agent", Value: []string{ "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46", }, }, { Name: "Accept-Encoding", Value: []string{"gzip, deflate"}, }, { Name: "Connection", Value: []string{"keep-alive"}, }, { Name: "Pragma", Value: []string{"no-cache"}, }, }, } if len(v.Version) > 0 { config.Version = &http.Version{Value: v.Version} } if len(v.Method) > 0 { config.Method = &http.Method{Value: v.Method} } if len(v.Path) > 0 { config.Uri = append([]string(nil), (v.Path)...) } if len(v.Headers) > 0 { config.Header = make([]*http.Header, 0, len(v.Headers)) for key, value := range v.Headers { if value == nil { return nil, errors.New("Empty HTTP header value: " + key) } config.Header = append(config.Header, &http.Header{ Name: key, Value: append([]string(nil), (*value)...), }) } } return config, nil }
func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection) error { switch network { case net.Network_TCP: return s.processTCP(ctx, conn) case net.Network_UDP: return s.handleUDPPayload(ctx, conn) default: return errors.New("Socks|Server: Unknown network: ", network) } }
func UnmarshalCommand(cmdID byte, data []byte) (protocol.ResponseCommand, error) { if len(data) <= 4 { return nil, errors.New("VMess|Command: Insufficient length.") } expectedAuth := Authenticate(data[4:]) actualAuth := serial.BytesToUint32(data[:4]) if expectedAuth != actualAuth { return nil, errors.New("VMess|Command: Invalid auth.") } var factory CommandFactory switch cmdID { case 1: factory = new(CommandSwitchAccountFactory) default: return nil, ErrUnknownCommand } return factory.Unmarshal(data[4:]) }