mirror of
https://github.com/masterking32/MasterHttpRelayVPN.git
synced 2026-05-17 21:24:37 +03:00
Implement lan sharing
This commit is contained in:
@@ -174,6 +174,29 @@ Firefox uses its own certificate store, so even after OS-level install you need
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## LAN Sharing (Optional)
|
||||||
|
|
||||||
|
By default, the proxy only listens on `127.0.0.1` (localhost), meaning only your computer can use it. To allow other devices on your local network (LAN) to use the proxy:
|
||||||
|
|
||||||
|
1. Set `"lan_sharing": true` in your `config.json`
|
||||||
|
2. The proxy will automatically listen on all network interfaces (`0.0.0.0`)
|
||||||
|
3. The startup log will show your LAN IP addresses that other devices can connect to
|
||||||
|
|
||||||
|
**Example LAN configuration:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"lan_sharing": true,
|
||||||
|
"listen_host": "0.0.0.0",
|
||||||
|
"listen_port": 8085
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Security Warning:** When LAN sharing is enabled, anyone on your local network can use your proxy. Ensure your network is trusted and consider additional security measures.
|
||||||
|
|
||||||
|
**On other devices:** Configure them to use your computer's LAN IP (shown in the startup log) and port 8085 as the HTTP proxy.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Modes Overview
|
## Modes Overview
|
||||||
|
|
||||||
This project focuses entirely on the **Apps Script** relay — a free Google account is all you need, no server, no VPS, no Cloudflare setup. Everything is configured out of the box for this mode.
|
This project focuses entirely on the **Apps Script** relay — a free Google account is all you need, no server, no VPS, no Cloudflare setup. Everything is configured out of the box for this mode.
|
||||||
@@ -188,8 +211,9 @@ This project focuses entirely on the **Apps Script** relay — a free Google acc
|
|||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `auth_key` | Password shared between your computer and the relay |
|
| `auth_key` | Password shared between your computer and the relay |
|
||||||
| `script_id` | Your Google Apps Script Deployment ID |
|
| `script_id` | Your Google Apps Script Deployment ID |
|
||||||
| `listen_host` | Where to listen (`127.0.0.1` = only this computer) |
|
| `listen_host` | Where to listen (`127.0.0.1` = only this computer, `0.0.0.0` = all interfaces for LAN sharing) |
|
||||||
| `listen_port` | Which port to listen on (default: `8085`) |
|
| `listen_port` | Which port to listen on (default: `8085`) |
|
||||||
|
| `lan_sharing` | Enable LAN sharing to allow other devices on your network to use the proxy (`false` by default) |
|
||||||
| `log_level` | How much detail to show: `DEBUG`, `INFO`, `WARNING`, `ERROR` |
|
| `log_level` | How much detail to show: `DEBUG`, `INFO`, `WARNING`, `ERROR` |
|
||||||
|
|
||||||
### Advanced Settings
|
### Advanced Settings
|
||||||
@@ -215,6 +239,7 @@ Install everything from [`requirements.txt`](requirements.txt). All listed packa
|
|||||||
| `h2` | HTTP/2 multiplexing to the Apps Script relay (significantly faster) |
|
| `h2` | HTTP/2 multiplexing to the Apps Script relay (significantly faster) |
|
||||||
| `brotli` | Decompression of `Content-Encoding: br` responses |
|
| `brotli` | Decompression of `Content-Encoding: br` responses |
|
||||||
| `zstandard` | Decompression of `Content-Encoding: zstd` responses |
|
| `zstandard` | Decompression of `Content-Encoding: zstd` responses |
|
||||||
|
| `netifaces` | Better network interface detection for LAN sharing (fallback available without it) |
|
||||||
|
|
||||||
### Load Balancing
|
### Load Balancing
|
||||||
|
|
||||||
|
|||||||
+31
-6
@@ -162,6 +162,7 @@ Firefox معمولا certificate store جداگانه دارد:
|
|||||||
|
|
||||||
نکته امنیتی: پوشه `ca/` را با کسی به اشتراک نگذارید. اگر خواستید از اول گواهی جدید بسازید، این پوشه را حذف کنید تا دوباره ساخته شود.
|
نکته امنیتی: پوشه `ca/` را با کسی به اشتراک نگذارید. اگر خواستید از اول گواهی جدید بسازید، این پوشه را حذف کنید تا دوباره ساخته شود.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## حالتهای موجود
|
## حالتهای موجود
|
||||||
@@ -170,15 +171,38 @@ Firefox معمولا certificate store جداگانه دارد:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## تنظیمات مهم
|
## اشتراکگذاری در شبکه محلی (اختیاری)
|
||||||
|
|
||||||
|
بهطور پیشفرض، پروکسی فقط به `127.0.0.1` (localhost) گوش میدهد، به این معنی که فقط کامپیوتر شما میتواند از آن استفاده کند. برای اینکه سایر دستگاههای موجود در شبکه محلی (LAN) شما بتوانند از این پروکسی استفاده کنند:
|
||||||
|
|
||||||
|
۱. در فایل `config.json` خود، مقدار `"lan_sharing"` را `true` قرار دهید.
|
||||||
|
۲. پروکسی به طور خودکار به تمام رابطهای شبکه (`0.0.0.0`) گوش خواهد داد.
|
||||||
|
۳. در لاگ راهاندازی، آدرسهای IP شبکه محلی شما که سایر دستگاهها میتوانند به آن متصل شوند، نمایش داده میشود.
|
||||||
|
|
||||||
|
**نمونه پیکربندی برای شبکه محلی:**
|
||||||
|
json
|
||||||
|
{
|
||||||
|
"lan_sharing": true,
|
||||||
|
"listen_host": "0.0.0.0",
|
||||||
|
"listen_port": 8085
|
||||||
|
}
|
||||||
|
|
||||||
|
**هشدار امنیتی:** وقتی اشتراکگذاری در شبکه محلی فعال باشد، هر کسی در شبکه محلی شما میتواند از پروکسی شما استفاده کند. اطمینان حاصل کنید که شبکه شما مورد اعتماد است و اقدامات امنیتی بیشتری را در نظر بگیرید.
|
||||||
|
|
||||||
|
**در سایر دستگاهها:** آنها را طوری پیکربندی کنید که از آدرس IP کامپیوتر شما در شبکه محلی (که در لاگ راهاندازی نمایش داده میشود) و پورت 8085 به عنوان پروکسی HTTP استفاده کنند.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## تنظیمات اصلی
|
||||||
|
|
||||||
| تنظیم | توضیح |
|
| تنظیم | توضیح |
|
||||||
|------|-------|
|
|------|-------|
|
||||||
| `auth_key` | رمز مشترک بین برنامه و رله |
|
| `auth_key` | رمز مشترک بین کامپیوتر شما و رله |
|
||||||
| `script_id` | Deployment ID مربوط به Apps Script |
|
| `script_id` | شناسه Deployment مربوط به Google Apps Script شما |
|
||||||
| `listen_host` | آدرس محلی برای اجرا |
|
| `listen_host` | محل گوش دادن (`127.0.0.1` = فقط همین کامپیوتر، `0.0.0.0` = همه اینترفیسها برای اشتراکگذاری LAN) |
|
||||||
| `listen_port` | پورت پراکسی |
|
| `listen_port` | پورتی که پروکسی روی آن اجرا میشود (پیشفرض: `8085`) |
|
||||||
| `log_level` | میزان جزئیات لاگ |
|
| `lan_sharing` | فعالسازی اشتراکگذاری LAN تا دستگاههای دیگر در شبکه شما بتوانند از پروکسی استفاده کنند (بهصورت پیشفرض `false`) |
|
||||||
|
| `log_level` | میزان جزئیات لاگ: `DEBUG`، `INFO`، `WARNING`، `ERROR` |
|
||||||
|
|
||||||
### تنظیمات پیشرفته
|
### تنظیمات پیشرفته
|
||||||
|
|
||||||
@@ -202,6 +226,7 @@ Firefox معمولا certificate store جداگانه دارد:
|
|||||||
| `h2` | ارتباط HTTP/2 با رله Apps Script (بهطور محسوسی سریعتر) |
|
| `h2` | ارتباط HTTP/2 با رله Apps Script (بهطور محسوسی سریعتر) |
|
||||||
| `brotli` | پشتیبانی از فشردهسازی `Content-Encoding: br` |
|
| `brotli` | پشتیبانی از فشردهسازی `Content-Encoding: br` |
|
||||||
| `zstandard` | پشتیبانی از فشردهسازی `Content-Encoding: zstd` |
|
| `zstandard` | پشتیبانی از فشردهسازی `Content-Encoding: zstd` |
|
||||||
|
| `netifaces` | تشخیص بهتر اینترفیسهای شبکه برای اشتراکگذاری LAN (در صورت نبود آن، حالت جایگزین در دسترس است) |
|
||||||
|
|
||||||
### استفاده از چند Script ID
|
### استفاده از چند Script ID
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
"socks5_port": 1080,
|
"socks5_port": 1080,
|
||||||
"log_level": "INFO",
|
"log_level": "INFO",
|
||||||
"verify_ssl": true,
|
"verify_ssl": true,
|
||||||
|
"lan_sharing": true,
|
||||||
"parallel_relay": 1,
|
"parallel_relay": 1,
|
||||||
"block_hosts": [],
|
"block_hosts": [],
|
||||||
"bypass_hosts": [
|
"bypass_hosts": [
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ if _SRC_DIR not in sys.path:
|
|||||||
|
|
||||||
from cert_installer import install_ca, is_ca_trusted
|
from cert_installer import install_ca, is_ca_trusted
|
||||||
from constants import __version__
|
from constants import __version__
|
||||||
|
from lan_utils import log_lan_access
|
||||||
from logging_utils import configure as configure_logging, print_banner
|
from logging_utils import configure as configure_logging, print_banner
|
||||||
from mitm import CA_CERT_FILE
|
from mitm import CA_CERT_FILE
|
||||||
from proxy_server import ProxyServer
|
from proxy_server import ProxyServer
|
||||||
@@ -205,6 +206,14 @@ def main():
|
|||||||
else:
|
else:
|
||||||
log.info("MITM CA is already trusted.")
|
log.info("MITM CA is already trusted.")
|
||||||
|
|
||||||
|
# ── LAN sharing configuration ────────────────────────────────────────
|
||||||
|
lan_sharing = config.get("lan_sharing", True)
|
||||||
|
if lan_sharing:
|
||||||
|
# If LAN sharing is enabled and host is still localhost, change to all interfaces
|
||||||
|
if config.get("listen_host", "127.0.0.1") == "127.0.0.1":
|
||||||
|
config["listen_host"] = "0.0.0.0"
|
||||||
|
log.info("LAN sharing enabled — listening on all interfaces")
|
||||||
|
|
||||||
log.info("HTTP proxy : %s:%d",
|
log.info("HTTP proxy : %s:%d",
|
||||||
config.get("listen_host", "127.0.0.1"),
|
config.get("listen_host", "127.0.0.1"),
|
||||||
config.get("listen_port", 8080))
|
config.get("listen_port", 8080))
|
||||||
@@ -213,6 +222,11 @@ def main():
|
|||||||
config.get("socks5_host", config.get("listen_host", "127.0.0.1")),
|
config.get("socks5_host", config.get("listen_host", "127.0.0.1")),
|
||||||
config.get("socks5_port", 1080))
|
config.get("socks5_port", 1080))
|
||||||
|
|
||||||
|
# Log LAN access addresses if sharing is enabled
|
||||||
|
if lan_sharing:
|
||||||
|
socks_port = config.get("socks5_port", 1080) if config.get("socks5_enabled", True) else None
|
||||||
|
log_lan_access(config.get("listen_port", 8080), socks_port)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
asyncio.run(_run(config))
|
asyncio.run(_run(config))
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|||||||
@@ -12,3 +12,6 @@ brotli>=1.1.0
|
|||||||
|
|
||||||
# Optional: Zstandard decompression (some CDNs now serve `zstd`)
|
# Optional: Zstandard decompression (some CDNs now serve `zstd`)
|
||||||
zstandard>=0.22.0
|
zstandard>=0.22.0
|
||||||
|
|
||||||
|
# Optional: Better network interface detection for LAN sharing
|
||||||
|
netifaces>=0.11.0
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
"""
|
||||||
|
LAN utilities for detecting network interfaces and IP addresses.
|
||||||
|
|
||||||
|
Provides functionality to enumerate local network interfaces and their
|
||||||
|
associated IP addresses for LAN proxy sharing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import ipaddress
|
||||||
|
import logging
|
||||||
|
import socket
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
|
log = logging.getLogger("LAN")
|
||||||
|
|
||||||
|
|
||||||
|
def get_network_interfaces() -> Dict[str, List[str]]:
|
||||||
|
"""
|
||||||
|
Get all network interfaces and their associated IP addresses.
|
||||||
|
|
||||||
|
Returns a dictionary mapping interface names to lists of IP addresses
|
||||||
|
(both IPv4 and IPv6). Only includes interfaces with valid IP addresses
|
||||||
|
that are not loopback.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, List[str]]: Interface name -> list of IP addresses
|
||||||
|
"""
|
||||||
|
interfaces = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
import netifaces
|
||||||
|
for iface in netifaces.interfaces():
|
||||||
|
addrs = netifaces.ifaddresses(iface)
|
||||||
|
ips = []
|
||||||
|
# IPv4 addresses
|
||||||
|
if netifaces.AF_INET in addrs:
|
||||||
|
for addr in addrs[netifaces.AF_INET]:
|
||||||
|
ip = addr.get('addr')
|
||||||
|
if ip and not ip.startswith('127.'):
|
||||||
|
ips.append(ip)
|
||||||
|
# IPv6 addresses (without scope)
|
||||||
|
if netifaces.AF_INET6 in addrs:
|
||||||
|
for addr in addrs[netifaces.AF_INET6]:
|
||||||
|
ip = addr.get('addr')
|
||||||
|
if ip and not ip.startswith('::1') and not '%' in ip:
|
||||||
|
# Remove scope if present
|
||||||
|
ips.append(ip.split('%')[0])
|
||||||
|
if ips:
|
||||||
|
interfaces[iface] = ips
|
||||||
|
except ImportError:
|
||||||
|
# Fallback to socket method for basic detection
|
||||||
|
log.debug("netifaces not available, using socket fallback")
|
||||||
|
interfaces = _get_interfaces_socket_fallback()
|
||||||
|
|
||||||
|
return interfaces
|
||||||
|
|
||||||
|
|
||||||
|
def _get_interfaces_socket_fallback() -> Dict[str, List[str]]:
|
||||||
|
"""
|
||||||
|
Fallback method to get network interfaces using socket.
|
||||||
|
|
||||||
|
This is less comprehensive than netifaces but works without extra dependencies.
|
||||||
|
"""
|
||||||
|
interfaces = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Get hostname and try to resolve to IPs
|
||||||
|
hostname = socket.gethostname()
|
||||||
|
try:
|
||||||
|
# Get IPv4 addresses
|
||||||
|
ipv4_info = socket.getaddrinfo(hostname, None, socket.AF_INET)
|
||||||
|
ipv4_addrs = [info[4][0] for info in ipv4_info if not info[4][0].startswith('127.')]
|
||||||
|
if ipv4_addrs:
|
||||||
|
interfaces['primary'] = list(set(ipv4_addrs)) # Remove duplicates
|
||||||
|
except socket.gaierror:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Get IPv6 addresses
|
||||||
|
ipv6_info = socket.getaddrinfo(hostname, None, socket.AF_INET6)
|
||||||
|
ipv6_addrs = []
|
||||||
|
for info in ipv6_info:
|
||||||
|
ip = info[4][0]
|
||||||
|
if not ip.startswith('::1') and not '%' in ip:
|
||||||
|
ipv6_addrs.append(ip.split('%')[0])
|
||||||
|
if ipv6_addrs:
|
||||||
|
interfaces['primary_ipv6'] = list(set(ipv6_addrs))
|
||||||
|
except socket.gaierror:
|
||||||
|
pass
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log.debug("Socket fallback failed: %s", e)
|
||||||
|
|
||||||
|
return interfaces
|
||||||
|
|
||||||
|
|
||||||
|
def get_lan_ips(port: int = 8085) -> List[str]:
|
||||||
|
"""
|
||||||
|
Get list of LAN-accessible proxy addresses.
|
||||||
|
|
||||||
|
Returns a list of IP:port combinations that can be used to access
|
||||||
|
the proxy from other devices on the local network.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
port: The port the proxy is listening on
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[str]: List of "IP:port" strings for LAN access
|
||||||
|
"""
|
||||||
|
interfaces = get_network_interfaces()
|
||||||
|
lan_addresses = []
|
||||||
|
|
||||||
|
for iface_ips in interfaces.values():
|
||||||
|
for ip in iface_ips:
|
||||||
|
try:
|
||||||
|
# Validate IP and check if it's a private address
|
||||||
|
addr = ipaddress.ip_address(ip)
|
||||||
|
if addr.is_private or addr.is_link_local:
|
||||||
|
lan_addresses.append(f"{ip}:{port}")
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Remove duplicates while preserving order
|
||||||
|
seen = set()
|
||||||
|
unique_addresses = []
|
||||||
|
for addr in lan_addresses:
|
||||||
|
if addr not in seen:
|
||||||
|
seen.add(addr)
|
||||||
|
unique_addresses.append(addr)
|
||||||
|
|
||||||
|
return unique_addresses
|
||||||
|
|
||||||
|
|
||||||
|
def log_lan_access(port: int = 8085, socks_port: Optional[int] = None):
|
||||||
|
"""
|
||||||
|
Log the LAN-accessible proxy addresses for user convenience.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
port: HTTP proxy port
|
||||||
|
socks_port: Optional SOCKS5 proxy port
|
||||||
|
"""
|
||||||
|
lan_http = get_lan_ips(port)
|
||||||
|
if lan_http:
|
||||||
|
log.info("LAN HTTP proxy : %s", ", ".join(lan_http))
|
||||||
|
else:
|
||||||
|
log.warning("No LAN IP addresses detected for HTTP proxy")
|
||||||
|
|
||||||
|
if socks_port:
|
||||||
|
lan_socks = get_lan_ips(socks_port)
|
||||||
|
if lan_socks:
|
||||||
|
log.info("LAN SOCKS5 proxy : %s", ", ".join(lan_socks))
|
||||||
|
else:
|
||||||
|
log.warning("No LAN IP addresses detected for SOCKS5 proxy")
|
||||||
Reference in New Issue
Block a user