Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add freebsd support #2246

Merged
merged 3 commits into from
Feb 14, 2020
Merged

add freebsd support #2246

merged 3 commits into from
Feb 14, 2020

Conversation

lucifer9
Copy link
Contributor

transparent proxy (pf rdr) in IPv4 environment
support both tcp and udp
enable TCP_FASTOPEN, SO_REUSEPORT_LB, SO_REUSEADDR
sockopt:mark is mapped to SO_USER_COOKIE

- transparent proxy (pf rdr) in IPv4 environment
- support both tcp and udp
- enable TCP_FASTOPEN, SO_REUSEPORT_LB, SO_REUSEADDR
- sockopt:mark is mapped to SO_USER_COOKIE
@kslr kslr merged commit 9691736 into v2ray:master Feb 14, 2020
@lucifer9 lucifer9 deleted the freebsd-pf branch February 15, 2020 02:12
@ToutyRater
Copy link
Contributor

@lucifer9
这是不是意味着可以在 FreeBSD 使用透明代理,就像 Linux 那样子的?

@lucifer9
Copy link
Contributor Author

@ToutyRater 是的。尽量用比较新的 FreeBSD 版本,使用 pf 来做防火墙规则就行,透明代理需要 root 权限。IPv4 环境我自用近半个月了。
IPv6 的支持代码里面也有,不过我这边没环境没法测试。提醒一下,IPv6 下转发地址,就是任意门监听的地址必须是 Global Scope 的,要不系统会拒绝转发(https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=193568)

@ToutyRater
Copy link
Contributor

谢谢,我之前查了好多关于 BSD 透明代理的资料,最终都无奈放弃。目前在用着 Linux,过段时间再研究 FreeBSD 的。
我也没有 IPv6 的环境,不过又多个 Issue 似乎都在表明 V2Ray 的 IPv6 透明代理无法正确获知目标地址。

@lucifer9
Copy link
Contributor Author

@ToutyRater 不同操作系统,不同防火墙下,获取目标地址的方式不一样。FreeBSD+pf 的组合我刚测试了下是正常的。Linux 下只需要一个小改动就行了。#2281

@ninepeach
Copy link

ninepeach commented Mar 21, 2020

我看新版本增加了freebsd的透明代理支持,测试有一下遇到一些问题。不知道是自己配置有问题,还是程序有bug,所有请哪位大神关注一下;

环境是pfsense2.4.4-p3,这个freebsd版本是11;

网关出口的nat规则如下:
rdr on bridge0 inet proto tcp from any to 61.135.169.125 -> 127.0.0.1 port 4666

网关上的v2ray取错了目标地址,以任意门的监听端口作为远程服务器的端口,所以报错如下:

--------------------------------------------------------------------------------------
2020/03/21 13:47:15 [Warning] v2ray.com/core: V2Ray 4.23.0 started
2020/03/21 13:47:23 [Debug] [387670091] v2ray.com/core/proxy/dokodemo: processing connection from: 192.168.2.2:41296
2020/03/21 13:47:23 [Info] [387670091] v2ray.com/core/app/dispatcher: sniffed domain: 61.135.169.125
2020/03/21 13:47:23 [Info] [387670091] v2ray.com/core/app/dispatcher: default route for tcp:61.135.169.125:4666
2020/03/21 13:47:23 [Info] [387670091] v2ray.com/core/transport/internet/tcp: dialing TCP to tcp:xxxx:xx
2020/03/21 13:47:23 [Info] [387670091] v2ray.com/core/proxy/vmess/outbound: tunneling request to tcp:61.135.169.125:4666 via tcp: xxxx:xxxx
2020/03/21 13:47:25 [Info] [387670091] v2ray.com/core/app/proxyman/inbound: connection ends > v2ray.com/core/proxy/dokodemo: connection ends > context canceled
2020/03/21 13:47:25 [Info] [387670091] v2ray.com/core/app/proxyman/outbound: failed to process outbound traffic > v2ray.com/core/proxy/vmess/outbound: connection ends > context canceled

客户端的配置文件如下:


