• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Gallopsled / pwntools / 9051612299

12 May 2024 01:04PM UTC coverage: 74.05% (-0.04%) from 74.089%
9051612299

Pull #2405

github

web-flow
Merge 8c883f9a1 into e92a30bbf
Pull Request #2405: Add "none" ssh authentication method

4464 of 7249 branches covered (61.58%)

0 of 4 new or added lines in 1 file covered. (0.0%)

4 existing lines in 2 files now uncovered.

13072 of 17653 relevant lines covered (74.05%)

0.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.38
/pwnlib/tubes/sock.py
1
from __future__ import absolute_import
1✔
2
from __future__ import division
1✔
3

4
import errno
1✔
5
import select
1✔
6
import six
1✔
7
import socket
1✔
8

9
from pwnlib.log import getLogger
1✔
10
from pwnlib.tubes.tube import tube
1✔
11

12
log = getLogger(__name__)
1✔
13

14
class sock(tube):
1✔
15
    """Base type used for :class:`.tubes.remote` and :class:`.tubes.listen` classes"""
16

17
    def __init__(self, *args, **kwargs):
1✔
18
        super(sock, self).__init__(*args, **kwargs)
1✔
19
        self.closed = {"recv": False, "send": False}
1✔
20

21
    # Overwritten for better usability
22
    def recvall(self, timeout = tube.forever):
1✔
23
        """recvall() -> str
24

25
        Receives data until the socket is closed.
26
        """
27

28
        if getattr(self, 'type', None) == socket.SOCK_DGRAM:
1!
29
            self.error("UDP sockets does not supports recvall")
×
30
        else:
31
            return super(sock, self).recvall(timeout)
1✔
32

33
    def recv_raw(self, numb, *a):
1✔
34
        if self.closed["recv"]:
1!
35
            raise EOFError
×
36

37
        while True:
1✔
38
            try:
1✔
39
                data = self.sock.recv(numb, *a)
1✔
40
                break
1✔
41
            except socket.timeout:
1!
42
                return None
1✔
43
            except IOError as e:
×
44
                if e.errno in (errno.EAGAIN, errno.ETIMEDOUT) or 'timed out' in e.strerror:
×
45
                    return None
×
46
                elif e.errno in (errno.ECONNREFUSED, errno.ECONNRESET):
×
47
                    self.shutdown("recv")
×
48
                    raise EOFError
×
49
                elif e.errno == errno.EINTR:
×
50
                    continue
×
51
                else:
52
                    raise
×
53

54
        if not data:
1✔
55
            self.shutdown("recv")
1✔
56
            raise EOFError
1✔
57

58
        return data
1✔
59

60
    def send_raw(self, data):
1✔
61
        if self.closed["send"]:
1!
62
            raise EOFError
×
63

64
        try:
1✔
65
            self.sock.sendall(data)
1✔
66
        except IOError as e:
×
67
            eof_numbers = (errno.EPIPE, errno.ECONNRESET, errno.ECONNREFUSED)
×
68
            if e.errno in eof_numbers or 'Socket is closed' in e.args:
×
69
                self.shutdown("send")
×
70
                raise EOFError
×
71
            else:
72
                raise
×
73

74
    def settimeout_raw(self, timeout):
1✔
75
        sock = getattr(self, 'sock', None)
1✔
76
        if sock:
1✔
77
            sock.settimeout(timeout)
1✔
78

79
    def can_recv_raw(self, timeout):
1✔
80
        """
81
        Tests:
82

83
            >>> l = listen()
84
            >>> r = remote('localhost', l.lport)
85
            >>> r.can_recv_raw(timeout=0)
86
            False
87
            >>> l.send(b'a')
88
            >>> r.can_recv_raw(timeout=1)
89
            True
90
            >>> r.recv()
91
            b'a'
92
            >>> r.can_recv_raw(timeout=0)
93
            False
94
            >>> l.close()
95
            >>> r.can_recv_raw(timeout=1)
96
            False
97
            >>> r.closed['recv']
98
            True
99
        """
100
        if not self.sock or self.closed["recv"]:
×
101
            return False
×
102

103
        # select() will tell us data is available at EOF
104
        can_recv = select.select([self.sock], [], [], timeout) == ([self.sock], [], [])
×
105

106
        if not can_recv:
×
107
            return False
×
108

109
        # Ensure there's actually data, not just EOF
110
        try:
