【问题标题】:TCP handshake via raw sockets, why recvfrom hangs?通过原始套接字进行 TCP 握手,为什么 recvfrom 挂起?
【发布时间】:2017-09-08 20:46:00
【问题描述】:

我正在尝试实现握手功能。我正在发送 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 日志

【问题讨论】:

    标签: python tcp handshake raw-sockets recvfrom


    【解决方案1】:

    问题出在这里:s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)raw(7) man page 说:

    IPPROTO_RAW 协议意味着启用 IP_HDRINCL 并且能够 发送在传递的标头中指定的任何 IP 协议。
    使用 raw 无法通过 IPPROTO_RAW 接收所有 IP 协议 插座。当接收到一个数据包时,它会被传递到任何具有 在传递给其他协议处理程序之前已绑定到其协议 (例如,内核协议模块)。
    IPPROTO_RAW 套接字仅用于发送。

    改用s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP) 并启用IP_HDRINCL 套接字选项以使用您自己的IP 标头: s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-22
      • 1970-01-01
      • 2017-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多