Start to learn about server status changes of TCP series (1)
The previous article introduced the TCP state machine and learned about the normal state change process of the TCP client through experiments.
So, this article will take a look at the normal state change process of the TCP server.
Server status changes
According to the TCP status change diagram in the previous article, the normal server status change process is as follows:
CLOSED-> LISTEN-> SYN_RECV-> ESTABLISHED-> CLOSE_WAIT-> LAST_ACK-> CLOSED
Server Status Change Experiment
The following uses the server status change table analyzed above to simulate normal server status changes using Pcap. Net.
Code Implementation
This is exactly the opposite of the previous ones. This time, we will run the Pcap. Net implementation server on the host machine and then run a client on the virtual machine.
For the server, the connection information of the source and target is set in the main program. This time, the server in the host will listen on port 3333.
Then, the Program sets the initial TCP status of the server to "LISTENING", and then runs the listener function directly.
// Open the output deviceusing (PacketCommunicator communicator = selectedDevice. open (System. int32.MaxValue, // name of the devicePacketDeviceOpenAttributes. promiscuous, // promiscuous mode1) // read timeout {EndPointInfo endPointInfo = new EndPointInfo ();
EndPointInfo. SourceMac = "08: 00: 27: 00: C0: D5 ";
EndPointInfo. DestinationMac = "";
EndPointInfo. SourceIp = "192.168.56.101 ";
EndPointInfo. DestinationIp = "";
EndPointInfo. SourcePort = 3333;
EndPointInfo. DestinationPort = 0;
Using (BerkeleyPacketFilter filter = communicator. CreateFilter ("tcp port" + endPointInfo. SourcePort ))
{
// Set the filter
Communicator. SetFilter (filter );
}
TcpStatus = TCPStatus. LISTENING;
PacketHandler (communicator, endPointInf)
}
The logic in this listener function "PacketHandler" is quite different from the previous client example.
First, there is a big difference between the TCP packet types that are expected to receive and actually sent, and second, the changes between statuses are completely different. However, the logic of the code is still based on the above server status change table.
private static void PacketHandler(PacketCommunicator communicator, EndPointInfo endPointInfo){Packet packet = null;bool running = true;do{PacketCommunicatorReceiveResult result = communicator.ReceivePacket(out packet);switch (result){case PacketCommunicatorReceiveResult.Timeout:// Timeout elapsedcontinue;case PacketCommunicatorReceiveResult.Ok:bool isRecvedPacket = (packet.Ethernet.IpV4.Destination.ToString() == endPointInfo.SourceIp) ? true : false;if (isRecvedPacket){switch (packet.Ethernet.IpV4.Tcp.ControlBits){case TcpControlBits.Synchronize:if (tcpStatus == TCPStatus.LISTENING){endPointInfo.DestinationMac = packet.Ethernet.Source.ToString();endPointInfo.DestinationIp = packet.Ethernet.IpV4.Source.ToString();endPointInfo.DestinationPort = packet.Ethernet.IpV4.Tcp.SourcePort;Utils.PacketInfoPrinter(packet);Packet synAck = Utils.BuildTcpResponsePacket(packet, TcpControlBits.Synchronize | TcpControlBits.Acknowledgment);communicator.SendPacket(synAck);tcpStatus = TCPStatus.SYN_RECEIVED;}break;case TcpControlBits.Acknowledgment:if (tcpStatus == TCPStatus.SYN_RECEIVED){tcpStatus = TCPStatus.ESTABLISHED;Utils.PacketInfoPrinter(packet, tcpStatus);}else if (tcpStatus == TCPStatus.LAST_ACK){tcpStatus = TCPStatus.CLOSED;Utils.PacketInfoPrinter(packet, tcpStatus);tcpStatus = TCPStatus.LISTENING;}else if (tcpStatus == TCPStatus.FIN_WAIT_1){tcpStatus = TCPStatus.FIN_WAIT_2;Utils.PacketInfoPrinter(packet);}break;case (TcpControlBits.Fin | TcpControlBits.Acknowledgment):if (tcpStatus == TCPStatus.FIN_WAIT_2){Utils.PacketInfoPrinter(packet);Packet ack = Utils.BuildTcpResponsePacket(packet, TcpControlBits.Acknowledgment);communicator.SendPacket(ack);tcpStatus = TCPStatus.TIME_WAIT;}else if (tcpStatus == TCPStatus.ESTABLISHED){Utils.PacketInfoPrinter(packet);Packet ack = Utils.BuildTcpResponsePacket(packet, TcpControlBits.Acknowledgment);communicator.SendPacket(ack);tcpStatus = TCPStatus.CLOSE_WAIT;}break;default:Utils.PacketInfoPrinter(packet);break;}}else{switch (packet.Ethernet.IpV4.Tcp.ControlBits){case (TcpControlBits.Synchronize | TcpControlBits.Acknowledgment):if (tcpStatus == TCPStatus.SYN_RECEIVED){Utils.PacketInfoPrinter(packet, tcpStatus);}