Repository: secdev/scapy

Issue:
Scapy StreamSocket.sr1 problem on OSX [Bug]
system: OSX 10.11.4

When i use StreamSocket.sr1 i got this error.

``` python
>>> from scapy.all import *
WARNING: No route found for IPv6 destination :: (no default route?)
>>> s=socket.socket()
>>> s.connect(('127.0.0.1',80))
>>> connection = StreamSocket(s, Raw)
>>> connection.sr1(Raw("Get"))
Begin emission:
Finished to send 1 packets.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "scapy/supersocket.py", line 52, in sr1
    a,b = sendrecv.sndrcv(self, *args, **kargs)
  File "scapy/sendrecv.py", line 129, in sndrcv
    r = pks.nonblock_recv()
AttributeError: 'StreamSocket' object has no attribute 'nonblock_recv'
```



Discussion:
I found `nonblock_recv` is only for `L2pcapSocket`,`L3dnetSocket` and  `L2dnetSocket` not for `StreamSocket`.
Should I simply add `nonblock_recv` Method to `StreamSocket`?

``` python
class StreamSocket(SimpleSocket):
    desc = "transforms a stream socket into a layer 2"
    def __init__(self, sock, basecls=None):
        if basecls is None:
            basecls = conf.raw_layer
        SimpleSocket.__init__(self, sock)
        self.basecls = basecls

    def recv(self, x=MTU):
        pkt = self.ins.recv(x, socket.MSG_PEEK)
        x = len(pkt)
        if x == 0:
            raise socket.error((100,"Underlying stream socket tore down"))
        pkt = self.basecls(pkt)
        pad = pkt.getlayer(conf.padding_layer)
        if pad is not None and pad.underlayer is not None:
            del(pad.underlayer.payload)
        while pad is not None and not isinstance(pad, NoPayload):
            x -= len(pad.load)
            pad = pad.payload
        self.ins.recv(x)
        return pkt

    def nonblock_recv(self):
        r = self.recv(MTU)
        return r
```

There is no need to implement `non_blockrecv()`. This error is caused by this [specific BSD test](https://github.com/secdev/scapy/blob/master/scapy/sendrecv.py#L126). I think that a better fix is the following:

``` python
if not isinstance(pks, StreamSocket) and (arch.FREEBSD or arch.DARWIN):
...
```

If this works, would you mind submit a PR ?

Thanks.

@guedou After i try your fix, i got following error:

``` python
Begin emission:
Finished to send 1 packets.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "scapy/supersocket.py", line 52, in sr1
    a,b = sendrecv.sndrcv(self, *args, **kargs)
  File "scapy/sendrecv.py", line 127, in sndrcv
    if not isinstance(pks, StreamSocket) and (arch.FREEBSD or arch.DARWIN):
NameError: global name 'StreamSocket' is not defined
```

I think i got your idea. After i fix this, will submit a PR.

Thanks


Resolving patch:
diff --git a/scapy/sendrecv.py b/scapy/sendrecv.py
--- a/scapy/sendrecv.py
+++ b/scapy/sendrecv.py
@@ -19,6 +19,7 @@
 import plist
 from error import log_runtime,log_interactive
 from base_classes import SetGen
+from supersocket import StreamSocket
 
 #################
 ## Debug class ##
@@ -123,7 +124,7 @@ def sndrcv(pks, pkt, timeout = None, inter = 0, verbose=None, chainCC=0, retry=0
                                 if remaintime <= 0:
                                     break
                             r = None
-                            if arch.FREEBSD or arch.DARWIN:
+                            if not isinstance(pks, StreamSocket) and (arch.FREEBSD or arch.DARWIN):
                                 inp, out, err = select(inmask,[],[], 0.05)
                                 if len(inp) == 0 or pks in inp:
                                     r = pks.nonblock_recv()


Test patch: