RAW 客户端-服务器套接字 python
RAW client-server socket python
我想在Python实现一个RAW socket,然后从Client向Server发送数据
与普通套接字不同,我尝试使用以下定义
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
但命令为
s.listen(1), s.connect()
不工作。
我不知道如何对 Client.py 和 Server.py 进行编程。
有人可以帮助我吗?
那是因为原始套接字根本不使用 Ethernet/TCP/IP 库。这是一个 RAW 套接字,您负责发送的任何数据。您还负责通过发送正确的 SYN/ACK 订单连接到您的同行。
传统套接字是一个“抽象”层,供您发送有效负载(数据)。
意思是你 connect 你的套接字到一个目的地,你告诉 socket 要发送什么数据,假设你使用的是基于 TCP 的套接字,你的数据将前面加上对应于 TCP 协议和版本的 header,您的数据可能会根据您尝试推送的数据量进行分段。
使用传统套接字,所有这些都会自动发生。
这是 TCP header 大致的样子(断章取意,但它会给你一个想法):
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
请注意,数据 是您通常所做的,但是在使用 RAW 套接字时,您需要将所有这些信息块发送到您的以太网电缆上.
我可以 post 今晚晚些时候写一些代码,如果有人不抢我的话,但这里有一个很好的简短用法示例:How Do I Use Raw Socket in Python?
tl;博士:
您需要构建以太网 header 和 TCP header 并根据 RFC 标准向其中添加数据(这可能是一个很好的起点:https://www.rfc-editor.org/rfc/rfc793 ).然后您需要“简单地”将其发送到您的“套接字”。 RAW 套接字没有魔法,您使用源地址+目标地址构建 header,然后将有效负载发送到电缆上,希望您正确构建数据包。
回复评论:
socket.accept()
- 此函数在传统套接字中用于“存储”session 信息(来源:端口 -> Destination:Port)。此函数从传入连接尝试的缓冲 queue 中获取客户端并“激活”它们。这不适用于原始套接字,原因是普通套接字的抽象层再次不存在。您的 RAW 套接字将侦听任何传入的 data(不是连接),这意味着您负责首先接收一个 SYN
数据包,您需要用 [=15] 响应该数据包=] 其中您将收到最终 ACK
。此时,您可以使用正确的信息(源端口等)在你们之间发送数据。
这是一个很好的 (ASCII) flow-chart 抽象层,在 普通套接字中提供 :
+---------+ ---------\ active OPEN
| CLOSED | \ -----------
+---------+<---------\ \ create TCB
| ^ \ \ snd SYN
passive OPEN | | CLOSE \ \
------------ | | ---------- \ \
create TCB | | delete TCB \ \
V | \ \
+---------+ CLOSE | \
| LISTEN | ---------- | |
+---------+ delete TCB | |
rcv SYN | | SEND | |
----------- | | ------- | V
+---------+ snd SYN,ACK / \ snd SYN +---------+
| |<----------------- ------------------>| |
| SYN | rcv SYN | SYN |
| RCVD |<-----------------------------------------------| SENT |
| | snd ACK | |
| |------------------ -------------------| |
+---------+ rcv ACK of SYN \ / rcv SYN,ACK +---------+
| -------------- | | -----------
| x | | snd ACK
| V V
| CLOSE +---------+
| ------- | ESTAB |
| snd FIN +---------+
| CLOSE | | rcv FIN
V ------- | | -------
+---------+ snd FIN / \ snd ACK +---------+
| FIN |<----------------- ------------------>| CLOSE |
| WAIT-1 |------------------ | WAIT |
+---------+ rcv FIN \ +---------+
| rcv ACK of FIN ------- | CLOSE |
| -------------- snd ACK | ------- |
V x V snd FIN V
+---------+ +---------+ +---------+
|FINWAIT-2| | CLOSING | | LAST-ACK|
+---------+ +---------+ +---------+
| rcv ACK of FIN | rcv ACK of FIN |
| rcv FIN -------------- | Timeout=2MSL -------------- |
| ------- x V ------------ x V
\ snd ACK +---------+delete TCB +---------+
------------------------>|TIME WAIT|------------------>| CLOSED |
+---------+ +---------+
这是一个服务器示例:
#!/usr/bin/env python
from socket import socket, AF_PACKET, SOCK_RAW
s = socket(AF_PACKET, SOCK_RAW)
#s.bind(("eth1", 0))
# We're putting together an ethernet frame here,
# NOTE: Not a full TCP frame, this is important to remember!
src_addr = "\x01\x02\x03\x04\x05\x06"
dst_addr = "\x01\x02\x03\x04\x05\x06"
payload = ("["*30)+"PAYLOAD"+("]"*30)
checksum = "\x1a\x2b\x3c\x4d"
ethertype = "\x08\x01"
s.send(dst_addr+src_addr+ethertype+payload+checksum)
找到一些我几乎没有开始使用的旧代码,可能会派上用场:https://github.com/Torxed/Scripts/tree/master/python/Laboratory
原始套接字是无连接的,这意味着 listen 和 accept 将不起作用。然而,您可以使用这个 Python 库:rawsocketpy 它允许在第 2 层使用原始套接字并实现类似服务器的选项。
#!/usr/bin/env python
from rawsocketpy import RawSocket
sock = RawSocket("wlp2s0", 0xEEFA)
sock.send("some data")
sock.send("personal data", dest="\xAA\xBB\xCC\xDD\xEE\xFF")
或服务器形式:
#!/usr/bin/env python
from rawsocketpy import RawRequestHandler, RawAsyncServerCallback
import time
def callback(handler, server):
print("Testing")
handler.setup()
handler.handle()
handler.finish()
class LongTaskTest(RawRequestHandler):
def handle(self):
time.sleep(1)
print(self.packet)
def finish(self):
print("End")
def setup(self):
print("Begin")
def main():
rs = RawAsyncServerCallback("wlp2s0", 0xEEFA, LongTaskTest, callback)
rs.spin()
if __name__ == '__main__':
main()
我想在Python实现一个RAW socket,然后从Client向Server发送数据
与普通套接字不同,我尝试使用以下定义
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
但命令为
s.listen(1), s.connect()
不工作。 我不知道如何对 Client.py 和 Server.py 进行编程。 有人可以帮助我吗?
那是因为原始套接字根本不使用 Ethernet/TCP/IP 库。这是一个 RAW 套接字,您负责发送的任何数据。您还负责通过发送正确的 SYN/ACK 订单连接到您的同行。
传统套接字是一个“抽象”层,供您发送有效负载(数据)。 意思是你 connect 你的套接字到一个目的地,你告诉 socket 要发送什么数据,假设你使用的是基于 TCP 的套接字,你的数据将前面加上对应于 TCP 协议和版本的 header,您的数据可能会根据您尝试推送的数据量进行分段。
使用传统套接字,所有这些都会自动发生。
这是 TCP header 大致的样子(断章取意,但它会给你一个想法):
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
请注意,数据 是您通常所做的,但是在使用 RAW 套接字时,您需要将所有这些信息块发送到您的以太网电缆上.
我可以 post 今晚晚些时候写一些代码,如果有人不抢我的话,但这里有一个很好的简短用法示例:How Do I Use Raw Socket in Python?
tl;博士:
您需要构建以太网 header 和 TCP header 并根据 RFC 标准向其中添加数据(这可能是一个很好的起点:https://www.rfc-editor.org/rfc/rfc793 ).然后您需要“简单地”将其发送到您的“套接字”。 RAW 套接字没有魔法,您使用源地址+目标地址构建 header,然后将有效负载发送到电缆上,希望您正确构建数据包。
回复评论:
socket.accept()
- 此函数在传统套接字中用于“存储”session 信息(来源:端口 -> Destination:Port)。此函数从传入连接尝试的缓冲 queue 中获取客户端并“激活”它们。这不适用于原始套接字,原因是普通套接字的抽象层再次不存在。您的 RAW 套接字将侦听任何传入的 data(不是连接),这意味着您负责首先接收一个 SYN
数据包,您需要用 [=15] 响应该数据包=] 其中您将收到最终 ACK
。此时,您可以使用正确的信息(源端口等)在你们之间发送数据。
这是一个很好的 (ASCII) flow-chart 抽象层,在 普通套接字中提供 :
+---------+ ---------\ active OPEN
| CLOSED | \ -----------
+---------+<---------\ \ create TCB
| ^ \ \ snd SYN
passive OPEN | | CLOSE \ \
------------ | | ---------- \ \
create TCB | | delete TCB \ \
V | \ \
+---------+ CLOSE | \
| LISTEN | ---------- | |
+---------+ delete TCB | |
rcv SYN | | SEND | |
----------- | | ------- | V
+---------+ snd SYN,ACK / \ snd SYN +---------+
| |<----------------- ------------------>| |
| SYN | rcv SYN | SYN |
| RCVD |<-----------------------------------------------| SENT |
| | snd ACK | |
| |------------------ -------------------| |
+---------+ rcv ACK of SYN \ / rcv SYN,ACK +---------+
| -------------- | | -----------
| x | | snd ACK
| V V
| CLOSE +---------+
| ------- | ESTAB |
| snd FIN +---------+
| CLOSE | | rcv FIN
V ------- | | -------
+---------+ snd FIN / \ snd ACK +---------+
| FIN |<----------------- ------------------>| CLOSE |
| WAIT-1 |------------------ | WAIT |
+---------+ rcv FIN \ +---------+
| rcv ACK of FIN ------- | CLOSE |
| -------------- snd ACK | ------- |
V x V snd FIN V
+---------+ +---------+ +---------+
|FINWAIT-2| | CLOSING | | LAST-ACK|
+---------+ +---------+ +---------+
| rcv ACK of FIN | rcv ACK of FIN |
| rcv FIN -------------- | Timeout=2MSL -------------- |
| ------- x V ------------ x V
\ snd ACK +---------+delete TCB +---------+
------------------------>|TIME WAIT|------------------>| CLOSED |
+---------+ +---------+
这是一个服务器示例:
#!/usr/bin/env python
from socket import socket, AF_PACKET, SOCK_RAW
s = socket(AF_PACKET, SOCK_RAW)
#s.bind(("eth1", 0))
# We're putting together an ethernet frame here,
# NOTE: Not a full TCP frame, this is important to remember!
src_addr = "\x01\x02\x03\x04\x05\x06"
dst_addr = "\x01\x02\x03\x04\x05\x06"
payload = ("["*30)+"PAYLOAD"+("]"*30)
checksum = "\x1a\x2b\x3c\x4d"
ethertype = "\x08\x01"
s.send(dst_addr+src_addr+ethertype+payload+checksum)
找到一些我几乎没有开始使用的旧代码,可能会派上用场:https://github.com/Torxed/Scripts/tree/master/python/Laboratory
原始套接字是无连接的,这意味着 listen 和 accept 将不起作用。然而,您可以使用这个 Python 库:rawsocketpy 它允许在第 2 层使用原始套接字并实现类似服务器的选项。
#!/usr/bin/env python
from rawsocketpy import RawSocket
sock = RawSocket("wlp2s0", 0xEEFA)
sock.send("some data")
sock.send("personal data", dest="\xAA\xBB\xCC\xDD\xEE\xFF")
或服务器形式:
#!/usr/bin/env python
from rawsocketpy import RawRequestHandler, RawAsyncServerCallback
import time
def callback(handler, server):
print("Testing")
handler.setup()
handler.handle()
handler.finish()
class LongTaskTest(RawRequestHandler):
def handle(self):
time.sleep(1)
print(self.packet)
def finish(self):
print("End")
def setup(self):
print("Begin")
def main():
rs = RawAsyncServerCallback("wlp2s0", 0xEEFA, LongTaskTest, callback)
rs.spin()
if __name__ == '__main__':
main()