• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
7
8"""
9Fields that hold random numbers.
10"""
11
12import copy
13import random
14import time
15import math
16import re
17import uuid
18import struct
19import string
20
21from scapy.base_classes import Net
22from scapy.compat import bytes_encode, chb, plain_str
23from scapy.utils import corrupt_bits, corrupt_bytes
24
25from typing import (
26    List,
27    TypeVar,
28    Generic,
29    Set,
30    Union,
31    Any,
32    Dict,
33    Optional,
34    Tuple,
35    cast,
36)
37
38####################
39#  Random numbers  #
40####################
41
42
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
48
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
56
57        self.top = sup - inf + 1
58
59        n = 0
60        while (1 << n) < self.top:
61            n += 1
62        self.n = n
63
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
69
70    def __iter__(self):
71        # type: () -> RandomEnumeration
72        return self
73
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)
90
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
97
98
99_T = TypeVar('_T')
100
101
102class VolatileValue(Generic[_T]):
103    def __repr__(self):
104        # type: () -> str
105        return "<%s>" % self.__class__.__name__
106
107    def _command_args(self):
108        # type: () -> str
109        return ''
110
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())
117
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)
125
126    def __ne__(self, other):
127        # type: (Any) -> bool
128        # Python 2.7 compat
129        return not self == other
130
131    __hash__ = None  # type: ignore
132
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)
138
139    def __str__(self):
140        # type: () -> str
141        return str(self._fix())
142
143    def __bytes__(self):
144        # type: () -> bytes
145        return bytes_encode(self._fix())
146
147    def __len__(self):
148        # type: () -> int
149        # Does not work for some types (int?)
150        return len(self._fix())  # type: ignore
151
152    def copy(self):
153        # type: () -> Any
154        return copy.copy(self)
155
156    def _fix(self):
157        # type: () -> _T
158        return cast(_T, None)
159
160
161class RandField(VolatileValue[_T], Generic[_T]):
162    pass
163
164
165_I = TypeVar("_I", int, float)
166
167
168class _RandNumeral(RandField[_I]):
169    """Implements integer management in RandField"""
170
171    def __int__(self):
172        # type: () -> int
173        return int(self._fix())
174
175    def __index__(self):
176        # type: () -> int
177        return int(self)
178
179    def __nonzero__(self):
180        # type: () -> bool
181        return bool(self._fix())
182    __bool__ = __nonzero__
183
184    def __add__(self, other):
185        # type: (_I) -> _I
186        return self._fix() + other
187
188    def __radd__(self, other):
189        # type: (_I) -> _I
190        return other + self._fix()
191
192    def __sub__(self, other):
193        # type: (_I) -> _I
194        return self._fix() - other
195
196    def __rsub__(self, other):
197        # type: (_I) -> _I
198        return other - self._fix()
199
200    def __mul__(self, other):
201        # type: (_I) -> _I
202        return self._fix() * other
203
204    def __rmul__(self, other):
205        # type: (_I) -> _I
206        return other * self._fix()
207
208    def __floordiv__(self, other):
209        # type: (_I) -> float
210        return self._fix() / other
211    __div__ = __floordiv__
212
213    def __lt__(self, other):
214        # type: (_I) -> bool
215        return self._fix() < other
216
217    def __le__(self, other):
218        # type: (_I) -> bool
219        return self._fix() <= other
220
221    def __ge__(self, other):
222        # type: (_I) -> bool
223        return self._fix() >= other
224
225    def __gt__(self, other):
226        # type: (_I) -> bool
227        return self._fix() > other
228
229
230class RandNum(_RandNumeral[int]):
231    """Instances evaluate to random integers in selected range"""
232    min = 0
233    max = 0
234
235    def __init__(self, min, max):
236        # type: (int, int) -> None
237        self.min = min
238        self.max = max
239
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()
245
246    def _fix(self):
247        # type: () -> int
248        return random.randrange(self.min, self.max + 1)
249
250    def __lshift__(self, other):
251        # type: (int) -> int
252        return self._fix() << other
253
254    def __rshift__(self, other):
255        # type: (int) -> int
256        return self._fix() >> other
257
258    def __and__(self, other):
259        # type: (int) -> int
260        return self._fix() & other
261
262    def __rand__(self, other):
263        # type: (int) -> int
264        return other & self._fix()
265
266    def __or__(self, other):
267        # type: (int) -> int
268        return self._fix() | other
269
270    def __ror__(self, other):
271        # type: (int) -> int
272        return other | self._fix()
273
274
275class RandFloat(_RandNumeral[float]):
276    def __init__(self, min, max):
277        # type: (int, int) -> None
278        self.min = min
279        self.max = max
280
281    def _fix(self):
282        # type: () -> float
283        return random.uniform(self.min, self.max)
284
285
286class RandBinFloat(RandFloat):
287    def _fix(self):
288        # type: () -> float
289        return cast(
290            float,
291            struct.unpack("!f", bytes(RandBin(4)))[0]
292        )
293
294
295class RandNumGamma(RandNum):
296    def __init__(self, alpha, beta):
297        # type: (int, int) -> None
298        self.alpha = alpha
299        self.beta = beta
300
301    def _command_args(self):
302        # type: () -> str
303        return "alpha=%r, beta=%r" % (self.alpha, self.beta)
304
305    def _fix(self):
306        # type: () -> int
307        return int(round(random.gammavariate(self.alpha, self.beta)))
308
309
310class RandNumGauss(RandNum):
311    def __init__(self, mu, sigma):
312        # type: (int, int) -> None
313        self.mu = mu
314        self.sigma = sigma
315
316    def _command_args(self):
317        # type: () -> str
318        return "mu=%r, sigma=%r" % (self.mu, self.sigma)
319
320    def _fix(self):
321        # type: () -> int
322        return int(round(random.gauss(self.mu, self.sigma)))
323
324
325class RandNumExpo(RandNum):
326    def __init__(self, lambd, base=0):
327        # type: (float, int) -> None
328        self.lambd = lambd
329        self.base = base
330
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
337
338    def _fix(self):
339        # type: () -> int
340        return self.base + int(round(random.expovariate(self.lambd)))
341
342
343class RandEnum(RandNum):
344    """Instances evaluate to integer sampling without replacement from the given interval"""  # noqa: E501
345
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)
351
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
358
359    def _fix(self):
360        # type: () -> int
361        return next(self.seq)
362
363
364class RandByte(RandNum):
365    def __init__(self):
366        # type: () -> None
367        RandNum.__init__(self, 0, 2**8 - 1)
368
369
370class RandSByte(RandNum):
371    def __init__(self):
372        # type: () -> None
373        RandNum.__init__(self, -2**7, 2**7 - 1)
374
375
376class RandShort(RandNum):
377    def __init__(self):
378        # type: () -> None
379        RandNum.__init__(self, 0, 2**16 - 1)
380
381
382class RandSShort(RandNum):
383    def __init__(self):
384        # type: () -> None
385        RandNum.__init__(self, -2**15, 2**15 - 1)
386
387
388class RandInt(RandNum):
389    def __init__(self):
390        # type: () -> None
391        RandNum.__init__(self, 0, 2**32 - 1)
392
393
394class RandSInt(RandNum):
395    def __init__(self):
396        # type: () -> None
397        RandNum.__init__(self, -2**31, 2**31 - 1)
398
399
400class RandLong(RandNum):
401    def __init__(self):
402        # type: () -> None
403        RandNum.__init__(self, 0, 2**64 - 1)
404
405
406class RandSLong(RandNum):
407    def __init__(self):
408        # type: () -> None
409        RandNum.__init__(self, -2**63, 2**63 - 1)
410
411
412class RandEnumByte(RandEnum):
413    def __init__(self):
414        # type: () -> None
415        RandEnum.__init__(self, 0, 2**8 - 1)
416
417
418class RandEnumSByte(RandEnum):
419    def __init__(self):
420        # type: () -> None
421        RandEnum.__init__(self, -2**7, 2**7 - 1)
422
423
424class RandEnumShort(RandEnum):
425    def __init__(self):
426        # type: () -> None
427        RandEnum.__init__(self, 0, 2**16 - 1)
428
429
430class RandEnumSShort(RandEnum):
431    def __init__(self):
432        # type: () -> None
433        RandEnum.__init__(self, -2**15, 2**15 - 1)
434
435
436class RandEnumInt(RandEnum):
437    def __init__(self):
438        # type: () -> None
439        RandEnum.__init__(self, 0, 2**32 - 1)
440
441
442class RandEnumSInt(RandEnum):
443    def __init__(self):
444        # type: () -> None
445        RandEnum.__init__(self, -2**31, 2**31 - 1)
446
447
448class RandEnumLong(RandEnum):
449    def __init__(self):
450        # type: () -> None
451        RandEnum.__init__(self, 0, 2**64 - 1)
452
453
454class RandEnumSLong(RandEnum):
455    def __init__(self):
456        # type: () -> None
457        RandEnum.__init__(self, -2**63, 2**63 - 1)
458
459
460class RandEnumKeys(RandEnum):
461    """Picks a random value from dict keys list. """
462
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)
467
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
475
476    def _fix(self):
477        # type: () -> Any
478        return self.enum[next(self.seq)]
479
480
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)
487
488    def _command_args(self):
489        # type: () -> str
490        return ", ".join(self._choice)
491
492    def _fix(self):
493        # type: () -> Any
494        return random.choice(self._choice)
495
496
497_S = TypeVar("_S", bytes, str)
498
499
500class _RandString(RandField[_S], Generic[_S]):
501    def __str__(self):
502        # type: () -> str
503        return plain_str(self._fix())
504
505    def __bytes__(self):
506        # type: () -> bytes
507        return bytes_encode(self._fix())
508
509    def __mul__(self, n):
510        # type: (int) -> _S
511        return self._fix() * n
512
513
514class RandString(_RandString[str]):
515    _DEFAULT_CHARS = (string.ascii_uppercase + string.ascii_lowercase +
516                      string.digits)
517
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
524
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
533
534        if self.chars != self._DEFAULT_CHARS:
535            ret += ", chars=%r" % self.chars
536        return ret
537
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
544
545
546class RandBin(_RandString[bytes]):
547    _DEFAULT_CHARS = b"".join(chb(c) for c in range(256))
548
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
555
556    def _command_args(self):
557        # type: () -> str
558        if not isinstance(self.size, VolatileValue):
559            return "size=%r" % self.size
560
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()
566
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
573
574
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"")
581
582    def _command_args(self):
583        # type: () -> str
584        return ", ".join((super(RandTermString, self)._command_args(),
585                          "term=%r" % self.term))
586
587    def _fix(self):
588        # type: () -> bytes
589        return RandBin._fix(self) + self.term
590
591
592class RandIP(_RandString[str]):
593    _DEFAULT_IPTEMPLATE = "0.0.0.0/0"
594
595    def __init__(self, iptemplate=_DEFAULT_IPTEMPLATE):
596        # type: (str) -> None
597        super(RandIP, self).__init__()
598        self.ip = Net(iptemplate)
599
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
606
607    def _fix(self):
608        # type: () -> str
609        return self.ip.choice()
610
611
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,)
630
631    def _command_args(self):
632        # type: () -> str
633        if self._template == "*":
634            return ""
635        return "template=%r" % self._template
636
637    def _fix(self):
638        # type: () -> str
639        return "%02x:%02x:%02x:%02x:%02x:%02x" % self.mac  # type: ignore
640
641
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
658
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("**")
669
670    def _command_args(self):
671        # type: () -> str
672        if self.tmpl == "**":
673            return ""
674        return "ip6template=%r" % self.tmpl
675
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)
703
704
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
718
719    def _command_args(self):
720        # type: () -> str
721        ret = []
722        if self.fmt:
723            ret.append("fmt=%r" % self.ori_fmt)
724
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())
730
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())
736
737        return ", ".join(ret)
738
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)
745
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)
762
763
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_
769
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
776
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    }
793
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
818
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
842
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
857
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
873
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)
942
943        return RandRegExp.stack_fix(stack[1:], index)
944
945    def __repr__(self):
946        # type: () -> str
947        return "<%s [%r]>" % (self.__class__.__name__, self._regexp)
948
949
950class RandSingularity(RandChoice):
951    pass
952
953
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)}
966
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()
982
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()
988
989
990class RandSingByte(RandSingNum):
991    def __init__(self):
992        # type: () -> None
993        RandSingNum.__init__(self, 0, 2**8 - 1)
994
995
996class RandSingSByte(RandSingNum):
997    def __init__(self):
998        # type: () -> None
999        RandSingNum.__init__(self, -2**7, 2**7 - 1)
1000
1001
1002class RandSingShort(RandSingNum):
1003    def __init__(self):
1004        # type: () -> None
1005        RandSingNum.__init__(self, 0, 2**16 - 1)
1006
1007
1008class RandSingSShort(RandSingNum):
1009    def __init__(self):
1010        # type: () -> None
1011        RandSingNum.__init__(self, -2**15, 2**15 - 1)
1012
1013
1014class RandSingInt(RandSingNum):
1015    def __init__(self):
1016        # type: () -> None
1017        RandSingNum.__init__(self, 0, 2**32 - 1)
1018
1019
1020class RandSingSInt(RandSingNum):
1021    def __init__(self):
1022        # type: () -> None
1023        RandSingNum.__init__(self, -2**31, 2**31 - 1)
1024
1025
1026class RandSingLong(RandSingNum):
1027    def __init__(self):
1028        # type: () -> None
1029        RandSingNum.__init__(self, 0, 2**64 - 1)
1030
1031
1032class RandSingSLong(RandSingNum):
1033    def __init__(self):
1034        # type: () -> None
1035        RandSingNum.__init__(self, -2**63, 2**63 - 1)
1036
1037
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)
1096
1097    def _command_args(self):
1098        # type: () -> str
1099        return ""
1100
1101    def __str__(self):
1102        # type: () -> str
1103        return str(self._fix())
1104
1105    def __bytes__(self):
1106        # type: () -> bytes
1107        return bytes_encode(self._fix())
1108
1109
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
1122
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)
1132
1133    def _fix(self):
1134        # type: () -> Any
1135        r = random.choice(self._pool)
1136        return r._fix()
1137
1138
1139class RandUUID(RandField[uuid.UUID]):
1140    """Generates a random UUID.
1141
1142    By default, this generates a RFC 4122 version 4 UUID (totally random).
1143
1144    See Python's ``uuid`` module documentation for more information.
1145
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).
1160
1161    Raises:
1162        ValueError: on invalid constructor arguments
1163    """
1164    # This was originally scapy.contrib.dce_rpc.RandUUID.
1165
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]
1174
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
1186
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
1193
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))
1216
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
1234
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))
1246
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.")
1255
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)
1272
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")
1292
1293
1294# Automatic timestamp
1295
1296
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
1303
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
1310
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)
1319
1320
1321class AutoTime(_AutoTime[float]):
1322    def _fix(self):
1323        # type: () -> float
1324        return time.time() - self.diff
1325
1326
1327class IntAutoTime(_AutoTime[int]):
1328    def _fix(self):
1329        # type: () -> int
1330        return int(time.time() - self.diff)
1331
1332
1333class ZuluTime(_AutoTime[str]):
1334    def __init__(self, diff=0):
1335        # type: (int) -> None
1336        super(ZuluTime, self).__init__(diff=diff)
1337
1338    def _fix(self):
1339        # type: () -> str
1340        return time.strftime("%y%m%d%H%M%SZ",
1341                             time.gmtime(time.time() + self.diff))
1342
1343
1344class GeneralizedTime(_AutoTime[str]):
1345    def __init__(self, diff=0):
1346        # type: (int) -> None
1347        super(GeneralizedTime, self).__init__(diff=diff)
1348
1349    def _fix(self):
1350        # type: () -> str
1351        return time.strftime("%Y%m%d%H%M%SZ",
1352                             time.gmtime(time.time() + self.diff))
1353
1354
1355class DelayedEval(VolatileValue[Any]):
1356    """ Example of usage: DelayedEval("time.time()") """
1357
1358    def __init__(self, expr):
1359        # type: (str) -> None
1360        self.expr = expr
1361
1362    def _command_args(self):
1363        # type: () -> str
1364        return "expr=%r" % self.expr
1365
1366    def _fix(self):
1367        # type: () -> Any
1368        return eval(self.expr)
1369
1370
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
1377
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)
1388
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
1397
1398
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
1405
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)
1415
1416    def _fix(self):
1417        # type: () -> bytes
1418        return corrupt_bytes(self.s, self.p, self.n)
1419
1420
1421class CorruptedBits(CorruptedBytes):
1422    def _fix(self):
1423        # type: () -> bytes
1424        return corrupt_bits(self.s, self.p, self.n)
1425