Search code examples
pythontcphandshakeraw-socketsrecvfrom

TCP handshake via raw sockets, why recvfrom hangs?


I am trying to implement handshaking functionality. I am sending SYN packet and server responds via ACK packet. For getting server response i have used recvfrom function which is hang. Here is my code.

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

The programm hangs on recvfrom(). What to do, What is the reason of this issue ? Actually the server send ACK packet. It can be seen in wireshark Here is Wireshark log enter image description here


Solution

  • The problem lays here: s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW), the raw(7) man page says:

    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.

    use s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP) instead and enable IP_HDRINCL socket option to use your own ip header: s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)