×
111
            self.recv_raw(1, socket.MSG_PEEK)
×
112
        except EOFError:
×
113
            return False
×
114

115
        return True
×
116

117
    def connected_raw(self, direction):
1✔
118
        """
119
        Tests:
120

121
            >>> l = listen()
122
            >>> r = remote('localhost', l.lport)
123
            >>> r.connected()
124
            True
125
            >>> l.close()
126
            >>> time.sleep(0.1) # Avoid race condition
127
            >>> r.connected()
128
            False
129
        """
130
        # If there's no socket, it's definitely closed
131
        if not self.sock:
1!
132
            return False
×
133

134
        # If we have noticed a connection close in a given direction before,
135
        # return fast.
136
        if self.closed.get(direction, False):
1!
137
            return False
×
138

139
        # If a connection is closed in all manners, return fast
140
        if all(self.closed.values()):
1!
141
            return False
×
142

143
        # Use poll() to determine the connection state
144
        want = {
1✔
145
            'recv': select.POLLIN,
146
            'send': select.POLLOUT,
147
            'any':  select.POLLIN | select.POLLOUT,
148
        }[direction]
149

150
        poll = select.poll()
1✔
151
        poll.register(self, want | select.POLLHUP | select.POLLERR)
1✔
152

153
        for fd, event in poll.poll(0):
1✔
154
            if event & select.POLLHUP:
1!
UNCOV
155
                self.close()
×
UNCOV
156
                return False
×
157
            if event & select.POLLIN:
1✔
158
                return True
1✔
159
            if event & select.POLLOUT:
1!
160
                return True
1✔
161

162
        return True
1✔
163

164
    def close(self):
1✔
165
        sock = getattr(self, 'sock', None)
1✔
166
        if not sock:
1✔
167
            return
1✔
168

169
        # Mark as closed in both directions
170
        self.closed['send'] = True
1✔
171
        self.closed['recv'] = True
1✔
172

173
        sock.close()
1✔
174
        self.sock = None
1✔
175
        self._close_msg()
1✔
176

177
    def _close_msg(self):
1✔
178
        self.info('Closed connection to %s port %s', self.rhost, self.rport)
1✔
179

180
    def fileno(self):
1✔
181
        if not self.sock:
1!
182
            self.error("A closed socket does not have a file number")
×
183

184
        return self.sock.fileno()
1✔
185

186
    def shutdown_raw(self, direction):
1✔
187
        if self.closed[direction]:
1✔
188
            return
1✔
189

190
        self.closed[direction] = True
1✔
191

192
        if direction == "send":
1✔
193
            try:
1✔
194
                self.sock.shutdown(socket.SHUT_WR)
1✔
195
            except IOError as e:
×
196
                if e.errno == errno.ENOTCONN:
×
197
                    pass
×
198
                else:
199
                    raise
×
200

201
        if direction == "recv":
1✔
202
            try:
1✔
203
                self.sock.shutdown(socket.SHUT_RD)
1✔
204
            except IOError as e:
1✔
205
                if e.errno == errno.ENOTCONN:
1!
206
                    pass
1✔
207
                else:
208
                    raise
×
209

210
        if False not in self.closed.values():
1✔
211
            self.close()
1✔
212

213
    @classmethod
1✔
214
    def _get_family(cls, fam):
1✔
215
        if isinstance(fam, six.integer_types):
1!
216
            pass
×
217
        elif fam == 'any':
1✔
218
            fam = socket.AF_UNSPEC
1✔
219
        elif fam.lower() in ['ipv4', 'ip4', 'v4', '4']:
1!
220
            fam = socket.AF_INET
×
221
        elif fam.lower() in ['ipv6', 'ip6', 'v6', '6']:
1!
222
            fam = socket.AF_INET6
1✔
223
        else:
224
            self.error("%s(): socket family %r is not supported",
×
225
                       cls.__name__,
226
                       fam)
227

228
        return fam
1✔
229

230
    @classmethod
1✔
231
    def _get_type(cls, typ):
1✔
232
        if isinstance(typ, six.integer_types):
1!
233
            pass
×
234
        elif typ == "tcp":
1!
235
            typ = socket.SOCK_STREAM
1✔
236
        elif typ == "udp":
×
237
            typ = socket.SOCK_DGRAM
×
238
        else:
239
            self.error("%s(): socket type %r is not supported",
×
240
                       cls.__name__,
241
                       typ)
242

243
        return typ
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc