kk Blog —— 通用基础


date [-d @int|str] [+%s|"+%F %T"]
netstat -ltunp
sar -n DEV 1

ShadowSocks原理

https://my.oschina.net/moziBlog/blog/3190520

ssh tunnel

1、首先用户和服务器基于 ssh 建立起一条加密的通道

2、用户通过建立起的隧道进行代理,通过 ssh server 向真实的服务发起请求

3、服务通过 ssh server,再通过创建好的隧道返回给用户

ssh 本身就是基于RSA 加密技术,无法获取数据传输的过程中的加密数据内容。但由于ssh本身的特征是明显的,所以通过分析连接的特征能得出是ss。

shadowsocks

shadowsocks将原来ssh创建的 Socks5协议拆开成 server 端和 client 端

1、客户端发出的请求基于Socks5协议跟 ss-local 端进行通讯,返个 ss-local 一般是本机或是代理服务器

2、ss-local 和 ss-server两端通过多种可选的加密方法进行通讯,用常规的 TCP包。

3、ss-server 将收到的加密数据进行解密,还原原来的请求,再发送到用户需要访问的服务,获得响应原路返回

SOCKS5 协议

http://www.moye.me/2017/08/03/analyze-socks5-protocol/

SOCKS5 协议并不负责代理服务器的数据传输环节,此协议只是在C/S两端真实交互之间,建立起一条从客户端到代理服务器的授信连接。来看看细节:

协议流程

从流程上来说,SOCKS5 是一个C/S 交互的协议,交互大概分为这么几步:

1
2
3
4
5
6
7
客户端发送认证协商
代理服务器就认证协商进行回复(如拒绝则本次会话结束)
	如需GSSAPI或用户名/密码认证,客户端发送认证信息
	代理服务器就对应项进行鉴权,并进行回复或拒绝
客户端发送希望连接的目标信息
代理服务器就连接信息进行确认或拒绝
【非协议内容】:代理服务器连接目标并 pipe 到客户端

协议细节

1. 认证

认证方法:

1
2
3
4
5
6
0x00: NO AUTHENTICATION REQUIRED
0x01: GSSAPI
0x02: USERNAME/PASSWORD
0x03: to X’7F’ IANA ASSIGNED
0x80: to X’FE’ RESERVED FOR PRIVATE METHODS
0xFF: NO ACCEPTABLE METHODS

1.1 客户端 -> 代理服务器,请求认证:

版本号(1字节)可供选认证方法(1字节)选择的方法(1~255字节)
固定为5选了多少种都有上表中哪些方法

1.2 代理服务器 -> 客户端,响应认证:

版本号(1字节)确认认证的方法
固定为5认证方法列表的某项:
0x00,则无需客户端发送进一步认证的信息
0x01,则需要客户端进行进一步认证,细节见 RFC1929
0x01,则需要客户端进行进一步认证,细节见RFC2743
0xFF,则相当于拒绝请求,客户端只能关闭连接

2. 请求信息

2.1 客户端 -> 代理服务器,发送目标信息:

版本号(1字节)命令(1字节)保留(1字节)请求类型(1字节)地址(不定长)端口(2字节)
固定为50x01: CONNECT
0x02: BIND
0x03: UDP ASSOCIATE
固定为 0x000x01: IP V4 地址
0x03: 域名
0x04: IP V6 地址
如果请求类型是域名,
第个1字节为 域名的长度

命令字段说明:

