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