|
22 | 22 | import com.igormaznitsa.jbbp.mapper.BinType; |
23 | 23 | import com.igormaznitsa.jbbp.model.*; |
24 | 24 | import com.igormaznitsa.jbbp.utils.JBBPUtils; |
25 | | -import java.io.InputStream; |
26 | 25 | import static org.junit.Assert.*; |
| 26 | +import java.io.StringWriter; |
27 | 27 | import org.junit.Test; |
| 28 | +import com.igormaznitsa.jbbp.io.JBBPBitInputStream; |
| 29 | +import com.igormaznitsa.jbbp.utils.JBBPTextWriter; |
28 | 30 |
|
29 | 31 | public class NetPacketParsingTest extends AbstractParserIntegrationTest { |
30 | 32 |
|
31 | 33 | @Test |
32 | 34 | public void testParsingTCPFrameInsideNetworkFrame() throws Exception { |
33 | | - final InputStream tcpFrameStream = getResourceAsInputStream("tcppacket.bin"); |
| 35 | + final JBBPBitInputStream netPacketStream = new JBBPBitInputStream(getResourceAsInputStream("tcppacket.bin")); |
34 | 36 | try { |
35 | 37 |
|
36 | | - final JBBPParser tcpParser = JBBPParser.prepare( |
37 | | - "skip:34; // skip bytes till the frame\n" |
38 | | - + "ushort SourcePort;" |
39 | | - + "ushort DestinationPort;" |
40 | | - + "int SequenceNumber;" |
41 | | - + "int AcknowledgementNumber;" |
42 | | - + "bit:1 NONCE;" |
43 | | - + "bit:3 RESERVED;" |
44 | | - + "bit:4 HLEN;" |
45 | | - + "bit:1 FIN;" |
46 | | - + "bit:1 SYN;" |
47 | | - + "bit:1 RST;" |
48 | | - + "bit:1 PSH;" |
49 | | - + "bit:1 ACK;" |
50 | | - + "bit:1 URG;" |
51 | | - + "bit:1 ECNECHO;" |
52 | | - + "bit:1 CWR;" |
53 | | - + "ushort WindowSize;" |
54 | | - + "ushort TCPCheckSum;" |
55 | | - + "ushort UrgentPointer;" |
56 | | - + "byte [$$-34-HLEN*4] Option;" |
57 | | - + "byte [_] Data;" |
| 38 | + // Minimal ethernet header without 802.1Q tag |
| 39 | + final JBBPParser ethernetParserHeaderWithout802_1QTag = JBBPParser.prepare( |
| 40 | + "byte[6] MacDestination;" |
| 41 | + +"byte[6] MacSource;" |
| 42 | + +"ushort EthertypeOrLength;" |
| 43 | + ); |
| 44 | + |
| 45 | + // Minimal IP header without options |
| 46 | + final JBBPParser ipParserHeaderWithoutOptions = JBBPParser.prepare( |
| 47 | + "bit:4 InternetHeaderLength;" |
| 48 | + +"bit:4 Version;" |
| 49 | + +"bit:2 ECN;" |
| 50 | + +"bit:6 DSCP;" |
| 51 | + +"ushort TotalPacketLength;" |
| 52 | + +"ushort Identification;" |
| 53 | + +"ushort IPFlagsAndFragmentOffset;" |
| 54 | + +"ubyte TTL;" |
| 55 | + +"ubyte Protocol;" |
| 56 | + +"ushort HeaderChecksum;" |
| 57 | + +"int SourceAddress;" |
| 58 | + +"int DestinationAddress;" |
58 | 59 | ); |
59 | 60 |
|
60 | | - final JBBPFieldStruct result = tcpParser.parse(tcpFrameStream); |
61 | | - |
62 | | - assertEquals(40018, result.findFieldForNameAndType("SourcePort", JBBPFieldUShort.class).getAsInt()); |
63 | | - assertEquals(56344, result.findFieldForNameAndType("DestinationPort", JBBPFieldUShort.class).getAsInt()); |
64 | | - assertEquals(0xE0084171, result.findFieldForNameAndType("SequenceNumber", JBBPFieldInt.class).getAsInt()); |
65 | | - assertEquals(0xAB616F71, result.findFieldForNameAndType("AcknowledgementNumber", JBBPFieldInt.class).getAsInt()); |
66 | | - |
67 | | - assertFalse(result.findFieldForNameAndType("FIN", JBBPFieldBit.class).getAsBool()); |
68 | | - assertFalse(result.findFieldForNameAndType("SYN", JBBPFieldBit.class).getAsBool()); |
69 | | - assertFalse(result.findFieldForNameAndType("RST", JBBPFieldBit.class).getAsBool()); |
70 | | - assertTrue(result.findFieldForNameAndType("PSH", JBBPFieldBit.class).getAsBool()); |
71 | | - assertTrue(result.findFieldForNameAndType("ACK", JBBPFieldBit.class).getAsBool()); |
72 | | - assertFalse(result.findFieldForNameAndType("URG", JBBPFieldBit.class).getAsBool()); |
73 | | - assertFalse(result.findFieldForNameAndType("ECNECHO", JBBPFieldBit.class).getAsBool()); |
74 | | - assertFalse(result.findFieldForNameAndType("CWR", JBBPFieldBit.class).getAsBool()); |
75 | | - assertFalse(result.findFieldForNameAndType("NONCE", JBBPFieldBit.class).getAsBool()); |
76 | | - assertFalse(result.findFieldForNameAndType("RESERVED", JBBPFieldBit.class).getAsBool()); |
77 | | - |
78 | | - assertEquals(5, result.findFieldForNameAndType("HLEN", JBBPFieldBit.class).getAsInt()); |
79 | | - |
80 | | - assertEquals(40880, result.findFieldForNameAndType("WindowSize", JBBPFieldUShort.class).getAsInt()); |
81 | | - assertEquals(0x8BB6, result.findFieldForNameAndType("TCPCheckSum", JBBPFieldUShort.class).getAsInt()); |
82 | | - assertEquals(0, result.findFieldForNameAndType("UrgentPointer", JBBPFieldUShort.class).getAsInt()); |
83 | | - |
84 | | - assertEquals(0, result.findFieldForNameAndType("Option", JBBPFieldArrayByte.class).size()); |
85 | | - assertEquals(119, result.findFieldForNameAndType("Data", JBBPFieldArrayByte.class).size()); |
| 61 | + final JBBPParser tcpHeader = JBBPParser.prepare( |
| 62 | + "ushort SourcePort;" |
| 63 | + + "ushort DestinationPort;" |
| 64 | + + "int SequenceNumber;" |
| 65 | + + "int AcknowledgementNumber;" |
| 66 | + + "bit:1 NONCE;" |
| 67 | + + "bit:3 RESERVED;" |
| 68 | + + "bit:4 HLEN;" |
| 69 | + + "bit:1 FIN;" |
| 70 | + + "bit:1 SYN;" |
| 71 | + + "bit:1 RST;" |
| 72 | + + "bit:1 PSH;" |
| 73 | + + "bit:1 ACK;" |
| 74 | + + "bit:1 URG;" |
| 75 | + + "bit:1 ECNECHO;" |
| 76 | + + "bit:1 CWR;" |
| 77 | + + "ushort WindowSize;" |
| 78 | + + "ushort TCPCheckSum;" |
| 79 | + + "ushort UrgentPointer;" |
| 80 | + + "byte [$$-HLEN*4] Option;" |
| 81 | + ); |
86 | 82 |
|
87 | | - } |
88 | | - finally { |
89 | | - JBBPUtils.closeQuietly(tcpFrameStream); |
| 83 | + |
| 84 | + // Check Ethernet header |
| 85 | + final JBBPFieldStruct parsedEthernetHeader = ethernetParserHeaderWithout802_1QTag.parse(netPacketStream); |
| 86 | + assertArrayEquals(new byte[]{(byte)0x60, (byte)0x67, (byte)0x20, (byte)0xE1, (byte)0xF9, (byte)0xF8},parsedEthernetHeader.findFieldForNameAndType("MacDestination", JBBPFieldArrayByte.class).getArray()); |
| 87 | + assertArrayEquals(new byte[]{(byte)0x00, (byte)0x26, (byte)0x44, (byte)0x74, (byte)0xFE, (byte)0x66},parsedEthernetHeader.findFieldForNameAndType("MacSource", JBBPFieldArrayByte.class).getArray()); |
| 88 | + assertEquals(0x800, parsedEthernetHeader.findFieldForNameAndType("EthertypeOrLength", JBBPFieldUShort.class).getAsInt()); |
| 89 | + |
| 90 | + // Check IP header |
| 91 | + netPacketStream.resetCounter(); |
| 92 | + final JBBPFieldStruct parsedIPHeader = ipParserHeaderWithoutOptions.parse(netPacketStream); |
| 93 | + |
| 94 | + assertEquals(4, parsedIPHeader.findFieldForNameAndType("Version",JBBPFieldBit.class).getAsInt()); |
| 95 | + assertEquals(5, parsedIPHeader.findFieldForNameAndType("InternetHeaderLength",JBBPFieldBit.class).getAsInt()); |
| 96 | + assertEquals(0, parsedIPHeader.findFieldForNameAndType("DSCP",JBBPFieldBit.class).getAsInt()); |
| 97 | + assertEquals(0, parsedIPHeader.findFieldForNameAndType("ECN",JBBPFieldBit.class).getAsInt()); |
| 98 | + |
| 99 | + final int ipTotalPacketLength = parsedIPHeader.findFieldForNameAndType("TotalPacketLength", JBBPFieldUShort.class).getAsInt(); |
| 100 | + |
| 101 | + assertEquals(159, ipTotalPacketLength); |
| 102 | + assertEquals(30810, parsedIPHeader.findFieldForNameAndType("Identification",JBBPFieldUShort.class).getAsInt()); |
| 103 | + |
| 104 | + final int ipFlagsAndFragmentOffset = parsedIPHeader.findFieldForNameAndType("IPFlagsAndFragmentOffset", JBBPFieldUShort.class).getAsInt(); |
| 105 | + |
| 106 | + assertEquals("Extracted IP flags", 0x2, ipFlagsAndFragmentOffset>>>13); |
| 107 | + assertEquals("Extracted Fragment offset", 0x00, ipFlagsAndFragmentOffset & 0x1FFF); |
| 108 | + |
| 109 | + assertEquals(0x39, parsedIPHeader.findFieldForNameAndType("TTL",JBBPFieldUByte.class).getAsInt()); |
| 110 | + assertEquals(0x06, parsedIPHeader.findFieldForNameAndType("Protocol",JBBPFieldUByte.class).getAsInt()); |
| 111 | + assertEquals(0x7DB6, parsedIPHeader.findFieldForNameAndType("HeaderChecksum",JBBPFieldUShort.class).getAsInt()); |
| 112 | + assertEquals(0xD5C7B393, parsedIPHeader.findFieldForNameAndType("SourceAddress",JBBPFieldInt.class).getAsInt()); |
| 113 | + assertEquals(0xC0A80145, parsedIPHeader.findFieldForNameAndType("DestinationAddress",JBBPFieldInt.class).getAsInt()); |
| 114 | + |
| 115 | + // Check TCP header |
| 116 | + netPacketStream.resetCounter(); |
| 117 | + final JBBPFieldStruct parsedTcpHeader = tcpHeader.parse(netPacketStream); |
| 118 | + |
| 119 | + assertEquals(40018, parsedTcpHeader.findFieldForNameAndType("SourcePort", JBBPFieldUShort.class).getAsInt()); |
| 120 | + assertEquals(56344, parsedTcpHeader.findFieldForNameAndType("DestinationPort", JBBPFieldUShort.class).getAsInt()); |
| 121 | + assertEquals(0xE0084171, parsedTcpHeader.findFieldForNameAndType("SequenceNumber", JBBPFieldInt.class).getAsInt()); |
| 122 | + assertEquals(0xAB616F71, parsedTcpHeader.findFieldForNameAndType("AcknowledgementNumber", JBBPFieldInt.class).getAsInt()); |
| 123 | + |
| 124 | + assertFalse(parsedTcpHeader.findFieldForNameAndType("FIN", JBBPFieldBit.class).getAsBool()); |
| 125 | + assertFalse(parsedTcpHeader.findFieldForNameAndType("SYN", JBBPFieldBit.class).getAsBool()); |
| 126 | + assertFalse(parsedTcpHeader.findFieldForNameAndType("RST", JBBPFieldBit.class).getAsBool()); |
| 127 | + assertTrue(parsedTcpHeader.findFieldForNameAndType("PSH", JBBPFieldBit.class).getAsBool()); |
| 128 | + assertTrue(parsedTcpHeader.findFieldForNameAndType("ACK", JBBPFieldBit.class).getAsBool()); |
| 129 | + assertFalse(parsedTcpHeader.findFieldForNameAndType("URG", JBBPFieldBit.class).getAsBool()); |
| 130 | + assertFalse(parsedTcpHeader.findFieldForNameAndType("ECNECHO", JBBPFieldBit.class).getAsBool()); |
| 131 | + assertFalse(parsedTcpHeader.findFieldForNameAndType("CWR", JBBPFieldBit.class).getAsBool()); |
| 132 | + assertFalse(parsedTcpHeader.findFieldForNameAndType("NONCE", JBBPFieldBit.class).getAsBool()); |
| 133 | + assertFalse(parsedTcpHeader.findFieldForNameAndType("RESERVED", JBBPFieldBit.class).getAsBool()); |
| 134 | + |
| 135 | + assertEquals(5, parsedTcpHeader.findFieldForNameAndType("HLEN", JBBPFieldBit.class).getAsInt()); |
| 136 | + |
| 137 | + assertEquals(40880, parsedTcpHeader.findFieldForNameAndType("WindowSize", JBBPFieldUShort.class).getAsInt()); |
| 138 | + assertEquals(0x8BB6, parsedTcpHeader.findFieldForNameAndType("TCPCheckSum", JBBPFieldUShort.class).getAsInt()); |
| 139 | + assertEquals(0, parsedTcpHeader.findFieldForNameAndType("UrgentPointer", JBBPFieldUShort.class).getAsInt()); |
| 140 | + |
| 141 | + assertEquals(0, parsedTcpHeader.findFieldForNameAndType("Option", JBBPFieldArrayByte.class).size()); |
| 142 | + |
| 143 | + // extract data |
| 144 | + final int payloadDataLength = ipTotalPacketLength - 20 - (int)netPacketStream.getCounter(); |
| 145 | + final byte [] data = netPacketStream.readByteArray(payloadDataLength); |
| 146 | + assertEquals(119, data.length); |
| 147 | + |
| 148 | + System.out.println(new JBBPTextWriter(new StringWriter()).Comment("Payload data of the Net packet").Byte(data).BR().toString()); |
| 149 | + |
| 150 | + final byte [] rest = netPacketStream.readByteArray(-1); |
| 151 | + assertEquals(0,rest.length); |
| 152 | + |
| 153 | + } finally { |
| 154 | + JBBPUtils.closeQuietly(netPacketStream); |
90 | 155 | } |
91 | 156 | } |
92 | 157 |
|
93 | 158 | @Test |
94 | 159 | public void testParseSomePacketGettedOverTCP_ExampleFromStackOverflow() throws Exception { |
95 | 160 | final class Parsed { |
96 | | - @Bin(outOrder = 1) byte begin; |
97 | | - @Bin(outOrder = 2, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_4) int version; |
98 | | - @Bin(outOrder = 3, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_4) int returnType; |
99 | | - @Bin(outOrder = 4) byte[] productCode; |
100 | | - @Bin(outOrder = 5, type = BinType.USHORT) int dataLength; |
| 161 | + |
| 162 | + @Bin(outOrder = 1) |
| 163 | + byte begin; |
| 164 | + @Bin(outOrder = 2, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_4) |
| 165 | + int version; |
| 166 | + @Bin(outOrder = 3, type = BinType.BIT, outBitNumber = JBBPBitNumber.BITS_4) |
| 167 | + int returnType; |
| 168 | + @Bin(outOrder = 4) |
| 169 | + byte[] productCode; |
| 170 | + @Bin(outOrder = 5, type = BinType.USHORT) |
| 171 | + int dataLength; |
101 | 172 | } |
102 | | - |
103 | | - final byte [] testArray = new byte[]{0x23, 0x21, (byte) 0x90, 0x23, 0x21, 0x22, 0x12, 0x00, (byte) 0xAA}; |
104 | | - |
| 173 | + |
| 174 | + final byte[] testArray = new byte[]{0x23, 0x21, (byte) 0x90, 0x23, 0x21, 0x22, 0x12, 0x00, (byte) 0xAA}; |
| 175 | + |
105 | 176 | final Parsed parsed = JBBPParser.prepare("byte begin; bit:4 version; bit:4 returnType; byte [5] productCode; ushort dataLength;") |
106 | | - .parse(testArray) |
107 | | - .mapTo(Parsed.class); |
| 177 | + .parse(testArray) |
| 178 | + .mapTo(Parsed.class); |
108 | 179 |
|
109 | 180 | assertEquals(0x23, parsed.begin); |
110 | 181 | assertEquals(0x01, parsed.version); |
111 | 182 | assertEquals(0x02, parsed.returnType); |
112 | 183 | assertArrayEquals(new byte[]{(byte) 0x90, 0x23, 0x21, 0x22, 0x12}, parsed.productCode); |
113 | 184 | assertEquals(0x00AA, parsed.dataLength); |
114 | | - |
| 185 | + |
115 | 186 | assertArrayEquals(testArray, JBBPOut.BeginBin().Bin(parsed).End().toByteArray()); |
116 | 187 | } |
117 | 188 |
|
118 | 189 | @Test |
119 | 190 | public void testParseUDP() throws Exception { |
120 | 191 | final class Parsed { |
121 | | - @Bin(outOrder = 1) char source; |
122 | | - @Bin(outOrder = 2) char destination; |
123 | | - @Bin(outOrder = 3) char length; |
124 | | - @Bin(outOrder = 4) char checksum; |
125 | | - @Bin(outOrder = 5) byte[] data; |
| 192 | + |
| 193 | + @Bin(outOrder = 1) |
| 194 | + char source; |
| 195 | + @Bin(outOrder = 2) |
| 196 | + char destination; |
| 197 | + @Bin(outOrder = 3) |
| 198 | + char length; |
| 199 | + @Bin(outOrder = 4) |
| 200 | + char checksum; |
| 201 | + @Bin(outOrder = 5) |
| 202 | + byte[] data; |
126 | 203 | } |
127 | 204 |
|
128 | | - final byte [] testArray = new byte[]{0x04, (byte) 0x89, 0x00, 0x35, 0x00, 0x2C, (byte) 0xAB, (byte) 0xB4, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x6F, 0x70, 0x64, 0x02, 0x69, 0x78, 0x06, 0x6E, 0x65, 0x74, 0x63, 0x6F, 0x6D, 0x03, 0x63, 0x6F, 0x6D, 0x00, 0x00, 0x01, 0x00, 0x01}; |
129 | | - |
| 205 | + final byte[] testArray = new byte[]{0x04, (byte) 0x89, 0x00, 0x35, 0x00, 0x2C, (byte) 0xAB, (byte) 0xB4, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x70, 0x6F, 0x70, 0x64, 0x02, 0x69, 0x78, 0x06, 0x6E, 0x65, 0x74, 0x63, 0x6F, 0x6D, 0x03, 0x63, 0x6F, 0x6D, 0x00, 0x00, 0x01, 0x00, 0x01}; |
| 206 | + |
130 | 207 | final Parsed parsed = JBBPParser.prepare("ushort source; ushort destination; ushort length; ushort checksum; byte [length-8] data;").parse(testArray).mapTo(Parsed.class); |
131 | | - |
| 208 | + |
132 | 209 | assertEquals(0x0489, parsed.source); |
133 | 210 | assertEquals(0x0035, parsed.destination); |
134 | 211 | assertEquals(0xABB4, parsed.checksum); |
135 | | - assertEquals(0x002C-8, parsed.data.length); |
136 | | - |
| 212 | + assertEquals(0x002C - 8, parsed.data.length); |
| 213 | + |
137 | 214 | assertArrayEquals(testArray, JBBPOut.BeginBin().Bin(parsed).End().toByteArray()); |
138 | 215 | } |
139 | 216 |
|
|
0 commit comments