blob: bf833b36bbf5426dca741b1578fc031a13a23eae [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Matus Fabianeea28d72017-01-13 04:15:54 -08002# IPFIX support for Scapy (RFC7011)
3
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004from scapy.all import (
5 bind_layers,
6 FieldLenField,
7 IntField,
8 Packet,
9 PacketListField,
10 ShortEnumField,
11 ShortField,
12 StrLenField,
13)
Paul Vinciguerra2cc29a52019-02-13 07:44:52 -080014from scapy.layers.inet import UDP
Matus Fabianeea28d72017-01-13 04:15:54 -080015
16
17# IPFIX Information Elements http://www.iana.org/assignments/ipfix/ipfix.xhtml
18information_elements = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020019 1: "octetDeltaCount",
20 2: "packetDeltaCount",
21 3: "deltaFlowCount",
22 4: "protocolIdentifier",
23 5: "ipClassOfService",
24 6: "tcpControlBits",
25 7: "sourceTransportPort",
26 8: "sourceIPv4Address",
27 9: "sourceIPv4PrefixLength",
28 10: "ingressInterface",
29 11: "destinationTransportPort",
30 12: "destinationIPv4Address",
31 13: "destinationIPv4PrefixLength",
32 14: "egressInterface",
33 15: "ipNextHopIPv4Address",
34 16: "bgpSourceAsNumber",
35 17: "bgpDestinationAsNumber",
36 18: "bgpNextHopIPv4Address",
37 19: "postMCastPacketDeltaCount",
38 20: "postMCastOctetDeltaCount",
39 21: "flowEndSysUpTime",
40 22: "flowStartSysUpTime",
41 23: "postOctetDeltaCount",
42 24: "postPacketDeltaCount",
43 25: "minimumIpTotalLength",
44 26: "maximumIpTotalLength",
45 27: "sourceIPv6Address",
46 28: "destinationIPv6Address",
47 29: "sourceIPv6PrefixLength",
48 30: "destinationIPv6PrefixLength",
49 31: "flowLabelIPv6",
50 32: "icmpTypeCodeIPv4",
51 33: "igmpType",
52 34: "samplingInterval",
53 35: "samplingAlgorithm",
54 36: "flowActiveTimeout",
55 37: "flowIdleTimeout",
56 38: "engineType",
57 39: "engineId",
58 40: "exportedOctetTotalCount",
59 41: "exportedMessageTotalCount",
60 42: "exportedFlowRecordTotalCount",
61 43: "ipv4RouterSc",
62 44: "sourceIPv4Prefix",
63 45: "destinationIPv4Prefix",
64 46: "mplsTopLabelType",
65 47: "mplsTopLabelIPv4Address",
66 48: "samplerId",
67 49: "samplerMode",
68 50: "samplerRandomInterval",
69 51: "classId",
70 52: "minimumTTL",
71 53: "maximumTTL",
72 54: "fragmentIdentification",
73 55: "postIpClassOfService",
74 56: "sourceMacAddress",
75 57: "postDestinationMacAddress",
76 58: "vlanId",
77 59: "postVlanId",
78 60: "ipVersion",
79 61: "flowDirection",
80 62: "ipNextHopIPv6Address",
81 63: "bgpNextHopIPv6Address",
82 64: "ipv6ExtensionHeaders",
83 70: "mplsTopLabelStackSection",
84 71: "mplsLabelStackSection2",
85 72: "mplsLabelStackSection3",
86 73: "mplsLabelStackSection4",
87 74: "mplsLabelStackSection5",
88 75: "mplsLabelStackSection6",
89 76: "mplsLabelStackSection7",
90 77: "mplsLabelStackSection8",
91 78: "mplsLabelStackSection9",
92 79: "mplsLabelStackSection10",
93 80: "destinationMacAddress",
94 81: "postSourceMacAddress",
95 82: "interfaceName",
96 83: "interfaceDescription",
97 84: "samplerName",
98 85: "octetTotalCount",
99 86: "packetTotalCount",
100 87: "flagsAndSamplerId",
101 88: "fragmentOffset",
102 89: "forwardingStatus",
103 90: "mplsVpnRouteDistinguisher",
104 91: "mplsTopLabelPrefixLength",
105 92: "srcTrafficIndex",
106 93: "dstTrafficIndex",
107 94: "applicationDescription",
108 95: "applicationId",
109 96: "applicationName",
110 98: "postIpDiffServCodePoint",
111 99: "multicastReplicationFactor",
Matus Fabianeea28d72017-01-13 04:15:54 -0800112 100: "className",
113 101: "classificationEngineId",
114 102: "layer2packetSectionOffset",
115 103: "layer2packetSectionSize",
116 104: "layer2packetSectionData",
117 128: "bgpNextAdjacentAsNumber",
118 129: "bgpPrevAdjacentAsNumber",
119 130: "exporterIPv4Address",
120 131: "exporterIPv6Address",
121 132: "droppedOctetDeltaCount",
122 133: "droppedPacketDeltaCount",
123 134: "droppedOctetTotalCount",
124 135: "droppedPacketTotalCount",
125 136: "flowEndReason",
126 137: "commonPropertiesId",
127 138: "observationPointId",
128 139: "icmpTypeCodeIPv6",
129 140: "mplsTopLabelIPv6Address",
130 141: "lineCardId",
131 142: "portId",
132 143: "meteringProcessId",
133 144: "exportingProcessId",
134 145: "templateId",
135 146: "wlanChannelId",
136 147: "wlanSSID",
137 148: "flowId",
138 149: "observationDomainId",
139 150: "flowStartSeconds",
140 151: "flowEndSeconds",
141 152: "flowStartMilliseconds",
142 153: "flowEndMilliseconds",
143 154: "flowStartMicroseconds",
144 155: "flowEndMicroseconds",
145 156: "flowStartNanoseconds",
146 157: "flowEndNanoseconds",
147 158: "flowStartDeltaMicroseconds",
148 159: "flowEndDeltaMicroseconds",
149 160: "systemInitTimeMilliseconds",
150 161: "flowDurationMilliseconds",
151 162: "flowDurationMicroseconds",
152 163: "observedFlowTotalCount",
153 164: "ignoredPacketTotalCount",
154 165: "ignoredOctetTotalCount",
155 166: "notSentFlowTotalCount",
156 167: "notSentPacketTotalCount",
157 168: "notSentOctetTotalCount",
158 169: "destinationIPv6Prefix",
159 170: "sourceIPv6Prefix",
160 171: "postOctetTotalCount",
161 172: "postPacketTotalCount",
162 173: "flowKeyIndicator",
163 174: "postMCastPacketTotalCount",
164 175: "postMCastOctetTotalCount",
165 176: "icmpTypeIPv4",
166 177: "icmpCodeIPv4",
167 178: "icmpTypeIPv6",
168 179: "icmpCodeIPv6",
169 180: "udpSourcePort",
170 181: "udpDestinationPort",
171 182: "tcpSourcePort",
172 183: "tcpDestinationPort",
173 184: "tcpSequenceNumber",
174 185: "tcpAcknowledgementNumber",
175 186: "tcpWindowSize",
176 187: "tcpUrgentPointer",
177 188: "tcpHeaderLength",
178 189: "ipHeaderLength",
179 190: "totalLengthIPv4",
180 191: "payloadLengthIPv6",
181 192: "ipTTL",
182 193: "nextHeaderIPv6",
183 194: "mplsPayloadLength",
184 195: "ipDiffServCodePoint",
185 196: "ipPrecedence",
186 197: "fragmentFlags",
187 198: "octetDeltaSumOfSquares",
188 199: "octetTotalSumOfSquares",
189 200: "mplsTopLabelTTL",
190 201: "mplsLabelStackLength",
191 202: "mplsLabelStackDepth",
192 203: "mplsTopLabelExp",
193 204: "ipPayloadLength",
194 205: "udpMessageLength",
195 206: "isMulticast",
196 207: "ipv4IHL",
197 208: "ipv4Options",
198 209: "tcpOptions",
199 210: "paddingOctets",
200 211: "collectorIPv4Address",
201 212: "collectorIPv6Address",
202 213: "exportInterface",
203 214: "exportProtocolVersion",
204 215: "exportTransportProtocol",
205 216: "collectorTransportPort",
206 217: "exporterTransportPort",
207 218: "tcpSynTotalCount",
208 219: "tcpFinTotalCount",
209 220: "tcpRstTotalCount",
210 221: "tcpPshTotalCount",
211 222: "tcpAckTotalCount",
212 223: "tcpUrgTotalCount",
213 224: "ipTotalLength",
214 225: "postNATSourceIPv4Address",
215 226: "postNATDestinationIPv4Address",
216 227: "postNAPTSourceTransportPort",
217 228: "postNAPTDestinationTransportPort",
218 229: "natOriginatingAddressRealm",
219 230: "natEvent",
220 231: "initiatorOctets",
221 232: "responderOctets",
222 233: "firewallEvent",
223 234: "ingressVRFID",
224 235: "egressVRFID",
225 236: "VRFname",
226 237: "postMplsTopLabelExp",
227 238: "tcpWindowScale",
228 239: "biflowDirection",
229 240: "ethernetHeaderLength",
230 241: "ethernetPayloadLength",
231 242: "ethernetTotalLength",
232 243: "dot1qVlanId",
233 244: "dot1qPriority",
234 245: "dot1qCustomerVlanId",
235 246: "dot1qCustomerPriority",
236 247: "metroEvcId",
237 248: "metroEvcType",
238 249: "pseudoWireId",
239 250: "pseudoWireType",
240 251: "pseudoWireControlWord",
241 252: "ingressPhysicalInterface",
242 253: "egressPhysicalInterface",
243 254: "postDot1qVlanId",
244 255: "postDot1qCustomerVlanId",
245 256: "ethernetType",
246 257: "postIpPrecedence",
247 258: "collectionTimeMilliseconds",
248 259: "exportSctpStreamId",
249 260: "maxExportSeconds",
250 261: "maxFlowEndSeconds",
251 262: "messageMD5Checksum",
252 263: "messageScope",
253 264: "minExportSeconds",
254 265: "minFlowStartSeconds",
255 266: "opaqueOctets",
256 267: "sessionScope",
257 268: "maxFlowEndMicroseconds",
258 269: "maxFlowEndMilliseconds",
259 270: "maxFlowEndNanoseconds",
260 271: "minFlowStartMicroseconds",
261 272: "minFlowStartMilliseconds",
262 273: "minFlowStartNanoseconds",
263 274: "collectorCertificate",
264 275: "exporterCertificate",
265 276: "dataRecordsReliability",
266 277: "observationPointType",
267 278: "newConnectionDeltaCount",
268 279: "connectionSumDurationSeconds",
269 280: "connectionTransactionId",
270 281: "postNATSourceIPv6Address",
271 282: "postNATDestinationIPv6Address",
272 283: "natPoolId",
273 284: "natPoolName",
274 285: "anonymizationFlags",
275 286: "anonymizationTechnique",
276 287: "informationElementIndex",
277 288: "p2pTechnology",
278 289: "tunnelTechnology",
279 290: "encryptedTechnology",
280 291: "basicList",
281 292: "subTemplateList",
282 293: "subTemplateMultiList",
283 294: "bgpValidityState",
284 295: "IPSecSPI",
285 296: "greKey",
286 297: "natType",
287 298: "initiatorPackets",
288 299: "responderPackets",
289 300: "observationDomainName",
290 301: "selectionSequenceId",
291 302: "selectorId",
292 303: "informationElementId",
293 304: "selectorAlgorithm",
294 305: "samplingPacketInterval",
295 306: "samplingPacketSpace",
296 307: "samplingTimeInterval",
297 308: "samplingTimeSpace",
298 309: "samplingSize",
299 310: "samplingPopulation",
300 311: "samplingProbability",
301 312: "dataLinkFrameSize",
302 313: "ipHeaderPacketSection",
303 314: "ipPayloadPacketSection",
304 315: "dataLinkFrameSection",
305 316: "mplsLabelStackSection",
306 317: "mplsPayloadPacketSection",
307 318: "selectorIdTotalPktsObserved",
308 319: "selectorIdTotalPktsSelected",
309 320: "absoluteError",
310 321: "relativeError",
311 322: "observationTimeSeconds",
312 323: "observationTimeMilliseconds",
313 324: "observationTimeMicroseconds",
314 325: "observationTimeNanoseconds",
315 326: "digestHashValue",
316 327: "hashIPPayloadOffset",
317 328: "hashIPPayloadSize",
318 329: "hashOutputRangeMin",
319 330: "hashOutputRangeMax",
320 331: "hashSelectedRangeMin",
321 332: "hashSelectedRangeMax",
322 333: "hashDigestOutput",
323 334: "hashInitialiserValue",
324 335: "selectorName",
325 336: "upperCILimit",
326 337: "lowerCILimit",
327 338: "confidenceLevel",
328 339: "informationElementDataType",
329 340: "informationElementDescription",
330 341: "informationElementName",
331 342: "informationElementRangeBegin",
332 343: "informationElementRangeEnd",
333 344: "informationElementSemantics",
334 345: "informationElementUnits",
335 346: "privateEnterpriseNumber",
336 347: "virtualStationInterfaceId",
337 348: "virtualStationInterfaceName",
338 349: "virtualStationUUID",
339 350: "virtualStationName",
340 351: "layer2SegmentId",
341 352: "layer2OctetDeltaCount",
342 353: "layer2OctetTotalCount",
343 354: "ingressUnicastPacketTotalCount",
344 355: "ingressMulticastPacketTotalCount",
345 356: "ingressBroadcastPacketTotalCount",
346 357: "egressUnicastPacketTotalCount",
347 358: "egressBroadcastPacketTotalCount",
348 359: "monitoringIntervalStartMilliSeconds",
349 360: "monitoringIntervalEndMilliSeconds",
350 361: "portRangeStart",
351 362: "portRangeEnd",
352 363: "portRangeStepSize",
353 364: "portRangeNumPorts",
354 365: "staMacAddress",
355 366: "staIPv4Address",
356 367: "wtpMacAddress",
357 368: "ingressInterfaceType",
358 369: "egressInterfaceType",
359 370: "rtpSequenceNumber",
360 371: "userName",
361 372: "applicationCategoryName",
362 373: "applicationSubCategoryName",
363 374: "applicationGroupName",
364 375: "originalFlowsPresent",
365 376: "originalFlowsInitiated",
366 377: "originalFlowsCompleted",
367 378: "distinctCountOfSourceIPAddress",
368 379: "distinctCountOfDestinationIPAddress",
369 380: "distinctCountOfSourceIPv4Address",
370 381: "distinctCountOfDestinationIPv4Address",
371 382: "distinctCountOfSourceIPv6Address",
372 383: "distinctCountOfDestinationIPv6Address",
373 384: "valueDistributionMethod",
374 385: "rfc3550JitterMilliseconds",
375 386: "rfc3550JitterMicroseconds",
376 387: "rfc3550JitterNanoseconds",
377 388: "dot1qDEI",
378 389: "dot1qCustomerDEI",
379 390: "flowSelectorAlgorithm",
380 391: "flowSelectedOctetDeltaCount",
381 392: "flowSelectedPacketDeltaCount",
382 393: "flowSelectedFlowDeltaCount",
383 394: "selectorIDTotalFlowsObserved",
384 395: "selectorIDTotalFlowsSelected",
385 396: "samplingFlowInterval",
386 397: "samplingFlowSpacing",
387 398: "flowSamplingTimeInterval",
388 399: "flowSamplingTimeSpacing",
389 400: "hashFlowDomain",
390 401: "transportOctetDeltaCount",
391 402: "transportPacketDeltaCount",
392 403: "originalExporterIPv4Address",
393 404: "originalExporterIPv6Address",
394 405: "originalObservationDomainId",
395 406: "intermediateProcessId",
396 407: "ignoredDataRecordTotalCount",
397 408: "dataLinkFrameType",
398 409: "sectionOffset",
399 410: "sectionExportedOctets",
400 411: "dot1qServiceInstanceTag",
401 412: "dot1qServiceInstanceId",
402 413: "dot1qServiceInstancePriority",
403 414: "dot1qCustomerSourceMacAddress",
404 415: "dot1qCustomerDestinationMacAddress",
405 417: "postLayer2OctetDeltaCount",
406 418: "postMCastLayer2OctetDeltaCount",
407 420: "postLayer2OctetTotalCount",
408 421: "postMCastLayer2OctetTotalCount",
409 422: "minimumLayer2TotalLength",
410 423: "maximumLayer2TotalLength",
411 424: "droppedLayer2OctetDeltaCount",
412 425: "droppedLayer2OctetTotalCount",
413 426: "ignoredLayer2OctetTotalCount",
414 427: "notSentLayer2OctetTotalCount",
415 428: "layer2OctetDeltaSumOfSquares",
416 429: "layer2OctetTotalSumOfSquares",
417 430: "layer2FrameDeltaCount",
418 431: "layer2FrameTotalCount",
419 432: "pseudoWireDestinationIPv4Address",
420 433: "ignoredLayer2FrameTotalCount",
421 434: "mibObjectValueInteger",
422 435: "mibObjectValueOctetString",
423 436: "mibObjectValueOID",
424 437: "mibObjectValueBits",
425 438: "mibObjectValueIPAddress",
426 439: "mibObjectValueCounter",
427 440: "mibObjectValueGauge",
428 441: "mibObjectValueTimeTicks",
429 442: "mibObjectValueUnsigned",
430 443: "mibObjectValueTable",
431 444: "mibObjectValueRow",
432 445: "mibObjectIdentifier",
433 446: "mibSubIdentifier",
434 447: "mibIndexIndicator",
435 448: "mibCaptureTimeSemantics",
436 449: "mibContextEngineID",
437 450: "mibContextName",
438 451: "mibObjectName",
439 452: "mibObjectDescription",
440 453: "mibObjectSyntax",
441 454: "mibModuleName",
442 455: "mobileIMSI",
443 456: "mobileMSISDN",
444 457: "httpStatusCode",
445 458: "sourceTransportPortsLimit",
446 459: "httpRequestMethod",
447 460: "httpRequestHost",
448 461: "httpRequestTarget",
Matus Fabiana431ad12018-01-04 04:03:14 -0800449 462: "httpMessageVersion",
450 466: "natQuotaExceededEvent",
451 471: "maxSessionEntries",
452 472: "maxBIBEntries",
453 473: "maxEntriesPerUser",
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200454 475: "maxFragmentsPendingReassembly",
Matus Fabianeea28d72017-01-13 04:15:54 -0800455}
456
457
458class IPFIX(Packet):
459 name = "IPFIX"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200460 fields_desc = [
461 ShortField("version", 10),
462 ShortField("length", None),
463 IntField("exportTime", None),
464 IntField("sequenceNumber", 1),
465 IntField("observationDomainID", 1),
466 ]
Matus Fabianeea28d72017-01-13 04:15:54 -0800467
468
469class FieldSpecifier(Packet):
470 name = "Field Specifier"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200471 fields_desc = [
472 ShortEnumField("informationElement", None, information_elements),
473 ShortField("fieldLength", None),
474 ]
Matus Fabianeea28d72017-01-13 04:15:54 -0800475
476 def extract_padding(self, s):
477 return "", s
478
479
480class Template(Packet):
481 name = "Template"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200482 fields_desc = [
483 ShortField("templateID", 256),
484 FieldLenField("fieldCount", None, count_of="fields"),
485 PacketListField(
486 "templateFields", [], FieldSpecifier, count_from=lambda p: p.fieldCount
487 ),
488 ]
Matus Fabianeea28d72017-01-13 04:15:54 -0800489
490
491class Data(Packet):
492 name = "Data"
493 fields_desc = [
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200494 StrLenField("data", "", length_from=lambda p: p.underlayer.length - 4)
495 ]
Matus Fabianeea28d72017-01-13 04:15:54 -0800496
497 def extract_padding(self, s):
498 return "", s
499
500
501class Set(Packet):
502 name = "Set"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200503 fields_desc = [ShortField("setID", 256), ShortField("length", None)]
Matus Fabianeea28d72017-01-13 04:15:54 -0800504
505 def guess_payload_class(self, payload):
506 if self.setID == 2:
507 return Template
508 elif self.setID > 255:
509 return Data
510 else:
511 return Packet.guess_payload_class(self, payload)
512
513
514bind_layers(IPFIX, Set)
515bind_layers(UDP, IPFIX, dport=4739)
516
517
Paul Vinciguerrae061dad2020-12-04 14:57:51 -0500518class IPFIXDecoder:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200519 """IPFIX data set decoder"""
Matus Fabianeea28d72017-01-13 04:15:54 -0800520
521 def __init__(self):
522 self._templates = []
523
524 def add_template(self, template):
525 """
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700526 Add IPFIX template
Matus Fabianeea28d72017-01-13 04:15:54 -0800527
528 :param template: IPFIX template
529 """
530 templateID = template.templateID
531 fields = []
532 rec_len = 0
533 for field in template.templateFields:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200534 fields.append({"name": field.informationElement, "len": field.fieldLength})
Matus Fabianeea28d72017-01-13 04:15:54 -0800535 rec_len += field.fieldLength
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200536 self._templates.append({"id": templateID, "fields": fields, "rec_len": rec_len})
Matus Fabianeea28d72017-01-13 04:15:54 -0800537
538 def decode_data_set(self, data_set):
539 """
540 Decode IPFIX data
541
542 :param data_set: IPFIX data set
543 :returns: List of decoded data records.
544 """
545 data = []
546 for template in self._templates:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200547 if template["id"] == data_set.setID:
Matus Fabianeea28d72017-01-13 04:15:54 -0800548 offset = 0
549 d = data_set[Data].data
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200550 for i in range(len(d) // template["rec_len"]):
Matus Fabianeea28d72017-01-13 04:15:54 -0800551 record = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200552 for field in template["fields"]:
553 f = d[offset : offset + field["len"]]
554 offset += field["len"]
555 record.update({field["name"]: f})
Matus Fabianeea28d72017-01-13 04:15:54 -0800556 data.append(record)
557 break
558 return data