Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Feature Request] 通过SRV或302重定向支持frps部署在内网 #5096

@wukan1986

Description

@wukan1986

Describe the feature request

安装Lucky等STUN内网穿透工具,就能将7000暴露到公网了。这样可以实现不借助公网服务器,一个子网访问另一个子网提供的各种网络服务。

其他frpc就可以连接到动态的serverPort和serverAddr,只要编辑frpc.toml即可。

Lucky可以配置将STUN端口通过WebHook更新到Cloudflare。有两种方案

  1. DNS SRV记录(也支持其他DNS服务商)
  2. Cloudflare 规则 302重定向

这两种方案都可以传递新域名(IP)和端口,然后用脚本来更新toml

SRV记录

# pip install dnspython
import dns.rdatatype
import dns.rdtypes.IN.SRV
import dns.resolver


def query_srv_record(service, protocol, domain):
    """
    查询SRV记录
    格式: _service._protocol.domain
    例如: _sip._tcp.example.com
    """
    srv_domain = f"_{service}._{protocol}.{domain}"

    try:
        resolver = dns.resolver.Resolver()

        # 设置DNS服务器(可选)
        # resolver.nameservers = ['8.8.8.8']

        # 查询SRV记录
        answer = resolver.resolve(srv_domain, 'SRV')

        results = []
        for rdata in answer:
            # SRV记录包含:优先级、权重、端口、目标主机
            srv_info = {
                'priority': rdata.priority,
                'weight': rdata.weight,
                'port': rdata.port,
                'target': rdata.target.to_text().rstrip('.')
            }
            results.append(srv_info)

        # 按优先级和权重排序
        results.sort(key=lambda x: (x['priority'], -x['weight']))
        return results

    except dns.resolver.NoAnswer:
        print(f"没有找到SRV记录: {srv_domain}")
        return []
    except dns.resolver.NXDOMAIN:
        print(f"域名不存在: {srv_domain}")
        return []
    except Exception as e:
        print(f"查询失败: {e}")
        return []


# 使用示例
srv_records = query_srv_record('frp', 'tcp', 'frp.example.com')
for record in srv_records:
    print(f"目标: {record['target']}:{record['port']} (优先级: {record['priority']}, 权重: {record['weight']})")

toml = """
serverAddr = "{target}"
serverPort = {port}
auth.token = "frp.example.com"

[[proxies]]
name = "test"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8080
remotePort = 7001

"""

toml = toml.format(target=srv_records[0]['target'], port=srv_records[0]['port'])
print(toml)

with open("frpc.toml", 'w', encoding='utf-8') as f:
    f.write(toml)

302重定向

from urllib.parse import urlparse

import requests

response = requests.get("https://www.baidu.com", allow_redirects=True)
# 获取最终的 URL(可能经过重定向)
final_url = response.url
parsed_url = urlparse(final_url)
port = parsed_url.port or (443 if parsed_url.scheme == 'https' else 80)
print(parsed_url.hostname, port)

toml = """
serverAddr = "{target}"
serverPort = {port}
auth.token = "frp.example.com"

[[proxies]]
name = "aaaa"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8080
remotePort = 7001

"""

toml = toml.format(target=parsed_url.hostname, port=port)
print(toml)

with open("frpc.toml", 'w', encoding='utf-8') as f:
    f.write(toml)

这两种办法的局限是都需要在启动frpc前更新toml,如果中途STUN重新打洞,需要重新启动脚本获取新端口,并重启frpc

如果frp原生支持这两种模式,那么可以省去重新更新端口的步骤,那就非常棒了

Describe alternatives you've considered

No response

Affected area

  • Docs
  • Installation
  • Performance and Scalability
  • Security
  • User Experience
  • Test and Release
  • Developer Infrastructure
  • Client Plugin
  • Server Plugin
  • Extensions
  • Others

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions