我想在Python中实现一个RAW套接字,然后将数据从客户端发送到服务器。
与普通套接字不同,我尝试使用以下定义
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
但命令为
s.listen(1), s.connect()
无效。 我不知道如何编写Client.py和Server.py。 有人能帮助我吗?
答案 0 :(得分:4)
这是因为原始套接字根本不会影响以太网/ TCP / IP库。它是一个RAW套接字,您负责发送的任何数据。您还可以通过发送正确的SYN / ACK命令来连接到您的对等方。
传统的套接字是一种抽象的"用于发送有效负载(数据)的层。 这意味着您将套接字连接到目的地,告诉套接字要发送哪些数据,假设您使用基于TCP的套接字,您的数据将被添加到对应于TCP协议和版本的标头,您的数据可能会根据您尝试推送的数据进行细分。
所有这些都是通过传统套接字自动发生的。
这是TCP标题的粗略看法(脱离上下文但会给你一个想法):
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套接字时,您需要将所有这些信息块发送到以太网电缆。
我可以在今晚晚些时候发布一些代码,也许是因为有人没有打败我,但这是一个很好的简短用法示例:How Do I Use Raw Socket in Python?
您需要构建以太网标头和TCP标头,并根据RFC标准将数据添加到其中(这可能是一个很好的起点:https://tools.ietf.org/html/rfc793)。然后你需要"简单地"将它发送到你的" socket"。 RAW套接字没有任何神奇之处,您可以使用源+目标地址构建标头,然后将有效负载发送到电缆上,希望您正确构建数据包。
socket.accept()
- 此功能在传统套接字中用于"存储"会话信息(来源:端口 - >目的地:端口)。此函数从缓冲的传入连接尝试队列中获取客户端,并且"激活"他们。这不适用于原始套接字,原因是普通套接字的抽象层再次出现,不存在。您的RAW套接字将侦听任何传入的数据(而非连接),这意味着您负责首先接收SYN
数据包,您需要使用{{1}进行响应您将在其中收到最终SYN-ACK
。此时,您可以使用正确的信息(源端口等)在您之间发送数据。
这是普通套接字中提供的抽象层的良好(ASCII)流程图:
ACK
+---------+ ---------\ 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 |
+---------+ +---------+
发现一些我刚开始使用的旧代码,可能会派上用场:https://github.com/Torxed/Scripts/tree/master/python/Laboratory
答案 1 :(得分:1)
原始套接字是无连接的,这意味着侦听和接受将不起作用。但是,您可以使用以下Python库:rawsocketpy,它允许在第2层上使用原始套接字并实现类似option的服务器。
#!/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()