pypcapkit 1.0.3.post1__cp39-none-any.whl → 1.1.0__cp39-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pcapkit/__init__.py +1 -1
- pcapkit/const/pcapng/option_type.py +1 -1
- pcapkit/const/reg/apptype.py +19017 -19017
- pcapkit/corekit/fields/collections.py +14 -14
- pcapkit/corekit/fields/field.py +33 -8
- pcapkit/corekit/fields/ipaddress.py +0 -1
- pcapkit/corekit/fields/misc.py +14 -19
- pcapkit/corekit/fields/numbers.py +2 -3
- pcapkit/corekit/fields/strings.py +2 -3
- pcapkit/corekit/infoclass.py +59 -6
- pcapkit/corekit/protochain.py +8 -1
- pcapkit/foundation/registry/protocols.py +108 -16
- pcapkit/protocols/data/__init__.py +4 -4
- pcapkit/protocols/data/internet/__init__.py +4 -4
- pcapkit/protocols/data/internet/mh.py +8 -6
- pcapkit/protocols/data/transport/__init__.py +4 -4
- pcapkit/protocols/data/transport/tcp.py +4 -4
- pcapkit/protocols/internet/mh.py +21 -21
- pcapkit/protocols/protocol.py +3 -2
- pcapkit/protocols/schema/__init__.py +4 -4
- pcapkit/protocols/schema/application/httpv2.py +17 -33
- pcapkit/protocols/schema/internet/__init__.py +4 -4
- pcapkit/protocols/schema/internet/hip.py +62 -111
- pcapkit/protocols/schema/internet/hopopt.py +46 -48
- pcapkit/protocols/schema/internet/ipv4.py +36 -41
- pcapkit/protocols/schema/internet/ipv6_opts.py +48 -52
- pcapkit/protocols/schema/internet/ipv6_route.py +12 -21
- pcapkit/protocols/schema/internet/mh.py +57 -86
- pcapkit/protocols/schema/misc/pcapng.py +182 -193
- pcapkit/protocols/schema/schema.py +252 -53
- pcapkit/protocols/schema/transport/__init__.py +4 -4
- pcapkit/protocols/schema/transport/tcp.py +54 -81
- pcapkit/protocols/transport/tcp.py +14 -14
- pcapkit/vendor/pcapng/option_type.py +26 -2
- pcapkit/vendor/reg/apptype.py +32 -5
- {pypcapkit-1.0.3.post1.dist-info → pypcapkit-1.1.0.dist-info}/METADATA +1 -1
- {pypcapkit-1.0.3.post1.dist-info → pypcapkit-1.1.0.dist-info}/RECORD +41 -41
- {pypcapkit-1.0.3.post1.dist-info → pypcapkit-1.1.0.dist-info}/LICENSE +0 -0
- {pypcapkit-1.0.3.post1.dist-info → pypcapkit-1.1.0.dist-info}/WHEEL +0 -0
- {pypcapkit-1.0.3.post1.dist-info → pypcapkit-1.1.0.dist-info}/entry_points.txt +0 -0
- {pypcapkit-1.0.3.post1.dist-info → pypcapkit-1.1.0.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
import copy
|
5
5
|
import io
|
6
|
-
from typing import TYPE_CHECKING, TypeVar, cast
|
6
|
+
from typing import TYPE_CHECKING, Generic, TypeVar, cast
|
7
7
|
|
8
8
|
from pcapkit.corekit.fields.field import _Field
|
9
9
|
from pcapkit.corekit.multidict import OrderedMultiDict
|
@@ -25,9 +25,10 @@ if TYPE_CHECKING:
|
|
25
25
|
from pcapkit.protocols.schema.schema import Schema
|
26
26
|
|
27
27
|
_TL = TypeVar('_TL', 'Schema', '_Field', 'bytes')
|
28
|
+
_TS = TypeVar('_TS', bound='Schema')
|
28
29
|
|
29
30
|
|
30
|
-
class ListField(_Field[List[_TL]]):
|
31
|
+
class ListField(_Field[List[_TL]], Generic[_TL]):
|
31
32
|
"""Field list for protocol fields.
|
32
33
|
|
33
34
|
Args:
|
@@ -55,7 +56,7 @@ class ListField(_Field[List[_TL]]):
|
|
55
56
|
def __init__(self, length: 'int | Callable[[dict[str, Any]], int]' = lambda _: -1,
|
56
57
|
item_type: 'Optional[_Field]' = None,
|
57
58
|
callback: 'Callable[[Self, dict[str, Any]], None]' = lambda *_: None) -> 'None':
|
58
|
-
self._name = '<list>'
|
59
|
+
#self._name = '<list>'
|
59
60
|
self._callback = callback
|
60
61
|
self._item_type = item_type
|
61
62
|
|
@@ -74,9 +75,8 @@ class ListField(_Field[List[_TL]]):
|
|
74
75
|
Returns:
|
75
76
|
Updated field instance.
|
76
77
|
|
77
|
-
|
78
|
-
|
79
|
-
instead of updating the current instance.
|
78
|
+
This method will return a new instance of :class:`ListField`
|
79
|
+
instead of updating the current instance.
|
80
80
|
|
81
81
|
"""
|
82
82
|
new_self = copy.copy(self)
|
@@ -160,7 +160,7 @@ class ListField(_Field[List[_TL]]):
|
|
160
160
|
return temp
|
161
161
|
|
162
162
|
|
163
|
-
class OptionField(ListField):
|
163
|
+
class OptionField(ListField, Generic[_TS]):
|
164
164
|
"""Field list for protocol options.
|
165
165
|
|
166
166
|
Args:
|
@@ -181,7 +181,7 @@ class OptionField(ListField):
|
|
181
181
|
"""
|
182
182
|
|
183
183
|
@property
|
184
|
-
def base_schema(self) -> 'Type[
|
184
|
+
def base_schema(self) -> 'Type[_TS]':
|
185
185
|
"""Base schema."""
|
186
186
|
return self._base_schema
|
187
187
|
|
@@ -191,7 +191,7 @@ class OptionField(ListField):
|
|
191
191
|
return self._type_name
|
192
192
|
|
193
193
|
@property
|
194
|
-
def registry(self) -> 'defaultdict[int | StdlibEnum | AenumEnum, Type[
|
194
|
+
def registry(self) -> 'defaultdict[int | StdlibEnum | AenumEnum, Type[_TS]]':
|
195
195
|
"""Option registry."""
|
196
196
|
return self._registry
|
197
197
|
|
@@ -206,13 +206,13 @@ class OptionField(ListField):
|
|
206
206
|
return self._option_padding
|
207
207
|
|
208
208
|
def __init__(self, length: 'int | Callable[[dict[str, Any]], int]' = lambda _: -1,
|
209
|
-
base_schema: 'Optional[Type[
|
209
|
+
base_schema: 'Optional[Type[_TS]]' = None,
|
210
210
|
type_name: 'str' = 'type',
|
211
|
-
registry: 'Optional[defaultdict[int | StdlibEnum | AenumEnum, Type[
|
211
|
+
registry: 'Optional[defaultdict[int | StdlibEnum | AenumEnum, Type[_TS]]]' = None,
|
212
212
|
eool: 'Optional[int | StdlibEnum | AenumEnum]' = None,
|
213
213
|
callback: 'Callable[[Self, dict[str, Any]], None]' = lambda *_: None) -> 'None':
|
214
214
|
super().__init__(length, None, callback)
|
215
|
-
self._name = '<option>'
|
215
|
+
#self._name = '<option>'
|
216
216
|
self._eool = eool
|
217
217
|
self._option_padding = 0
|
218
218
|
|
@@ -228,7 +228,7 @@ class OptionField(ListField):
|
|
228
228
|
raise FieldValueError('Field <option> has no registry.')
|
229
229
|
self._registry = registry
|
230
230
|
|
231
|
-
def unpack(self, buffer: 'bytes | IO[bytes]', packet: 'dict[str, Any]') -> 'list[
|
231
|
+
def unpack(self, buffer: 'bytes | IO[bytes]', packet: 'dict[str, Any]') -> 'list[_TS]':
|
232
232
|
"""Unpack field value from :obj:`bytes`.
|
233
233
|
|
234
234
|
Args:
|
@@ -256,7 +256,7 @@ class OptionField(ListField):
|
|
256
256
|
new_packet = packet.copy()
|
257
257
|
new_packet[self.name] = OrderedMultiDict()
|
258
258
|
|
259
|
-
temp = [] # type: list[
|
259
|
+
temp = [] # type: list[_TS]
|
260
260
|
while length > 0:
|
261
261
|
# unpack option type using base schema
|
262
262
|
meta = self._base_schema.unpack(file, length, packet) # type: ignore[call-arg,misc,var-annotated]
|
pcapkit/corekit/fields/field.py
CHANGED
@@ -16,6 +16,8 @@ if TYPE_CHECKING:
|
|
16
16
|
|
17
17
|
from typing_extensions import Literal, Self
|
18
18
|
|
19
|
+
from pcapkit.protocols.schema.schema import Schema
|
20
|
+
|
19
21
|
_T = TypeVar('_T')
|
20
22
|
|
21
23
|
|
@@ -41,6 +43,10 @@ class _Field(Generic[_T], metaclass=abc.ABCMeta):
|
|
41
43
|
:meth:`~_Field.pack` should be considerate of the template format
|
42
44
|
and the actual value provided for packing.
|
43
45
|
|
46
|
+
Args:
|
47
|
+
*args: Arbitrary positional arguments.
|
48
|
+
**kwargs: Arbitrary keyword arguments.
|
49
|
+
|
44
50
|
"""
|
45
51
|
|
46
52
|
if TYPE_CHECKING:
|
@@ -98,9 +104,8 @@ class _Field(Generic[_T], metaclass=abc.ABCMeta):
|
|
98
104
|
Returns:
|
99
105
|
Updated field instance.
|
100
106
|
|
101
|
-
|
102
|
-
|
103
|
-
updating the current instance.
|
107
|
+
This method will return a new instance of :class:`_Field` instead of
|
108
|
+
updating the current instance.
|
104
109
|
|
105
110
|
"""
|
106
111
|
new_self = copy.copy(self)
|
@@ -109,7 +114,9 @@ class _Field(Generic[_T], metaclass=abc.ABCMeta):
|
|
109
114
|
|
110
115
|
# NOTE: This method is created as a placeholder for the necessary attributes.
|
111
116
|
def __init__(self, *args: 'Any', **kwargs: 'Any') -> 'None':
|
112
|
-
|
117
|
+
if not hasattr(self, '_name'):
|
118
|
+
self._name = f'<{type(self).__name__[:-5].lower()}>'
|
119
|
+
|
113
120
|
self._default = NoValue
|
114
121
|
self._template = '0s'
|
115
122
|
self._callback = lambda *_: None
|
@@ -119,6 +126,22 @@ class _Field(Generic[_T], metaclass=abc.ABCMeta):
|
|
119
126
|
return f'<{self.__class__.__name__}>'
|
120
127
|
return f'<{self.__class__.__name__} {self.name}>'
|
121
128
|
|
129
|
+
def __set_name__(self, owner: 'Schema', name: 'str') -> 'None':
|
130
|
+
"""Set field name and update field list (if applicable).
|
131
|
+
|
132
|
+
This method is to be called by the metaclass during class creation.
|
133
|
+
It is used to set the field name and update the field list, i.e.,
|
134
|
+
:attr:`Schema.__fields__ <pcapkit.protocols.schema.schema.Schema.__fields__>`
|
135
|
+
mapping dictionary.
|
136
|
+
|
137
|
+
"""
|
138
|
+
# Update field list (if applicable)
|
139
|
+
if hasattr(owner, '__fields__'):
|
140
|
+
owner.__fields__[name] = self
|
141
|
+
|
142
|
+
# Set field name
|
143
|
+
self.name = name
|
144
|
+
|
122
145
|
def pre_process(self, value: '_T', packet: 'dict[str, Any]') -> 'Any': # pylint: disable=unused-argument
|
123
146
|
"""Process field value before construction (packing).
|
124
147
|
|
@@ -204,7 +227,10 @@ class Field(_Field[_T], Generic[_T]):
|
|
204
227
|
def __init__(self, length: 'int | Callable[[dict[str, Any]], int]',
|
205
228
|
default: '_T | NoValueType' = NoValue,
|
206
229
|
callback: 'Callable[[Self, dict[str, Any]], None]' = lambda *_: None) -> 'None':
|
207
|
-
self._name = '<unknown>'
|
230
|
+
#self._name = '<unknown>'
|
231
|
+
if not hasattr(self, '_name'):
|
232
|
+
self._name = f'<{type(self).__name__[:-5].lower()}>'
|
233
|
+
|
208
234
|
self._default = default
|
209
235
|
self._callback = callback
|
210
236
|
|
@@ -222,9 +248,8 @@ class Field(_Field[_T], Generic[_T]):
|
|
222
248
|
Returns:
|
223
249
|
New instance of :class:`Field`.
|
224
250
|
|
225
|
-
|
226
|
-
|
227
|
-
updating the current instance.
|
251
|
+
This method will return a new instance of :class:`Field` instead of
|
252
|
+
updating the current instance.
|
228
253
|
|
229
254
|
"""
|
230
255
|
new_self = copy.copy(self)
|
pcapkit/corekit/fields/misc.py
CHANGED
@@ -141,9 +141,8 @@ class ConditionalField(_Field[_TC]):
|
|
141
141
|
Returns:
|
142
142
|
Updated field instance.
|
143
143
|
|
144
|
-
|
145
|
-
|
146
|
-
instead of updating the current instance.
|
144
|
+
This method will return a new instance of :class:`ConditionalField`
|
145
|
+
instead of updating the current instance.
|
147
146
|
|
148
147
|
"""
|
149
148
|
new_self = copy.copy(self)
|
@@ -273,7 +272,7 @@ class PayloadField(_Field[_TP]):
|
|
273
272
|
default: '_TP | NoValueType | bytes' = NoValue,
|
274
273
|
protocol: 'Optional[Type[_TP]]' = None,
|
275
274
|
callback: 'Callable[[Self, dict[str, Any]], None]' = lambda *_: None) -> 'None':
|
276
|
-
self._name = '<payload>'
|
275
|
+
#self._name = '<payload>'
|
277
276
|
self._default = default # type: ignore[assignment]
|
278
277
|
self._protocol = protocol # type: ignore[assignment]
|
279
278
|
self._callback = callback
|
@@ -293,9 +292,8 @@ class PayloadField(_Field[_TP]):
|
|
293
292
|
Returns:
|
294
293
|
Updated field instance.
|
295
294
|
|
296
|
-
|
297
|
-
|
298
|
-
instead of updating the current instance.
|
295
|
+
This method will return a new instance of :class:`PayloadField`
|
296
|
+
instead of updating the current instance.
|
299
297
|
|
300
298
|
"""
|
301
299
|
new_self = copy.copy(self)
|
@@ -409,7 +407,7 @@ class SwitchField(_Field[_TC]):
|
|
409
407
|
return self._field
|
410
408
|
|
411
409
|
def __init__(self, selector: 'Callable[[dict[str, Any]], _Field[_TC]]' = lambda _: NoValueField()) -> 'None': # type: ignore[assignment,return-value]
|
412
|
-
self._name = '<switch>'
|
410
|
+
#self._name = '<switch>'
|
413
411
|
self._field = cast('_Field[_TC]', NoValueField())
|
414
412
|
self._selector = selector
|
415
413
|
|
@@ -422,9 +420,8 @@ class SwitchField(_Field[_TC]):
|
|
422
420
|
Returns:
|
423
421
|
New field instance.
|
424
422
|
|
425
|
-
|
426
|
-
|
427
|
-
instead of updating the current instance.
|
423
|
+
This method will return a new instance of :class:`SwitchField`
|
424
|
+
instead of updating the current instance.
|
428
425
|
|
429
426
|
"""
|
430
427
|
new_self = copy.copy(self)
|
@@ -527,7 +524,7 @@ class SchemaField(_Field[_TS]):
|
|
527
524
|
default: '_TS | NoValueType | bytes' = NoValue,
|
528
525
|
packet: 'Optional[dict[str, Any]]' = None,
|
529
526
|
callback: 'Callable[[Self, dict[str, Any]], None]' = lambda *_: None) -> 'None':
|
530
|
-
self._name = '<schema>'
|
527
|
+
#self._name = '<schema>'
|
531
528
|
self._callback = callback
|
532
529
|
|
533
530
|
if packet is None:
|
@@ -557,9 +554,8 @@ class SchemaField(_Field[_TS]):
|
|
557
554
|
Returns:
|
558
555
|
New field instance.
|
559
556
|
|
560
|
-
|
561
|
-
|
562
|
-
instead of updating the current instance.
|
557
|
+
This method will return a new instance of :class:`SchemaField`
|
558
|
+
instead of updating the current instance.
|
563
559
|
|
564
560
|
"""
|
565
561
|
new_self = copy.copy(self)
|
@@ -679,7 +675,7 @@ class ForwardMatchField(_Field[_TC]):
|
|
679
675
|
return self._field
|
680
676
|
|
681
677
|
def __init__(self, field: '_Field[_TC]') -> 'None':
|
682
|
-
self._name = '<forward_match>'
|
678
|
+
#self._name = '<forward_match>'
|
683
679
|
self._field = field
|
684
680
|
|
685
681
|
def __call__(self, packet: 'dict[str, Any]') -> 'Self':
|
@@ -691,9 +687,8 @@ class ForwardMatchField(_Field[_TC]):
|
|
691
687
|
Returns:
|
692
688
|
Updated field instance.
|
693
689
|
|
694
|
-
|
695
|
-
|
696
|
-
instead of updating the current instance.
|
690
|
+
This method will return a new instance of :class:`ConditionalField`
|
691
|
+
instead of updating the current instance.
|
697
692
|
|
698
693
|
"""
|
699
694
|
new_self = copy.copy(self)
|
@@ -92,9 +92,8 @@ class NumberField(Field[int], Generic[_T]):
|
|
92
92
|
Returns:
|
93
93
|
New instance of :class:`NumberField`.
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
updating the current instance.
|
95
|
+
This method will return a new instance of :class:`NumberField` instead of
|
96
|
+
updating the current instance.
|
98
97
|
|
99
98
|
"""
|
100
99
|
new_self = super().__call__(packet)
|
@@ -56,9 +56,8 @@ class _TextField(Field[_T], Generic[_T]):
|
|
56
56
|
Returns:
|
57
57
|
New instance of :class:`_TextField`.
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
updating the current instance.
|
59
|
+
This method will return a new instance of :class:`_TextField` instead of
|
60
|
+
updating the current instance.
|
62
61
|
|
63
62
|
"""
|
64
63
|
new_self = super().__call__(packet)
|
pcapkit/corekit/infoclass.py
CHANGED
@@ -10,6 +10,7 @@ designed to work alike :func:`dataclasses.dataclass` as introduced
|
|
10
10
|
in :pep:`557`.
|
11
11
|
|
12
12
|
"""
|
13
|
+
import abc
|
13
14
|
import collections.abc
|
14
15
|
import enum
|
15
16
|
import itertools
|
@@ -49,6 +50,11 @@ def info_final(cls: 'ST', *, _finalised: 'bool' = True) -> 'ST':
|
|
49
50
|
class. It can be useful to reduce runtime generation
|
50
51
|
time as well as caching already generated attributes.
|
51
52
|
|
53
|
+
Notes:
|
54
|
+
The decorator should only be used on the *final*
|
55
|
+
class, otherwise, any subclasses derived from a
|
56
|
+
finalised info class will not be re-finalised.
|
57
|
+
|
52
58
|
Args:
|
53
59
|
cls: Info class.
|
54
60
|
_finalised: Whether to make the info class as finalised.
|
@@ -56,11 +62,6 @@ def info_final(cls: 'ST', *, _finalised: 'bool' = True) -> 'ST':
|
|
56
62
|
Returns:
|
57
63
|
Finalised info class.
|
58
64
|
|
59
|
-
Notes:
|
60
|
-
The decorator should only be used on the *final*
|
61
|
-
class, otherwise, any subclasses derived from a
|
62
|
-
finalised info class will not be re-finalised.
|
63
|
-
|
64
65
|
:meta decorator:
|
65
66
|
"""
|
66
67
|
if cls.__finalised__ == FinalisedState.FINAL:
|
@@ -140,7 +141,59 @@ def info_final(cls: 'ST', *, _finalised: 'bool' = True) -> 'ST':
|
|
140
141
|
return final(cls)
|
141
142
|
|
142
143
|
|
143
|
-
class
|
144
|
+
class InfoMeta(abc.ABCMeta):
|
145
|
+
"""Meta class to add dynamic support to :class:`Info`.
|
146
|
+
|
147
|
+
This meta class is used to generate necessary attributes for the
|
148
|
+
:class:`Info` class. It can be useful to reduce runtime generation
|
149
|
+
cost as well as caching already generated attributes.
|
150
|
+
|
151
|
+
* :attr:`Info.__additional__` and :attr:`Info.__excluded__` are
|
152
|
+
lists of additional and excluded field names, which are used to
|
153
|
+
determine certain names to be included or excluded from the field
|
154
|
+
dictionary. They will be automatically populated from the class
|
155
|
+
attributes of the :class:`Info` class and its base classes.
|
156
|
+
|
157
|
+
.. note::
|
158
|
+
|
159
|
+
This is implemented thru the :meth:`__new__` method, which will
|
160
|
+
inherit the additional and excluded field names from the base
|
161
|
+
classes, as well as populating the additional and excluded field
|
162
|
+
from the subclass attributes.
|
163
|
+
|
164
|
+
.. code-block:: python
|
165
|
+
|
166
|
+
class A(Info):
|
167
|
+
__additional__ = ['a', 'b']
|
168
|
+
|
169
|
+
class B(A):
|
170
|
+
__additional__ = ['c', 'd']
|
171
|
+
|
172
|
+
class C(B):
|
173
|
+
__additional__ = ['e', 'f']
|
174
|
+
|
175
|
+
print(A.__additional__) # ['a', 'b']
|
176
|
+
print(B.__additional__) # ['a', 'b', 'c', 'd']
|
177
|
+
print(C.__additional__) # ['a', 'b', 'c', 'd', 'e', 'f']
|
178
|
+
|
179
|
+
"""
|
180
|
+
|
181
|
+
def __new__(cls, name: 'str', bases: 'tuple[type, ...]', attrs: 'dict[str, Any]', **kwargs: 'Any') -> 'Type[Info]':
|
182
|
+
if '__additional__' not in attrs:
|
183
|
+
attrs['__additional__'] = []
|
184
|
+
if '__excluded__' not in attrs:
|
185
|
+
attrs['__excluded__'] = []
|
186
|
+
|
187
|
+
for base in bases:
|
188
|
+
if hasattr(base, '__additional__'):
|
189
|
+
attrs['__additional__'].extend(
|
190
|
+
name for name in base.__additional__ if name not in attrs['__additional__'])
|
191
|
+
if hasattr(base, '__excluded__'):
|
192
|
+
attrs['__excluded__'].extend(name for name in base.__excluded__ if name not in attrs['__excluded__'])
|
193
|
+
return super().__new__(cls, name, bases, attrs, **kwargs) # type: ignore[return-value]
|
194
|
+
|
195
|
+
|
196
|
+
class Info(Mapping[str, VT], Generic[VT], metaclass=InfoMeta):
|
144
197
|
"""Turn dictionaries into :obj:`object` like instances.
|
145
198
|
|
146
199
|
* :class:`Info` objects inherit from :obj:`dict` type
|
pcapkit/corekit/protochain.py
CHANGED
@@ -26,7 +26,14 @@ __all__ = ['ProtoChain']
|
|
26
26
|
|
27
27
|
|
28
28
|
class ProtoChain(collections.abc.Sequence):
|
29
|
-
"""Protocols chain.
|
29
|
+
"""Protocols chain.
|
30
|
+
|
31
|
+
Args:
|
32
|
+
proto: New protocol class on the top stack.
|
33
|
+
alias: New protocol alias on the top stack.
|
34
|
+
basis: Original protocol chain as base stacks.
|
35
|
+
|
36
|
+
"""
|
30
37
|
|
31
38
|
#: Internal data storage for protocol chain.
|
32
39
|
__data__: 'tuple[tuple[str, Type[Protocol]], ...]'
|