Oct 03

SNI 分流后获取客户端 IP 一般通过 proxy_protocol 来实现,但分流后的某些程序不能识别 proxy_protocol 怎么办?比如我的 DoH 服务器要 IP 地址,但某木头马并不支持,我开启 proxy_protocol 这马就死了。

我们看代码片段,注意注释。

nginx.conf 主配置文件片段:

stream {
    # 这里就是 SNI 识别,将域名映射成一个配置名
    map $ssl_preread_server_name $backend_name {
        我的域名.坑 web;
        马.我的域名.坑 马;
        # 域名都不匹配情况下的默认值
        default web;
    }
    # 转发到 web 服务器
        upstream web {
        server 127.0.0.1:444;
    }
    # 转发到 马 前置服务器
        upstream 马 {
        server 127.0.0.1:446;
    }
    # 为 马 去除 proxy_protocol
    server {
        #nginx server 443 开启 proxy_protocol 后,分流后的所有服务也必须开启 proxy_protocol,否则会报错
        listen 127.0.0.1:446 proxy_protocol so_keepalive=on;
        proxy_protocol off; #然而,我们在这儿把 proxy_protocol 关闭掉,因为 马 不支持!这是关键
        proxy_connect_timeout 300s;
        proxy_timeout 300s;
        proxy_pass 127.0.0.1:445; #这就是 马 实际吃草的地方
    }

     # 监听 443 并开启 ssl_preread
     server {
         listen 443 reuseport;
         listen [::]:443 reuseport;
         proxy_pass $backend_name;
         ssl_preread on; #开启了分流
         proxy_protocol on; #开启了 proxy_protocol
    }
}

虚拟站点配置文件代码块,大致如下:

