//
//请找到:// const targetHost = isIPv6(clientIP) ? IPV6_TARGET : getIPv4TargetByPath(url.pathname); // 稳妥方案
// const targetHost = IPV6_TARGET; // 我自己在用的方案
// 这两个意思是,对于手机飞牛app,如果你手机app没有ipv6地址,那么就通过ipv4连接到CF的服务器,CF服务器
//通过通过飞牛中继ipv4连接到你的NAS;我自己在用的方案是:无论我是的手机否拥有ipv6地址,cf服务器都通过ipv6连接
//到我的nas
//根据你自己的情况修改,选择哪种回程类型
// === 目标地址配置区 ===
const IPV6_TARGET = "https://xxxxx";// xxxxx替换为你的域名
const IPV4_LOGIN_TARGET = "https://xxxxx.5ddd.com";// xxxxx替换为你的飞牛ID的域名
const IPV4_SHARE_TARGET = "https://s.fnnas.net";
// === 探测配置 ===
const PROBE_FILE = "/favicon.ico";
const TIMEOUT = 2500;
// === User-Agent 识别 ===
const BROWSER_UA_KEYWORDS = ['Mozilla/5.0', 'Chrome/', 'Firefox/', 'Safari/', 'Edge/'];
const APP_UA_KEYWORDS = ['Dart/', 'dart:io', 'FeiNiuNAS', 'Dalvik', 'CFNetwork', 'okhttp'];
const BOT_UA_KEYWORDS = [
'bot', 'spider', 'crawler', 'scraper', 'curl', 'wget', 'python-requests', 'java', 'go-http-client',
'Googlebot', 'bingbot', 'Baiduspider', 'YandexBot', 'AhrefsBot', 'Nmap', 'sqlmap',
'HeadlessChrome', 'Puppeteer', 'Playwright'
];
// === 飞牛App特定域名识别 ===
const FEINIU_APP_DOMAINS = [
'https://xxxxx',// 替换为你的域名
'https://xxxxx.5ddd.com' // xxxxx替换为你的飞牛ID的域名
];
// === 安全防护配置 ===
const SECURITY_CONFIG = {
CHECK_SUSPICIOUS_HEADERS: true,
SUSPICIOUS_HEADERS: [
{ header: 'X-Forwarded-Host' }, { header: 'X-Original-URL' },
{ header: 'X-Rewrite-URL' }, { header: 'X-Scanner' },
{ header: 'Acunetix-Product' }, { header: 'X-WIPP' },
]
};
// === 辅助函数 ===
function getUserAgentType(userAgent) {
if (!userAgent) return 'unknown';
const uaLower = userAgent.toLowerCase();
if (BOT_UA_KEYWORDS.some(keyword => uaLower.includes(keyword.toLowerCase()))) return 'bot';
if (APP_UA_KEYWORDS.some(keyword => userAgent.includes(keyword))) return 'app';
if (BROWSER_UA_KEYWORDS.some(keyword => userAgent.includes(keyword))) return 'browser';
return 'unknown';
}
function isFeiNiuAppDomain(hostname) {
return FEINIU_APP_DOMAINS.some(domain => hostname.includes(domain));
}
function hasSuspiciousHeaders(headers) {
if (!SECURITY_CONFIG.CHECK_SUSPICIOUS_HEADERS) return false;
for (const suspicious of SECURITY_CONFIG.SUSPICIOUS_HEADERS) {
if (headers.has(suspicious.header)) return true;
}
return false;
}
function generateBotResponse(request) {
const html = <!DOCTYPE html><html><head><title>403 Forbidden</title></head><body><h1>Access Forbidden</h1></body></html>
;
return new Response(html, {
status: 403,
headers: { 'Content-Type': 'text/html;charset=UTF-8', 'X-Robots-Tag': 'noindex, nofollow' }
});
}
function isIPv6(ip) {
return ip ? ip.includes(':') : false;
}
function getIPv4TargetByPath(pathname) {
return (pathname && pathname.startsWith('/s/')) ? IPV4_SHARE_TARGET : IPV4_LOGIN_TARGET;
}
// === 主处理函数 ===
export default {
async fetch(request, env, ctx) {
try {
const url = new URL(request.url);
const clientIP = request.headers.get("CF-Connecting-IP") || "";
const userAgent = request.headers.get("User-Agent") || "";
const hostname = url.hostname;
const originalPathAndQuery = url.pathname + url.search;
// --- 1. 安全检查先行 ---
const uaType = getUserAgentType(userAgent);
const isSuspicious = hasSuspiciousHeaders(request.headers);
const isFeiNiuDomain = isFeiNiuAppDomain(hostname);
if (uaType === 'bot' || isSuspicious) {
return generateBotResponse(request);
}
// --- 2. App客户端处理:直接代理 ---
// 识别飞牛App的两种方式:User-Agent或特定域名
if (uaType === 'app' || isFeiNiuDomain) {
console.log(`Processing FeiNiu App request from: ${clientIP}, UA: ${userAgent}, Domain: ${hostname}`);
// const targetHost = isIPv6(clientIP) ? IPV6_TARGET : getIPv4TargetByPath(url.pathname); // 稳妥方案
const targetHost = IPV6_TARGET; // 我自己在用的方案
//这两个意思是,对于手机飞牛app,如果你手机app没有ipv6地址,那么就通过ipv4连接到CF的服务器,CF服务器通过通过飞牛中继ipv4连接到你的NAS;我自己在用的方案是:无论我是的手机否拥有ipv6地址,cf服务器都通过ipv6连接到我的nas//
const targetUrl = new URL(originalPathAndQuery, targetHost);
// 复制原始请求的所有头信息,但移除可能引起问题的头
const newHeaders = new Headers(request.headers);
newHeaders.set('Host', targetUrl.hostname);
const proxyRequest = new Request(targetUrl, {
method: request.method,
headers: newHeaders,
body: request.body,
redirect: 'follow'
});
return fetch(proxyRequest);
}
// --- 3. 浏览器文档请求处理 ---
const dest = request.headers.get('Sec-Fetch-Dest');
if (uaType === 'browser' && (dest === 'document' || !dest)) {
const ipv4FallbackUrl = getIPv4TargetByPath(url.pathname) + originalPathAndQuery;
const html = `<!DOCTYPE html><html lang="zh-CN"><head><title>飞牛NAS - 智能路由网关</title><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet"><noscript><meta http-equiv="refresh" content="0;url=${ipv4FallbackUrl}"></noscript><style>:root{--bg-gradient-start:#1d2b4e;--bg-gradient-end:#0c0c1e;--card-bg:rgba(255,255,255,.08);--text-primary:#fff;--text-secondary:#adb5bd;--accent-color:#3498db;--success-color:#2ecc71}*{margin:0;padding:0;box-sizing:border-box}body{font-family:'Poppins',sans-serif;display:flex;justify-content:center;align-items:center;height:100vh;background:linear-gradient(135deg,var(--bg-gradient-start) 0%,var(--bg-gradient-end) 100%);color:var(--text-primary);overflow:hidden}.container{width:90%;max-width:400px;padding:40px 30px;background:var(--card-bg);border-radius:20px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.1);box-shadow:0 8px 32px 0 rgba(0,0,0,.3);text-align:center;animation:fadeIn 1s ease-out}@keyframes fadeIn{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.icon-container{width:80px;height:80px;margin:0 auto 25px}.icon-container svg{width:100%;height:100%}.icon-container .radar-circle{fill:none;stroke:var(--accent-color);stroke-width:3;transform-origin:center;animation:radar-spin 2s linear infinite}.icon-container .check-path{fill:none;stroke:var(--success-color);stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:48;stroke-dashoffset:48;opacity:0}.icon-container.success .radar-circle{animation:none;opacity:0;transition:opacity .3s}.icon-container.success .check-path{opacity:1;animation:draw-check .8s ease-out forwards}@keyframes radar-spin{from{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes draw-check{to{stroke-dashoffset:0}}h1{font-size:24px;font-weight:600;margin-bottom:10px}.status-text{font-size:16px;color:var(--text-secondary);height:24px;transition:opacity .5s ease}.fallback{display:none;margin-top:25px;font-size:14px;color:var(--text-secondary);animation:fadeIn .5s 1s ease-out forwards;opacity:0}.fallback a{color:var(--accent-color);text-decoration:none;font-weight:600}.fallback a:hover{text-decoration:underline}</style></head><body><div class="container"><div class="icon-container" id="icon-container"><svg viewBox="0 0 52 52"><circle class="radar-circle" cx="26" cy="26" r="24"/><path class="check-path" d="M14 27l7.5 7.5L38 22"/></svg></div><h1>飞牛NAS 智能网关</h1><p class="status-text" id="status">正在分析您的网络环境...</p><div class="fallback" id="fallback">如果长时间未跳转,请 <a href="${ipv4FallbackUrl}">点击这里</a> 手动访问。</div></div>