修订文档, sockopt 和 utils包的代码.

This commit is contained in:
hahafool
2022-04-21 21:34:56 +08:00
parent 28279dfc31
commit e7ae557b91
21 changed files with 133 additions and 67 deletions

View File

@@ -1,4 +1,4 @@
[![GoDoc][1]][2] [![MIT licensed][3]][4] [![Go Report Card][5]][6]
[![GoDoc][1]][2] [![MIT licensed][3]][4] [![Go Report Card][5]][6] [![Downloads][7]][8] [![release][9]][8] ![GoVersion][10]
[1]: https://godoc.org/github.com/hahahrfool/v2ray_simple?status.svg
[2]: https://godoc.org/github.com/hahahrfool/v2ray_simple
@@ -6,6 +6,11 @@
[4]: LICENSE
[5]: https://goreportcard.com/badge/github.com/hahahrfool/v2ray_simple
[6]: https://goreportcard.com/report/github.com/hahahrfool/v2ray_simple
[7]: https://img.shields.io/github/downloads/hahahrfool/v2ray_simple/total.svg
[8]: https://github.com/hahahrfool/v2ray_simple/releases/latest
[9]: https://img.shields.io/github/release/hahahrfool/v2ray_simple/all.svg?style=flat-square
[10]: https://img.shields.io/github/go-mod/go-version/hahahrfool/v2ray_simple?style=flat-square
# verysimple
@@ -25,13 +30,13 @@ vs的一些亮点是 全协议readv加速lazy技术vless v1hysteria 阻
支持的功能有:
ws(以及earlydata)/grpc/quic(以及hy阻控)/smux,
socks5/http/dokodemo/tproxy(透明代理)/trojan/simplesocks/vless/vless_v1,
tproxy(即透明代理)/trojan/simplesocks/vless/vless_v1/socks5/http/dokodemo,
ws(以及earlydata)/grpc/quic(以及hy阻控)/smux,
dns(udp/tls)/route(geoip/geosite)/fallback(path/sni/alpn),
tcp/udp/unix domain socket, uTls, lazy, http伪装头, cli/apiServer
tcp/udp/unix domain socket, uTls, lazy, http伪装头, cli(交互模式)/apiServer
为了不吓跑小白,目前 本 README 把安装、使用方式 放在了前面,如果你要直接阅读本作的技术介绍部分,点击跳转 -> [创新点](#创新点)
@@ -296,8 +301,6 @@ api服务器tproxy 透明代理; http伪装头
这里的v1是 verysimple 自己制定的,总是要摸着石头过河嘛。标准的讨论详见 [vless_v1](docs/vless_v1.md)
在客户端的 配置url中添加 `?version=1` 即可生效。
总之强制tls简单修订了一下协议格式然后重点完善了fullcone。
verysimple 实现了 一种独创的 非mux型“分离信道”方法的 udp over tcp 的fullcone

View File

@@ -38,9 +38,7 @@ func checkConfigAndTryRunApiServer() {
//阻塞
func runApiServer(adminUUID string) {
if ce := utils.CanLogInfo("Start Api Server"); ce != nil {
ce.Write()
}
utils.Info("Start Api Server")
ser := newApiServer("admin", adminUUID)

View File

@@ -7,7 +7,7 @@
下面的命令也不要整个一大段拷贝而要分条拷贝到vps并运行。
## 第〇步,准备阶段
## 第〇步,准备
首先确保自己服务器相应端口都是打开状态防火墙要处理一下。然后安装一些BBR之类的加速组件。
@@ -20,6 +20,8 @@
注意如果你以前用过verysimple则最好在运行前将自己配置文件先拷贝到其它地方防止下面代码将你原来配置误删除。
或者你可以先解压 新版verysimple可执行文件 到其他位置,然后再用 mv 覆盖掉老版本 的可执行文件 和 examples 目录。
### 命令
```sh
sudo rm -rf /usr/local/etc/verysimple
sudo mkdir -p /usr/local/etc/verysimple

View File

@@ -292,6 +292,10 @@ func (a *Addr) IsEmpty() bool {
return a.Name == "" && len(a.IP) == 0 && a.Network == "" && a.Port == 0
}
func (a *Addr) IsIpv6() bool {
return a.IP.To4() == nil
}
func (a *Addr) GetNetIPAddr() (na netip.Addr) {
if len(a.IP) < 1 {
return

View File

@@ -100,7 +100,7 @@ func (addr Addr) DialWithOpt(sockopt *Sockopt) (net.Conn, error) {
}
dialer.Control = func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
SetSockOpt(int(fd), sockopt, addr.IsUDP())
SetSockOpt(int(fd), sockopt, addr.IsUDP(), addr.IsIpv6())
})
}

View File

@@ -77,7 +77,7 @@ func ListenAndAccept(network, addr string, sockopt *Sockopt, acceptFunc func(net
}
if sockopt != nil {
SetSockOptForListener(tcplistener, sockopt, false)
SetSockOptForListener(tcplistener, sockopt, false, ta.IP.To4() == nil)
}
go loopAccept(tcplistener, acceptFunc)
@@ -138,7 +138,7 @@ func (addr Addr) ListenUDP_withOpt(sockopt *Sockopt) (net.PacketConn, error) {
var lc net.ListenConfig
lc.Control = func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
SetSockOpt(int(fd), sockopt, true)
SetSockOpt(int(fd), sockopt, true, addr.IsIpv6())
})
}
return lc.ListenPacket(context.Background(), "udp", addr.String())

View File

@@ -23,13 +23,13 @@ type ConnWithFile interface {
File() (f *os.File, err error)
}
func SetSockOptForListener(tcplistener ListenerWithFile, sockopt *Sockopt, isudp bool) {
func SetSockOptForListener(tcplistener ListenerWithFile, sockopt *Sockopt, isudp bool, isipv6 bool) {
fileDescriptorSource, err := tcplistener.File()
if err != nil {
return
}
defer fileDescriptorSource.Close()
SetSockOpt(int(fileDescriptorSource.Fd()), sockopt, isudp)
SetSockOpt(int(fileDescriptorSource.Fd()), sockopt, isudp, isipv6)
}
//SetSockOpt 是平台相关的.

View File

@@ -5,7 +5,7 @@ import (
"syscall"
)
func SetSockOpt(fd int, sockopt *Sockopt, isudp bool) {
func SetSockOpt(fd int, sockopt *Sockopt, isudp bool, isipv6 bool) {
if sockopt == nil {
return
}
@@ -18,7 +18,7 @@ func SetSockOpt(fd int, sockopt *Sockopt, isudp bool) {
setTproxy(int(fd))
if isudp {
setTproxy_udp(int(fd))
setTproxy_udp(int(fd), isipv6)
}
}
@@ -28,12 +28,15 @@ func setTproxy(fd int) error {
return syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1)
}
func setTproxy_udp(fd int) error {
func setTproxy_udp(fd int, isipv6 bool) error {
err1 := syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1)
if err1 != nil {
return err1
}
return syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1)
if isipv6 {
return syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1)
}
return nil
}
func setSomark(fd int, somark int) error {

View File

@@ -3,6 +3,5 @@
package netLayer
func SetSockOpt(fd int, sockopt *Sockopt, isudp bool) {
func SetSockOpt(fd int, sockopt *Sockopt, isudp bool, isipv6 bool) {
}

View File

@@ -35,6 +35,62 @@ https://github.com/FarFetchd/simple_tproxy_example/blob/master/tproxy_captive_po
同时trojan-go还使用了
https://github.com/cybozu-go/transocks/blob/master/original_dst_linux.go
Iptables
iptables配置教程
https://toutyrater.github.io/app/tproxy.html
下面把该教程的重要部分搬过来。
ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100
iptables -t mangle -N V2RAY
iptables -t mangle -A V2RAY -d 127.0.0.1/32 -j RETURN
iptables -t mangle -A V2RAY -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A V2RAY -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A V2RAY -d 192.168.0.0/16 -p tcp -j RETURN
iptables -t mangle -A V2RAY -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN
iptables -t mangle -A V2RAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A V2RAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A PREROUTING -j V2RAY
iptables -t mangle -N V2RAY_MASK
iptables -t mangle -A V2RAY_MASK -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A V2RAY_MASK -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A V2RAY_MASK -d 192.168.0.0/16 -p tcp -j RETURN
iptables -t mangle -A V2RAY_MASK -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN
iptables -t mangle -A V2RAY_MASK -j RETURN -m mark --mark 0xff
iptables -t mangle -A V2RAY_MASK -p udp -j MARK --set-mark 1
iptables -t mangle -A V2RAY_MASK -p tcp -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -j V2RAY_MASK # 应用规则
Persistant iptables
单独设置iptables重启后会消失. 下面是持久化方法
mkdir -p /etc/iptables && iptables-save > /etc/iptables/rules.v4
vi /etc/systemd/system/tproxyrule.service
[Unit]
Description=Tproxy rule
After=network.target
Wants=network.target
[Service]
Type=oneshot
ExecStart=/sbin/ip rule add fwmark 1 table 100 ; /sbin/ip route add local 0.0.0.0/0 dev lo table 100 ; /sbin/iptables-restore /etc/iptables/rules.v4
[Install]
WantedBy=multi-user.target
systemctl enable tproxyrule
*/
package tproxy

View File

@@ -11,6 +11,8 @@ import (
"unsafe"
)
//credit: https://github.com/LiamHaworth/go-tproxy/blob/master/tproxy_udp.go , which is under MIT License
// ListenUDP will construct a new UDP listener
// socket with the Linux IP_TRANSPARENT option
// set on the underlying socket

View File

@@ -45,7 +45,7 @@ func (s *Server) Handshake(underlay net.Conn) (result net.Conn, msgConn netLayer
}
defer underlay.SetReadDeadline(time.Time{})
readbs := utils.GetBytes(utils.StandardBytesLength)
readbs := utils.GetBytes(utils.MTU)
wholeReadLen, err := underlay.Read(readbs)
if err != nil {

View File

@@ -276,7 +276,7 @@ func (u *ServerUDPConn) ReadMsgFrom() ([]byte, netLayer.Addr, error) {
if !addr.IP.Equal(u.clientSupposedAddr.IP) || addr.Port != u.clientSupposedAddr.Port {
//just random attack message.
return nil, netLayer.Addr{}, utils.ErrInErr{ErrDesc: "socks5 UDPConn ReadMsg failed, addr not comming from supposed client addr", ErrDetail: utils.ErrInvalidData, Data: addr.String()}
return nil, netLayer.Addr{}, utils.ErrInErr{ErrDesc: "socks5 UDPConn ReadMsg failed, addr not coming from supposed client addr", ErrDetail: utils.ErrInvalidData, Data: addr.String()}
}
}

View File

@@ -66,7 +66,7 @@ func (s *Server) Handshake(underlay net.Conn) (result net.Conn, msgConn netLayer
}
defer underlay.SetReadDeadline(time.Time{})
readbs := utils.GetBytes(utils.StandardBytesLength)
readbs := utils.GetBytes(utils.MTU)
wholeReadLen, err := underlay.Read(readbs)
if err != nil {

View File

@@ -142,7 +142,7 @@ func (s *Server) Handshake(underlay net.Conn) (result net.Conn, msgConn netLayer
// 因此v1.0.3以及更老版本都是直接一段一段read的。
//但是因为需要支持fallback技术所以还是要 进行缓存
readbs := utils.GetBytes(utils.StandardBytesLength)
readbs := utils.GetBytes(utils.MTU)
wholeReadLen, err := underlay.Read(readbs)
if err != nil {

View File

@@ -133,7 +133,7 @@ func MergeBuffers(bs [][]byte) (result []byte, duplicate bool) {
return b0, false
}
if allLen <= MaxBufLen {
if allLen <= MaxPacketLen {
result = GetPacket()
} else {

View File

@@ -25,8 +25,6 @@ const (
// LogLevel 值越小越唠叨, 废话越多值越大打印的越少见log_开头的常量;
//
// 默认是 info级别.因为还在开发中,所以默认级别高一些有好处,方便排错
//
//我们的loglevel具体值 与 zap的 loglevel+1 的含义等价
var (
LogLevel int
@@ -109,7 +107,7 @@ func InitLog() {
if ShouldLogToFile && LogOutFileName != "" {
jsonConf := zap.NewProductionEncoderConfig()
jsonConf.EncodeTime = zapcore.TimeEncoderOfLayout("060102 150405.000") //用一种比较简短的方式输出时间,年月日 时分秒.毫秒。 年只需输出后两位数字即可, 不管Y2K问题, 80年后要是还没实现网络自由那这个世界完蛋了.
jsonConf.EncodeTime = zapcore.TimeEncoderOfLayout("060102 150405.000") //用一种比较简短的方式输出时间,年月日 时分秒.毫秒。 年只需输出后两位数字即可, 不管Y2K问题, 80年后要是还没实现网络自由那这个世界完蛋了.
jsonConf.LevelKey = "L"
jsonConf.TimeKey = "T"
jsonConf.MessageKey = "M"
@@ -123,7 +121,6 @@ func InitLog() {
}
//zap.NewDevelopmentEncoderConfig()
ZapLogger.Info("zap log init complete.")
}

View File

@@ -6,43 +6,47 @@ import (
)
var (
standardBytesPool sync.Pool //专门储存 长度为 StandardBytesLength 的 []byte
mtuPool sync.Pool //专门储存 长度为 MTU 的 []byte
// 作为参考对比tcp默认是 16384, 16k实际上范围是1k128k之间
// 而 udp则最大还不到 64k。(65535208)
// io.Copy 内部默认buffer大小为 32k
// packetPool 专门储存 长度为 MaxPacketLen 的 []byte
//
// 参考对比: tcp默认是 16k范围是1k128k;
// 而 udp则最大还不到 64k (65535208);
// io.Copy 内部默认buffer大小为 32k;
// 总之 我们64k已经够了
standardPacketPool sync.Pool // 专门储存 长度为 MaxBufLen 的 []byte
packetPool sync.Pool
bufPool sync.Pool //储存 *bytes.Buffer
)
//即MTU, Maximum transmission unit, 参照的是 Ethernet v2 的MTU;
const StandardBytesLength int = 1500
const (
//即 Maximum transmission unit, 参照的是 Ethernet v2 的MTU;
MTU int = 1500
//注意wifi信号MTU是 2304我们并未考虑wifi,主要是因为就算用wifi传, 早晚还是要经过以太网,除非两个wifi设备互传
// https://en.wikipedia.org/wiki/Maximum_transmission_unit
//注意wifi信号MTU是 2304我们并未考虑wifi,主要是因为就算用wifi传, 早晚还是要经过以太网,除非两个wifi设备互传
// https://en.wikipedia.org/wiki/Maximum_transmission_unit
//本作设定的最大buf大小64k
const MaxBufLen = 64 * 1024
//本作设定的最大包 长度大小64k
MaxPacketLen = 64 * 1024
)
func init() {
standardBytesPool = sync.Pool{
mtuPool = sync.Pool{
New: func() interface{} {
return make([]byte, StandardBytesLength)
return make([]byte, MTU)
},
}
standardPacketPool = sync.Pool{
packetPool = sync.Pool{
New: func() interface{} {
return make([]byte, MaxBufLen)
return make([]byte, MaxPacketLen)
},
}
bufPool = sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
return new(bytes.Buffer)
},
}
}
@@ -60,31 +64,31 @@ func PutBuf(buf *bytes.Buffer) {
//建议在 Read net.Conn 时, 使用 GetPacket函数 获取到足够大的 []byteMaxBufLen
func GetPacket() []byte {
return standardPacketPool.Get().([]byte)
return packetPool.Get().([]byte)
}
// 放回用 GetPacket 获取的 []byte
func PutPacket(bs []byte) {
c := cap(bs)
if c < MaxBufLen {
if c >= StandardBytesLength {
standardBytesPool.Put(bs[:StandardBytesLength])
if c < MaxPacketLen {
if c >= MTU {
mtuPool.Put(bs[:MTU])
}
return
}
standardPacketPool.Put(bs[:MaxBufLen])
packetPool.Put(bs[:MaxPacketLen])
}
// 从Pool中获取一个 StandardBytesLength 长度的 []byte
// 从Pool中获取一个 MTU 长度的 []byte
func GetMTU() []byte {
return standardBytesPool.Get().([]byte)
return mtuPool.Get().([]byte)
}
// 从pool中获取 []byte, 根据给出长度不同来源于的Pool会不同.
func GetBytes(size int) []byte {
if size <= StandardBytesLength {
bs := standardBytesPool.Get().([]byte)
if size <= MTU {
bs := mtuPool.Get().([]byte)
return bs[:size]
}
@@ -95,12 +99,12 @@ func GetBytes(size int) []byte {
// 根据bs长度 选择放入各种pool中, 只有 cap(bs)>=1500 才会被处理
func PutBytes(bs []byte) {
c := cap(bs)
if c < StandardBytesLength {
if c < MTU {
return
} else if c >= StandardBytesLength && c < MaxBufLen {
standardBytesPool.Put(bs[:StandardBytesLength])
} else if c >= MaxBufLen {
standardPacketPool.Put(bs[:MaxBufLen])
} else if c >= MTU && c < MaxPacketLen {
mtuPool.Put(bs[:MTU])
} else if c >= MaxPacketLen {
packetPool.Put(bs[:MaxPacketLen])
}
}

View File

@@ -12,12 +12,12 @@ import (
func fixAndroidTimezone() {
out, err := exec.Command("/system/bin/getprop", "persist.sys.timezone").Output()
if err != nil {
log.Println("fixAndroidTimezone failed", err)
log.Println("fixAndroidTimezone failed when calling /system/bin/getprop,", err)
return
}
z, err := time.LoadLocation(strings.TrimSpace(string(out)))
if err != nil {
log.Println("fixAndroidTimezone failed", err)
log.Println("fixAndroidTimezone failed,", err)
return
}
time.Local = z

View File

@@ -2,7 +2,6 @@
package utils
import (
"errors"
"flag"
"math/rand"
"strings"
@@ -78,6 +77,6 @@ func WrapFuncForPromptUI(f func(string) bool) func(string) error {
if f(s) {
return nil
}
return errors.New("not valid")
return ErrInvalidData
}
}

View File

@@ -3,17 +3,16 @@ package utils
import (
"crypto/rand"
"encoding/hex"
"errors"
"strings"
)
func StrToUUID(s string) (uuid [16]byte, err error) {
if len(s) != 36 {
return uuid, errors.New("invalid UUID Str: " + s)
return uuid, ErrInErr{ErrDesc: "invalid UUID Str", ErrDetail: ErrInvalidData, Data: s}
}
b := []byte(strings.Replace(s, "-", "", -1))
if len(b) != 32 {
return uuid, errors.New("invalid UUID Str: " + s)
return uuid, ErrInErr{ErrDesc: "invalid UUID Str", ErrDetail: ErrInvalidData, Data: s}
}
_, err = hex.Decode(uuid[:], b)
return