2015-11-18 33 views
3

我正在嘗試使用原始套接字向服務器發送GET請求。我使用原始套接字,因此我可以編輯數據包窗口大小。這是我的代碼。爲什麼我的TCP數據包不像協議分析器的TCP數據包?

import socket, sys 
from struct import * 

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 

#create a raw socket 
try: 
    s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) 
except socket.error , msg: 
    print 'Socket could not be created. Error Code : ' + str(msg[0]) + ' Message ' + msg[1] 
    sys.exit() 

# tell kernel not to put in headers, since we are providing it, when using IPPROTO_RAW this is not necessary 
# s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) 


packet = ''; 

source_ip = '192.168.2.7' 
dest_ip = '216.86.145.50' # or socket.gethostbyname('www.google.com') 

# ip header fields 
ip_ihl = 5 
ip_ver = 4 
ip_tos = 0 
ip_tot_len = 0 # kernel will fill the correct total length 
ip_id = 54321 #Id of this packet 
ip_frag_off = 0 
ip_ttl = 255 
ip_proto = socket.IPPROTO_TCP 
ip_check = 0 # kernel will fill the correct checksum 
ip_saddr = socket.inet_aton (source_ip) #Spoof the source ip address if you want to 
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 = 1234 # source port 
tcp_dest = 80 # destination port 
tcp_seq = 454 
tcp_ack_seq = 0 
tcp_doff = 5  
#tcp flags 
tcp_fin = 0 
tcp_syn = 1 
tcp_rst = 0 
tcp_psh = 0 
tcp_ack = 0 
tcp_urg = 0 
tcp_window = socket.htons (2048) 
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) 

user_data = "GET/HTTP/1.1\r\nHost:www.example.com\n\nUser-Agent:Mozilla 5.0\r\n\r\n" 


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) + len(user_data) 

psh = pack('!4s4sBBH' , source_address , dest_address , placeholder , protocol , tcp_length); 
psh = psh + tcp_header + user_data; 

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 + user_data 


s.sendto(packet, (dest_ip , 0)) 

我正在使用Wireshark查看要發送的數據包。問題是輸出不是TCP GET請求數據包。在線鯊魚的輸出是白色的,在協議下它說IPv4和信息說:144未知(255)。我該如何解決?

+0

你是否記錄過'packet'的字節_before_你sendto'套接字?一個明顯的開始將是驗證您的代碼生成的TCP和IP字段具有您想要的值。 –

+0

代碼建議1/2:將代碼分解成單獨的功能!這將隔離任何錯誤,並且會讓讀者關注幾個重要的變量。像'tcp_flags = _create_tcp_flags()'這樣的東西會隱藏6個無用的變量,同時揭示所有的位錯只是計算一個常量值。 –

+0

代碼建議2/2:不要重複使用變量,特別是在長功能中。例如,'tcp_header'意味着兩種不同的東西之一,具體取決於你何時查看它,所以它應該是兩個名字。另外,可能很難說出一個錯誤的重新分配......「second-tcp_header」不僅僅是不同的數據---它建立在不同的_way_中。故意的? (這引出了我之前關於函數的評論,可以給出意圖揭示的名字...) –

回答

2

像@Sivir說你需要建立一個三方握手,因爲你想使用TCP協議。理論上,握手應該是這樣的

  • YourProgram:發送一個SYN包
  • 服務器:發送SYNACK包
  • YourProgram:發送ACK包

更多有關這方面的信息可以發現here

1

這是因爲你發送一個單一的數據包,但在TCP中你必須先建立連接(3 ways handshake),然後發送請求,然後關閉連接。

儘管可以使用原始套接字來實現它,但在連接期間需要控制一些參數。如果你說出爲什麼你需要控制窗口大小,可能有辦法在沒有TCP協議實現的情況下執行。

+0

我是否正確在與普通套接字說你會使用connect()函數來處理3方式握手。但我認爲事情與原始套接字更復雜?我會怎麼做? –