/// <summary> /// Connection to IP /// </summary> /// <param name="ip">IP</param> /// <param name="port">Port</param> /// <returns></returns> public static unsafe TCPConnection Connect(byte[] ip, ushort port) { ushort inPort = RequestPort(); int startSeq = Random.Rand(); if (!ARP.IpExists(ip)) { byte[] mac = new byte[6]; for (int i = 0; i < 6; i++) { mac[i] = 0xFF; } ARP.ArpSend(ARP.OP_REQUEST, mac, ip); Heap.Free(mac); } while (!ARP.IpExists(ip)) { Tasking.Yield(); } TCPConnection con = new TCPConnection(); con.DestPort = port; con.InPort = inPort; con.State = TCPConnectionState.CLOSED; con.XID = Random.Rand(); con.SequenceNumber = (uint)startSeq; con.NextSequenceNumber = Byte.ReverseBytes(Byte.ReverseBytes(con.SequenceNumber) + 1); con.Type = TCPConnectionType.CONNECTION; con.ReceiveQueue = new Queue(); for (int i = 0; i < 4; i++) { con.IP[i] = ip[i]; } m_connections[inPort] = con; handleConnection(con, null, null, 0); return(con); }
/// <summary> /// Established handler /// </summary> /// <param name="connection"></param> /// <param name="sourceIP"></param> /// <param name="buffer"></param> /// <param name="size"></param> private static unsafe void LastAckHandler(TCPConnection connection, byte[] sourceIP, byte *buffer, uint size) { TCPHeader *header = (TCPHeader *)buffer; /** * * Possible flags: * - PUSH * - FIN */ if ((header->Flags & FLAG_ACK) > 0) { connection.State = TCPConnectionState.TIME_WAIT; } else { } }
/// <summary> /// Bind to IP /// </summary> /// <param name="port"></param> /// <returns></returns> public static unsafe TCPConnection Bind(ushort port) { if (m_connections[port] != null) { return(null); } TCPConnection ptr = new TCPConnection(); ptr.InPort = port; ptr.State = TCPConnectionState.LISTEN; ptr.Clients = new Dictionary(); ptr.Type = TCPConnectionType.CONNECTION; ptr.ReceiveQueue = new Queue(); m_connections[port] = ptr; return(ptr); }
/// <summary> /// CLOSING handler /// </summary> /// <param name="con"></param> /// <param name="buffer"></param> private unsafe static void closingHandler(TCPConnection con, byte *buffer) { TCPHeader *header = (TCPHeader *)buffer; if ((header->Flags & (FLAG_ACK)) > 0) { con.SequenceNumber = Byte.ReverseBytes(Byte.ReverseBytes(con.SequenceNumber) + 1); con.AcknowledgeNumber = Byte.ReverseBytes(Byte.ReverseBytes(header->Sequence) + 1); // AND We're DONE! setConnectionForWait(con); } else { // Error handling? } }
/// <summary> /// FIN wait2 handler /// </summary> /// <param name="con"></param> /// <param name="buffer"></param> private unsafe static void finWaitTwoHandler(TCPConnection con, byte *buffer) { TCPHeader *header = (TCPHeader *)buffer; if ((header->Flags & (FLAG_FIN)) > 0) { con.SequenceNumber = Byte.ReverseBytes(Byte.ReverseBytes(con.SequenceNumber) + 1); con.AcknowledgeNumber = Byte.ReverseBytes(Byte.ReverseBytes(header->Sequence) + 1); SendPacket(con.IP, con.SequenceNumber, con.AcknowledgeNumber, con.InPort, con.DestPort, FLAG_ACK, null, 0); setConnectionForWait(con); } else { } }
/// <summary> /// Syn sent handler /// </summary> /// <param name="con"></param> /// <param name="buffer"></param> private unsafe static void SynSentHandler(TCPConnection con, byte *buffer) { TCPHeader *header = (TCPHeader *)buffer; if ((header->Flags & (FLAG_SYN | FLAG_ACK)) == (FLAG_SYN | FLAG_ACK)) { con.SequenceNumber = Byte.ReverseBytes(Byte.ReverseBytes(con.SequenceNumber) + 1); con.State = TCPConnectionState.ESTABLISHED; con.AcknowledgeNumber = Byte.ReverseBytes(Byte.ReverseBytes(header->Sequence) + 1); SendPacket(con.IP, con.SequenceNumber, Byte.ReverseBytes(Byte.ReverseBytes(header->Sequence) + 1), con.InPort, con.DestPort, FLAG_ACK, null, 0); } else { // Failed? } }
/// <summary> /// Syn received /// </summary> /// <param name="con"></param> /// <param name="buffer"></param> private unsafe static void SynReceivedHandler(TCPConnection con, byte *buffer) { TCPHeader *header = (TCPHeader *)buffer; /** * ACK received? */ if ((header->Flags & (FLAG_ACK)) > 0) { con.SequenceNumber = Byte.ReverseBytes(Byte.ReverseBytes(con.SequenceNumber) + 1); con.State = TCPConnectionState.ESTABLISHED; /** * Do we need to notify we have a new connection? */ if (con.Type == TCPConnectionType.CHILD_CONNECTION) { /** * Put ACCEPT in queue */ TCPPacketDescriptor *buf = (TCPPacketDescriptor *)Heap.Alloc(sizeof(TCPPacketDescriptor)); buf->Size = 4; buf->Type = TCPPacketDescriptorTypes.ACCEPT; buf->Data = (byte *)Heap.Alloc(4); buf->xid = con.XID; for (int i = 0; i < 4; i++) { buf->Data[i] = con.IP[i]; } con.BaseConnection.ReceiveQueue.Push(buf); } } else { // Failed? } }
/// <summary> /// Close (reset) connection /// </summary> /// <param name="connection"></param> public static unsafe void Close(TCPConnection connection) { connection.State = TCPConnectionState.FIN_WAIT1; SendPacket(connection.IP, connection.SequenceNumber, connection.AcknowledgeNumber, connection.InPort, connection.DestPort, FLAG_FIN | FLAG_ACK, null, 0); }
/// <summary> /// Send packet on connection /// </summary> /// <param name="connection"></param> /// <param name="buffer"></param> /// <param name="size"></param> public static unsafe void Send(TCPConnection connection, byte *buffer, uint size) { SendPacket(connection.IP, connection.SequenceNumber, connection.AcknowledgeNumber, connection.InPort, connection.DestPort, FLAG_PSH | FLAG_ACK, buffer, (int)size); connection.SequenceNumber = Byte.ReverseBytes(Byte.ReverseBytes(connection.SequenceNumber) + size); }
/// <summary> /// Established handler /// </summary> /// <param name="connection"></param> /// <param name="sourceIP"></param> /// <param name="buffer"></param> /// <param name="size"></param> private static unsafe void EstablishedHandler(TCPConnection connection, byte[] sourceIP, byte *buffer, uint size) { TCPHeader *header = (TCPHeader *)buffer; /** * * Possible flags: * - PUSH * - FIN */ if ((header->Flags & (FLAG_FIN | FLAG_ACK)) == (FLAG_FIN | FLAG_ACK)) { connection.AcknowledgeNumber = Byte.ReverseBytes(Byte.ReverseBytes(header->Sequence) + 1); SendPacket(connection.IP, connection.SequenceNumber, Byte.ReverseBytes(Byte.ReverseBytes(header->Sequence) + 1), connection.InPort, connection.DestPort, FLAG_ACK, null, 0); setConnectionForWait(connection); } else if ((header->Flags & FLAG_FIN) > 0) { /** * Todo: We need acknowledge our application here with status CLOSE_WAIT, for now we shift over to the LAST_ACK state */ connection.AcknowledgeNumber = Byte.ReverseBytes(Byte.ReverseBytes(header->Sequence) + 1); connection.State = TCPConnectionState.LAST_ACK; SendPacket(connection.IP, connection.SequenceNumber, Byte.ReverseBytes(Byte.ReverseBytes(header->Sequence) + 1), connection.InPort, connection.DestPort, FLAG_ACK, null, 0); Sleep(300); SendPacket(connection.IP, connection.SequenceNumber, 0x00, connection.InPort, connection.DestPort, FLAG_FIN, null, 0); } if ((header->Flags & FLAG_PSH) > 0) { int sizePacket = (int)size - sizeof(TCPHeader); /** * Push packet in Queue */ TCPPacketDescriptor *buf = (TCPPacketDescriptor *)Heap.Alloc(sizeof(TCPPacketDescriptor)); buf->Size = sizePacket; buf->Type = TCPPacketDescriptorTypes.RECEIVE; buf->Data = (byte *)Heap.Alloc(sizePacket); buf->xid = connection.XID; Memory.Memcpy(buf->Data, buffer + sizeof(TCPHeader), sizePacket); Queue queue = connection.ReceiveQueue; /** * Is this a connection or a member? */ if (connection.Type != TCPConnectionType.CONNECTION) { queue = connection.BaseConnection.ReceiveQueue; } queue.Push(buf); connection.AcknowledgeNumber = Byte.ReverseBytes(Byte.ReverseBytes(header->Sequence) + (uint)sizePacket); SendPacket(connection.IP, connection.SequenceNumber, connection.AcknowledgeNumber, connection.InPort, connection.DestPort, FLAG_ACK, null, 0); } else { } }
/// <summary> /// Listen state handler /// </summary> /// <param name="connection"></param> /// <param name="sourceIP"></param> /// <param name="buffer"></param> /// <param name="size"></param> private static unsafe void HandleListen(TCPConnection connection, byte[] sourceIP, byte *buffer, uint size) { TCPHeader *header = (TCPHeader *)buffer; ushort srcPort = header->SourcePort; long id = GenerateID(sourceIP, srcPort); TCPConnection clientConnection = (TCPConnection)connection.Clients.GetByKey(id); /** * Do we need to create a connection or just pass it though? */ if (clientConnection == null) { /** * We only handle SYN packets here! */ if ((header->Flags & FLAG_SYN) == 0) { //Close(connection); return; } /** * Add connection to clients list */ clientConnection = new TCPConnection(); clientConnection.XID = id; clientConnection.InPort = connection.InPort; clientConnection.DestPort = Byte.ReverseBytes(header->SourcePort); clientConnection.SequenceNumber = (uint)Random.Rand(); clientConnection.State = TCPConnectionState.SYN_RECEIVED; clientConnection.IP = new byte[4]; for (int i = 0; i < 4; i++) { clientConnection.IP[i] = sourceIP[i]; } clientConnection.AcknowledgeNumber = Byte.ReverseBytes(header->Acknowledge); clientConnection.Type = TCPConnectionType.CHILD_CONNECTION; clientConnection.Clients = connection.Clients; clientConnection.BaseConnection = connection; connection.Clients.Add(id, clientConnection); /** * Send SYN_ACK and transition to SYN_RECEIVED state */ clientConnection.SequenceNumber = Byte.ReverseBytes(Byte.ReverseBytes(connection.SequenceNumber) + 1); clientConnection.State = TCPConnectionState.SYN_RECEIVED; clientConnection.AcknowledgeNumber = Byte.ReverseBytes(Byte.ReverseBytes(header->Sequence) + 1); SendPacket(clientConnection.IP, clientConnection.SequenceNumber, Byte.ReverseBytes(Byte.ReverseBytes(header->Sequence) + 1), clientConnection.InPort, clientConnection.DestPort, FLAG_SYN | FLAG_ACK, null, 0); } else { handleConnection(clientConnection, sourceIP, buffer, size); } }
/// <summary> /// Closed state handler /// </summary> /// <param name="con"></param> private static void ClosedHandler(TCPConnection con) { SendPacket(con.IP, con.SequenceNumber, 0, con.InPort, con.DestPort, FLAG_SYN, null, 0); con.State = TCPConnectionState.SYN_SENT; }