{
  "log": {
    //"access": "/var/log/v2ray/access.log",
    //"error": "/var/log/v2ray/error.log",
    // Log level, one of "debug", "info", "warning", "error", "none"
    "loglevel": "debug"
  },
  "inbounds": [{
    "port": 1081,

    "listen": "0.0.0.0",
    "tag": "socks-inbound",
    "protocol": "socks",

    "settings": {
      "auth": "noauth",
      "udp": true,
      "ip": "127.0.0.1"
    },

    "sniffing": {
      "enabled": true,
      "destOverride": ["http", "tls"]
    }
  },
  {
   "port": 4666,
   "protocol": "dokodemo-door",
   "settings": {
     "network": "tcp,udp",
     "timeout": 30,
     "followRedirect": true
   },
   "sniffing": {
     "enabled": true,
     "destOverride": ["http", "tls"]
   },
   "streamSettings": {
     "sockopt": {
       "tproxy": "Redirect" 
     }
   }
 }],
  "outbounds": [{
    "protocol": "vmess",
    "settings":
    {
        "vnext": [
        {
            "address": "xxxxxxxxxxxxxxxx",
            "port": 13651,
            "users": [
            {
              "id": "xxxxxxxxxxxxxxxxxx",
              "level": 1,
              "alterId": 102
            }]
        }]
    },
    "streamSettings": {
     "sockopt": {
       "mark": 255
     }
   }
  },{
    "protocol": "blackhole",
    "settings": {},
    "tag": "blocked"
  }],

  "routing": {
    "domainStrategy": "IPOnDemand",
    "rules":[
      {
        "type": "field",
        "ip": ["geoip:private"],
        "outboundTag": "blocked"
      },
      {
        "type": "field",
        "domain": ["geosite:category-ads"],
        "outboundTag": "blocked"
      }
    ]
  },

  "dns": {
  },

  "policy": {
    "levels": {
      "0": {
        "uplinkOnly": 0,
        "downlinkOnly": 0
      }
    },
    "system": {
      "statsInboundUplink": false,
      "statsInboundDownlink": false
    }
  },

  "other": {}
}

@fbion
Copy link

fbion commented Mar 22, 2020

@ToutyRater 是的。尽量用比较新的 FreeBSD 版本,使用 pf 来做防火墙规则就行,透明代理需要 root 权限。IPv4 环境我自用近半个月了。
IPv6 的支持代码里面也有,不过我这边没环境没法测试。提醒一下,IPv6 下转发地址,就是任意门监听的地址必须是 Global Scope 的,要不系统会拒绝转发(https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=193568)

哦霍?mac os pf同样适用?

@lucifer9
Copy link
Contributor Author

{
"log": {
//"access": "/var/log/v2ray/access.log",
//"error": "/var/log/v2ray/error.log",
// Log level, one of "debug", "info", "warning", "error", "none"
"loglevel": "debug"
},
"inbounds": [{
"port": 1081,

"listen": "0.0.0.0",
"tag": "socks-inbound",
"protocol": "socks",

"settings": {
  "auth": "noauth",
  "udp": true,
  "ip": "127.0.0.1"
},

"sniffing": {
  "enabled": true,
  "destOverride": ["http", "tls"]
}

},
{
"port": 4666,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp,udp",
"timeout": 30,
"followRedirect": true
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
},
"streamSettings": {
"sockopt": {
"tproxy": "Redirect"
}
}
}],
"outbounds": [{
"protocol": "vmess",
"settings":
{
"vnext": [
{
"address": "xxxxxxxxxxxxxxxx",
"port": 13651,
"users": [
{
"id": "xxxxxxxxxxxxxxxxxx",
"level": 1,
"alterId": 102
}]
}]
},
"streamSettings": {
"sockopt": {
"mark": 255
}
}
},{
"protocol": "blackhole",
"settings": {},
"tag": "blocked"
}],

"routing": {
"domainStrategy": "IPOnDemand",
"rules":[
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "blocked"
},
{
"type": "field",
"domain": ["geosite:category-ads"],
"outboundTag": "blocked"
}
]
},

"dns": {
},

"policy": {
"levels": {
"0": {
"uplinkOnly": 0,
"downlinkOnly": 0
}
},
"system": {
"statsInboundUplink": false,
"statsInboundDownlink": false
}
},

"other": {}
}

