• Github每日精选(第11期):端对端的数据传输croc


    croc

    在这里插入图片描述

    关于

    croc 可以轻松安全地将内容从一台计算机发送到另一台计算机。一开始觉得这不就是飞鸽传书的功能吗?

    其实他跟飞鸽出书还是有很多不同的,操作方式更加的简单而且发现对方更加的快速。我们来看怎么个用法。

    crocgithub下的地址在这里

    croc是一种允许任何两台计算机简单安全地传输文件和文件夹的工具。AFAIK,croc是唯一可以执行以下所有操作的 CLI 文件传输工具:

    • 允许任何两台计算机传输数据
    • 提供端到端加密(使用 PAKE)
    • 实现轻松的跨平台传输(Windows、Linux、Mac)
    • 允许多个文件传输
    • 允许恢复被中断的传输
    • 不需要本地服务器或端口转发
    • ipv6-优先和 ipv4 背后
    • 可以使用代理,比如tor

    在这里插入图片描述

    安装

    Windows下的安装,直接就先下载exe,如果是ubuntu下,可以使用deb的安装方式。

    dpkg -i croc_9.6.0_Linux-64bit.deb
    
    • 1

    使用–发送呵呵接收文件

    croc 没有用户界面都是使用命令就能完成所有的动作,他可以在各个端进行传输,比如可以在windowsubuntu下,相互发送数据。

    比如在Windows下:

    我们想发送windows下的bash_autocomplete这个文件,我们在windows的控制台下,输入croc send bash_autocomplete 表示发送bash_autocomplete这个文件,这时候windows生成了一个密钥的东西7584-flipper-tommy-tribal,这个码就是发送码,接收端收到这个码就可以用来接收文件了。

    croc send bash_autocomplete
    Sending 'bash_autocomplete' (558 B)
    Code is: 7584-flipper-tommy-tribal
    On the other computer run
    
    croc 7584-flipper-tommy-tribal
    
    Sending (->192.168.100.170:49540)
    bash_autocomplete 100% |████████████████████| (558/558 B, 132.038 kB/s)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    ubuntu下:

    直接输入接收码·7584-flipper-tommy-tribal,用来接收’bash_autocomplete’的文件。

    root@ubuntu:~# croc 7584-flipper-tommy-tribal
    Accept 'bash_autocomplete' (558 B)? (Y/n) y
    
    Receiving (<-192.168.100.1:9009)
    bash_autocomplete 100% |████████████████████| (558/558 B, 125.051 kB/s)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这样我们的文件就接收完成了。

    如果还有别的需求可以看更多的文档。

    代码分析

    croc 是用go语言写的,看看核心代码,这里是接收文件的逻辑,可以大致的看下,从配对到文件的发送都写在这里。

    // Receive will receive a file
    func (c *Client) Receive() (err error) {
    	fmt.Fprintf(os.Stderr, "connecting...")
    	// recipient will look for peers first
    	// and continue if it doesn't find any within 100 ms
    	usingLocal := false
    	isIPset := false
    
    	if c.Options.OnlyLocal || c.Options.IP != "" {
    		c.Options.RelayAddress = ""
    		c.Options.RelayAddress6 = ""
    	}
    
    	if c.Options.IP != "" {
    		// check ip version
    		if strings.Count(c.Options.IP, ":") >= 2 {
    			log.Debug("assume ipv6")
    			c.Options.RelayAddress6 = c.Options.IP
    		}
    		if strings.Contains(c.Options.IP, ".") {
    			log.Debug("assume ipv4")
    			c.Options.RelayAddress = c.Options.IP
    		}
    		isIPset = true
    	}
    
    	if !c.Options.DisableLocal && !isIPset {
    		log.Debug("attempt to discover peers")
    		var discoveries []peerdiscovery.Discovered
    		var wgDiscovery sync.WaitGroup
    		var dmux sync.Mutex
    		wgDiscovery.Add(2)
    		go func() {
    			defer wgDiscovery.Done()
    			ipv4discoveries, err1 := peerdiscovery.Discover(peerdiscovery.Settings{
    				Limit:     1,
    				Payload:   []byte("ok"),
    				Delay:     20 * time.Millisecond,
    				TimeLimit: 200 * time.Millisecond,
    			})
    			if err1 == nil && len(ipv4discoveries) > 0 {
    				dmux.Lock()
    				err = err1
    				discoveries = append(discoveries, ipv4discoveries...)
    				dmux.Unlock()
    			}
    		}()
    		go func() {
    			defer wgDiscovery.Done()
    			ipv6discoveries, err1 := peerdiscovery.Discover(peerdiscovery.Settings{
    				Limit:     1,
    				Payload:   []byte("ok"),
    				Delay:     20 * time.Millisecond,
    				TimeLimit: 200 * time.Millisecond,
    				IPVersion: peerdiscovery.IPv6,
    			})
    			if err1 == nil && len(ipv6discoveries) > 0 {
    				dmux.Lock()
    				err = err1
    				discoveries = append(discoveries, ipv6discoveries...)
    				dmux.Unlock()
    			}
    		}()
    		wgDiscovery.Wait()
    
    		if err == nil && len(discoveries) > 0 {
    			log.Debugf("all discoveries: %+v", discoveries)
    			for i := 0; i < len(discoveries); i++ {
    				log.Debugf("discovery %d has payload: %+v", i, discoveries[i])
    				if !bytes.HasPrefix(discoveries[i].Payload, []byte("croc")) {
    					log.Debug("skipping discovery")
    					continue
    				}
    				log.Debug("switching to local")
    				portToUse := string(bytes.TrimPrefix(discoveries[i].Payload, []byte("croc")))
    				if portToUse == "" {
    					portToUse = models.DEFAULT_PORT
    				}
    				address := net.JoinHostPort(discoveries[i].Address, portToUse)
    				errPing := tcp.PingServer(address)
    				if errPing == nil {
    					log.Debugf("successfully pinged '%s'", address)
    					c.Options.RelayAddress = address
    					c.ExternalIPConnected = c.Options.RelayAddress
    					c.Options.RelayAddress6 = ""
    					usingLocal = true
    					break
    				} else {
    					log.Debugf("could not ping: %+v", errPing)
    				}
    			}
    		}
    		log.Debugf("discoveries: %+v", discoveries)
    		log.Debug("establishing connection")
    	}
    	var banner string
    	durations := []time.Duration{200 * time.Millisecond, 5 * time.Second}
    	err = fmt.Errorf("found no addresses to connect")
    	for i, address := range []string{c.Options.RelayAddress6, c.Options.RelayAddress} {
    		if address == "" {
    			continue
    		}
    		var host, port string
    		host, port, _ = net.SplitHostPort(address)
    		// Default port to :9009
    		if port == "" {
    			host = address
    			port = models.DEFAULT_PORT
    		}
    		log.Debugf("got host '%v' and port '%v'", host, port)
    		address = net.JoinHostPort(host, port)
    		log.Debugf("trying connection to %s", address)
    		c.conn[0], banner, c.ExternalIP, err = tcp.ConnectToTCPServer(address, c.Options.RelayPassword, c.Options.SharedSecret[:3], durations[i])
    		if err == nil {
    			c.Options.RelayAddress = address
    			break
    		}
    		log.Debugf("could not establish '%s'", address)
    	}
    	if err != nil {
    		err = fmt.Errorf("could not connect to %s: %w", c.Options.RelayAddress, err)
    		log.Debug(err)
    		return
    	}
    	log.Debugf("receiver connection established: %+v", c.conn[0])
    	log.Debugf("banner: %s", banner)
    
    	if !usingLocal && !c.Options.DisableLocal && !isIPset {
    		// ask the sender for their local ips and port
    		// and try to connect to them
    		log.Debug("sending ips?")
    		var data []byte
    		if err := c.conn[0].Send(ipRequest); err != nil {
    			log.Errorf("ips send error: %v", err)
    		}
    		data, err = c.conn[0].Receive()
    		if err != nil {
    			return
    		}
    		log.Debugf("ips data: %s", data)
    		var ips []string
    		if err := json.Unmarshal(data, &ips); err != nil {
    			log.Debugf("ips unmarshal error: %v", err)
    		}
    		if len(ips) > 1 {
    			port := ips[0]
    			ips = ips[1:]
    			for _, ip := range ips {
    				ipv4Addr, ipv4Net, errNet := net.ParseCIDR(fmt.Sprintf("%s/24", ip))
    				log.Debugf("ipv4Add4: %+v, ipv4Net: %+v, err: %+v", ipv4Addr, ipv4Net, errNet)
    				localIps, _ := utils.GetLocalIPs()
    				haveLocalIP := false
    				for _, localIP := range localIps {
    					localIPparsed := net.ParseIP(localIP)
    					if ipv4Net.Contains(localIPparsed) {
    						haveLocalIP = true
    						break
    					}
    				}
    				if !haveLocalIP {
    					log.Debugf("%s is not a local IP, skipping", ip)
    					continue
    				}
    
    				serverTry := net.JoinHostPort(ip, port)
    				conn, banner2, externalIP, errConn := tcp.ConnectToTCPServer(serverTry, c.Options.RelayPassword, c.Options.SharedSecret[:3], 500*time.Millisecond)
    				if errConn != nil {
    					log.Debug(errConn)
    					log.Debugf("could not connect to " + serverTry)
    					continue
    				}
    				log.Debugf("local connection established to %s", serverTry)
    				log.Debugf("banner: %s", banner2)
    				// reset to the local port
    				banner = banner2
    				c.Options.RelayAddress = serverTry
    				c.ExternalIP = externalIP
    				c.conn[0].Close()
    				c.conn[0] = nil
    				c.conn[0] = conn
    				break
    			}
    		}
    	}
    
    	if err := c.conn[0].Send(handshakeRequest); err != nil {
    		log.Errorf("handshake send error: %v", err)
    	}
    	c.Options.RelayPorts = strings.Split(banner, ",")
    	if c.Options.NoMultiplexing {
    		log.Debug("no multiplexing")
    		c.Options.RelayPorts = []string{c.Options.RelayPorts[0]}
    	}
    	log.Debug("exchanged header message")
    	fmt.Fprintf(os.Stderr, "\rsecuring channel...")
    	err = c.transfer()
    	if err == nil {
    		if c.numberOfTransferredFiles+len(c.EmptyFoldersToTransfer) == 0 {
    			fmt.Fprintf(os.Stderr, "\rNo files transferred.")
    		}
    	}
    	return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
  • 相关阅读:
    happens-before规则——理解happens-before规则
    基于单片机设计的水平仪(STC589C52+MPU6050)
    题348.差分约束-acwing-Q362--区间
    前端国际化你还在一个个翻译?复制粘贴,让你坐着喝茶
    【C/C++笔试练习】——数组名和&数组名、switch循环语句、数据在计算机中的存储顺序、字符串中找出连续最长的数字串、数组中出现次数超过一半的数字
    【力扣】415. 字符串相加(大数相加)<模拟>
    83文章解读与程序——《考虑储能优化的微网能量管理双层模型》已提供下载资源
    C#:模式匹配与模式
    【QML】QML性能优化 | 3D场景优化
    提高网站性能的10种方法:加速用户体验和降低服务器负担
  • 原文地址:https://blog.csdn.net/weixin_40425640/article/details/125935610