1
2
3
CONNECT:  用于客户端请求服务器进行代理
BIND:  用于客户端向服务器上报自己的反向连接监听地址(应用场景如 FTP 下载,客户端需要接受来自服务器的连接
UDP ASSOCIATE:用于请求建立到 UDP 数据报中继的连接

2.2 代理服务器 -> 客户端,确认连接:

版本号(1字节)确认回应(1字节)保留(1字节)响应类型(1字节)地址(不定长)端口(2字节)
固定为50x00: succeeded
0x01: general SOCKS server failure
0x02: connection not allowed by ruleset
0x03: Network unreachable
0x04: Host unreachable
0x05: Connection refused
0x06: TTL expired
0x07: Command not supported
0x08: Address type not supported
0x09: to X’FF’ unassigned
固定为 0x00 仅用于响应客
户端BIND命令:
0x01: IP V4 地址
0x03: 域名
0x04: IP V6 地址
仅用于响应客
户端BIND命令:
如果请求
类型是域名,
第个1字节为
域名的长度
仅用于响应客
户端BIND命令

可以看出,在代理服务器确认回应为 0x00 时,此次 SOCKS5 协议协商部分顺利完成,宣告进入到数据传输阶段(也可以说,这之后发生的事已经与SOCKS5协议无关)。

WebSocket协议

https://zhuanlan.zhihu.com/p/145628937

概念

WebSocket 是基于TCP/IP协议,独立于HTTP协议的通信协议。

WebSocket 是双向通讯,有状态,客户端一(多)个与服务端一(多)双向实时响应(客户端 ⇄ 服务端)。

WebSocket 是应用在浏览器的 Socket (是 Socket 模型接口的实现),Socket 是一个网络通信接口 (通信规范)。

WebSocket协议端口是80。

WebSocket SSL协议端口是443。

Socket是TCP/IP协议的网络数据通讯接口(一种底层的通讯的方式)。

Socket是IP地址和端口号的组合。例如:192.168.1.100:8080。

版本

RFC 6455 规范 是大多数浏览器实现的 WebSocket API 协议。

工作原理

  1. 用户打开Web浏览器,并访问Web站点。

  2. Web浏览器(客户端)与Web服务端建立连接。

  3. Web浏览器(客户端)能定时收发Web服务端数据,Web服务端也能定时收发Web浏览器数据。

WebSocket协议不受同源策略影响。

请求消息体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 请求头部分
# [请求方式] [资源路径] [版本]
GET /xxx HTTP/1.1
# 主机。
Host: server.example.com
# 协议升级。
Upgrade: websocket
# 连接状态。
Connection: Upgrade
# websocket客户端生成的随机字符。
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
# websocket协议的子协议,自定义字符,可以理解为频道。
Sec-WebSocket-Protocol: chat, superchat
# websocket协议的版本是13。
Sec-WebSocket-Version: 13

响应消息体

1
2
3
4
5
6
7
8
9
10
11
# 响应头部分
# [版本] [状态码]
HTTP/1.1 101 Switching Protocols
# 协议升级。
Upgrade: websocket
# 连接状态。
Connection: Upgrade
# WebSocket服务端根据Sec-WebSocket-Key生成的随机字符。
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
# WebSocket协议的子协议,自定义字符,可以理解为频道。
Sec-WebSocket-Protocol: chat

Upgrade字段仅限HTTP/1.1版本协议,不适合HTTP/2.0版本协议。

101 Switching Protocols 是HTTP协议状态码,不是websocket协议状态码。

状态码

连接成功状态码

101:HTTP协议切换为WebSocket协议。

连接关闭状态码

1000:正常断开连接。

1001:服务器断开连接。

1002:websocket协议错误。

1003:客户端接受了不支持数据格式(只允许接受文本消息,不允许接受二进制数据,是客户端限制不接受二进制数据,而不是websocket协议不支持二进制数据)。

1006:异常关闭。

1007:客户端接受了无效数据格式(文本消息编码不是utf-8)。

1009:传输数据量过大。

1010:客户端终止连接。

1011:服务器终止连接。

1012:服务端正在重新启动。

1013:服务端临时终止。

1014:通过网关或代理请求服务器,服务器无法及时响应。

1015:TLS握手失败。

连接关闭状态码是WebSocket对象的onclose属性返回的。

其他状态码不常用,所以就不列举说明。


server.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#coding:utf-8
import socket
addr = ('192.168.8.107', 88)
fd = socket.socket()
fd.bind(addr)
fd.listen(5)
while True:
	conn,addr = fd.accept()
	rcv = conn.recv(4096)
	rarr = rcv.split('\r\n\r\n', -1)
	if len(rarr) != 0:
		print(rarr[0])
		#file_data = rarr[1]
		status = "HTTP/1.1 101 Switching Protocols\r\n"
		headers = "Upgrade: websocket\r\nConnection: Upgrade\r\nDate: Sat, 1 Mar 2021 12:33:44 GMT\r\nContent-Type: text/plain\r\nPragma:no-cache\r\n\r\n"
		send_data = status + headers
		conn.send(bytes(send_data))
		while True :
			rcv = conn.recv(100)
			print(rcv)
			conn.send("jjjjjj" + rcv)
	conn.close()

client.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#coding:utf-8
import socket
import time
addr = ('192.168.8.107', 88)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
	ret = s.connect(addr)
except socket.error as msg:
	print (msg)
print (ret)
strs="GET /test.txt HTTP/1.1\r\nHost:test.com\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n\r\n"
tt = s.send(strs)
print (tt)
while True:
	rstrs="kkkkkkkkkkkkkkkkk"
	s.send(bytes(rstrs))
	time.sleep(1)
	t=s.recv(100)
	print (t)
s.close()