Construct IP and ICMP headers for Python socket programming, pythonicmp
In the past two days, an experiment requires you to construct your own IP Address Header. If you encounter many problems, you have finally completed the experiment in one day.
There are a lot of questions about socket on the Internet. I only record the problems I encountered when constructing an IP header. Because I have never played the socket to construct the IP Address Header, I found some code on the Internet, but the Code does not work. Due to various problems, it is fruitless to collect information on the Internet, I finally solved the problem by adding my own brain holes.
I want to construct an ICMP return request with a custom IP Address Header. I found a code segment on the Internet and changed it. It looks like this:
1 import socket 2 import struct 3 def checksum(source_string): 4 sum = 0 5 countTo = (len(source_string)/2)*2 6 count = 0 7 while count<countTo: 8 thisVal = ord(source_string[count + 1])*256 + ord(source_string[count]) 9 sum = sum + thisVal10 sum = sum & 0xffffffff 11 count = count + 212 if countTo<len(source_string):13 sum = sum + ord(source_string[len(source_string) - 1])14 sum = sum & 0xffffffff 15 sum = (sum >> 16) + (sum & 0xffff)16 sum = sum + (sum >> 16)17 answer = ~sum18 answer = answer & 0xffff19 answer = answer >> 8 | (answer << 8 & 0xff00)20 return answer21 def ping(ip):22 s=socket.socket(socket.AF_INET,socket.SOCK_RAW,255)24 s.setsockopt(0, socket.IP_HDRINCL, 1)25 # now start constructing the packet26 27 source_ip = '172.16.12.1'28 dest_ip = ip29 30 # ip header fields31 ihl = 532 version = 433 tos = 034 tot_len = 2835 id = 036 frag_off = 037 ttl = 25538 protocol = 139 check = 0 40 saddr =socket.inet_aton ( source_ip ) #Spoof the source ip address if you want to41 daddr = socket.inet_aton ( dest_ip )44 ihl_version = (version << 4) + ihl45 # the ! in the pack format string means network order46 ip_header = struct.pack('!BBHHHBBH4s4s', ihl_version, tos, tot_len, id, frag_off, ttl, protocol, check, saddr, daddr)47 packet = struct.pack(48 "!BBHHH", 8, 0, 0, 0, 049 )50 chksum=checksum(packet)51 packet = struct.pack(52 "!BBHHH", 8, 0, chksum, 0, 053 )54 packet=ip_header+packet55 s.sendto(packet,(ip,1))56 print "done"57 58 if __name__=='__main__':59 ping('172.31.0.1')
The procedure is very simple, that is, you can create a socket and then construct the header and then send it again. However, generally, the socket cannot change the IP header by yourself. It can only be constructed from the data part of the IP datagram, the original socket is required to construct the IP header. The original socket can be constructed from the IP header. However, if the original socket requires the root permission, I will use the IDE in OS X, the program always reports an error socket. error: [Errno 1] Operation not permitted. It is because of permission issues that sudo does have no permission to run on the terminal (Ps: If you want to open IDE with root permission, if you do not want to switch your account, sudo is in the terminal. /IDE on the line) Now you have the permission and start to report other errors, prompting socket. error: [Errno 22] Invalid argument.
This is the code for creating the original socket. The third value in the first line is the value of IPPROTO_RAW. To construct an IP header, add the second line of code to set IP_HDRINCL, the first value 0 is the value of IPPROTO_IP.
s=socket.socket(socket.AF_INET,socket.SOCK_RAW,255)
s.setsockopt(0, socket.IP_HDRINCL, 1)
If this parameter is set to OS X, the Invalid argument error will be reported at the location where sendto () is called. Later, the error is found in the third parameter 255 in the first line. After testing, it is found that
In OS X, if this parameter is set to 0 or 255, an error is returned.
In WINDOWS, no error is reported if this parameter is set to 0 or 255.
In LINUX, if this parameter is set to 0, an error is returned. If this parameter is set to 255, no error is returned.
Now we can construct an ICMP return request for any source IP address and destination IP address. The ID, length, and checksum of the IP header field can be set to 0, and the kernel protocol stack can be corrected.
When packet capture on linux finds that the destination IP address is a Host IP address that does not exist in the same subnet, the ICMP packet cannot be captured because the host sends an ARP packet request to the MAC address of the destination IP address and does not receive a response, the Request timeout for icmp_seq prompted by the PING command is generated because the ARP Request is not answered.