我有这个简单的客户端代码,它将消息发送到服务器,然后回应服务器响应。
import socket, sys, time
HOST = 'localhost'
PORT = 11000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
msg = raw_input()
s.send(msg)
data = s.recv(len(msg))
s.close()
print 'Received: ', data
我希望在这里使用原始套接字,以便能够从服务器的响应数据包中获取IP_ID字段,但我不知道如何。
无论我在网上看到多少,我都没有找到一个如何做的好例子。
(只是为了澄清,我真的不需要向服务器发送原始数据包,我可以使用正常的SOCK_STREAM来发送消息,但我需要使用原始套接字来获取响应'IP_ID。)< / p>
任何人都可以编辑我的代码并以最简单的方式向我展示如何操作吗? 我设法找到的是我需要用socket.SOCK_RAW替换socket.SOCK_STREAM,但我还是很远。
非常感谢
答案 0 :(得分:3)
从原始套接字读取并解析出IP_ID是微不足道的:
response, addr = s.recvfrom(65535)
response_id = struct.unpack('!H', response[4:6])
print response_id
困难的部分是让某人首先向您发送数据包。我很确定你不能同时在原始模式和流模式下使用相同的套接字,所以你需要用一堆很多替换connect
和send
构造和发送适当的TCP数据包以启动连接的更复杂的代码。像scapy
这样的库会为你做所有困难的事情,但如果你想手动完成,你只需要仔细阅读RFC 791和RFC 793,做一切繁琐的工作东西(确保你得到所有的endianness),你就在路上。
在* BSD(包括OS X)上,内核将填写IP长度,TCP长度,最重要的是TCP校验和。如果你必须自己处理这些问题会更加痛苦。 (如果这在你的平台上不起作用,你可能会这样做,或者我搞砸了OS X自动为我修复的其他东西,而你的平台却没有。)
import socket
import struct
def make_ip(proto, srcip, dstip, ident=54321):
saddr = socket.inet_aton(srcip)
daddr = socket.inet_aton(dstip)
ihl_ver = (4 << 4) | 5
return struct.pack('!BBHHHBBH4s4s' ,
ihl_ver, 0, 0, ident, 0, 255, proto, 0, saddr, daddr)
def make_tcp(srcport, dstport, payload, seq=123, ackseq=0,
fin=False, syn=True, rst=False, psh=False, ack=False, urg=False,
window=5840):
offset_res = (5 << 4) | 0
flags = (fin | (syn << 1) | (rst << 2) |
(psh <<3) | (ack << 4) | (urg << 5))
return struct.pack('!HHLLBBHHH',
srcport, dstport, seq, ackseq, offset_res,
flags, window, 0, 0)
srcip = dstip = '127.0.0.1'
srcport, dstport = 11001, 11000
payload = '[TESTING]\n'
ip = make_ip(socket.IPPROTO_TCP, srcip, dstip)
tcp = make_tcp(srcport, dstport, payload)
packet = ip + tcp + payload
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
s.sendto(packet, (dstip, 0))
response, addr = s.recvfrom(65535)
response_id = struct.unpack('!H', response[4:6])
print response_id
每次我运行这个时,我会得到一个nak(如果没有人正在侦听端口11000)或带有随机IP_ID
的ack数据包,就像你期望的那样。