说明: 命令有风险,需自行承担
思路
利用ip6tables将pxy代理程序的数据包重定向到nginx+njs的检查服务, 检查通过后放行
- 浏览器 检查请求头中的cookie
- App 检查请求头中的X-Forwarded-Host(和你手机共用公网IP的可以访问)
使用
- 浏览器: 访问
https://你的FNID.fnos.net/验证地址
- APP: 先通过浏览器访问验证地址,打开登陆页面后, 再打开APP用 FNID 登陆
配置
重定向流量
此操作会导致通过fnConnect的链接中断, 请在内网操作
利用ip6tables重定向数据包, 重启设备后该配置丢失, 需再次执行
ip6tables -t nat -I OUTPUT 1 -p tcp --dport 5666 -d ::1 -j DNAT --to-destination [::1]:6010
自建检查服务
拉去最新的nginx镜像, 并新建nginx实例, 网络选host, 映射如下文件(目前只能选到文件夹,但是输入框可以编辑)
/vol1/1000/App/nginx-pxy/js_tool.js > /etc/nginx/js_tool.js
/vol1/1000/App/nginx-pxy/no_token.html > /etc/nginx/no_token.html
/vol1/1000/App/nginx-pxy/nginx.conf.txt > /etc/nginx/nginx.conf
const config = {
token_name: 'x-my-fn-token',
token_value: '验证字符串', // 如: miao_ao_123456
token_url: '/验证地址', // 如: /miao_ao
site_name: '你的FNID'+'.fnos.net',
dict_key: 'white_ip', // 固定值,不修改
time: 60*5 // IP验证有效时间(秒)
}
let tk = config.token_name+'='+config.token_value;
function handleRoot(r){
let xff = 'XFF-'+(r.headersIn['x-forwarded-for']);
let host_302 = r.headersIn['X-Forwarded-Host'] == config.site_name ? ("https://"+config.site_name+"/") : '/';
r.log('xff:' +xff + ', comming:' + r.uri);
if(r.uri == '/favicon.ico'
|| r.uri == '/trimcon'
|| r.uri == '/trimcon/cookie'
|| r.uri == '/trimcon/redirect'){
r.internalRedirect('@r_proxy');
return;
}
if(r.uri == config.token_url){
if(xff) ngx.shared[config.dict_key].set(xff, 'Y');
r.headersOut['Set-Cookie'] = tk+'; Path=/; SameSite=Strict; HttpOnly;'+(host_302 == '/' ? '' : ' Secure');
r.return(302, host_302);
return; // 设置访问IP和cookie验证
}
if(r.headersIn.cookie && r.headersIn.cookie.indexOf(tk) != -1){
r.internalRedirect('@r_proxy');
return; // cookie验证通过
}
if(xff && ngx.shared[config.dict_key].get(xff) == 'Y'){
if(xff) ngx.shared[config.dict_key].set(xff, 'Y');
r.internalRedirect('@r_proxy');
return; // 访问IP验证通过
}
// 其余的拦截
r.return(302,host_302 + 'no_token.html');
}
export default { handleRoot };
<html><body>403</body></html>
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log info;
pid /run/nginx.pid;
load_module modules/ngx_http_js_module.so;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
js_shared_dict_zone zone=white_ip:1m timeout=60s;
js_import js_tool from /etc/nginx/js_tool.js;
client_max_body_size 1G;
server {
listen [::1]:6010;
#listen 192.168.8.6:6011;
server_tokens off;
location @r_proxy{
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $http_x_forwarded_for;
proxy_pass http://127.0.0.1:5666;
}
location = /no_token.html {
alias /etc/nginx/no_token.html;
}
location / {
js_content js_tool.handleRoot;
}
}
}