在Day13和Day14介紹了TCP的封包結構,TCP是連接導向的協議,所以在建立連線前需要和對方確認和對方的通信收發是正常的,在斷開連接也需要和對方確認沒有額外需要傳輸的封包才會斷開連線
作為發送raw封包的第一個實作,當然從最難的TCP開始囉!會了TCP的發送,同時也會了底下第二層和第三層header的封裝,所以拆分很多天,盡量講的鉅細靡遺
在發送tcp的封包前,先看一下第二層、第三層和tcp的header怎麼封裝,分別為_buildEthHeader()
和_buildIPHeader()
def _buildEthHeader(self):
dMAC = '02:42:ac:11:00:05' # 要根據目的地的Mac address設定
dMAC = binascii.unhexlify(str.encode(''.join((dMAC.split(':')))))
eth_header = struct.pack('!6s6sH' , dMAC, self.mac, socket.htons(8))
return eth_header
def _buildIPHeader(self):
pktID = 123 # 隨便設定packet id
IHL_VERSION, TYPE_OF_SERVICE, total_len, FRAGMENT_STATUS, TIME_TO_LIVE, PROTOCOL, check_sum_of_hdr, src_IP,dest_IP = \
69, 0, 40, 16384, 64, 6, 0, socket.inet_aton(socket.gethostbyname(socket.gethostname())), socket.inet_aton(self.dip)
ip_header = struct.pack('!BBHHHBBH4s4s', IHL_VERSION, TYPE_OF_SERVICE, total_len, pktID, FRAGMENT_STATUS, TIME_TO_LIVE, PROTOCOL, check_sum_of_hdr, src_IP,dest_IP)
check_sum_of_hdr = getIPChecksum(ip_header)
ip_header = struct.pack('!BBHHHBBH4s4s', IHL_VERSION, TYPE_OF_SERVICE, total_len, pktID, FRAGMENT_STATUS, TIME_TO_LIVE, PROTOCOL, check_sum_of_hdr, src_IP,dest_IP)
return ip_header
def _buildTCPHeader(self, tcp_len, seq, ack_num, flags, window): # 其中,seq, ack_num,
flags這三個參數最重要
self.seq = seq
self.ack_num = ack_num
src_IP = socket.inet_aton(self.sip)
dest_IP = socket.inet_aton(self.dip)
src_port, dest_port, offset, checksum, urgent_ptr = \
self.sport, self.dport, tcp_len << 4, 0, 0
tcp_header = struct.pack('!HHIIBBHHH' , src_port, dest_port, self.seq, self.ack_num, offset, flags, window, checksum, urgent_ptr)
pseudo_hdr = struct.pack('!4s4sBBH', src_IP, dest_IP,0 , socket.IPPROTO_TCP, len(tcp_header))
checksum = getTCPChecksum(pseudo_hdr + tcp_header)
tcp_header = tcp_header[:16] + struct.pack('H', checksum) + tcp_header[18:]
return tcp_header
有了這兩個函數,那麼建構tcp的封包如下
packet = _buildEthHeader() + _buildIPHeader() + _buildTCPHeader() + data
sock.send(packet)
接下來講如何利用這三個函數建立三方交握的可靠連接
完整的tcp三方交握和四向揮手程式碼可以看這裡
https://gist.github.com/kaichiachen/283f1b57e517f9ed558de6c2d15daf62