Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/volatile.py: 32%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) Philippe Biondi <phil@secdev.org>
5# Copyright (C) Michael Farrell <micolous+git@gmail.com>
6# Copyright (C) Gauthier Sebaux
8"""
9Fields that hold random numbers.
10"""
12import copy
13import random
14import time
15import math
16import re
17import uuid
18import struct
19import string
21from scapy.base_classes import Net
22from scapy.compat import bytes_encode, chb, plain_str
23from scapy.utils import corrupt_bits, corrupt_bytes
25from typing import (
26 List,
27 TypeVar,
28 Generic,
29 Set,
30 Union,
31 Any,
32 Dict,
33 Optional,
34 Tuple,
35 cast,
36)
38####################
39# Random numbers #
40####################
43class RandomEnumeration:
44 """iterate through a sequence in random order.
45 When all the values have been drawn, if forever=1, the drawing is done again. # noqa: E501
46 If renewkeys=0, the draw will be in the same order, guaranteeing that the same # noqa: E501
47 number will be drawn in not less than the number of integers of the sequence""" # noqa: E501
49 def __init__(self, inf, sup, seed=None, forever=1, renewkeys=0):
50 # type: (int, int, Optional[int], int, int) -> None
51 self.forever = forever
52 self.renewkeys = renewkeys
53 self.inf = inf
54 self.rnd = random.Random(seed)
55 self.sbox_size = 256
57 self.top = sup - inf + 1
59 n = 0
60 while (1 << n) < self.top:
61 n += 1
62 self.n = n
64 self.fs = min(3, (n + 1) // 2)
65 self.fsmask = 2**self.fs - 1
66 self.rounds = max(self.n, 3)
67 self.turns = 0
68 self.i = 0
70 def __iter__(self):
71 # type: () -> RandomEnumeration
72 return self
74 def next(self):
75 # type: () -> int
76 while True:
77 if self.turns == 0 or (self.i == 0 and self.renewkeys):
78 self.cnt_key = self.rnd.randint(0, 2**self.n - 1)
79 self.sbox = [self.rnd.randint(0, self.fsmask)
80 for _ in range(self.sbox_size)]
81 self.turns += 1
82 while self.i < 2**self.n:
83 ct = self.i ^ self.cnt_key
84 self.i += 1
85 for _ in range(self.rounds): # Unbalanced Feistel Network
86 lsb = ct & self.fsmask
87 ct >>= self.fs
88 lsb ^= self.sbox[ct % self.sbox_size]
89 ct |= lsb << (self.n - self.fs)
91 if ct < self.top:
92 return self.inf + ct
93 self.i = 0
94 if not self.forever:
95 raise StopIteration
96 __next__ = next
99_T = TypeVar('_T')
102class VolatileValue(Generic[_T]):
103 def __repr__(self):
104 # type: () -> str
105 return "<%s>" % self.__class__.__name__
107 def _command_args(self):
108 # type: () -> str
109 return ''
111 def command(self, json=False):
112 # type: (bool) -> Union[Dict[str, str], str]
113 if json:
114 return {"type": self.__class__.__name__, "value": self._command_args()}
115 else:
116 return "%s(%s)" % (self.__class__.__name__, self._command_args())
118 def __eq__(self, other):
119 # type: (Any) -> bool
120 x = self._fix()
121 y = other._fix() if isinstance(other, VolatileValue) else other
122 if not isinstance(x, type(y)):
123 return False
124 return bool(x == y)
126 def __ne__(self, other):
127 # type: (Any) -> bool
128 # Python 2.7 compat
129 return not self == other
131 __hash__ = None # type: ignore
133 def __getattr__(self, attr):
134 # type: (str) -> Any
135 if attr in ["__setstate__", "__getstate__"]:
136 raise AttributeError(attr)
137 return getattr(self._fix(), attr)
139 def __str__(self):
140 # type: () -> str
141 return str(self._fix())
143 def __bytes__(self):
144 # type: () -> bytes
145 return bytes_encode(self._fix())
147 def __len__(self):
148 # type: () -> int
149 # Does not work for some types (int?)
150 return len(self._fix()) # type: ignore
152 def copy(self):
153 # type: () -> Any
154 return copy.copy(self)
156 def _fix(self):
157 # type: () -> _T
158 return cast(_T, None)
161class RandField(VolatileValue[_T], Generic[_T]):
162 pass
165_I = TypeVar("_I", int, float)
168class _RandNumeral(RandField[_I]):
169 """Implements integer management in RandField"""
171 def __int__(self):
172 # type: () -> int
173 return int(self._fix())
175 def __index__(self):
176 # type: () -> int
177 return int(self)
179 def __nonzero__(self):
180 # type: () -> bool
181 return bool(self._fix())
182 __bool__ = __nonzero__
184 def __add__(self, other):
185 # type: (_I) -> _I
186 return self._fix() + other
188 def __radd__(self, other):
189 # type: (_I) -> _I
190 return other + self._fix()
192 def __sub__(self, other):
193 # type: (_I) -> _I
194 return self._fix() - other
196 def __rsub__(self, other):
197 # type: (_I) -> _I
198 return other - self._fix()
200 def __mul__(self, other):
201 # type: (_I) -> _I
202 return self._fix() * other
204 def __rmul__(self, other):
205 # type: (_I) -> _I
206 return other * self._fix()
208 def __floordiv__(self, other):
209 # type: (_I) -> float
210 return self._fix() / other
211 __div__ = __floordiv__
213 def __lt__(self, other):
214 # type: (_I) -> bool
215 return self._fix() < other
217 def __le__(self, other):
218 # type: (_I) -> bool
219 return self._fix() <= other
221 def __ge__(self, other):
222 # type: (_I) -> bool
223 return self._fix() >= other
225 def __gt__(self, other):
226 # type: (_I) -> bool
227 return self._fix() > other
230class RandNum(_RandNumeral[int]):
231 """Instances evaluate to random integers in selected range"""
232 min = 0
233 max = 0
235 def __init__(self, min, max):
236 # type: (int, int) -> None
237 self.min = min
238 self.max = max
240 def _command_args(self):
241 # type: () -> str
242 if self.__class__.__name__ == 'RandNum':
243 return "min=%r, max=%r" % (self.min, self.max)
244 return super(RandNum, self)._command_args()
246 def _fix(self):
247 # type: () -> int
248 return random.randrange(self.min, self.max + 1)
250 def __lshift__(self, other):
251 # type: (int) -> int
252 return self._fix() << other
254 def __rshift__(self, other):
255 # type: (int) -> int
256 return self._fix() >> other
258 def __and__(self, other):
259 # type: (int) -> int
260 return self._fix() & other
262 def __rand__(self, other):
263 # type: (int) -> int
264 return other & self._fix()
266 def __or__(self, other):
267 # type: (int) -> int
268 return self._fix() | other
270 def __ror__(self, other):
271 # type: (int) -> int
272 return other | self._fix()
275class RandFloat(_RandNumeral[float]):
276 def __init__(self, min, max):
277 # type: (int, int) -> None
278 self.min = min
279 self.max = max
281 def _fix(self):
282 # type: () -> float
283 return random.uniform(self.min, self.max)
286class RandBinFloat(RandFloat):
287 def _fix(self):
288 # type: () -> float
289 return cast(
290 float,
291 struct.unpack("!f", bytes(RandBin(4)))[0]
292 )
295class RandNumGamma(RandNum):
296 def __init__(self, alpha, beta):
297 # type: (int, int) -> None
298 self.alpha = alpha
299 self.beta = beta
301 def _command_args(self):
302 # type: () -> str
303 return "alpha=%r, beta=%r" % (self.alpha, self.beta)
305 def _fix(self):
306 # type: () -> int
307 return int(round(random.gammavariate(self.alpha, self.beta)))
310class RandNumGauss(RandNum):
311 def __init__(self, mu, sigma):
312 # type: (int, int) -> None
313 self.mu = mu
314 self.sigma = sigma
316 def _command_args(self):
317 # type: () -> str
318 return "mu=%r, sigma=%r" % (self.mu, self.sigma)
320 def _fix(self):
321 # type: () -> int
322 return int(round(random.gauss(self.mu, self.sigma)))
325class RandNumExpo(RandNum):
326 def __init__(self, lambd, base=0):
327 # type: (float, int) -> None
328 self.lambd = lambd
329 self.base = base
331 def _command_args(self):
332 # type: () -> str
333 ret = "lambd=%r" % self.lambd
334 if self.base != 0:
335 ret += ", base=%r" % self.base
336 return ret
338 def _fix(self):
339 # type: () -> int
340 return self.base + int(round(random.expovariate(self.lambd)))
343class RandEnum(RandNum):
344 """Instances evaluate to integer sampling without replacement from the given interval""" # noqa: E501
346 def __init__(self, min, max, seed=None):
347 # type: (int, int, Optional[int]) -> None
348 self._seed = seed
349 self.seq = RandomEnumeration(min, max, seed)
350 super(RandEnum, self).__init__(min, max)
352 def _command_args(self):
353 # type: () -> str
354 ret = "min=%r, max=%r" % (self.min, self.max)
355 if self._seed:
356 ret += ", seed=%r" % self._seed
357 return ret
359 def _fix(self):
360 # type: () -> int
361 return next(self.seq)
364class RandByte(RandNum):
365 def __init__(self):
366 # type: () -> None
367 RandNum.__init__(self, 0, 2**8 - 1)
370class RandSByte(RandNum):
371 def __init__(self):
372 # type: () -> None
373 RandNum.__init__(self, -2**7, 2**7 - 1)
376class RandShort(RandNum):
377 def __init__(self):
378 # type: () -> None
379 RandNum.__init__(self, 0, 2**16 - 1)
382class RandSShort(RandNum):
383 def __init__(self):
384 # type: () -> None
385 RandNum.__init__(self, -2**15, 2**15 - 1)
388class RandInt(RandNum):
389 def __init__(self):
390 # type: () -> None
391 RandNum.__init__(self, 0, 2**32 - 1)
394class RandSInt(RandNum):
395 def __init__(self):
396 # type: () -> None
397 RandNum.__init__(self, -2**31, 2**31 - 1)
400class RandLong(RandNum):
401 def __init__(self):
402 # type: () -> None
403 RandNum.__init__(self, 0, 2**64 - 1)
406class RandSLong(RandNum):
407 def __init__(self):
408 # type: () -> None
409 RandNum.__init__(self, -2**63, 2**63 - 1)
412class RandEnumByte(RandEnum):
413 def __init__(self):
414 # type: () -> None
415 RandEnum.__init__(self, 0, 2**8 - 1)
418class RandEnumSByte(RandEnum):
419 def __init__(self):
420 # type: () -> None
421 RandEnum.__init__(self, -2**7, 2**7 - 1)
424class RandEnumShort(RandEnum):
425 def __init__(self):
426 # type: () -> None
427 RandEnum.__init__(self, 0, 2**16 - 1)
430class RandEnumSShort(RandEnum):
431 def __init__(self):
432 # type: () -> None
433 RandEnum.__init__(self, -2**15, 2**15 - 1)
436class RandEnumInt(RandEnum):
437 def __init__(self):
438 # type: () -> None
439 RandEnum.__init__(self, 0, 2**32 - 1)
442class RandEnumSInt(RandEnum):
443 def __init__(self):
444 # type: () -> None
445 RandEnum.__init__(self, -2**31, 2**31 - 1)
448class RandEnumLong(RandEnum):
449 def __init__(self):
450 # type: () -> None
451 RandEnum.__init__(self, 0, 2**64 - 1)
454class RandEnumSLong(RandEnum):
455 def __init__(self):
456 # type: () -> None
457 RandEnum.__init__(self, -2**63, 2**63 - 1)
460class RandEnumKeys(RandEnum):
461 """Picks a random value from dict keys list. """
463 def __init__(self, enum, seed=None):
464 # type: (Dict[Any, Any], Optional[int]) -> None
465 self.enum = list(enum)
466 RandEnum.__init__(self, 0, len(self.enum) - 1, seed)
468 def _command_args(self):
469 # type: () -> str
470 # Note: only outputs the list of keys, but values are irrelevant anyway
471 ret = "enum=%r" % self.enum
472 if self._seed:
473 ret += ", seed=%r" % self._seed
474 return ret
476 def _fix(self):
477 # type: () -> Any
478 return self.enum[next(self.seq)]
481class RandChoice(RandField[Any]):
482 def __init__(self, *args):
483 # type: (*Any) -> None
484 if not args:
485 raise TypeError("RandChoice needs at least one choice")
486 self._choice = list(args)
488 def _command_args(self):
489 # type: () -> str
490 return ", ".join(self._choice)
492 def _fix(self):
493 # type: () -> Any
494 return random.choice(self._choice)
497_S = TypeVar("_S", bytes, str)
500class _RandString(RandField[_S], Generic[_S]):
501 def __str__(self):
502 # type: () -> str
503 return plain_str(self._fix())
505 def __bytes__(self):
506 # type: () -> bytes
507 return bytes_encode(self._fix())
509 def __mul__(self, n):
510 # type: (int) -> _S
511 return self._fix() * n
514class RandString(_RandString[str]):
515 _DEFAULT_CHARS = (string.ascii_uppercase + string.ascii_lowercase +
516 string.digits)
518 def __init__(self, size=None, chars=_DEFAULT_CHARS):
519 # type: (Optional[Union[int, RandNum]], str) -> None
520 if size is None:
521 size = RandNumExpo(0.01)
522 self.size = size
523 self.chars = chars
525 def _command_args(self):
526 # type: () -> str
527 ret = ""
528 if isinstance(self.size, VolatileValue):
529 if self.size.lambd != 0.01 or self.size.base != 0:
530 ret += "size=%r" % self.size.command()
531 else:
532 ret += "size=%r" % self.size
534 if self.chars != self._DEFAULT_CHARS:
535 ret += ", chars=%r" % self.chars
536 return ret
538 def _fix(self):
539 # type: () -> str
540 s = ""
541 for _ in range(int(self.size)):
542 s += random.choice(self.chars)
543 return s
546class RandBin(_RandString[bytes]):
547 _DEFAULT_CHARS = b"".join(chb(c) for c in range(256))
549 def __init__(self, size=None, chars=_DEFAULT_CHARS):
550 # type: (Optional[Union[int, RandNum]], bytes) -> None
551 if size is None:
552 size = RandNumExpo(0.01)
553 self.size = size
554 self.chars = chars
556 def _command_args(self):
557 # type: () -> str
558 if not isinstance(self.size, VolatileValue):
559 return "size=%r" % self.size
561 if isinstance(self.size, RandNumExpo) and \
562 self.size.lambd == 0.01 and self.size.base == 0:
563 # Default size for RandString, skip
564 return ""
565 return "size=%r" % self.size.command()
567 def _fix(self):
568 # type: () -> bytes
569 s = b""
570 for _ in range(int(self.size)):
571 s += struct.pack("!B", random.choice(self.chars))
572 return s
575class RandTermString(RandBin):
576 def __init__(self, size, term):
577 # type: (Union[int, RandNum], bytes) -> None
578 self.term = bytes_encode(term)
579 super(RandTermString, self).__init__(size=size)
580 self.chars = self.chars.replace(self.term, b"")
582 def _command_args(self):
583 # type: () -> str
584 return ", ".join((super(RandTermString, self)._command_args(),
585 "term=%r" % self.term))
587 def _fix(self):
588 # type: () -> bytes
589 return RandBin._fix(self) + self.term
592class RandIP(_RandString[str]):
593 _DEFAULT_IPTEMPLATE = "0.0.0.0/0"
595 def __init__(self, iptemplate=_DEFAULT_IPTEMPLATE):
596 # type: (str) -> None
597 super(RandIP, self).__init__()
598 self.ip = Net(iptemplate)
600 def _command_args(self):
601 # type: () -> str
602 rep = "%s/%s" % (self.ip.net, self.ip.mask)
603 if rep == self._DEFAULT_IPTEMPLATE:
604 return ""
605 return "iptemplate=%r" % rep
607 def _fix(self):
608 # type: () -> str
609 return self.ip.choice()
612class RandMAC(_RandString[str]):
613 def __init__(self, _template="*"):
614 # type: (str) -> None
615 super(RandMAC, self).__init__()
616 self._template = _template
617 _template += ":*:*:*:*:*"
618 template = _template.split(":")
619 self.mac = () # type: Tuple[Union[int, RandNum], ...]
620 for i in range(6):
621 v = 0 # type: Union[int, RandNum]
622 if template[i] == "*":
623 v = RandByte()
624 elif "-" in template[i]:
625 x, y = template[i].split("-")
626 v = RandNum(int(x, 16), int(y, 16))
627 else:
628 v = int(template[i], 16)
629 self.mac += (v,)
631 def _command_args(self):
632 # type: () -> str
633 if self._template == "*":
634 return ""
635 return "template=%r" % self._template
637 def _fix(self):
638 # type: () -> str
639 return "%02x:%02x:%02x:%02x:%02x:%02x" % self.mac # type: ignore
642class RandIP6(_RandString[str]):
643 def __init__(self, ip6template="**"):
644 # type: (str) -> None
645 super(RandIP6, self).__init__()
646 self.tmpl = ip6template
647 self.sp = [] # type: List[Union[int, RandNum, str]]
648 for v in self.tmpl.split(":"):
649 if not v or v == "**":
650 self.sp.append(v)
651 continue
652 if "-" in v:
653 a, b = v.split("-")
654 elif v == "*":
655 a = b = ""
656 else:
657 a = b = v
659 if not a:
660 a = "0"
661 if not b:
662 b = "ffff"
663 if a == b:
664 self.sp.append(int(a, 16))
665 else:
666 self.sp.append(RandNum(int(a, 16), int(b, 16)))
667 self.variable = "" in self.sp
668 self.multi = self.sp.count("**")
670 def _command_args(self):
671 # type: () -> str
672 if self.tmpl == "**":
673 return ""
674 return "ip6template=%r" % self.tmpl
676 def _fix(self):
677 # type: () -> str
678 nbm = self.multi
679 ip = [] # type: List[str]
680 for i, n in enumerate(self.sp):
681 if n == "**":
682 nbm -= 1
683 remain = 8 - (len(self.sp) - i - 1) - len(ip) + nbm
684 if "" in self.sp:
685 remain += 1
686 if nbm or self.variable:
687 remain = random.randint(0, remain)
688 for j in range(remain):
689 ip.append("%04x" % random.randint(0, 65535))
690 elif isinstance(n, RandNum):
691 ip.append("%04x" % int(n))
692 elif n == 0:
693 ip.append("0")
694 elif not n:
695 ip.append("")
696 else:
697 ip.append("%04x" % int(n))
698 if len(ip) == 9:
699 ip.remove("")
700 if ip[-1] == "":
701 ip[-1] = "0"
702 return ":".join(ip)
705class RandOID(_RandString[str]):
706 def __init__(self, fmt=None, depth=RandNumExpo(0.1), idnum=RandNumExpo(0.01)): # noqa: E501
707 # type: (Optional[str], RandNumExpo, RandNumExpo) -> None
708 super(RandOID, self).__init__()
709 self.ori_fmt = fmt
710 self.fmt = None # type: Optional[List[Union[str, Tuple[int, ...]]]]
711 if fmt is not None:
712 self.fmt = [
713 tuple(map(int, x.split("-"))) if "-" in x else x
714 for x in fmt.split(".")
715 ]
716 self.depth = depth
717 self.idnum = idnum
719 def _command_args(self):
720 # type: () -> str
721 ret = []
722 if self.fmt:
723 ret.append("fmt=%r" % self.ori_fmt)
725 if not isinstance(self.depth, VolatileValue):
726 ret.append("depth=%r" % self.depth)
727 elif not isinstance(self.depth, RandNumExpo) or \
728 self.depth.lambd != 0.1 or self.depth.base != 0:
729 ret.append("depth=%s" % self.depth.command())
731 if not isinstance(self.idnum, VolatileValue):
732 ret.append("idnum=%r" % self.idnum)
733 elif not isinstance(self.idnum, RandNumExpo) or \
734 self.idnum.lambd != 0.01 or self.idnum.base != 0:
735 ret.append("idnum=%s" % self.idnum.command())
737 return ", ".join(ret)
739 def __repr__(self):
740 # type: () -> str
741 if self.ori_fmt is None:
742 return "<%s>" % self.__class__.__name__
743 else:
744 return "<%s [%s]>" % (self.__class__.__name__, self.ori_fmt)
746 def _fix(self):
747 # type: () -> str
748 if self.fmt is None:
749 return ".".join(str(self.idnum) for _ in range(1 + self.depth))
750 else:
751 oid = []
752 for i in self.fmt:
753 if i == "*":
754 oid.append(str(self.idnum))
755 elif i == "**":
756 oid += [str(self.idnum) for i in range(1 + self.depth)]
757 elif isinstance(i, tuple):
758 oid.append(str(random.randrange(*i)))
759 else:
760 oid.append(i)
761 return ".".join(oid)
764class RandRegExp(RandField[str]):
765 def __init__(self, regexp, lambda_=0.3):
766 # type: (str, float) -> None
767 self._regexp = regexp
768 self._lambda = lambda_
770 def _command_args(self):
771 # type: () -> str
772 ret = "regexp=%r" % self._regexp
773 if self._lambda != 0.3:
774 ret += ", lambda_=%r" % self._lambda
775 return ret
777 special_sets = {
778 "[:alnum:]": "[a-zA-Z0-9]",
779 "[:alpha:]": "[a-zA-Z]",
780 "[:ascii:]": "[\x00-\x7F]",
781 "[:blank:]": "[ \t]",
782 "[:cntrl:]": "[\x00-\x1F\x7F]",
783 "[:digit:]": "[0-9]",
784 "[:graph:]": "[\x21-\x7E]",
785 "[:lower:]": "[a-z]",
786 "[:print:]": "[\x20-\x7E]",
787 "[:punct:]": "[!\"\\#$%&'()*+,\\-./:;<=>?@\\[\\\\\\]^_{|}~]",
788 "[:space:]": "[ \t\r\n\v\f]",
789 "[:upper:]": "[A-Z]",
790 "[:word:]": "[A-Za-z0-9_]",
791 "[:xdigit:]": "[A-Fa-f0-9]",
792 }
794 @staticmethod
795 def choice_expand(s):
796 # type: (str) -> str
797 m = ""
798 invert = s and s[0] == "^"
799 while True:
800 p = s.find("-")
801 if p < 0:
802 break
803 if p == 0 or p == len(s) - 1:
804 m = "-"
805 if p:
806 s = s[:-1]
807 else:
808 s = s[1:]
809 else:
810 c1 = s[p - 1]
811 c2 = s[p + 1]
812 rng = "".join(map(chr, range(ord(c1), ord(c2) + 1)))
813 s = s[:p - 1] + rng + s[p + 1:]
814 res = m + s
815 if invert:
816 res = "".join(chr(x) for x in range(256) if chr(x) not in res)
817 return res
819 @staticmethod
820 def stack_fix(lst, index):
821 # type: (List[Any], List[Any]) -> str
822 r = ""
823 mul = 1
824 for e in lst:
825 if isinstance(e, list):
826 if mul != 1:
827 mul = mul - 1
828 r += RandRegExp.stack_fix(e[1:] * mul, index)
829 # only the last iteration should be kept for back reference
830 f = RandRegExp.stack_fix(e[1:], index)
831 for i, idx in enumerate(index):
832 if e is idx:
833 index[i] = f
834 r += f
835 mul = 1
836 elif isinstance(e, tuple):
837 kind, val = e
838 if kind == "cite":
839 r += index[val - 1]
840 elif kind == "repeat":
841 mul = val
843 elif kind == "choice":
844 if mul == 1:
845 c = random.choice(val)
846 r += RandRegExp.stack_fix(c[1:], index)
847 else:
848 r += RandRegExp.stack_fix([e] * mul, index)
849 mul = 1
850 else:
851 if mul != 1:
852 r += RandRegExp.stack_fix([e] * mul, index)
853 mul = 1
854 else:
855 r += str(e)
856 return r
858 def _fix(self):
859 # type: () -> str
860 stack = [None]
861 index = []
862 # Give up on typing this
863 current = stack # type: Any
864 i = 0
865 regexp = self._regexp
866 for k, v in self.special_sets.items():
867 regexp = regexp.replace(k, v)
868 ln = len(regexp)
869 interp = True
870 while i < ln:
871 c = regexp[i]
872 i += 1
874 if c == '(':
875 current = [current]
876 current[0].append(current)
877 elif c == '|':
878 p = current[0]
879 ch = p[-1]
880 if not isinstance(ch, tuple):
881 ch = ("choice", [current])
882 p[-1] = ch
883 else:
884 ch[1].append(current)
885 current = [p]
886 elif c == ')':
887 ch = current[0][-1]
888 if isinstance(ch, tuple):
889 ch[1].append(current)
890 index.append(current)
891 current = current[0]
892 elif c == '[' or c == '{':
893 current = [current]
894 current[0].append(current)
895 interp = False
896 elif c == ']':
897 current = current[0]
898 choice = RandRegExp.choice_expand("".join(current.pop()[1:]))
899 current.append(RandChoice(*list(choice)))
900 interp = True
901 elif c == '}':
902 current = current[0]
903 num = "".join(current.pop()[1:])
904 e = current.pop()
905 if "," not in num:
906 current.append([current] + [e] * int(num))
907 else:
908 num_min, num_max = num.split(",")
909 if not num_min:
910 num_min = "0"
911 if num_max:
912 n = RandNum(int(num_min), int(num_max))
913 else:
914 n = RandNumExpo(self._lambda, base=int(num_min))
915 current.append(("repeat", n))
916 current.append(e)
917 interp = True
918 elif c == '\\':
919 c = regexp[i]
920 if c == "s":
921 current.append(RandChoice(" ", "\t"))
922 elif c in "0123456789":
923 current.append("cite", ord(c) - 0x30)
924 i += 1
925 elif not interp:
926 current.append(c)
927 elif c == '+':
928 e = current.pop()
929 current.append([current] + [e] * (int(random.expovariate(self._lambda)) + 1)) # noqa: E501
930 elif c == '*':
931 e = current.pop()
932 current.append([current] + [e] * int(random.expovariate(self._lambda))) # noqa: E501
933 elif c == '?':
934 if random.randint(0, 1):
935 current.pop()
936 elif c == '.':
937 current.append(RandChoice(*[chr(x) for x in range(256)]))
938 elif c == '$' or c == '^':
939 pass
940 else:
941 current.append(c)
943 return RandRegExp.stack_fix(stack[1:], index)
945 def __repr__(self):
946 # type: () -> str
947 return "<%s [%r]>" % (self.__class__.__name__, self._regexp)
950class RandSingularity(RandChoice):
951 pass
954class RandSingNum(RandSingularity):
955 @staticmethod
956 def make_power_of_two(end):
957 # type: (int) -> Set[int]
958 sign = 1
959 if end == 0:
960 end = 1
961 if end < 0:
962 end = -end
963 sign = -1
964 end_n = int(math.log(end) / math.log(2)) + 1
965 return {sign * 2**i for i in range(end_n)}
967 def __init__(self, mn, mx):
968 # type: (int, int) -> None
969 self._mn = mn
970 self._mx = mx
971 sing = {0, mn, mx, int((mn + mx) / 2)}
972 sing |= self.make_power_of_two(mn)
973 sing |= self.make_power_of_two(mx)
974 for i in sing.copy():
975 sing.add(i + 1)
976 sing.add(i - 1)
977 for i in sing.copy():
978 if not mn <= i <= mx:
979 sing.remove(i)
980 super(RandSingNum, self).__init__(*sing)
981 self._choice.sort()
983 def _command_args(self):
984 # type: () -> str
985 if self.__class__.__name__ == 'RandSingNum':
986 return "mn=%r, mx=%r" % (self._mn, self._mx)
987 return super(RandSingNum, self)._command_args()
990class RandSingByte(RandSingNum):
991 def __init__(self):
992 # type: () -> None
993 RandSingNum.__init__(self, 0, 2**8 - 1)
996class RandSingSByte(RandSingNum):
997 def __init__(self):
998 # type: () -> None
999 RandSingNum.__init__(self, -2**7, 2**7 - 1)
1002class RandSingShort(RandSingNum):
1003 def __init__(self):
1004 # type: () -> None
1005 RandSingNum.__init__(self, 0, 2**16 - 1)
1008class RandSingSShort(RandSingNum):
1009 def __init__(self):
1010 # type: () -> None
1011 RandSingNum.__init__(self, -2**15, 2**15 - 1)
1014class RandSingInt(RandSingNum):
1015 def __init__(self):
1016 # type: () -> None
1017 RandSingNum.__init__(self, 0, 2**32 - 1)
1020class RandSingSInt(RandSingNum):
1021 def __init__(self):
1022 # type: () -> None
1023 RandSingNum.__init__(self, -2**31, 2**31 - 1)
1026class RandSingLong(RandSingNum):
1027 def __init__(self):
1028 # type: () -> None
1029 RandSingNum.__init__(self, 0, 2**64 - 1)
1032class RandSingSLong(RandSingNum):
1033 def __init__(self):
1034 # type: () -> None
1035 RandSingNum.__init__(self, -2**63, 2**63 - 1)
1038class RandSingString(RandSingularity):
1039 def __init__(self):
1040 # type: () -> None
1041 choices_list = ["",
1042 "%x",
1043 "%%",
1044 "%s",
1045 "%i",
1046 "%n",
1047 "%x%x%x%x%x%x%x%x%x",
1048 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
1049 "%",
1050 "%%%",
1051 "A" * 4096,
1052 b"\x00" * 4096,
1053 b"\xff" * 4096,
1054 b"\x7f" * 4096,
1055 b"\x80" * 4096,
1056 " " * 4096,
1057 "\\" * 4096,
1058 "(" * 4096,
1059 "../" * 1024,
1060 "/" * 1024,
1061 "${HOME}" * 512,
1062 " or 1=1 --",
1063 "' or 1=1 --",
1064 '" or 1=1 --',
1065 " or 1=1; #",
1066 "' or 1=1; #",
1067 '" or 1=1; #',
1068 ";reboot;",
1069 "$(reboot)",
1070 "`reboot`",
1071 "index.php%00",
1072 b"\x00",
1073 "%00",
1074 "\\",
1075 "../../../../../../../../../../../../../../../../../etc/passwd", # noqa: E501
1076 "%2e%2e%2f" * 20 + "etc/passwd",
1077 "%252e%252e%252f" * 20 + "boot.ini",
1078 "..%c0%af" * 20 + "etc/passwd",
1079 "..%c0%af" * 20 + "boot.ini",
1080 "//etc/passwd",
1081 r"..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\boot.ini", # noqa: E501
1082 "AUX:",
1083 "CLOCK$",
1084 "COM:",
1085 "CON:",
1086 "LPT:",
1087 "LST:",
1088 "NUL:",
1089 "CON:",
1090 r"C:\CON\CON",
1091 r"C:\boot.ini",
1092 r"\\myserver\share",
1093 "foo.exe:",
1094 "foo.exe\\", ]
1095 super(RandSingString, self).__init__(*choices_list)
1097 def _command_args(self):
1098 # type: () -> str
1099 return ""
1101 def __str__(self):
1102 # type: () -> str
1103 return str(self._fix())
1105 def __bytes__(self):
1106 # type: () -> bytes
1107 return bytes_encode(self._fix())
1110class RandPool(RandField[VolatileValue[Any]]):
1111 def __init__(self, *args):
1112 # type: (*Tuple[VolatileValue[Any], int]) -> None
1113 """Each parameter is a volatile object or a couple (volatile object, weight)""" # noqa: E501
1114 self._args = args
1115 pool = [] # type: List[VolatileValue[Any]]
1116 for p in args:
1117 w = 1
1118 if isinstance(p, tuple):
1119 p, w = p # type: ignore
1120 pool += [cast(VolatileValue[Any], p)] * w
1121 self._pool = pool
1123 def _command_args(self):
1124 # type: () -> str
1125 ret = []
1126 for p in self._args:
1127 if isinstance(p, tuple):
1128 ret.append("(%s, %r)" % (p[0].command(), p[1]))
1129 else:
1130 ret.append(p.command())
1131 return ", ".join(ret)
1133 def _fix(self):
1134 # type: () -> Any
1135 r = random.choice(self._pool)
1136 return r._fix()
1139class RandUUID(RandField[uuid.UUID]):
1140 """Generates a random UUID.
1142 By default, this generates a RFC 4122 version 4 UUID (totally random).
1144 See Python's ``uuid`` module documentation for more information.
1146 Args:
1147 template (optional): A template to build the UUID from. Not valid with
1148 any other option.
1149 node (optional): A 48-bit Host ID. Only valid for version 1 (where it
1150 is optional).
1151 clock_seq (optional): An integer of up to 14-bits for the sequence
1152 number. Only valid for version 1 (where it is
1153 optional).
1154 namespace: A namespace identifier, which is also a UUID. Required for
1155 versions 3 and 5, must be omitted otherwise.
1156 name: string, required for versions 3 and 5, must be omitted otherwise.
1157 version: Version of UUID to use (1, 3, 4 or 5). If omitted, attempts to
1158 guess which version to generate, defaulting to version 4
1159 (totally random).
1161 Raises:
1162 ValueError: on invalid constructor arguments
1163 """
1164 # This was originally scapy.contrib.dce_rpc.RandUUID.
1166 _BASE = "([0-9a-f]{{{0}}}|\\*|[0-9a-f]{{{0}}}:[0-9a-f]{{{0}}})"
1167 _REG = re.compile(
1168 r"^{0}-?{1}-?{1}-?{2}{2}-?{2}{2}{2}{2}{2}{2}$".format(
1169 _BASE.format(8), _BASE.format(4), _BASE.format(2)
1170 ),
1171 re.I
1172 )
1173 VERSIONS = [1, 3, 4, 5]
1175 def __init__(self,
1176 template=None, # type: Optional[Any]
1177 node=None, # type: Optional[int]
1178 clock_seq=None, # type: Optional[int]
1179 namespace=None, # type: Optional[uuid.UUID]
1180 name=None, # type: Optional[str]
1181 version=None, # type: Optional[Any]
1182 ):
1183 # type: (...) -> None
1184 self._template = template
1185 self._ori_version = version
1187 self.uuid_template = None
1188 self.clock_seq = None
1189 self.namespace = None
1190 self.name = None
1191 self.node = None
1192 self.version = None
1194 if template:
1195 if node or clock_seq or namespace or name or version:
1196 raise ValueError("UUID template must be the only parameter, "
1197 "if specified")
1198 tmp = RandUUID._REG.match(template)
1199 if tmp:
1200 template = tmp.groups()
1201 else:
1202 # Invalid template
1203 raise ValueError("UUID template is invalid")
1204 rnd_f = [RandInt] + [RandShort] * 2 + [RandByte] * 8
1205 uuid_template = [] # type: List[Union[int, RandNum]]
1206 for i, t in enumerate(template):
1207 if t == "*":
1208 uuid_template.append(rnd_f[i]())
1209 elif ":" in t:
1210 mini, maxi = t.split(":")
1211 uuid_template.append(
1212 RandNum(int(mini, 16), int(maxi, 16))
1213 )
1214 else:
1215 uuid_template.append(int(t, 16))
1217 self.uuid_template = tuple(uuid_template)
1218 else:
1219 if version:
1220 if version not in RandUUID.VERSIONS:
1221 raise ValueError("version is not supported")
1222 else:
1223 self.version = version
1224 else:
1225 # No version specified, try to guess...
1226 # This could be wrong, and cause an error later!
1227 if node or clock_seq:
1228 self.version = 1
1229 elif namespace and name:
1230 self.version = 5
1231 else:
1232 # Don't know, random!
1233 self.version = 4
1235 # We have a version, now do things...
1236 if self.version == 1:
1237 if namespace or name:
1238 raise ValueError("namespace and name may not be used with "
1239 "version 1")
1240 self.node = node
1241 self.clock_seq = clock_seq
1242 elif self.version in (3, 5):
1243 if node or clock_seq:
1244 raise ValueError("node and clock_seq may not be used with "
1245 "version {}".format(self.version))
1247 self.namespace = namespace
1248 self.name = name
1249 elif self.version == 4:
1250 if namespace or name or node or clock_seq:
1251 raise ValueError("node, clock_seq, node and clock_seq may "
1252 "not be used with version 4. If you "
1253 "did not specify version, you need to "
1254 "specify it explicitly.")
1256 def _command_args(self):
1257 # type: () -> str
1258 ret = []
1259 if self._template:
1260 ret.append("template=%r" % self._template)
1261 if self.node:
1262 ret.append("node=%r" % self.node)
1263 if self.clock_seq:
1264 ret.append("clock_seq=%r" % self.clock_seq)
1265 if self.namespace:
1266 ret.append("namespace=%r" % self.namespace)
1267 if self.name:
1268 ret.append("name=%r" % self.name)
1269 if self._ori_version:
1270 ret.append("version=%r" % self._ori_version)
1271 return ", ".join(ret)
1273 def _fix(self):
1274 # type: () -> uuid.UUID
1275 if self.uuid_template:
1276 return uuid.UUID(("%08x%04x%04x" + ("%02x" * 8))
1277 % self.uuid_template)
1278 elif self.version == 1:
1279 return uuid.uuid1(self.node, self.clock_seq)
1280 elif self.version == 3:
1281 if not self.namespace or not self.name:
1282 raise ValueError("Missing namespace or name")
1283 return uuid.uuid3(self.namespace, self.name)
1284 elif self.version == 4:
1285 return uuid.uuid4()
1286 elif self.version == 5:
1287 if not self.namespace or not self.name:
1288 raise ValueError("Missing namespace or name")
1289 return uuid.uuid5(self.namespace, self.name)
1290 else:
1291 raise ValueError("Unhandled version")
1294# Automatic timestamp
1297class _AutoTime(_RandNumeral[_T], # type: ignore
1298 Generic[_T]):
1299 def __init__(self, base=None, diff=None):
1300 # type: (Optional[int], Optional[float]) -> None
1301 self._base = base
1302 self._ori_diff = diff
1304 if diff is not None:
1305 self.diff = diff
1306 elif base is None:
1307 self.diff = 0.
1308 else:
1309 self.diff = time.time() - base
1311 def _command_args(self):
1312 # type: () -> str
1313 ret = []
1314 if self._base:
1315 ret.append("base=%r" % self._base)
1316 if self._ori_diff:
1317 ret.append("diff=%r" % self._ori_diff)
1318 return ", ".join(ret)
1321class AutoTime(_AutoTime[float]):
1322 def _fix(self):
1323 # type: () -> float
1324 return time.time() - self.diff
1327class IntAutoTime(_AutoTime[int]):
1328 def _fix(self):
1329 # type: () -> int
1330 return int(time.time() - self.diff)
1333class ZuluTime(_AutoTime[str]):
1334 def __init__(self, diff=0):
1335 # type: (int) -> None
1336 super(ZuluTime, self).__init__(diff=diff)
1338 def _fix(self):
1339 # type: () -> str
1340 return time.strftime("%y%m%d%H%M%SZ",
1341 time.gmtime(time.time() + self.diff))
1344class GeneralizedTime(_AutoTime[str]):
1345 def __init__(self, diff=0):
1346 # type: (int) -> None
1347 super(GeneralizedTime, self).__init__(diff=diff)
1349 def _fix(self):
1350 # type: () -> str
1351 return time.strftime("%Y%m%d%H%M%SZ",
1352 time.gmtime(time.time() + self.diff))
1355class DelayedEval(VolatileValue[Any]):
1356 """ Example of usage: DelayedEval("time.time()") """
1358 def __init__(self, expr):
1359 # type: (str) -> None
1360 self.expr = expr
1362 def _command_args(self):
1363 # type: () -> str
1364 return "expr=%r" % self.expr
1366 def _fix(self):
1367 # type: () -> Any
1368 return eval(self.expr)
1371class IncrementalValue(VolatileValue[int]):
1372 def __init__(self, start=0, step=1, restart=-1):
1373 # type: (int, int, int) -> None
1374 self.start = self.val = start
1375 self.step = step
1376 self.restart = restart
1378 def _command_args(self):
1379 # type: () -> str
1380 ret = []
1381 if self.start:
1382 ret.append("start=%r" % self.start)
1383 if self.step != 1:
1384 ret.append("step=%r" % self.step)
1385 if self.restart != -1:
1386 ret.append("restart=%r" % self.restart)
1387 return ", ".join(ret)
1389 def _fix(self):
1390 # type: () -> int
1391 v = self.val
1392 if self.val == self.restart:
1393 self.val = self.start
1394 else:
1395 self.val += self.step
1396 return v
1399class CorruptedBytes(VolatileValue[bytes]):
1400 def __init__(self, s, p=0.01, n=None):
1401 # type: (str, float, Optional[Any]) -> None
1402 self.s = s
1403 self.p = p
1404 self.n = n
1406 def _command_args(self):
1407 # type: () -> str
1408 ret = []
1409 ret.append("s=%r" % self.s)
1410 if self.p != 0.01:
1411 ret.append("p=%r" % self.p)
1412 if self.n:
1413 ret.append("n=%r" % self.n)
1414 return ", ".join(ret)
1416 def _fix(self):
1417 # type: () -> bytes
1418 return corrupt_bytes(self.s, self.p, self.n)
1421class CorruptedBits(CorruptedBytes):
1422 def _fix(self):
1423 # type: () -> bytes
1424 return corrupt_bits(self.s, self.p, self.n)