pcapplusplus-sys 0.1.0

Compile PcapPlusPlus and make its library and header files available. See also https://github.com/seladb/PcapPlusPlus
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
#ifndef PACKETPP_SSH_LAYER
#define PACKETPP_SSH_LAYER

#include "Layer.h"

/**
 * @file
 * This file introduces classes and structures that represent the SSH (Secure Shell) protocol.
 *
 * An overview of this protocol can be found here: https://en.wikipedia.org/wiki/Ssh_(Secure_Shell)
 *
 * For more details please refer to RFC 4253: https://tools.ietf.org/html/rfc4253
 *
 * These current implementation supports parsing of SSH packets when possible (meaning when they are not encrypted).
 * Creation and editing of SSH packets is currently __not supported__.
 *
 * SSH typically uses TCP port 22 so PcapPlusPlus assumes all traffic on this port is SSH traffic.
 * PcapPlusPlus uses some heuristics to determine the type of the SSH message (which will be covered later).
 * If it doesn't find a match to one of the other SSH messages, it assumes it is an encrypted SSH message.
 *
 * Following is an overview of the SSH protocol classes currently supported in PcapPlusPlus. They cover the different messages of the SSH protocol:
 *
  @verbatim

                                 +----------------------------+      SSH version identification
                             +---|  SSHIdentificationMessage  | ===> as described here:
                             |   +----------------------------+      https://tools.ietf.org/html/rfc4253#section-4.2
                             |
  +------------+             |   +----------------------------+      SSH handshake message
  |  SSHLayer  |-------------+---|  SSHHandshakeMessage       | ===> which is typically one of the messages described here:
  | (abstract) |             |   +----------------------------+      https://tools.ietf.org/html/rfc4253#section-12
  +------------+             |                 |
                             |                 |     +----------------------------+      SSH Key Exchange message
                             |                 +-----|  SSHKeyExchangeInitMessage | ===> as described here:
                             |                       +----------------------------+      https://tools.ietf.org/html/rfc4253#section-7
                             |
                             |   +----------------------------+
                             +---|  SSHEncryptedMessage       | ===> An encrypted SSH message
                                 +----------------------------+

  @endverbatim

  * The following points describe the heuristics for deciding the message type for each packet:
  * 1. If the data starts with the characters "SSH-" and ends with "\n" (or "\r\n") it's assumed the message is of type
  *    pcpp#SSHIdentificationMessage
  * 2. Try to determine if this is a non-encrypted SSH handshake message:
  *    - Look at the first 4 bytes of the data which may contain the packet length and see if the value is smaller of equal
  *      than the entire layer length
  *    - The next byte contains the padding length, check if it's smaller or equal than the packet length
  *    - The next byte contains the message type, check if the value is a valid message type as described in:
  *      <https://tools.ietf.org/html/rfc4253#section-12>
  *
  *    If all of these condition are met, this message is either pcpp#SSHKeyExchangeInitMessage (if message type is
  *    pcpp#SSHHandshakeMessage#SSH_MSG_KEX_INIT) or pcpp#SSHHandshakeMessage (for all other message types)
  * 3. If non of these conditions are met, it is assumed this is an encrypted message (pcpp#SSHEncryptedMessage)
 */

/**
 * \namespace pcpp
 * \brief The main namespace for the PcapPlusPlus lib
 */
namespace pcpp
{

	/**
	 * @class SSHLayer
	 * This is the base class for the SSH layer. It is an abstract class that cannot be instantiated.
	 * It holds some common functionality, but its most important method is createSSHMessage()
	 * which takes raw data and creates an SSH message according to the heuristics described
	 * in the SSHLayer.h file description
	 */
	class SSHLayer : public Layer
	{
	public:
		/**
		 * A static method that takes raw packet data and uses the heuristics described in the
		 * SSHLayer.h file description to create an SSH layer instance. This method assumes the data is
		 * indeed SSH data and not some other arbitrary data
		 * @param[in] data A pointer to the raw data
		 * @param[in] dataLen Size of the data in bytes
		 * @param[in] prevLayer A pointer to the previous layer
		 * @param[in] packet A pointer to the Packet instance where layer will be stored in
		 * @return An instance of one of the classes that inherit SSHLayer as described in the
		 * SSHLayer.h file description
		 */
		static SSHLayer* createSSHMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);

