Repository: secdev/scapy

Issue:
"Generating sets of packets" (as explained in the documentation) does not work for mixed sequence and range (e.g. IP(ttl=[1,2,(5,9)]))
Hi,
as explained in the [tutorial](http://scapy.readthedocs.io/en/latest/usage.html#generating-sets-of-packets)  
these two lines 
`b=IP(ttl=[1,2,(5,9)])`
`[p for p in b]` 
should create a set of 7 packets, like
`[<IP ttl=1 |>, <IP ttl=2 |>, <IP ttl=5 |>, <IP ttl=6 |>, <IP ttl=7 |>, <IP ttl=8 |>, <IP ttl=9 |>]`.

But the result is just:
`[<IP  ttl=1 |>, <IP  ttl=2 |>, <IP  ttl=(5, 9) |>]`

If I just use a "sequence" (`IP(ttl=[1,2,5,7,9])`) or "range" (`IP(ttl=(1,9)`), the result is that I expected. 

So, there are recent changesin scpay and the documentation is outdated or Is this a bug or I'm just stupid ;) ?

Thanks!


Discussion:
Here is the commit that introduces this regression:

```
$ python test.py
[<IP  ttl=1 |>, <IP  ttl=2 |>, <IP  ttl=5 |>, <IP  ttl=6 |>, <IP  ttl=7 |>, <IP  ttl=8 |>, <IP  ttl=9 |>]
7
$ git bisect good
4dbc2b99d385f82049f2c6716357a94e51be5f79 is the first bad commit
commit 4dbc2b99d385f82049f2c6716357a94e51be5f79
Author: Pierre LALET <pierre.lalet@cea.fr>
Date:   Thu Jan 21 12:49:13 2016 +0100

    Use xrange objects to (internally) represent tuples in field values

:040000 040000 37909dc2daf7daa0a27076f69e75a8c64f328d06 f03375175c5442a19535b7392053180f0fe9c935 M	scapy
```

@p-l- can you have a look ?

Resolving patch:
diff --git a/scapy/base_classes.py b/scapy/base_classes.py
--- a/scapy/base_classes.py
+++ b/scapy/base_classes.py
@@ -20,20 +20,29 @@ class Gen(object):
     __slots__ = []
     def __iter__(self):
         return iter([])
-    
+
+
+def _get_values(value):
+    """Generate a range object from (start, stop[, step]) tuples, or
+return value.
+
+    """
+    if (isinstance(value, tuple) and (2 <= len(value) <= 3) and \
+        all(hasattr(i, "__int__") for i in value)):
+        # We use values[1] + 1 as stop value for (x)range to maintain
+        # the behavior of using tuples as field `values`
+        return range(*((int(value[0]), int(value[1]) + 1)
+                       + tuple(int(v) for v in value[2:])))
+    return value
+
+
 class SetGen(Gen):
     def __init__(self, values, _iterpacket=1):
         self._iterpacket=_iterpacket
         if isinstance(values, (list, BasePacketList)):
-            self.values = list(values)
-        elif (isinstance(values, tuple) and (2 <= len(values) <= 3) and \
-             all(hasattr(i, "__int__") for i in values)):
-            # We use values[1] + 1 as stop value for (x)range to maintain
-            # the behavior of using tuples as field `values`
-            self.values = [range(*((int(values[0]), int(values[1]) + 1)
-                                    + tuple(int(v) for v in values[2:])))]
+            self.values = [_get_values(val) for val in values]
         else:
-            self.values = [values]
+            self.values = [_get_values(values)]
     def transf(self, element):
         return element
     def __iter__(self):


Test patch:
diff --git a/test/regression.uts b/test/regression.uts
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -1043,7 +1043,7 @@ assert True
 ############
 + More complex tests
 
-= Implicit logic
+= Implicit logic 1
 ~ IP TCP
 a = Ether() / IP(ttl=(5, 10)) / TCP(dport=[80, 443])
 ls(a)
@@ -1051,6 +1051,14 @@ ls(a, verbose=True)
 l = [p for p in a]
 len(l) == 12
 
+= Implicit logic 2
+~ IP
+a = IP(ttl=[1,2,(5,9)])
+ls(a)
+ls(a, verbose=True)
+l = [p for p in a]
+len(l) == 7
+
 
 ############
 ############