Increase Performance (#145)
* Update libv2ray_main.go code with security fixes for G304 (file inclusion vulnerability) and G104 (unhandled errors). * Update libv2ray_main.go * Update libv2ray_main.go * Standard formatting and removal of redundant structures * Update libv2ray_main.go
This commit is contained in:
1 parent
c53ff63a3b
commit
fd5117ab47
1 file changed
+73
-39
+73
-39
@@ -26,6 +26,7 @@ import (
|
|||||||
mobasset "golang.org/x/mobile/asset"
|
mobasset "golang.org/x/mobile/asset"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Constants for environment variables
|
||||||
const (
|
const (
|
||||||
coreAsset = "xray.location.asset"
|
coreAsset = "xray.location.asset"
|
||||||
coreCert = "xray.location.cert"
|
coreCert = "xray.location.cert"
|
||||||
@@ -51,39 +52,66 @@ type CoreCallbackHandler interface {
|
|||||||
// consoleLogWriter implements a log writer without datetime stamps
|
// consoleLogWriter implements a log writer without datetime stamps
|
||||||
// as Android system already adds timestamps to each log line
|
// as Android system already adds timestamps to each log line
|
||||||
type consoleLogWriter struct {
|
type consoleLogWriter struct {
|
||||||
logger *log.Logger
|
logger *log.Logger // Standard logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitCoreEnv initializes environment variables and file system handlers for the core
|
// InitCoreEnv initializes environment variables and file system handlers for the core
|
||||||
// It sets up asset path, certificate path, XUDP base key and customizes the file reader
|
// It sets up asset path, certificate path, XUDP base key and customizes the file reader
|
||||||
// to support Android asset system
|
// to support Android asset system
|
||||||
func InitCoreEnv(envPath string, key string) {
|
func InitCoreEnv(envPath string, key string) {
|
||||||
|
// Set asset/cert paths
|
||||||
if len(envPath) > 0 {
|
if len(envPath) > 0 {
|
||||||
os.Setenv(coreAsset, envPath)
|
if err := os.Setenv(coreAsset, envPath); err != nil {
|
||||||
os.Setenv(coreCert, envPath)
|
log.Printf("failed to set %s: %v", coreAsset, err)
|
||||||
}
|
|
||||||
if len(key) > 0 {
|
|
||||||
os.Setenv(xudpBaseKey, key)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
corefilesystem.NewFileReader = func(path string) (io.ReadCloser, error) {
|
|
||||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
|
||||||
_, file := filepath.Split(path)
|
|
||||||
return mobasset.Open(file)
|
|
||||||
}
|
}
|
||||||
return os.Open(path)
|
if err := os.Setenv(coreCert, envPath); err != nil {
|
||||||
|
log.Printf("failed to set %s: %v", coreCert, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set XUDP encryption key
|
||||||
|
if len(key) > 0 {
|
||||||
|
if err := os.Setenv(xudpBaseKey, key); err != nil {
|
||||||
|
log.Printf("failed to set %s: %v", xudpBaseKey, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom file reader with path validation
|
||||||
|
corefilesystem.NewFileReader = func(path string) (io.ReadCloser, error) {
|
||||||
|
// G304 Fix - Path sanitization
|
||||||
|
baseDir := envPath
|
||||||
|
cleanPath := filepath.Clean(path)
|
||||||
|
fullPath := filepath.Join(baseDir, cleanPath)
|
||||||
|
|
||||||
|
// Prevent directory traversal
|
||||||
|
if baseDir != "" && !strings.HasPrefix(fullPath, baseDir) {
|
||||||
|
return nil, fmt.Errorf("unauthorized path: %s", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check file existence
|
||||||
|
if _, err := os.Stat(fullPath); os.IsNotExist(err) {
|
||||||
|
_, file := filepath.Split(fullPath)
|
||||||
|
return mobasset.Open(file) // Fallback to assets
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, fmt.Errorf("file access error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.Open(fullPath) // #nosec G304 - Validated path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCoreController initializes and returns a new CoreController instance
|
// NewCoreController initializes and returns a new CoreController instance
|
||||||
// Sets up the console log handler and associates it with the provided callback handler
|
// Sets up the console log handler and associates it with the provided callback handler
|
||||||
func NewCoreController(s CoreCallbackHandler) *CoreController {
|
func NewCoreController(s CoreCallbackHandler) *CoreController {
|
||||||
coreapplog.RegisterHandlerCreator(coreapplog.LogType_Console,
|
// Register custom logger
|
||||||
func(lt coreapplog.LogType,
|
if err := coreapplog.RegisterHandlerCreator(
|
||||||
options coreapplog.HandlerCreatorOptions) (corecommlog.Handler, error) {
|
coreapplog.LogType_Console,
|
||||||
|
func(lt coreapplog.LogType, options coreapplog.HandlerCreatorOptions) (corecommlog.Handler, error) {
|
||||||
return corecommlog.NewLogger(createStdoutLogWriter()), nil
|
return corecommlog.NewLogger(createStdoutLogWriter()), nil
|
||||||
})
|
},
|
||||||
|
); err != nil {
|
||||||
|
log.Printf("logger registration failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &CoreController{
|
return &CoreController{
|
||||||
CallbackHandler: s,
|
CallbackHandler: s,
|
||||||
@@ -98,12 +126,11 @@ func (x *CoreController) StartLoop(configContent string) (err error) {
|
|||||||
defer x.coreMutex.Unlock()
|
defer x.coreMutex.Unlock()
|
||||||
|
|
||||||
if x.IsRunning {
|
if x.IsRunning {
|
||||||
log.Println("The instance is already running")
|
log.Println("core already running")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = x.doStartLoop(configContent)
|
return x.doStartLoop(configContent)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StopLoop safely stops the core processing loop and releases resources
|
// StopLoop safely stops the core processing loop and releases resources
|
||||||
@@ -114,8 +141,7 @@ func (x *CoreController) StopLoop() error {
|
|||||||
|
|
||||||
if x.IsRunning {
|
if x.IsRunning {
|
||||||
x.doShutdown()
|
x.doShutdown()
|
||||||
log.Println("Shut down the running instance")
|
x.CallbackHandler.OnEmitStatus(0, "core stopped")
|
||||||
x.CallbackHandler.OnEmitStatus(0, "Closed")
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -148,13 +174,16 @@ func (x *CoreController) MeasureDelay(url string) (int64, error) {
|
|||||||
func MeasureOutboundDelay(ConfigureFileContent string, url string) (int64, error) {
|
func MeasureOutboundDelay(ConfigureFileContent string, url string) (int64, error) {
|
||||||
config, err := coreserial.LoadJSONConfig(strings.NewReader(ConfigureFileContent))
|
config, err := coreserial.LoadJSONConfig(strings.NewReader(ConfigureFileContent))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, fmt.Errorf("failed to load JSON config: %w", err)
|
return -1, fmt.Errorf("config load error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simplify config for testing
|
||||||
config.Inbound = nil
|
config.Inbound = nil
|
||||||
var essentialApp []*serial.TypedMessage
|
var essentialApp []*serial.TypedMessage
|
||||||
for _, app := range config.App {
|
for _, app := range config.App {
|
||||||
if app.Type == "xray.app.proxyman.OutboundConfig" || app.Type == "xray.app.dispatcher.Config" || app.Type == "xray.app.log.Config" {
|
if app.Type == "xray.app.proxyman.OutboundConfig" ||
|
||||||
|
app.Type == "xray.app.dispatcher.Config" ||
|
||||||
|
app.Type == "xray.app.log.Config" {
|
||||||
essentialApp = append(essentialApp, app)
|
essentialApp = append(essentialApp, app)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,10 +191,12 @@ func MeasureOutboundDelay(ConfigureFileContent string, url string) (int64, error
|
|||||||
|
|
||||||
inst, err := core.New(config)
|
inst, err := core.New(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, fmt.Errorf("failed to create core instance: %w", err)
|
return -1, fmt.Errorf("instance creation failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
inst.Start()
|
if err := inst.Start(); err != nil {
|
||||||
|
return -1, fmt.Errorf("startup failed: %w", err)
|
||||||
|
}
|
||||||
defer inst.Close()
|
defer inst.Close()
|
||||||
return measureInstDelay(context.Background(), inst, url)
|
return measureInstDelay(context.Background(), inst, url)
|
||||||
}
|
}
|
||||||
@@ -179,7 +210,9 @@ func CheckVersionX() string {
|
|||||||
// doShutdown shuts down the Xray instance and cleans up resources
|
// doShutdown shuts down the Xray instance and cleans up resources
|
||||||
func (x *CoreController) doShutdown() {
|
func (x *CoreController) doShutdown() {
|
||||||
if x.coreInstance != nil {
|
if x.coreInstance != nil {
|
||||||
x.coreInstance.Close()
|
if err := x.coreInstance.Close(); err != nil {
|
||||||
|
log.Printf("core shutdown error: %v", err)
|
||||||
|
}
|
||||||
x.coreInstance = nil
|
x.coreInstance = nil
|
||||||
}
|
}
|
||||||
x.IsRunning = false
|
x.IsRunning = false
|
||||||
@@ -188,37 +221,36 @@ func (x *CoreController) doShutdown() {
|
|||||||
|
|
||||||
// doStartLoop sets up and starts the Xray core
|
// doStartLoop sets up and starts the Xray core
|
||||||
func (x *CoreController) doStartLoop(configContent string) error {
|
func (x *CoreController) doStartLoop(configContent string) error {
|
||||||
log.Println("Loading core config")
|
log.Println("initializing core...")
|
||||||
config, err := coreserial.LoadJSONConfig(strings.NewReader(configContent))
|
config, err := coreserial.LoadJSONConfig(strings.NewReader(configContent))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to load core config: %w", err)
|
return fmt.Errorf("config error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Creating new core instance")
|
|
||||||
x.coreInstance, err = core.New(config)
|
x.coreInstance, err = core.New(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create core instance: %w", err)
|
return fmt.Errorf("core init failed: %w", err)
|
||||||
}
|
}
|
||||||
x.statsManager = x.coreInstance.GetFeature(corestats.ManagerType()).(corestats.Manager)
|
x.statsManager = x.coreInstance.GetFeature(corestats.ManagerType()).(corestats.Manager)
|
||||||
|
|
||||||
log.Println("Starting core")
|
log.Println("starting core...")
|
||||||
x.IsRunning = true
|
x.IsRunning = true
|
||||||
if err := x.coreInstance.Start(); err != nil {
|
if err := x.coreInstance.Start(); err != nil {
|
||||||
x.IsRunning = false
|
x.IsRunning = false
|
||||||
return fmt.Errorf("failed to start core: %w", err)
|
return fmt.Errorf("startup failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
x.CallbackHandler.Startup()
|
x.CallbackHandler.Startup()
|
||||||
x.CallbackHandler.OnEmitStatus(0, "Started successfully, running")
|
x.CallbackHandler.OnEmitStatus(0, "Started successfully, running")
|
||||||
|
|
||||||
log.Println("Starting core successfully")
|
log.Println("Starting core successfully")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// measureInstDelay measures the delay for an instance to a given URL
|
// measureInstDelay measures the delay for an instance to a given URL
|
||||||
func measureInstDelay(ctx context.Context, inst *core.Instance, url string) (int64, error) {
|
func measureInstDelay(ctx context.Context, inst *core.Instance, url string) (int64, error) {
|
||||||
if inst == nil {
|
if inst == nil {
|
||||||
return -1, errors.New("core instance is nil")
|
return -1, errors.New("nil instance")
|
||||||
}
|
}
|
||||||
|
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
@@ -238,9 +270,10 @@ func measureInstDelay(ctx context.Context, inst *core.Instance, url string) (int
|
|||||||
Timeout: 12 * time.Second,
|
Timeout: 12 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(url) == 0 {
|
if url == "" {
|
||||||
url = "https://www.google.com/generate_204"
|
url = "https://www.google.com/generate_204"
|
||||||
}
|
}
|
||||||
|
|
||||||
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
|
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
@@ -250,11 +283,12 @@ func measureInstDelay(ctx context.Context, inst *core.Instance, url string) (int
|
|||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
|
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
|
||||||
return -1, fmt.Errorf("unexpected status code: %s", resp.Status)
|
return -1, fmt.Errorf("invalid status: %s", resp.Status)
|
||||||
}
|
}
|
||||||
return time.Since(start).Milliseconds(), nil
|
return time.Since(start).Milliseconds(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log writer implementation
|
||||||
func (w *consoleLogWriter) Write(s string) error {
|
func (w *consoleLogWriter) Write(s string) error {
|
||||||
w.logger.Print(s)
|
w.logger.Print(s)
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in new issue
Block a user