		/**
		 * A static method that takes src and dst ports and determines whether it's SSH traffic or not.
		 * @param[in] portSrc The source TCP port to examine
		 * @param[in] portDst The dest TCP port to examine
		 * @return Currently the implementation is very simple and returns "true" if either src or dst ports
		 * are equal to 22, "false" otherwise
		 */
		static bool isSSHPort(uint16_t portSrc, uint16_t portDst) { return portSrc == 22 || portDst == 22; }

		// implement abstract methods

		/**
		 * Several SSH records can reside in a single packets. This method examins the remaining data and creates additional
		 * SSH records if applicable
		 */
		void parseNextLayer();

		/**
		 * Does nothing for this layer
		 */
		void computeCalculateFields() {}

		OsiModelLayer getOsiModelLayer() const { return OsiModelApplicationLayer; }

	protected:
		// protected c'tor, this class cannot be instantiated
		SSHLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : Layer(data, dataLen, prevLayer, packet) { m_Protocol = SSH; }

	private:
		// this layer supports only parsing
		SSHLayer();
	};



	/**
	 * @class SSHIdentificationMessage
	 * A class that represents SSH identification message as described in RFC 4253: <https://tools.ietf.org/html/rfc4253#section-4.2>
	 *
	 * The message content is typically a string that contains the protocol version, software version and a few more details.
	 * This string can be retrieved using the getIdentificationMessage() method
	 */
	class SSHIdentificationMessage : public SSHLayer
	{
	public:
		/**
		 * @return The SSH identification message which is typically the content of this message
		 */
		std::string getIdentificationMessage();

		/**
		 * A static method that takes raw data and tries to parse it as an SSH identification message using the heuristics described
	 	 * in the SSHLayer.h file description. It returns a SSHIdentificationMessage instance if such a message can be identified or NULL
		 * otherwise.
		 * @param[in] data A pointer to the raw data
		 * @param[in] dataLen Size of the data in bytes
		 * @param[in] prevLayer A pointer to the previous layer
		 * @param[in] packet A pointer to the Packet instance where layer will be stored in
		 * @return An instance of SSHIdentificationMessage or NULL if this is not an identification message
		 */
		static SSHIdentificationMessage* tryParse(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);

		// implement abstract methods

		/**
		 * @return The size of the identification message
		 */
		size_t getHeaderLen() const { return m_DataLen; }

		std::string toString() const;

	private:
		// this layer supports only parsing
		SSHIdentificationMessage();

		// private c'tor, this class cannot be instantiated
		SSHIdentificationMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : SSHLayer(data, dataLen, prevLayer, packet) {}

	};


	/**
	 * @class SSHHandshakeMessage
	 * A class representing all of the non-encrypted SSH handshake messages.
	 * An handshake message typically has the following structure:
	 *
		@verbatim
		0         1         2         3         4         5         6
		+---------+---------+---------+---------+---------+---------+-----------     ---------+
		|            Packet Length              | Padding | Message |  Message  ....  Padding |
		|                                       | Length  |  Type   |  Content  ....          |
		+---------------------------------------+---------+---------+-----------     ---------+
		@endverbatim
	 *
	 * The first 4 bytes hold the packet length, followed by 1 byte that holds the padding length (which comes at the end of the message),
	 * then 1 byte that holds the message type (which can be of type SSHHandshakeMessage#SSHHandshakeMessageType) and then the message content.
	 * At the end of the content there is typically padding.
	 *
	 * This class provides access to all of these values. The message content itself is not parse with the exception of SSHKeyExchangeInitMessage
	 * which inherits from this class and provides parsing of the Key Exchange Init message.
	 */
	class SSHHandshakeMessage : public SSHLayer
	{
	public:
		/**
		 * An enum that represents SSH non-encrypted message types
		 */
		enum SSHHandshakeMessageType
		{
			/** Key Exchange Init message */
			SSH_MSG_KEX_INIT = 20,
			/** New Keys message */
			SSH_MSG_NEW_KEYS = 21,
			/** Diffie-Hellman Key Exchange Init message */
			SSH_MSG_KEX_DH_INIT = 30,
			/**  message */
			SSH_MSG_KEX_DH_REPLY = 31,
			/** Diffie-Hellman Group Exchange Init message */
			SSH_MSG_KEX_DH_GEX_INIT = 32,
			/** "Diffie-Hellman Group Exchange Reply message */
			SSH_MSG_KEX_DH_GEX_REPLY = 33,
			/** Diffie-Hellman Group Exchange Request message */
			SSH_MSG_KEX_DH_GEX_REQUEST = 34,
			/** Unknown message */
			SSH_MSG_UNKNOWN = 999
		};

		/**
		 * @return The message type
		 */
		SSHHandshakeMessageType getMessageType() const;

		/**
		 * @return A string representation of the message type
		 */
		std::string getMessageTypeStr() const;

		/**
		 * @return A raw byte stream of the message content
		 */
		uint8_t* getSSHHandshakeMessage() const;

		/**
		 * @return The message content length in [bytes] which is calculated by the overall packet length
		 * minus the message header (which includes packet length, padding length and message type) and
		 * minus the padding bytes
		 */
		size_t getSSHHandshakeMessageLength() const;

		/**
		 * @return The padding length in [bytes]
		 */
		size_t getPaddingLength() const;

		/**
		 * A static method that takes raw packet data and uses some heuristics described in the
		 * SSHLayer.h file description to parse it as SSH handshake message instance
		 * @param[in] data A pointer to the raw data
		 * @param[in] dataLen Size of the data in bytes
		 * @param[in] prevLayer A pointer to the previous layer
		 * @param[in] packet A pointer to the Packet instance where layer will be stored in
		 * @return Upon successful parsing the return value would be an instance of SSHKeyExchangeInitMessage
		 * for Key Exchange Init message or SSHHandshakeMessage for any other message type. If parsing fails NULL
		 * will be returned
		 */
		static SSHHandshakeMessage* tryParse(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);

		// implement abstract methods

		/**
		 * @return The size of the SSH handshake message including the padding and message header
		 */
		size_t getHeaderLen() const;

		std::string toString() const;

	protected:

		/**
		 * An internal struct representing the SSH handshake message header
		 */
		#pragma pack(push, 1)
		struct ssh_message_base
		{
			uint32_t packetLength;
			uint8_t paddingLength;
			uint8_t messageCode;
		};
		#pragma pack(pop)

		// this layer supports only parsing
		SSHHandshakeMessage();

		// private c'tor, this class cannot be instantiated
		SSHHandshakeMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : SSHLayer(data, dataLen, prevLayer, packet) {}

		ssh_message_base* getMsgBaseHeader() const { return (ssh_message_base*)m_Data; }
	};


	/**
	 * @class SSHKeyExchangeInitMessage
	 * A class representing the SSH Key Exchange Init message. This is a non-encrypted message that contains information
	 * about the algorithms used for key exchange, encryption, MAC and compression. This class provides methods to access
	 * these details
	 */
	class SSHKeyExchangeInitMessage : public SSHHandshakeMessage
	{
	public:
		/**
		 * A c'tor for this class that accepts raw message data. Please avoid using it as it's used internally
		 * when parsing SSH handshake messages in SSHHandshakeMessage#tryParse()
 		 * @param[in] data A pointer to the raw data
		 * @param[in] dataLen Size of the data in bytes
		 * @param[in] prevLayer A pointer to the previous layer
		 * @param[in] packet A pointer to the Packet instance where layer will be stored in
		 */
		SSHKeyExchangeInitMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);

		/**
		 * Each SSH Key Exchange Init message contains a random 16-byte value generated by the sender.
		 * This method returns a pointer to this 16-byte cookie. To get the value as a hex string
		 * please refer to getCookieAsHexStream()
		 * @return A pointer to the 16-byte cookie value or NULL if the message is malformed
		 */
		uint8_t* getCookie();

		/**
		 * Each SSH Key Exchange Init message contains a random 16-byte value generated by the sender.
		 * This method returns the 16-byte cookie as a hex stream. To get the raw data please refer to
		 * getCookie()
		 * @return A hex stream of the 16-byte cookie value or an empty string if the message is malformed
		 */
		std::string getCookieAsHexStream();

		/**
		 * @return A comma-separated list of the key exchange algorithms used in this session.
		 * Can be empty if the value is missing or the message is malformed
		 */
		std::string getKeyExchangeAlgorithms() { return getFieldValue(0); }

		/**
		 * @return A comma-separated list of the algorithms supported for the server host key.
		 * Can be empty if the value is missing or the message is malformed
		 */
		std::string getServerHostKeyAlgorithms() { return getFieldValue(1); }

		/**
		 * @return A comma-separated list of acceptable symmetric encryption algorithms (also known as ciphers)
		 * from the client to the server. Can be empty if the value is missing or the message is malformed
		 */
		std::string getEncryptionAlgorithmsClientToServer() { return getFieldValue(2); }

		/**
		 * @return A comma-separated list of acceptable symmetric encryption algorithms (also known as ciphers)
		 * from the server to the client. Can be empty if the value is missing or the message is malformed
		 */
		std::string getEncryptionAlgorithmsServerToClient() { return getFieldValue(3); }

		/**
		 * @return A comma-separated list of acceptable MAC algorithms from the client to the server.
		 * Can be empty if the value is missing or the message is malformed
		 */
		std::string getMacAlgorithmsClientToServer() { return getFieldValue(4); }

		/**
		 * @return A comma-separated list of acceptable MAC algorithms from the server to the client.
		 * Can be empty if the value is missing or the message is malformed
		 */
		std::string getMacAlgorithmsServerToClient() { return getFieldValue(5); }

		/**
		 * @return A comma-separated list of acceptable compression algorithms from the client to the server.
		 * Can be empty if the value is missing or the message is malformed
		 */
		std::string getCompressionAlgorithmsClientToServer() { return getFieldValue(6); }

		/**
		 * @return A comma-separated list of acceptable compression algorithms from the server to the client.
		 * Can be empty if the value is missing or the message is malformed
		 */
		std::string getCompressionAlgorithmsServerToClient() { return getFieldValue(7); }

		/**
		 * @return A comma-separated list of language tags from the client to the server.
		 * Can be empty if the value is missing or the message is malformed
		 */
		std::string getLanguagesClientToServer() { return getFieldValue(8); }

		/**
		 * @return A comma-separated list of language tags from the server to the client.
		 * Can be empty if the value is missing or the message is malformed
		 */
		std::string getLanguagesServerToClient() { return getFieldValue(9); }

		/**
		 * @return Indicates whether a guessed key exchange packet follows. If a
		 * guessed packet will be sent, the return value is true. If no guessed
		 * packet will be sent or if this value is missing, the return value is false.
		 */
		bool isFirstKexPacketFollows();

	private:
		size_t m_FieldOffsets[11];
		bool m_OffsetsInitialized;

		void parseMessageAndInitOffsets();

		std::string getFieldValue(int fieldOffsetIndex);
	};


	/**
	 * @class SSHEncryptedMessage
	 * A class representing an SSH encrypted message. In such messages there is very little information to extract from the packet,
	 * hence this class doesn't expose any methods or getters, other than the ones inherited from parent classes.
	 *
	 * It is assumed that any SSH message which does not fit to any of the other SSH message types, according to the heuristics described in
	 * the SSHLayer.h file description, is considered as an encrypted message.
	 */
	class SSHEncryptedMessage : public SSHLayer
	{
	public:

		/**
		 * A c'tor for this class that accepts raw message data. Please avoid using it as it's used internally
		 * when parsing SSH messagess in SSHLayer#createSSHMessage()
		 */
		SSHEncryptedMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : SSHLayer(data, dataLen, prevLayer, packet) {}

		// implement abstract methods

		/**
		 * @return The size of the message which is equal to the size of the layer
		 */
		size_t getHeaderLen() const { return m_DataLen; }

		std::string toString() const;
	};

}

#endif // PACKETPP_SSH_LAYER