在hyper-v虚拟环境下测试没能复现。可否贴一下你的pfsense网络环境呢,我这边没做网桥和vlan(pfsense默认),也许有这方面原因。我是用的tcp 53端口做的测试,dig a www.baidu.com @8.8.8.8 +tcp,config.json 用的你上面给出的。
pf的配置和v2ray log如下:
rdr on hn0 inet proto tcp from any to any port = domain -> 127.0.0.1 port 4666

[2.4.4-RELEASE][[email protected]]/root: ./v2ray -config config.json
V2Ray 4.23.0 (V2Fly, a community-driven edition of V2Ray.) Custom (go1.14 freebsd/amd64)
A unified platform for anti-censorship.
2020/03/22 18:07:43 [Info] v2ray.com/core/common/platform/ctlcmd:
v2ctl> Read config: config.json
2020/03/22 18:07:43 [Debug] v2ray.com/core/app/log: Logger started
2020/03/22 18:07:43 [Info] v2ray.com/core/app/dns: DNS: created localhost client
2020/03/22 18:07:43 [Debug] v2ray.com/core/app/proxyman/inbound: creating stream worker on 0.0.0.0:1081
2020/03/22 18:07:43 [Debug] v2ray.com/core/app/proxyman/inbound: creating stream worker on 0.0.0.0:4666
2020/03/22 18:07:43 [Info] v2ray.com/core/transport/internet/tcp: listening TCP on 0.0.0.0:1081
2020/03/22 18:07:43 [Info] v2ray.com/core/transport/internet/udp: listening UDP on 0.0.0.0:1081
2020/03/22 18:07:43 [Info] v2ray.com/core/transport/internet/tcp: listening TCP on 0.0.0.0:4666
2020/03/22 18:07:43 [Info] v2ray.com/core/transport/internet/udp: listening UDP on 0.0.0.0:4666
2020/03/22 18:07:43 [Warning] v2ray.com/core: V2Ray 4.23.0 started
2020/03/22 18:07:45 [Debug] [2373677638] v2ray.com/core/proxy/dokodemo: processing connection from: 10.93.23.180:58611
2020/03/22 18:07:45 [Info] [2373677638] v2ray.com/core/app/dispatcher: default route for tcp:8.8.8.8:53
2020/03/22 18:07:45 [Info] [2373677638] v2ray.com/core/transport/internet/tcp: dialing TCP to tcp:xxxxxxxxxx:8888
2020/03/22 18:07:45 [Info] [2373677638] v2ray.com/core/proxy/vmess/outbound: tunneling request to tcp:8.8.8.8:53 via tcp:xxxxxxx:8888

@lucifer9
Copy link
Contributor Author

lucifer9 commented Mar 22, 2020

@ToutyRater 是的。尽量用比较新的 FreeBSD 版本,使用 pf 来做防火墙规则就行,透明代理需要 root 权限。IPv4 环境我自用近半个月了。
IPv6 的支持代码里面也有,不过我这边没环境没法测试。提醒一下,IPv6 下转发地址,就是任意门监听的地址必须是 Global Scope 的,要不系统会拒绝转发(https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=193568)

哦霍?mac os pf同样适用?

Mac 不行,因为Mac下的pf跟freebsd上面的pf比起来,一些内部的数据结构不同。当然改起来也不太麻烦。不过话又说回来,真的有必要用Mac来做透明代理么... 😃

@fbion
Copy link

fbion commented Mar 22, 2020

@ToutyRater 是的。尽量用比较新的 FreeBSD 版本,使用 pf 来做防火墙规则就行,透明代理需要 root 权限。IPv4 环境我自用近半个月了。
IPv6 的支持代码里面也有,不过我这边没环境没法测试。提醒一下,IPv6 下转发地址,就是任意门监听的地址必须是 Global Scope 的,要不系统会拒绝转发(https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=193568)

哦霍?mac os pf同样适用?

Mac 不行,因为Mac下的pf跟freebsd上面的pf比起来,一些内部的数据结构不同。当然改起来也不太麻烦。不过话又说回来,真的有必要用Mac来做透明代理么... 😃

好玩呗 - -
https://github.com/monsterxx03/snet/blob/6a91e622093ef41c59ea8449a110189e3d501af4/redirector/pfctl_darwin.go
这里有现成的 不支持ipv6
我目前用adguard home和tun2socks fake dns,只代理必需的google youtube之类走v2ray
其实macos用户比freebsd多点吧- -

