mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-12-24 13:27:56 +08:00
修订文档, sockopt 和 utils包的代码.
This commit is contained in:
15
README.md
15
README.md
@@ -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 v1,hysteria 阻
|
||||
|
||||
支持的功能有:
|
||||
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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 是平台相关的.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -3,6 +3,5 @@
|
||||
|
||||
package netLayer
|
||||
|
||||
func SetSockOpt(fd int, sockopt *Sockopt, isudp bool) {
|
||||
|
||||
func SetSockOpt(fd int, sockopt *Sockopt, isudp bool, isipv6 bool) {
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -133,7 +133,7 @@ func MergeBuffers(bs [][]byte) (result []byte, duplicate bool) {
|
||||
return b0, false
|
||||
}
|
||||
|
||||
if allLen <= MaxBufLen {
|
||||
if allLen <= MaxPacketLen {
|
||||
result = GetPacket()
|
||||
|
||||
} else {
|
||||
|
||||
@@ -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.")
|
||||
}
|
||||
|
||||
|
||||
@@ -6,43 +6,47 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
standardBytesPool sync.Pool //专门储存 长度为 StandardBytesLength 的 []byte
|
||||
mtuPool sync.Pool //专门储存 长度为 MTU 的 []byte
|
||||
|
||||
// 作为参考对比,tcp默认是 16384, 16k,实际上范围是1k~128k之间
|
||||
// 而 udp则最大还不到 64k。(65535-20-8)
|
||||
// io.Copy 内部默认buffer大小为 32k
|
||||
// packetPool 专门储存 长度为 MaxPacketLen 的 []byte
|
||||
//
|
||||
// 参考对比: tcp默认是 16k,范围是1k~128k;
|
||||
// 而 udp则最大还不到 64k (65535-20-8);
|
||||
// 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函数 获取到足够大的 []byte(MaxBufLen)
|
||||
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])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user