1. Preamble
If I only need to study the behavior of Linux's tcp stack, I can satisfy all my needs by just using packetdrill. packetdrill is the one that lets me tease the tcp stack to my heart's content.Simple manual for packetdrill。
The tragedy, however, is that in addition to studying the behavior of the TCP stack for Linux, you also need to study the behavior of the tcp stack for Windows, which is not open source and feels like it should have quite a few unknown potholes in it.
In order to be able to reproduce some of the network behavior of the Windows tcp stack, here the use of python's scapy packet construction to tease the Windows tcp stack. scapy in the tcp data message injection will have a little bit of delay, this tool in the requirements of the strict latency of the scenario can not be used (or packetdrill is good to use, awkward). For the current scenarios encountered, can barely be used, and then have been accustomed to jacking python, it is relatively easy to get started.
2. Basic grammar
- Installing scapy
Use yum install to install it directly on Centos 7.2.
yum install
- help solves most of the problems.
[root@localhost ~]# scapy INFO: Can't import python gnuplot wrapper . Won't be able to plot. INFO: Can't import PyX. Won't be able to use psdump() or pdfdump(). WARNING: No route found for IPv6 destination :: (no default route?) Welcome to Scapy (2.2.0) >>> help(send)
Most of the time, if you see something you don't understand, please use help. followed by the official reference manuals
- basic grammar
ip/tcp/http packet manipulation
>>> IP() <IP |> >>>> IP()/TCP() <IP frag=0 proto=tcp |<TCP |>> >>>> IP(proto=55)/TCP() <IP frag=0 proto=55 |<TCP >> >>>> Ether()/IP()/TCP() <Ether type=IPv4 |<IP frag=0 proto=tcp |<TCP |>>> >>>> IP()/TCP()/"GET /HTTP/1.0\r\n\r\n" The data part can be used directly as a string <IP frag=0 proto=tcp |<TCP |<Raw load='GET /HTTP/1.0\r\n\r\n' |>>> >>>> Ether()/IP()/UDP() <Ether type=IPv4 |<IP frag=0 proto=udp |<UDP |>>> >>>> Ether()/IP()/IP()/UDP() <Ether type=IPv4 |<IP frag=0 proto=ipencap |<IP frag=0 proto=udp |<UDP |>>>> >>> str(IP()) 'E\x00\x00\x14\x00\x01\x00\x00@\x00|\xe7\x7f\x00\x00\x01\x7f\x00\x00\x01' >>> IP(_) <IP version=4L ihl=5L tos=0x0 len=20 id=1 flags= frag=0L ttl=64 proto=hopopt chksum=0x7ce7 src=127.0.0.1 dst=127.0.0.1 |> >>> a=Ether()/IP(dst="")/TCP()/"GET / HTTP/1.0 \n\n" >>> hexdump(a) 0000 00 03 0F 19 6A 49 08 00 27 FE D8 12 08 00 45 00 ....jI..'.....E. 0010 00 43 00 01 00 00 40 06 70 78 C0 A8 73 C6 B4 61 .C....@.px..s..a 0020 21 6C 00 14 00 50 00 00 00 00 00 00 00 00 50 02 !l...P........P. 0030 20 00 B3 75 00 00 47 45 54 20 2F 69 6E 64 65 78 ..u..GET /index 0040 2E 68 74 6D 6C 20 48 54 54 50 2F 31 2E 30 20 0A .html HTTP/1.0 . 0050 0A . >>> b=str(a) >>> b "\x00\x03\x0f\x19jI\x08\x00'\xfe\xd8\x12\x08\x00E\x00\x00C\x00\x01\x00\x00@\x06px \xc0\xa8s\xc6\xb4a!l\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\xb3u \x00\x00GET / HTTP/1.0 \n\n"
1. Packet sending
The sending of packets mainly consists of the following functions send/sendp/sr/sr1/srp The main differences are:
The send function works at the third level
send(IP(dst="192.168.115.188")/ICMP())
The sendp function works at layer 2, where you can select the NIC and protocol
sendp(Ether()/IP(dst="192.168.115.188",ttl=(1,4)),iface="eth0")
The role of the fuzz function: you can change some of the default value can not be calculated (such as checksums and checksums), change the value is random, but the type is consistent with the value of the field.
send(IP(dst="")/UDP()/NTP(version=4),loop=2) # fuzz() not used send(IP(dst=" ")/fuzz(UDP()/NTP(version=4)),loop=2) #utilizationfuzz()
The SR() function is used to send packets and receive responses. This function returns the packets with and without responses; this function is also considered the core of scapy, and it returns two lists of data, an answer list and an unanswered list.
>>> sr(IP(dst="192.168.115.1")/TCP(dport=[21,22,23])) Begin emission: Finished to send 3 packets. *** Received 3 packets, got 3 answers, remaining 0 packets Results: TCP:3 UDP:0 ICMP:0 Other:0>, Unanswered: TCP:0 UDP:0 ICMP:0 Other:0 >>> ans,unans=_ It's alsoscapyIt's at the heart of the >>> () 0000 IP / TCP 192.168.115.198:ftp_data > 192.168.115.1:ftp S ==> IP / TCP 192.168.115.1:ftp > 192.168.115.198:ftp_data RA / Padding 0001 IP / TCP 192.168.115.198:ftp_data > 192.168.115.1:ssh S ==> IP / TCP 192.168.115.1:ssh > 192.168.115.198:ftp_data RA / Padding 0002 IP / TCP 192.168.115.198:ftp_data > 192.168.115.1:telnet S ==> IP / TCP 192.168.115.1:telnet > 192.168.115.198:ftp_data SA / Padding >>>sr(IP(dst="192.168.115.1")/TCP(dport=[21,22,23]),inter=0.5,retry=-2,timeout=1) When the network environment is bad,You can also addinter retry timeoutand other additional information,
The function sr1() is a variant of sr() that returns only the packet (or set of packets) sent in response. The packets sent by these two functions must be Layer 3 packets (IP, ARP, etc.). The function SRP(), on the other hand, is located at layer 2 (Ethernet, 802.3, etc.).
>>> p=sr1(IP(dst="192.168.115.188")/ICMP()/"test") Begin emission: .....Finished to send 1 packets. .* Received 7 packets, got 1 answers, remaining 0 packets >>> p <IP version=4L ihl=5L tos=0x0 len=32 id=26000 flags= frag=0L ttl=128 proto=icmp chksum=0x6c79 src=192.168.115.188 dst=192.168.115.198 options=[] |<ICMP type=echo-reply code=0 chksum=0x1826 id=0x0 seq=0x0 |<Raw load='test' |<Padding load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |>>>> >>> () ###[ IP ]### version= 4L ihl= 5L tos= 0x0 len= 32 id= 26000 flags= frag= 0L ttl= 128 proto= icmp chksum= 0x6c79 src= 192.168.115.188 dst= 192.168.115.198 \options\ ###[ ICMP ]### type= echo-reply code= 0 chksum= 0x1826 id= 0x0 seq= 0x0 ###[ Raw ]### load= 'test' ###[ Padding ]### load= '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1. Packet sniff
a=sniff(count=1,filter="tcp and host 192.168.1.1 and port 80")
The use of sniff is mainly used for packet reception, according to the conditions set by the filter, the packet that meets the conditions will be received back.
3. Scene construction
The disadvantage of scapy is that he is only responsible for constructing packets, which is one-way. Unlike packetdrill which is so perfect, packetdrill not only constructs packets, but also implements system calls to construct different scenarios, and also helps you check whether the packets sent out by the stack meet expectations. The process of ruffling the tcp stack is not limited to two ends, one end of the system call to simulate the behavior of the stack, and the other end is the packet we construct. Common scenarios are mainly: server scenarios, client scenarios.
- Server Scene:
The server scenario uses system calls (i.e., userland programs), while the client is a package constructed by scapy.
Construct a simple three times handshake here after sending data to the server side. To prevent Linux client rst.
iptables -A OUTPUT -p tcp --tcp-flags RST RST -s 192.168.56.1 -j DROP
#!/usr/local/bin/python from import * # VARIABLES src = [1] dst = [2] sport = (1024,65535) dport = int([3]) # SYN ip=IP(src=src,dst=dst) SYN=TCP(sport=sport,dport=dport,flags='S',seq=1000) SYNACK=sr1(ip/SYN) # ACK ACK=TCP(sport=sport, dport=dport, flags='A', seq=, ack= + 1) send(ip/ACK)
Here you can install a nginx to verify.
- Client Scenario:
The client-side scenario uses system calls (i.e., user-state programs), while the server-side is a scapy constructor package.
A simple http server is constructed here using scapy. To prevent the stack from sending RSTs, iptables needs to be set up.
iptables -A OUTPUT -p tcp --tcp-flags RST RST --sport 80 -j DROP
#!/usr/bin/python from import * # Interacts with a client by going through the three-way handshake. # Shuts down the connection immediately after the connection has been established. # Akaljed Dec 2010, # Wait for client to connect. a=sniff(count=1,filter="tcp and host 192.168.1.1 and port 80") # some variables for later use. ValueOfPort=a[0].sport SeqNr=a[0].seq AckNr=a[0].seq+1 # Generating the IP layer: ip=IP(src="192.168.1.1", dst="192.168.1.2") # Generating TCP layer: TCP_SYNACK=TCP(sport=80, dport=ValueOfPort, flags="SA", seq=SeqNr, ack=AckNr, options=[('MSS', 1460)]) #send SYNACK to remote host AND receive ACK. ANSWER=sr1(ip/TCP_SYNACK) # Capture next TCP packets with dport 80. (contains http GET request) GEThttp = sniff(filter="tcp and port 80",count=1,prn=lambda x:("{IP:%%: %%}")) AckNr=AckNr+len(GEThttp[0].load) SeqNr=a[0].seq+1 # Print the GET request # (Sanity check: size of data should be greater than 1.) if len(GEThttp[0].load)>1: print GEThttp[0].load # Generate custom http file content. html1="HTTP/1.1 200 OK\x0d\x0aDate: Wed, 29 Sep 2010 20:19:05 GMT\x0d\x0aServer: Testserver\x0d\x0aConnection: Keep-Alive\x0d\x0aContent-Type: text/html; charset=UTF-8\x0d\x0aContent-Length: 291\x0d\x0a\x0d\x0a<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\"><html><head><title>Testserver</title></head><body bgcolor=\"black\" text=\"white\" link=\"blue\" vlink=\"purple\" alink=\"red\"><p><font face=\"Courier\" color=\"blue\">-Welcome to test server-------------------------------</font></p></body></html>" # Generate TCP data data1=TCP(sport=80, dport=ValueOfPort, flags="PA", seq=SeqNr, ack=AckNr, options=[('MSS', 1460)]) # Construct whole network packet, send it and fetch the returning ack. ackdata1=sr1(ip/data1/html1) # Store new sequence number. SeqNr= # Generate RST-ACK packet Bye=TCP(sport=80, dport=ValueOfPort, flags="FA", seq=SeqNr, ack=AckNr, options=[('MSS', 1460)]) send(ip/Bye) # The End
This server only needs to use wget or curl for authentication.
4. References
/projects/scapy/doc/#starting-scapy
/2010/12/12/scapy-as-webserver/
/2012/12/
summarize
Above is the entire content of this article, I hope the content of this article for your study or work has a certain reference learning value, thank you for your support. If you want to know more about the content please check the following related links