File size: 3,616 Bytes
6a5b8d8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"""

Main entry point for Outline/IKEv2 VPN server

"""

import os
import sys
import asyncio
import logging
import json
import socket
from pathlib import Path
from contextlib import closing

# Add project root to path
project_root = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, project_root)

from core.outline_server import OutlineServer
from core.ikev2_server import IKEv2Server as IPsecManager
from core.process_lock import ProcessLock

# Setup logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(),
        logging.FileHandler('vpn_server.log')
    ]
)

logger = logging.getLogger(__name__)

def find_available_port(start_port: int, end_port: int = 65535) -> int:
    """Find an available port in the given range"""
    for port in range(start_port, end_port + 1):
        with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
            try:
                sock.bind(('', port))
                return port
            except socket.error:
                continue
    raise RuntimeError(f"No available ports in range {start_port}-{end_port}")

async def main():
    # Initialize process lock
    process_lock = ProcessLock()
    if not process_lock.acquire():
        logger.error("Another instance of the VPN server is already running")
        sys.exit(1)

    try:
        # Load configuration
        config_path = os.path.join(project_root, 'config', 'server_config.json')
        if not os.path.exists(config_path):
            default_config = {
                "server": {
                    "host": "0.0.0.0",
                    "port": 8388,  # Default Shadowsocks port
                    "virtual_network": "10.0.0.0/24",
                    "dns_servers": ["8.8.8.8", "8.8.4.4"],
                    "fallback_ports": [8389, 8390, 8391, 8392]
                }
            }
            os.makedirs(os.path.dirname(config_path), exist_ok=True)
            with open(config_path, 'w') as f:
                json.dump(default_config, f, indent=4)
            logger.info("Created default configuration")

        # Load configuration
        with open(config_path, 'r') as f:
            config = json.load(f)

        # Find available port
        try:
            port = config["server"]["port"]
            with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
                sock.bind(('', port))
        except socket.error:
            logger.warning(f"Default port {port} is in use, finding alternative...")
            port = find_available_port(8388)
            config["server"]["port"] = port
            logger.info(f"Using alternative port: {port}")

        # Start Outline server with elevated privileges check
        if os.name != 'nt' and os.geteuid() != 0:  # Not running as root on Unix
            logger.error("VPN server must be run with administrator/root privileges")
            sys.exit(1)

        server = OutlineServer(config)
        await server.start()

        # Keep running until interrupted
        while True:
            await asyncio.sleep(1)

    except KeyboardInterrupt:
        logger.info("Shutting down VPN server...")
        if 'server' in locals():
            await server.stop()

    except Exception as e:
        logger.error(f"Server error: {e}")
        sys.exit(1)

    finally:
        process_lock.release()

if __name__ == "__main__":
    asyncio.run(main())