root/scapy/volatile.py

Revision 930:9dcf73256a4a, 13.2 kB (checked in by Phil <phil@secdev.org>, 3 months ago)

Made volatile objects pickable again

Line 
1 ## This file is part of Scapy
2 ## See http://www.secdev.org/projects/scapy for more informations
3 ## Copyright (C) Philippe Biondi <phil@secdev.org>
4 ## This program is published under a GPLv2 license
5
6 import random,time
7 from base_classes import Net
8 from utils import corrupt_bits,corrupt_bytes
9
10 ####################
11 ## Random numbers ##
12 ####################
13
14
15 class RandomSequence:
16     """iterate through a sequence in random order.
17        When all the values have been drawn, if forever=1, the drawing is done again.
18        If renewkeys=0, the draw will be in the same order, guaranteeing that the same
19        number will be drawn in not less than the number of integers of the sequence"""
20     def __init__(self, inf, sup, seed=None, forever=1, renewkeys=0):
21         self.forever = forever
22         self.renewkeys = renewkeys
23         self.inf = inf
24         self.rnd = random.Random(seed)
25         self.sbox_size = 256
26
27         self.top = sup-inf+1
28    
29         n=0
30         while (1<<n) < self.top:
31             n += 1
32         self.n =n
33
34         self.fs = min(3,(n+1)/2)
35         self.fsmask = 2**self.fs-1
36         self.rounds = max(self.n,3)
37         self.turns = 0
38         self.i = 0
39
40     def __iter__(self):
41         return self
42     def next(self):
43         while True:
44             if self.turns == 0 or (self.i == 0 and self.renewkeys):
45                 self.sbox = [self.rnd.randint(0,self.fsmask) for k in xrange(self.sbox_size)]
46             self.turns += 1
47             while self.i < 2**self.n:
48                 ct = self.i
49                 self.i += 1
50                 for k in range(self.rounds): # Unbalanced Feistel Network
51                     lsb = ct & self.fsmask
52                     ct >>= self.fs
53                     lsb ^= self.sbox[ct%self.sbox_size]
54                     ct |= lsb << (self.n-self.fs)
55                
56                 if ct < self.top:
57                     return self.inf+ct
58             self.i = 0
59             if not self.forever:
60                 raise StopIteration
61
62
63 class VolatileValue:
64     def __repr__(self):
65         return "<%s>" % self.__class__.__name__
66     def __getattr__(self, attr):
67         if attr == "__setstate__":
68             raise AttributeError(attr)
69         return getattr(self._fix(),attr)
70     def _fix(self):
71         return None
72
73
74 class RandField(VolatileValue):
75     pass
76
77 class RandNum(RandField):
78     min = 0
79     max = 0
80     def __init__(self, min, max):
81         self.min = min
82         self.max = max
83     def _fix(self):
84         # XXX: replace with sth that guarantee unicity
85         return random.randrange(self.min, self.max+1)
86
87 class RandNumGamma(RandField):
88     def __init__(self, alpha, beta):
89         self.alpha = alpha
90         self.beta = beta
91     def _fix(self):
92         return int(round(random.gammavariate(self.alpha, self.beta)))
93
94 class RandNumGauss(RandField):
95     def __init__(self, mu, sigma):
96         self.mu = mu
97         self.sigma = sigma
98     def _fix(self):
99         return int(round(random.gauss(self.mu, self.sigma)))
100
101 class RandNumExpo(RandField):
102     def __init__(self, lambd, base=0):
103         self.lambd = lambd
104         self.base = base
105     def _fix(self):
106         return self.base+int(round(random.expovariate(self.lambd)))
107
108 class RandSeq(RandNum):
109     def __init__(self, min, max):
110         self.seq = RandomSequence(min,max)
111     def _fix(self):
112         return self.seq.next()
113
114 class RandByte(RandSeq):
115     def __init__(self):
116         RandSeq.__init__(self, 0, 2L**8-1)
117
118 class RandShort(RandSeq):
119     def __init__(self):
120         RandSeq.__init__(self, 0, 2L**16-1)
121
122 class RandInt(RandSeq):
123     def __init__(self):
124         RandSeq.__init__(self, 0, 2L**32-1)
125
126 class RandSInt(RandSeq):
127     def __init__(self):
128         RandSeq.__init__(self, -2L**31, 2L**31-1)
129
130 class RandLong(RandSeq):
131     def __init__(self):
132         RandSeq.__init__(self, 0, 2L**64-1)
133
134 class RandSLong(RandSeq):
135     def __init__(self):
136         RandSeq.__init__(self, -2L**63, 2L**63-1)
137
138 class RandChoice(RandField):
139     def __init__(self, *args):
140         if not args:
141             raise TypeError("RandChoice needs at least one choice")
142         self._choice = args
143     def _fix(self):
144         return random.choice(self._choice)
145    
146 class RandString(RandField):
147     def __init__(self, size, chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"):
148         self.chars = chars
149         self.size = size
150     def _fix(self):
151         s = ""
152         for i in range(self.size):
153             s += random.choice(self.chars)
154         return s
155
156 class RandBin(RandString):
157     def __init__(self, size):
158         RandString.__init__(self, size, "".join(map(chr,range(256))))
159
160
161 class RandTermString(RandString):
162     def __init__(self, size, term):
163         RandString.__init__(self, size, "".join(map(chr,range(1,256))))
164         self.term = term
165     def _fix(self):
166         return RandString._fix(self)+self.term
167    
168    
169
170 class RandIP(RandString):
171     def __init__(self, iptemplate="0.0.0.0/0"):
172         self.ip = Net(iptemplate)
173     def _fix(self):
174         return self.ip.choice()
175
176 class RandMAC(RandString):
177     def __init__(self, template="*"):
178         template += ":*:*:*:*:*"
179         template = template.split(":")
180         self.mac = ()
181         for i in range(6):
182             if template[i] == "*":
183                 v = RandByte()
184             elif "-" in template[i]:
185                 x,y = template[i].split("-")
186                 v = RandSeq(int(x,16), int(y,16))
187             else:
188                 v = int(template[i],16)
189             self.mac += (v,)
190     def _fix(self):
191         return "%02x:%02x:%02x:%02x:%02x:%02x" % self.mac
192    
193
194 class RandOID(RandString):
195     def __init__(self, fmt=None, depth=RandNumExpo(0.1), idnum=RandNumExpo(0.01)):
196         self.ori_fmt = fmt
197         if fmt is not None:
198             fmt = fmt.split(".")
199             for i in range(len(fmt)):
200                 if "-" in fmt[i]:
201                     fmt[i] = tuple(map(int, fmt[i].split("-")))
202         self.fmt = fmt
203         self.depth = depth
204         self.idnum = idnum
205     def __repr__(self):
206         if self.ori_fmt is None:
207             return "<%s>" % self.__class__.__name__
208         else:
209             return "<%s [%s]>" % (self.__class__.__name__, self.ori_fmt)
210     def _fix(self):
211         if self.fmt is None:
212             return ".".join(map(str, [self.idnum for i in xrange(1+self.depth)]))
213         else:
214             oid = []
215             for i in self.fmt:
216                 if i == "*":
217                     oid.append(str(self.idnum))
218                 elif i == "**":
219                     oid += map(str, [self.idnum for i in xrange(1+self.depth)])
220                 elif type(i) is tuple:
221                     oid.append(str(random.randrange(*i)))
222                 else:
223                     oid.append(i)
224             return ".".join(oid)
225            
226
227 from pprint import pprint
228        
229 class RandRegExp(RandField):
230     def __init__(self, regexp, lambda_=0.3,):
231         self._regexp = regexp
232         self._lambda = lambda_
233
234     @staticmethod
235     def choice_expand(s): #XXX does not support special sets like (ex ':alnum:')
236         m = ""
237         invert = s and s[0] == "^"
238         while True:
239             p = s.find("-")
240             if p < 0:
241                 break
242             if p == 0 or p == len(s)-1:
243                 m = "-"
244                 if p:
245                     s = s[:-1]
246                 else:
247                     s = s[1:]
248             else:
249                 c1 = s[p-1]
250                 c2 = s[p+1]
251                 rng = "".join(map(chr, range(ord(c1),ord(c2)+1)))
252                 s = s[:p-1]+rng+s[p+1:]
253         res = m+s
254         if invert:
255             res = "".join([chr(x) for x in xrange(256) if chr(x) not in res])
256         return res
257
258     @staticmethod
259     def stack_fix(lst, index):
260         r = ""
261         mul = 1
262         for e in lst:
263             if type(e) is list:
264                 if mul != 1:
265                     mul = mul-1
266                     r += RandRegExp.stack_fix(e[1:]*mul, index)
267                 # only the last iteration should be kept for back reference
268                 f = RandRegExp.stack_fix(e[1:], index)
269                 for i,idx in enumerate(index):
270                     if e is idx:
271                         index[i] = f
272                 r += f
273                 mul = 1
274             elif type(e) is tuple:
275                 kind,val = e
276                 if kind == "cite":
277                     r += index[val-1]
278                 elif kind == "repeat":
279                     mul = val
280
281                 elif kind == "choice":
282                     if mul == 1:
283                         c = random.choice(val)
284                         r += RandRegExp.stack_fix(c[1:], index)
285                     else:
286                         r += RandRegExp.stack_fix([e]*mul, index)
287                         mul = 1
288             else:
289                 if mul != 1:
290                     r += RandRegExp.stack_fix([e]*mul, index)
291                     mul = 1
292                 else:
293                     r += str(e)
294         return r
295
296     def _fix(self):
297         stack = [None]
298         index = []
299         current = stack
300         i = 0
301         ln = len(self._regexp)
302         interp = True
303         while i < ln:
304             c = self._regexp[i]
305             i+=1
306            
307             if c == '(':
308                 current = [current]
309                 current[0].append(current)
310             elif c == '|':
311                 p = current[0]
312                 ch = p[-1]
313                 if type(ch) is not tuple:
314                     ch = ("choice",[current])
315                     p[-1] = ch
316                 else:
317                     ch[1].append(current)
318                 current = [p]
319             elif c == ')':
320                 ch = current[0][-1]
321                 if type(ch) is tuple:
322                     ch[1].append(current)
323                 index.append(current)
324                 current = current[0]
325             elif c == '[' or c == '{':
326                 current = [current]
327                 current[0].append(current)
328                 interp = False
329             elif c == ']':
330                 current = current[0]
331                 choice = RandRegExp.choice_expand("".join(current.pop()[1:]))
332                 current.append(RandChoice(*list(choice)))
333                 interp = True
334             elif c == '}':
335                 current = current[0]
336                 num = "".join(current.pop()[1:])
337                 e = current.pop()
338                 if "," not in num:
339                     n = int(num)
340                     current.append([current]+[e]*n)
341                 else:
342                     num_min,num_max = num.split(",")
343                     if not num_min:
344                         num_min = "0"
345                     if num_max:
346                         n = RandNum(int(num_min),int(num_max))
347                     else:
348                         n = RandNumExpo(self._lambda,base=int(num_min))
349                     current.append(("repeat",n))
350                     current.append(e)
351                 interp = True
352             elif c == '\\':
353                 c = self._regexp[i]
354                 if c == "s":
355                     c = RandChoice(" ","\t")
356                 elif c in "0123456789":
357                     c = ("cite",ord(c)-0x30)
358                 current.append(c)
359                 i += 1
360             elif not interp:
361                 current.append(c)
362             elif c == '+':
363                 e = current.pop()
364                 current.append([current]+[e]*(int(random.expovariate(self._lambda))+1))
365             elif c == '*':
366                 e = current.pop()
367                 current.append([current]+[e]*int(random.expovariate(self._lambda)))
368             elif c == '?':
369                 if random.randint(0,1):
370                     current.pop()
371             elif c == '.':
372                 current.append(RandChoice(*[chr(x) for x in xrange(256)]))
373             elif c == '$' or c == '^':
374                 pass
375             else:
376                 current.append(c)
377
378         return RandRegExp.stack_fix(stack[1:], index)
379     def __repr__(self):
380         return "<%s [%r]>" % (self.__class__.__name__, self._regexp)
381                
382                
383        
384        
385
386 # Automatic timestamp
387
388 class AutoTime(VolatileValue):
389     def __init__(self, base=None):
390         if base == None:
391             self.diff = 0
392         else:
393             self.diff = time.time()-base
394     def _fix(self):
395         return time.time()-self.diff
396            
397 class IntAutoTime(AutoTime):
398     def _fix(self):
399         return int(time.time()-self.diff)
400
401
402 class ZuluTime(AutoTime):
403     def __init__(self, diff=None):
404         self.diff=diff
405     def _fix(self):
406         return time.strftime("%y%m%d%H%M%SZ",time.gmtime(time.time()+self.diff))
407
408
409 class DelayedEval(VolatileValue):
410     """ Exemple of usage: DelayedEval("time.time()") """
411     def __init__(self, expr):
412         self.expr = expr
413     def _fix(self):
414         return eval(self.expr)
415
416
417 class IncrementalValue(VolatileValue):
418     def __init__(self, start=0, step=1, restart=-1):
419         self.start = self.val = start
420         self.step = step
421         self.restart = restart
422     def _fix(self):
423         v = self.val
424         if self.val == self.restart :
425             self.val = self.start
426         else:
427             self.val += self.step
428         return v
429
430 class CorruptedBytes(VolatileValue):
431     def __init__(self, s, p=0.01, n=None):
432         self.s = s
433         self.p = p
434         self.n = n
435     def _fix(self):
436         return corrupt_bytes(self.s, self.p, self.n)
437
438 class CorruptedBits(CorruptedBytes):
439     def _fix(self):
440         return corrupt_bits(self.s, self.p, self.n)
441
Note: See TracBrowser for help on using the browser.