public static BufferSegment ToArray(IPFrame frame) { if (frame == null) { throw new ArgumentNullException(nameof(frame)); } BufferSegment payload_segment = frame.Payload; BufferSegment options_segment = frame.Options; int options_size = options_segment?.Length ?? 0; int payload_offset = sizeof(ip_hdr) + options_size; int payload_size = payload_segment?.Length ?? 0; byte[] message_data = new byte[payload_offset + payload_size]; fixed(byte *pinned = message_data) { ip_hdr *iphdr = (ip_hdr *)pinned; iphdr->dest = frame.DestinationAddressV4; iphdr->src = frame.SourceAddressV4; iphdr->_ttl = (byte)frame.Ttl; iphdr->_proto = (byte)frame.ProtocolType; iphdr->_v_hl = (byte)(4 << 4 | payload_offset >> 2); iphdr->_tos = frame.Tos; // Routine Mode iphdr->_len = CheckSum.htons((ushort)message_data.Length); iphdr->_id = CheckSum.htons(frame.Id); iphdr->_flags = CheckSum.ntohs((ushort)frame.Flags); if (options_size > 0) { IntPtr destination_options = (IntPtr)(pinned + sizeof(ip_hdr)); Marshal.Copy(options_segment.Buffer, options_segment.Offset, destination_options, options_size); } if (payload_size > 0) { using (MemoryStream ms = new MemoryStream(message_data, payload_offset, payload_size)) { ms.Write(payload_segment.Buffer, payload_segment.Offset, payload_size); } } iphdr->_chksum = CheckSum.inet_chksum(pinned, payload_offset); if (iphdr->_chksum == 0) { iphdr->_chksum = 0xffff; } } return(new BufferSegment(message_data)); }
public static IPFrame ParseFrame(BufferSegment packet, bool checksum = true) { if (packet == null) { return(null); } IPFrame frame = null; packet.UnsafeAddrOfPinnedArrayElement((payload) => { ip_hdr *iphdr = (ip_hdr *)payload; if (iphdr == null) { return; } if (ip_hdr.IPH_V(iphdr) != 4) { return; } int iphdr_hlen = ip_hdr.IPH_HL(iphdr) << 2; if (iphdr_hlen > packet.Length) { return; } if (iphdr_hlen < IP_HLEN) { return; } int ttl = ip_hdr.IPH_TTL(iphdr); if (ttl <= 0) { return; } if (checksum && iphdr->_chksum != 0) { int cksum = CheckSum.inet_chksum(iphdr, iphdr_hlen); if (cksum != 0) { return; } } if (ip_addr_isbroadcast(iphdr->src) || ip_addr_isbroadcast(iphdr->dest)) { return; } if ((ip_hdr.IPH_OFFSET(iphdr) & CheckSum.ntohs((ushort)(IPFlags.IP_OFFMASK | IPFlags.IP_MF))) != 0) // 不允许IP分片(NAT不太容易处理好分片) { return; } ProtocolType protocolType = (ProtocolType)ip_hdr.IPH_PROTO(iphdr); if (protocolType == (ProtocolType)IP_PROTO_UDP || protocolType == (ProtocolType)IP_PROTO_TCP || protocolType == (ProtocolType)IP_PROTO_ICMP || protocolType == (ProtocolType)IP_PROTO_GRE) { BufferSegment message_data = new BufferSegment(packet.Buffer, packet.Offset + iphdr_hlen, packet.Length - iphdr_hlen); BufferSegment options_data = null; int options_size = (iphdr_hlen - sizeof(ip_hdr)); if (options_size <= 0) { options_data = new BufferSegment(BufferSegment.Empty); } else { options_data = new BufferSegment(packet.Buffer, packet.Offset + sizeof(ip_hdr), options_size); } frame = new IPFrame(protocolType, new IPAddress(iphdr->src), new IPAddress(iphdr->dest), message_data) { Id = CheckSum.ntohs(iphdr->_id), Ttl = ttl, Tos = iphdr->_tos, Options = options_data, Flags = (IPFlags)CheckSum.ntohs(iphdr->_flags), }; } }); return(frame); }
public static int IPH_TTL(ip_hdr *hdr) { return((hdr)->_ttl & 0xff); }
public static int IPH_OFFSET(ip_hdr *hdr) { return((hdr)->_flags); }
public static int IPH_PROTO(ip_hdr *hdr) { return((hdr)->_proto & 0xff); }
public static int IPH_HL(ip_hdr *hdr) { return((hdr)->_v_hl & 0x0f); }
#pragma warning restore 0649 public static int IPH_V(ip_hdr *hdr) { return((hdr)->_v_hl >> 4); }