@lucifer9
Copy link
Contributor Author

@fbion 如果只有一台电脑,透明代理代理自己还不如用v2ray+proxifier。如果好几台Mac,随便某个开个代理服务也方便过透明代理。除非是局域网内有Windows或者Linux命令行这种,透明代理才会比较方便。不过这种时候我宁愿开虚拟机做透明代理了。macOS 改一下 pfioc_natlook 的定义和相关读写的部分就行了。有可能有些系统常量定义不一样。苹果自己的开源站点也都能查到。

@fbion
Copy link

fbion commented Mar 23, 2020

@lucifer9 是的 proxifier蛮好用
只是有时候需要udp走mkcp 用tun2socks实现
只是想找找开源的替代 哈哈
日常用的macos 确实没必要走pf透明代理
不方便

@ninepeach
Copy link

ninepeach commented Mar 23, 2020

感谢您的回复,我更新到了git上的最新的版本;目前遇到的情况是这样的,tcp可以通;upd遇到问题;upd发出去的包可以到达目标服务器,但是回不来;

环境pfsen2.4.4-p3

no nat proto carp all
nat-anchor "natearly/*" all
nat-anchor "natrules/*" all
nat on pppoe0 inet from 127.0.0.0/8 to any port = isakmp -> xxxx static-port
nat on pppoe0 inet from 192.168.2.0/24 to any port = isakmp -> xxxx static-port
nat on pppoe0 inet6 from ::1 to any port = isakmp -> (pppoe0) round-robin static-port
nat on pppoe0 inet from 127.0.0.0/8 to any -> xxxx port 1024:65535
nat on pppoe0 inet from 192.168.2.0/24 to any -> xxxx port 1024:65535
nat on pppoe0 inet6 from ::1 to any -> (pppoe0) port 1024:65535 round-robin
no rdr proto carp all
rdr-anchor "relayd/*" all
rdr-anchor "tftp-proxy/*" all
rdr on bridge0 inet proto tcp from any to <gfwlist> -> 127.0.0.1 port 4666
rdr on bridge0 inet proto udp from any to <gfwlist> -> 127.0.0.1 port 4666
rdr-anchor "miniupnpd" all

dns查询

[root] nslookup  www.baidu.com 8.8.8.8
; reply from unexpected source: 192.168.2.1#43337, expected 8.8.8.8#53
;; reply from unexpected source: 192.168.2.1#43337, expected 8.8.8.8#53
;; reply from unexpected source: 192.168.2.1#43337, expected 8.8.8.8#53
;; connection timed out; no servers could be reached

返回日志

2020/03/23 01:33:14 [Debug] v2ray.com/core/transport/internet/udp: UDP original destination: udp:8.8.8.8:53
2020/03/23 01:33:14 [Debug] [1849992955] v2ray.com/core/proxy/dokodemo: processing connection from: 192.168.2.71:51903
2020/03/23 01:33:14 [Warning] [1849992955] v2ray.com/core/transport/internet: failed to bind source address to [8 8 8 8] > v2ray.com/core/transport/internet: failed to set resuse_port > protocol not available
2020/03/23 01:33:14 [Info] [1849992955] v2ray.com/core/app/dispatcher: default route for udp:8.8.8.8:53
2020/03/23 01:33:14 [Info] [1849992955] v2ray.com/core/transport/internet/tcp: dialing TCP to tcp:remove_ip:port
2020/03/23 01:33:14 [Info] [1849992955] v2ray.com/core/proxy/vmess/outbound: tunneling request to udp:8.8.8.8:53 via tcp:remove_ip:port
2020/03/23 01:33:19 [Debug] v2ray.com/core/transport/internet/udp: UDP original destination: udp:8.8.8.8:53
2020/03/23 01:33:24 [Debug] v2ray.com/core/transport/internet/udp: UDP original destination: udp:8.8.8.8:53

