Configuration¶
pcapkit.utilities.config holds every tunable limit of pcapkit
(#1726). Each limit is read from a PCAPKIT_* environment variable
once, when the module is imported:
A value that is not an integer, or is below the variable’s minimum, warns with a
ConfigWarningand falls back to the default.A limit takes
-1for no limit. That, or a value above the default, is accepted and warns with aConfigWarningnaming the risk below.
Each warning names the variable and the value it was given, e.g.
PCAPKIT_FALLBACK_LIMIT='-7' is not an integer of at least 0, or -1 for no
limit; using the default, 10000. It obeys the warning filters, so under
-W error or PYTHONWARNINGS=error an out-of-range value makes
import pcapkit raise ConfigWarning.
Readers look each value up as config.<NAME> at call time, so patching a name
here reaches every engine and protocol that reads it.
The pcapkit.vendor crawlers’ PCAPKIT_VENDOR_RETRY,
PCAPKIT_CI_MODE, PCAPKIT_HTTP_PROXY and
PCAPKIT_HTTPS_PROXY are not held here. They are read by
pcapkit.vendor.default, the first two with the readers below, and documented with it under Environment Variables.
PCAPKIT_DEVMODE, PCAPKIT_VERBOSE and PCAPKIT_SPHINX
are read by pcapkit.utilities.logging, which needs them while it loads
and so cannot import this module. A bad value of one falls back to off, and is
reported with a ConfigWarning once
pcapkit.utilities.warnings has loaded.
Added in version 1.5.0.
Limits¶
Variable |
Default |
Accepted |
Risk past the default, or at |
|---|---|---|---|
|
|
Python’s recursion limit: a deep frame may raise |
|
|
|
as above, once |
|
|
|
each capture remembered pins one packet in memory |
|
|
|
a large or endless object graph is dumped without bound |
|
|
|
the cache retains every bytestring it was asked about |
|
|
|
a bogus record length allocates that much in one read |
|
|
|
a hostile capture’s declared length is zero-filled in memory (#554) |
|
|
|
lying lengths amplify into memory without being charged (#573) |
|
|
|
as above, per octet actually read (#573) |
- PCAPKIT_FRAME_LAYER_LIMIT¶
Sets
FRAME_LAYER_LIMIT.
- PCAPKIT_EXTENSION_HEADER_LIMIT¶
Sets
EXTENSION_HEADER_LIMIT.
- PCAPKIT_IPV6_TCP_WARNED_LIMIT¶
Sets
IPV6_TCP_WARNED_LIMIT.
- PCAPKIT_FALLBACK_LIMIT¶
Sets
FALLBACK_LIMIT.
- PCAPKIT_DETECT_CACHE_SIZE¶
Sets
DETECT_CACHE_SIZE. Read once, whenpcapkit.utilities.chardetis imported.
- PCAPKIT_READ_CHUNK¶
Sets
READ_CHUNK.
- PCAPKIT_MAX_ZERO_PAD_LENGTH¶
Sets
MAX_ZERO_PAD_LENGTH.
- PCAPKIT_MAX_ZERO_PAD_SHORTFALL¶
Sets
MAX_ZERO_PAD_SHORTFALL.
- PCAPKIT_ZERO_PAD_BUDGET_RATIO¶
Sets
ZERO_PAD_BUDGET_RATIO.
- pcapkit.utilities.config.FRAME_LAYER_LIMIT = 64¶
Most layers dissected in one frame (#1610),
PCAPKIT_FRAME_LAYER_LIMIT.A layer is one entry of the frame’s protocol chain, counted from the first layer the frame record carries, usually its link layer; a protocol constructed from its own octets is not counted itself, so the count starts at the first layer it dissects. IPv6 extension headers are layers like any other, whether
IPv6walks them or each dissects the next. What follows the last layer is kept asRaw, with oneProtocolWarning, unless it would have been left raw anyway or there is nothing left.Each layer dissects the next from inside its own parse, so without the bound a deep enough frame, such as IP in IP or stacked 802.1Q tags, stops wherever Python’s recursion limit falls, which depends on the interpreter and on how deep the caller’s own stack is. A tunnel does not restart the count, and nor does the end of a chain of extension headers, which
EXTENSION_HEADER_LIMITbounds on its own.Added in version 1.5.0: Moved from
pcapkit.protocols.protocol.FRAME_LAYER_LIMIT(#1726).- Type:
- pcapkit.utilities.config.EXTENSION_HEADER_LIMIT = 32¶
Most IPv6 extension headers dissected in one chain, i.e. one after another with no other layer between them (#1604),
PCAPKIT_EXTENSION_HEADER_LIMIT.The walk stops there, and what follows the last of them is kept as
Raw, with oneProtocolWarning. That holds whether the chain follows IPv6, which walks it in a loop (IPv6._decode_next_layer), or another layer such as IPv4, where each header dissects the next one itself (Internet._import_next_layer). Behind IPv4, thescapytoolkit steps over at most this many in the octets to find TCP; the third-party engines are otherwise best effort here (#1687).RFC 8200 Section 4.1 allows each extension header at most once, and the Destination Options header at most twice, so no compliant chain gets close. Without the bound, a chain dissected header by header stops wherever Python’s recursion limit falls, which depends on the interpreter. Each header is a layer, so
FRAME_LAYER_LIMITapplies as well.Rebuilding a frame with
from_data()stops where parsing it did, and warns once too (#1619), c.f.Internet._make_payload.Added in version 1.5.0: Moved from
pcapkit.protocols.internet.internet.EXTENSION_HEADER_LIMIT(#1726).- Type:
- pcapkit.utilities.config.IPV6_TCP_WARNED_LIMIT = 32¶
How many captures the
pypcapfileengine remembers having warned about for TCP over IPv6,PCAPKIT_IPV6_TCP_WARNED_LIMIT.Each one pins a packet of its own in memory, so the memory is bounded and the oldest is forgotten first. Up to this many captures read at the same time warn exactly once each.
Added in version 1.5.0: Moved from
pcapkit.toolkit.pypcapfile.IPV6_TCP_WARNED_LIMIT(#1726).- Type:
- pcapkit.utilities.config.FALLBACK_LIMIT = 10000¶
Most objects
DictDumper._append_fallbackexpands for one top-level object, counting an object once per time it is met,PCAPKIT_FALLBACK_LIMIT;-1expands without bound.No fallback object in the
foundation,dumpkitorinterfacetest legs expands into more than 7, so the default leaves three orders of magnitude of room.Added in version 1.5.0: Moved from
pcapkit.dumpkit.common.FALLBACK_LIMIT(#1726).- Type:
- pcapkit.utilities.config.DETECT_CACHE_SIZE = 1024¶
How many distinct bytestrings
detect()remembers,PCAPKIT_DETECT_CACHE_SIZE;-1leaves the cache unbounded.Unlike the other limits, this one is read once, when
pcapkit.utilities.chardetis imported, as the size of itsfunctools.lru_cache().Added in version 1.5.0: Moved from
pcapkit.utilities.chardet.DETECT_CACHE_SIZE(#1726).- Type:
- pcapkit.utilities.config.READ_CHUNK = 1048576¶
Most octets
SeekableReaderasks of its stream in one read,PCAPKIT_READ_CHUNK;-1asks for the whole read at once.A read allocates what it asks for up front, so a record’s bogus length is read in pieces.
Added in version 1.5.0: Moved from
pcapkit.corekit.io._READ_CHUNK(#1726).- Type:
- pcapkit.utilities.config.MAX_ZERO_PAD_LENGTH = 262144¶
Ceiling on the zero-padding
FieldBase.unpackwill still perform for a field whose declared length outruns its buffer.This is libpcap’s own
MAXIMUM_SNAPLEN– the point past which libpcap itself treats a capture’s declared snapshot length as corrupt or byte-order-swapped rather than real – and it is the same figure this package’s own PCAP writer defaultssnaplento (pcapkit.protocols.misc.pcap.header.Header.make()). No single field within one captured packet is legitimately larger than the largest packet libpcap itself is willing to believe, so nothing this library parses should ever declare a length past it.The bound is deliberately not “any declared length beyond what the buffer holds”:
ListField.unpackandOptionField.unpackdepend on reading a short, sometimes empty, tail past a truncated area and having it decode as zero – that is how an over-longihl, or a capture cut short by the snapshot length, reads as end-of-option-list orPad1instead of wedging or raising (see #431). Every such read is of a fixed-width, few-octet field, always far under this ceiling, so it is untouched; only a length past it – which no fixed-width field ever legitimately is – gets refused.A ceiling on one field says nothing about how many fields a parse may pad, which is what
MAX_ZERO_PAD_SHORTFALLandZERO_PAD_BUDGET_RATIObelow are for. See #573.Set with
PCAPKIT_MAX_ZERO_PAD_LENGTH.-1lifts the ceiling, and lifts the running budget ofZERO_PAD_BUDGET_RATIOwith it, since the ceiling is the one-off term of that budget’s allowance.Added in version 1.5.0: Moved from
pcapkit.corekit.fields.field._MAX_ZERO_PAD_LENGTH(#1726).- Type:
- pcapkit.utilities.config.MAX_ZERO_PAD_SHORTFALL = 65536¶
Shortfall
FieldBase.unpackwill always zero-pad for, whatever else a parse has already padded.MAX_ZERO_PAD_LENGTHbounds each field on its own, and a packet holds many fields, so it leaves the sum unbounded: a declared length just under the ceiling is honoured however often it is declared. Measured on this tree, 200 minimal PCAP-NG Decryption Secrets Blocks – 4,800 wire octets, each block declaringsecrets_lengthof 262,142 against two supplied octets throughUnknownSecrets.data(pcapkit/protocols/schema/misc/pcapng.py) – retained 50.0 MiB, an amplification of 10,922x per block. Every individual field was under the ceiling, so nothing refused any of them (#573).The sum therefore wants a budget, and this is the figure that makes one safe. A budget on its own is not: a capture cut short by its snapshot length pads legitimately and must keep parsing (#431, and the reasoning that declined #554), and it pads far more than it reads, so any running budget tight enough to matter starts refusing real captures. Worse, it refuses them sometimes – measured on this tree with a running budget alone, the same legitimate 54-octet frame parsed to one result on 37 of 40 calls and to another on calls 26, 33 and 39, because whether it fit depended on what had been parsed before it. A guard whose answer moves with history is not a guard.
65,536 is what removes that. It is the whole span of a 16-bit wire length field – which is how an IP header, an IPv6 payload, a TCP or IPv4 option and a PCAP-NG option all declare their size – so no shortfall that one of those can produce is subject to the budget at all, and every one of them is padded unconditionally. Measured: the largest legitimate single shortfall found anywhere was 65,495 octets, from a snapshot-truncated offload-sized frame (100 frames at
incl_len54 declaring an IPv4 total length of 65,535, padding 6,549,500 octets from 7,024 read), and 64,750 from a truncated PCAP-NG option. Both sit under this figure, and so does anything else a 16-bit field can ask for.What is left above it is the band a 32-bit wire length reaches – PCAP-NG’s own block and secrets lengths, which is where #573’s amplification lives – and legitimately that is a once-per-file event, since only the last block of a truncated capture is cut short. So the band gets the running budget below, whose one-off term already covers any single such event outright.
Set with
PCAPKIT_MAX_ZERO_PAD_SHORTFALL.-1disables the running budget: every shortfall withinMAX_ZERO_PAD_LENGTHis then padded without being charged to it.Added in version 1.5.0: Moved from
pcapkit.corekit.fields.field._MAX_ZERO_PAD_SHORTFALL(#1726).- Type:
- pcapkit.utilities.config.ZERO_PAD_BUDGET_RATIO = 16¶
Zero padding past
MAX_ZERO_PAD_SHORTFALLthatFieldBase.unpackwill synthesise in total for every octet a parse has actually been given, over and above the one-offMAX_ZERO_PAD_LENGTHallowance.A shortfall in this band – past 65,536 octets and so past anything a 16-bit wire length can declare, but within
MAX_ZERO_PAD_LENGTH– is a PCAP-NG block or secrets length, a 32-bit figure. One of those, on its own, is legitimate: it is what the final block of a capture truncated at EOF looks like, and theMAX_ZERO_PAD_LENGTHterm of the allowance covers it whole, from a cold start, because such a shortfall cannot exceed that ceiling and still be padded at all.Repeating one is not legitimate, and that is what 16 is chosen to catch. Truncation cuts the end of a file, so a capture has one short block, not two hundred; #573’s shape has two hundred because they are declared rather than cut. 16 octets of further allowance per octet genuinely read leaves any real file an allowance orders of magnitude past the one event it can want, while bounding the sum for a file whose blocks all lie.
Set with
PCAPKIT_ZERO_PAD_BUDGET_RATIO.-1lifts the running budget;MAX_ZERO_PAD_LENGTHstill bounds each field.Added in version 1.5.0: Moved from
pcapkit.corekit.fields.field._ZERO_PAD_BUDGET_RATIO(#1726).- Type:
Readers¶
The limits above are read with these, and a module that keeps a variable of its own reads it with them too, so that a bad value is reported the same way.
- pcapkit.utilities.config.read_limit(name, default, *, minimum=0, risk=None)[source]¶
Read the integer environment variable
PCAPKIT_<name>.A value that is not an integer, or is below
minimum, is reported with aConfigWarningnaming the variable and the value, anddefaultis used instead.- Parameters:
name (
str) – Variable name, without thePCAPKIT_prefix.default (
int) – Value used when the variable is unset or invalid.minimum (
int) – Smallest value accepted, besides-1whereriskis set.risk (
str|None) – What lifting the limit risks. If set,-1means no limit, and-1or any value abovedefaultis reported with it. IfNone,-1is not accepted and nothing is reported.
- Return type:
- Returns:
The value of the variable, or
default.
Added in version 1.5.0.
- pcapkit.utilities.config.read_flag(name, default=False)[source]¶
Read the boolean environment variable
PCAPKIT_<name>.The value is read with surrounding whitespace stripped and case-insensitively, and is one of
1,yes,trueoron, or of0,no,falseoroff. Any other value is reported with aConfigWarningnaming the variable and the value, anddefaultis used instead.- Parameters:
- Return type:
- Returns:
The value of the variable, or
default.
Added in version 1.5.0.