mirror of
https://github.com/masterking32/MasterHttpRelayVPN.git
synced 2026-05-18 07:34:35 +03:00
Merge pull request #13 from EmranHejazi/features/lan-sharing
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
|
||||
|
||||
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 |
|
||||
| `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`) |
|
||||
| `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` |
|
||||
|
||||
### 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) |
|
||||
| `brotli` | Decompression of `Content-Encoding: br` responses |
|
||||
| `zstandard` | Decompression of `Content-Encoding: zstd` responses |
|
||||
| `netifaces` | Better network interface detection for LAN sharing (fallback available without it) |
|
||||
|
||||
### Load Balancing
|
||||
|
||||
|
||||
+31
-6
@@ -162,6 +162,7 @@ Firefox معمولا certificate store جداگانه دارد:
|
||||
|
||||
نکته امنیتی: پوشه `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` | رمز مشترک بین برنامه و رله |
|
||||
| `script_id` | Deployment ID مربوط به Apps Script |
|
||||
| `listen_host` | آدرس محلی برای اجرا |
|
||||
| `listen_port` | پورت پراکسی |
|
||||
| `log_level` | میزان جزئیات لاگ |
|
||||
| `auth_key` | رمز مشترک بین کامپیوتر شما و رله |
|
||||
| `script_id` | شناسه Deployment مربوط به Google Apps Script شما |
|
||||
| `listen_host` | محل گوش دادن (`127.0.0.1` = فقط همین کامپیوتر، `0.0.0.0` = همه اینترفیسها برای اشتراکگذاری LAN) |
|
||||
| `listen_port` | پورتی که پروکسی روی آن اجرا میشود (پیشفرض: `8085`) |
|
||||
| `lan_sharing` | فعالسازی اشتراکگذاری LAN تا دستگاههای دیگر در شبکه شما بتوانند از پروکسی استفاده کنند (بهصورت پیشفرض `false`) |
|
||||
| `log_level` | میزان جزئیات لاگ: `DEBUG`، `INFO`، `WARNING`، `ERROR` |
|
||||
|
||||
### تنظیمات پیشرفته
|
||||
|
||||
@@ -202,6 +226,7 @@ Firefox معمولا certificate store جداگانه دارد:
|
||||
| `h2` | ارتباط HTTP/2 با رله Apps Script (بهطور محسوسی سریعتر) |
|
||||
| `brotli` | پشتیبانی از فشردهسازی `Content-Encoding: br` |
|
||||
| `zstandard` | پشتیبانی از فشردهسازی `Content-Encoding: zstd` |
|
||||
| `netifaces` | تشخیص بهتر اینترفیسهای شبکه برای اشتراکگذاری LAN (در صورت نبود آن، حالت جایگزین در دسترس است) |
|
||||
|
||||
### استفاده از چند Script ID
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"socks5_port": 1080,
|
||||
"log_level": "INFO",
|
||||
"verify_ssl": true,
|
||||
"lan_sharing": true,
|
||||
"parallel_relay": 1,
|
||||
"block_hosts": [],
|
||||
"bypass_hosts": [
|
||||
|
||||
@@ -22,6 +22,7 @@ if _SRC_DIR not in sys.path:
|
||||
|
||||
from cert_installer import install_ca, is_ca_trusted
|
||||
from constants import __version__
|
||||
from lan_utils import log_lan_access
|
||||
from logging_utils import configure as configure_logging, print_banner
|
||||
from mitm import CA_CERT_FILE
|
||||
from proxy_server import ProxyServer
|
||||
@@ -205,6 +206,14 @@ def main():
|
||||
else:
|
||||
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",
|
||||
config.get("listen_host", "127.0.0.1"),
|
||||
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_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:
|
||||
asyncio.run(_run(config))
|
||||
except KeyboardInterrupt:
|
||||
|
||||
@@ -12,3 +12,6 @@ brotli>=1.1.0
|
||||
|
||||
# Optional: Zstandard decompression (some CDNs now serve `zstd`)
|
||||
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