server
{
     #nginx server 443 开启 proxy_protocol 后,分流后的所有服务也必须开启 proxy_protocol,否则会报错
    listen 127.0.0.1:444 ssl http2 reuseport proxy_protocol;
    #下面三行给反代的 DoH 服务器传递了客户端 IP
    set_real_ip_from 127.0.0.1;
    real_ip_recursive on;
    real_ip_header proxy_protocol;

    server_name 三达不溜.我的域名.坑 我的域名.坑;
    index index.html index.htm index.php default.html default.htm default.php;
    root  /home/wwwroot/我的域名.坑;

    ssl_certificate /usr/local/nginx/conf/ssl/fullchain.cer;
    ssl_certificate_key /usr/local/nginx/conf/ssl/我的域名.坑_ssl.key;

    #反代 DoH 服务器
    location /dns-query {
        proxy_pass       http://127.0.0.1:8053/dns-query;
        proxy_set_header Host      $host;
        proxy_set_header X-Real-IP $remote_addr; #我要,真实的,IP!
    }

差不多这样。 :evil: :twisted: :cool:

来自 https://github.com/trojan-gfw/trojan/issues/433#issuecomment-692878138 的方法更加精妙:

stream {
    log_format basic '$remote_addr - $remote_user [$time_local] '
                     '$protocol $status $bytes_sent $bytes_received '
                     '$session_time';
    map $ssl_preread_server_name $backend {
        trojan6.domain.com unix:/run/nginx-trojan-stream.sock;
        trojan.domain.com unix:/run/nginx-trojan-stream.sock;
        default 127.0.0.1:443;
    }
    server {
        listen unix:/run/nginx-trojan-stream.sock proxy_protocol;
        proxy_pass 127.0.0.1:8443;
    }
    server {
        listen 0.0.0.0:443;
        listen [::]:443;
        proxy_pass $backend;
        ssl_preread on;
        proxy_protocol on;
    }
}

http {
    log_format combined '$proxy_protocol_addr - $remote_user [$time_local] '
                        '"$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent"';
    server {
        listen 127.0.0.1:80 proxy_protocol;
        listen [::1]:443 ssl proxy_protocol;
        ...
    }
}

http 的 log_format 中,原来的将原来的 $remote_addr 替换成 $proxy_protocol_addr 就成了。

stream 中的第一个 server 就是为了接收带 proxy_protocol 的 stream,然后发出不带 proxy_protocol 的 stream 给 trojan。

另外,我用的是在 Ubuntu 20.04上 的 Nginx v.1.18.0,来自官方 apt 源的。


Nov 12

DNSQuerySniffer 查看系统 DNS 查询状况时发现每次查询都有重传 (DNS Retransmission) 现象(抓取方式选 WinPcap 时出现,选 Raw Sockets 不会)

折腾了好多天,卸载无数网络协议/驱动,最后发现卸载 VMware Bridge Protocol 现象消失,关掉开启的虚拟机也可以让现象消失。

这就不知道是 VMware 问题还是 WinPcap 问题了。。。 :?: :roll:

后续:

1. 上面已知 Bridge 模式会重传;
2. 试过 NAT 模式不会重传,但有无数 PTR 请求刷屏;
3. 用 Host-Only 模式,共享上网,目前一切OK。


Aug 29

ECS (edns-client-subnet)的支持上,国内 DNS派,国外 Google 支持最好,而 Overture 支持上发 EDNS 信息,基于这几个特点,可以在 VPS (无论在国内还是国外)建立一个 CDN 友好的 DNS 服务器。

国外 VPS 配置范例:

{
"BindAddress": ":5353",
"DebugHTTPAddress": "127.0.0.1:5555",
"PrimaryDNS": [
{
"Name": "DNSPaiS",
"Address": "218.30.118.6:53",
"Protocol": "udp",
"SOCKS5Address": "",
"Timeout": 6,
"EDNSClientSubnet": {
"Policy": "auto",
"ExternalIP": "223.73.56.110",
"NoCookie": true
}
},
{
"Name": "DNSPaiM",
"Address": "101.226.4.6:53",
"Protocol": "udp",
"SOCKS5Address": "",
"Timeout": 6,
"EDNSClientSubnet": {
"Policy": "auto",
"ExternalIP": "223.73.56.110",
"NoCookie": true
}
}
],
"AlternativeDNS": [
{
"Name": "GoogleM",
"Address": "8.8.8.8:53",
"Protocol": "udp",
"SOCKS5Address": "",
"Timeout": 3,
"EDNSClientSubnet": {
"Policy": "auto",
"ExternalIP": "223.73.56.110",
"NoCookie": true
}
},
{
"Name": "GoogleS",
"Address": "8.8.4.4:53",
"Protocol": "udp",
"SOCKS5Address": "",
"Timeout": 3,
"EDNSClientSubnet": {
"Policy": "auto",
"ExternalIP": "223.73.56.110",
"NoCookie": true
}
}
],
"OnlyPrimaryDNS": false,
"IPv6UseAlternativeDNS": false,
"WhenPrimaryDNSAnswerNoneUse": "PrimaryDNS",
"IPNetworkFile": {
"Primary": "./cn.zone",
"Alternative": "./ip_network_alternative_sample"
},
"DomainFile": {
"Primary": "./domain_primary_sample",
"Alternative": "./domain_alternative_sample",
"Matcher": "regex-list"
},
"HostsFile": "./hosts_sample",
"MinimumTTL": 0,
"DomainTTLFile" : "./domain_ttl_sample",
"CacheSize" : 10000,
"RejectQType": [255]
}

国内/路由器等配置范例:(注意与国外的主要差别,使用了 Google 的 DNS-Over-TLS,否则会被污染)

{
"BindAddress": "0.0.0.0:5554",
"DebugHTTPAddress": "0.0.0.0:8081",
"PrimaryDNS": [
{
"Name": "DNSPaiS",
"Address": "123.125.81.6:53",
"Protocol": "udp",
"SOCKS5Address": "",
"Timeout": 3,
"EDNSClientSubnet": {
"Policy": "auto",
"ExternalIP": "223.73.56.110",
"NoCookie": true
}
},
{
"Name": "DNSPaiM",
"Address": "101.226.4.6:53",
"Protocol": "udp",
"SOCKS5Address": "",
"Timeout": 3,
"EDNSClientSubnet": {
"Policy": "auto",
"ExternalIP": "223.73.56.110",
"NoCookie": true
}
}
],
"AlternativeDNS": [
{
"Name": "GoogleM",
"Address": "dns.google:853@8.8.8.8",
"Protocol": "tcp-tls",
"SOCKS5Address": "",
"Timeout": 6,
"EDNSClientSubnet": {
"Policy": "auto",
"ExternalIP": "223.73.56.110",
"NoCookie": true
}
},
{
"Name": "GoogleS",
"Address": "dns.google:853@8.8.4.4",
"Protocol": "tcp-tls",
"SOCKS5Address": "",
"Timeout": 6,
"EDNSClientSubnet": {
"Policy": "auto",
"ExternalIP": "223.73.56.110",
"NoCookie": true
}
}
],
"OnlyPrimaryDNS": false,
"IPv6UseAlternativeDNS": false,
"WhenPrimaryDNSAnswerNoneUse": "AlternativeDNS",
"IPNetworkFile": {
"Primary": "/opt/etc/cn.zone",
"Alternative": "/opt/etc/empty"
},
"DomainFile": {
"Primary": "/opt/etc/empty",
"Alternative": "/opt/etc/empty"
},
"HostsFile": "",
"MinimumTTL": 300,
"DomainTTLFile" : "/opt/etc/domain_ttl.txt",
"CacheSize" : 8192,
"RejectQtype": [255]
}

:cool: :cool: :cool:


Aug 27

劫持 53 就算了,还他妈长期缓存一些错误的结果,记录下。注释的是曾经错误的目前好了的。

#SHIT CMCC
#server=/ikafan.com/127.0.0.1#5053
#server=/ikafan.com/211.136.17.107#53
#server=/ikafan.com/211.136.20.203#53
#ignore-address=42.236.6.20
server=/g.csdnimg.cn/127.0.0.1#5053

:evil: :evil: :evil:

Tags: ,

May 04

CoreDNS 1.5 彻底废除了 Proxy 插件,用 Forward 插件替代,但想不到怎么写才能实现分流,它不允许一个服务器块中用两次 forward。

只好重新把 Proxy 插件编译进去,添加原 coredns/proxy 插件,编译会出错:

proxy.go:107:22: state.ErrorMessage undefined (type request.Request has no field or method ErrorMessage)

暴力修改过的版本,可以编译通过并且可用:https://github.com/rampageX/proxy

编译方法:

按照官方的方法,git clone 下来后,修改 plugin.cfg ,添加一句:

proxy:github.com/rampageX/proxy

然后 make 即可。

root@phicomm-n1:/devel/src/coredns# ./coredns -plugins
Server types:
dns

Caddyfile loaders:
flag
default

Other plugins:
dns.alternate
dns.any
dns.auto
dns.autopath
dns.bind
dns.cache
dns.cancel
dns.chaos
dns.debug
dns.dnssec
dns.dnstap
dns.erratic
dns.errors
dns.etcd
dns.federation
dns.file
dns.forward
dns.grpc
dns.health
dns.hosts
dns.k8s_external
dns.kubernetes
dns.loadbalance
dns.log
dns.loop
dns.metadata
dns.nsid
dns.pprof
dns.prometheus
dns.proxy
dns.ready
dns.reload
dns.rewrite
dns.root
dns.route53
dns.secondary
dns.template
dns.tls
dns.trace
dns.whoami
on

:mrgreen: :mrgreen: :mrgreen:


[1/5]  1 2 3 4 5 >