配置文件


  "inbounds": [{
    "port": 1081,

    "listen": "0.0.0.0",
    "tag": "socks-inbound",
    "protocol": "socks",

    "settings": {
      "auth": "noauth",
      "udp": true,
      "ip": "127.0.0.1"
    },

    "sniffing": {
      "enabled": true,
      "destOverride": ["http", "tls"]
    }
  },
  {
   "port": 4666,
   "protocol": "dokodemo-door",
   "settings": {
     "network": "tcp,udp",
     "timeout": 30,
     "followRedirect": true
   },
   "sniffing": {
     "enabled": true,
     "destOverride": ["http", "tls"]
   },
   "streamSettings": {
     "sockopt": {
       "tproxy": "Redirect" 
     }
   }
 }],

补充:
自己写了一个upd server和client的例子,测试经过透明代理也是回不来。

@lucifer9
Copy link
Contributor Author

@magicst0ne Sorry,FreeBSD 11 没有 SO_REUSEPORT_LB 的支持,我之前没注意到这个所以代码只能在FreeBSD 12和以后的版本跑。#2366 加上了SO_REUSEPORT来支持FreeBSD 11以及基于它的pfsense,实测通过。

@cattyhouse
Copy link

@lucifer9 can you document on how to setup freebsd pf rules for transparent proxy? Googled around, no useful information

@lucifer9
Copy link
Contributor Author

@lucifer9 can you document on how to setup freebsd pf rules for transparent proxy? Googled around, no useful information

Sure. I use the following rules when testing:

int_if = "hn0"
ext_if = "hn1"
localnet = $int_if:network
table { 10.0.0.0/8,127.0.0.0/8,192.168.0.0/16, v2ray_server_ip }

rdr pass on $int_if proto { tcp, udp } from any to ! -> 127.0.0.1 port v2ray_dokodemo_port
nat on $ext_if from $localnet to any -> ($ext_if)

If you also want to redirect the traffic of your FreeBSD box, you may add the following:

rdr pass on lo0 proto { tcp,udp } from $ext_if to ! -> 127.0.0.1 port v2ray_dokodemo_port
pass out on $ext_if route-to lo0 proto { tcp,udp } from $ext_if to !

@cattyhouse
Copy link

cattyhouse commented Jul 10, 2020

@lucifer9 thanks, you defined a table (with no name) but it was not used anywhere in your example.

@lucifer9
Copy link
Contributor Author

@lucifer9 thanks, you defined a table (with no name) but it was not used anywhere in your example.

Sorry, Github Editor ate the character.
The full example with code block:

int_if = "hn0"
ext_if = "hn1"
localnet = $int_if:network
table <t> { 10.0.0.0/8,127.0.0.0/8,192.168.0.0/16, v2ray_server_ip}

rdr pass on $int_if proto { tcp,udp } from any to ! <t> -> 127.0.0.1 port v2ray_dokodemo_port
rdr pass on lo0 proto { tcp,udp } from $ext_if to ! <t> -> 127.0.0.1 port v2ray_dokodemo_port
nat on $ext_if from $localnet to any -> ($ext_if)
pass out on $ext_if route-to lo0 proto { tcp,udp } from $ext_if to ! <t>

@MaurUppi
Copy link

MaurUppi commented Aug 25, 2020

@lucifer9

@lucifer9 thanks, you defined a table (with no name) but it was not used anywhere in your example.

Sorry, Github Editor ate the character.
The full example with code block:

int_if = "hn0"
ext_if = "hn1"
localnet = $int_if:network
table <t> { 10.0.0.0/8,127.0.0.0/8,192.168.0.0/16, v2ray_server_ip}

rdr pass on $int_if proto { tcp,udp } from any to ! <t> -> 127.0.0.1 port v2ray_dokodemo_port
rdr pass on lo0 proto { tcp,udp } from $ext_if to ! <t> -> 127.0.0.1 port v2ray_dokodemo_port
nat on $ext_if from $localnet to any -> ($ext_if)
pass out on $ext_if route-to lo0 proto { tcp,udp } from $ext_if to ! <t>

@lucifer9 这对略懂CLI的人来说太难了,没看懂。 可否写一篇blog介绍一下如何在pfSense上设置?
我的诉求:

但我不懂得怎么配置,,,,,以及unbound要不要改动什么。。

BTW, 貌似pfSense Firewall alias 及 pfBlockerNG 都不支持 - DOMAIN-SUFFIX 这样的 wildcard ?这样貌似达不到Clash及类似软件的灵活性?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants