通过原始套接字进行 TCP 握手,为什么 recvfrom 挂起?
TCP handshake via raw sockets, why recvfrom hangs?
我正在尝试实现握手功能。我正在发送 SYN 数据包,服务器通过 ACK 数据包进行响应。为了获得服务器响应,我使用了挂起的 recvfrom 函数。这是我的代码。
import socket, sys
from struct import *
import codecs
def checksum(msg):
s = 0
for i in range(0, len(msg), 2):
w = ord(msg[i]) + (ord(msg[i+1]) << 8 )
s = s + w
s = (s>>16) + (s & 0xffff);
s = s + (s >> 16);
s = ~s & 0xffff
return s
try:
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
s.bind(("", "63798"))
except socket.error , msg:
print 'Socket could not be created. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
packet = '';
source_ip = '172.16.87.84'
dest_ip = '172.16.10.1'
# ip header fields
ip_ihl = 5
ip_ver = 4
ip_tos = 0
ip_tot_len = 0
ip_id = 54321
ip_frag_off = 0
ip_ttl = 255
ip_proto = socket.IPPROTO_TCP
ip_check = 0
ip_saddr = socket.inet_aton ( source_ip )
ip_daddr = socket.inet_aton ( dest_ip )
ip_ihl_ver = (ip_ver << 4) + ip_ihl
ip_header = pack('!BBHHHBBH4s4s' , ip_ihl_ver, ip_tos, ip_tot_len, ip_id, ip_frag_off, ip_ttl, ip_proto, ip_check, ip_saddr, ip_daddr)
# tcp header fields
tcp_source = 63798 # source port
tcp_dest = 8888 # destination port
tcp_seq = 104
tcp_ack_seq = 0
tcp_doff = 5 #4 bit size of tcp header, 5 * 4 = 20 bytes
#tcp flags
tcp_fin = 0
tcp_syn = 1
tcp_rst = 0
tcp_psh = 0
tcp_ack = 0
tcp_urg = 0
tcp_window = socket.htons (5840)
tcp_check = 0
tcp_urg_ptr = 0
tcp_offset_res = (tcp_doff << 4) + 0
tcp_flags = tcp_fin + (tcp_syn << 1) + (tcp_rst << 2) + (tcp_psh <<3) + (tcp_ack << 4) + (tcp_urg << 5)
tcp_header = pack('!HHLLBBHHH' , tcp_source, tcp_dest, tcp_seq, tcp_ack_seq, tcp_offset_res, tcp_flags, tcp_window, tcp_check, tcp_urg_ptr)
source_address = socket.inet_aton( source_ip )
dest_address = socket.inet_aton(dest_ip)
placeholder = 0
protocol = socket.IPPROTO_TCP
tcp_length = len(tcp_header)
psh = pack('!4s4sBBH' , source_address , dest_address , placeholder , protocol , tcp_length);
psh = psh + tcp_header;
tcp_check = checksum(psh)
tcp_header = pack('!HHLLBBH' , tcp_source, tcp_dest, tcp_seq, tcp_ack_seq, tcp_offset_res, tcp_flags, tcp_window) + pack('H' , tcp_check) + pack('!H' , tcp_urg_ptr)
packet = ip_header + tcp_header
s.sendto(packet, (dest_ip , 8888 ))
s.recvfrom(1024) # Here is recevfrom hangs
程序在 recvfrom() 上挂起。怎么办,这个问题的原因是什么?
实际上服务器发送ACK数据包。在wireshark中可以看到
这是 Wireshark 日志
问题出在这里:s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
,raw(7) man page 说:
A protocol of IPPROTO_RAW implies enabled IP_HDRINCL and is able to
send any IP protocol that is specified in the passed header.
Receiving of all IP protocols via IPPROTO_RAW is not possible using raw
sockets. When a packet is received, it is passed to any raw sockets which have
been bound to its protocol before it is passed to other protocol handlers
(e.g., kernel protocol modules).
An IPPROTO_RAW
socket is send only.
改用 s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
并启用 IP_HDRINCL
套接字选项以使用您自己的 ip header:
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
我正在尝试实现握手功能。我正在发送 SYN 数据包,服务器通过 ACK 数据包进行响应。为了获得服务器响应,我使用了挂起的 recvfrom 函数。这是我的代码。
import socket, sys
from struct import *
import codecs
def checksum(msg):
s = 0
for i in range(0, len(msg), 2):
w = ord(msg[i]) + (ord(msg[i+1]) << 8 )
s = s + w
s = (s>>16) + (s & 0xffff);
s = s + (s >> 16);
s = ~s & 0xffff
return s
try:
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
s.bind(("", "63798"))
except socket.error , msg:
print 'Socket could not be created. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
packet = '';
source_ip = '172.16.87.84'
dest_ip = '172.16.10.1'
# ip header fields
ip_ihl = 5
ip_ver = 4
ip_tos = 0
ip_tot_len = 0
ip_id = 54321
ip_frag_off = 0
ip_ttl = 255
ip_proto = socket.IPPROTO_TCP
ip_check = 0
ip_saddr = socket.inet_aton ( source_ip )
ip_daddr = socket.inet_aton ( dest_ip )
ip_ihl_ver = (ip_ver << 4) + ip_ihl
ip_header = pack('!BBHHHBBH4s4s' , ip_ihl_ver, ip_tos, ip_tot_len, ip_id, ip_frag_off, ip_ttl, ip_proto, ip_check, ip_saddr, ip_daddr)
# tcp header fields
tcp_source = 63798 # source port
tcp_dest = 8888 # destination port
tcp_seq = 104
tcp_ack_seq = 0
tcp_doff = 5 #4 bit size of tcp header, 5 * 4 = 20 bytes
#tcp flags
tcp_fin = 0
tcp_syn = 1
tcp_rst = 0
tcp_psh = 0
tcp_ack = 0
tcp_urg = 0
tcp_window = socket.htons (5840)
tcp_check = 0
tcp_urg_ptr = 0
tcp_offset_res = (tcp_doff << 4) + 0
tcp_flags = tcp_fin + (tcp_syn << 1) + (tcp_rst << 2) + (tcp_psh <<3) + (tcp_ack << 4) + (tcp_urg << 5)
tcp_header = pack('!HHLLBBHHH' , tcp_source, tcp_dest, tcp_seq, tcp_ack_seq, tcp_offset_res, tcp_flags, tcp_window, tcp_check, tcp_urg_ptr)
source_address = socket.inet_aton( source_ip )
dest_address = socket.inet_aton(dest_ip)
placeholder = 0
protocol = socket.IPPROTO_TCP
tcp_length = len(tcp_header)
psh = pack('!4s4sBBH' , source_address , dest_address , placeholder , protocol , tcp_length);
psh = psh + tcp_header;
tcp_check = checksum(psh)
tcp_header = pack('!HHLLBBH' , tcp_source, tcp_dest, tcp_seq, tcp_ack_seq, tcp_offset_res, tcp_flags, tcp_window) + pack('H' , tcp_check) + pack('!H' , tcp_urg_ptr)
packet = ip_header + tcp_header
s.sendto(packet, (dest_ip , 8888 ))
s.recvfrom(1024) # Here is recevfrom hangs
程序在 recvfrom() 上挂起。怎么办,这个问题的原因是什么?
实际上服务器发送ACK数据包。在wireshark中可以看到
这是 Wireshark 日志
问题出在这里:s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
,raw(7) man page 说:
A protocol of IPPROTO_RAW implies enabled IP_HDRINCL and is able to send any IP protocol that is specified in the passed header.
Receiving of all IP protocols via IPPROTO_RAW is not possible using raw sockets. When a packet is received, it is passed to any raw sockets which have been bound to its protocol before it is passed to other protocol handlers (e.g., kernel protocol modules).
AnIPPROTO_RAW
socket is send only.
改用 s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
并启用 IP_HDRINCL
套接字选项以使用您自己的 ip header:
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)