Exemple #1
0
    def __init__(self, my_sa=0xF9, interface='can0'):
        self.my_sa = my_sa
        self.interface = interface
        self.can_socket = socket.socket(socket.PF_CAN, socket.SOCK_DGRAM,
                                        socket.CAN_J1939)
        addr_set = False
        while self.my_sa < 256 and not addr_set:
            try:
                self.can_socket.bind((self.interface, socket.J1939_NO_NAME,
                                      socket.J1939_NO_PGN, self.my_sa))
            except OSError:
                print("Failed to bind %s with id %d" %
                      (self.interface, self.my_sa))
                self.my_sa += 1
            except Exception as e:
                raise e
            else:
                addr_set = True
        if not addr_set:
            try:
                self.can_socket.bind((self.interface, socket.J1939_NO_NAME,
                                      socket.J1939_NO_PGN, 0xff))
                self.my_sa = 0xff
            except Exception as e:
                print("last-try binding failed: %s" % (repr(e)))

        self.can_socket.settimeout(5)
        socket.CMSG_SPACE(1) + socket.CMSG_SPACE(8)  #what does this do?
    def recv(self):
        while not self.terminated:
            try:
                fds = array.array('i')
                header, ancdata = xrecvmsg(
                    self.sock, 8,
                    socket.CMSG_SPACE(MAXFDS * fds.itemsize) +
                    socket.CMSG_SPACE(CMSGCRED_SIZE))

                if header == b'' or len(header) != 8:
                    break

                magic, length = struct.unpack('II', header)
                if magic != 0xdeadbeef:
                    debug_log('Message with wrong magic dropped (magic {0:x})'.
                              format(magic))
                    continue

                message, _, = xrecvmsg(self.sock, length)
                if message == b'' or len(message) != length:
                    break

                debug_log("Received data: {0}", message)
                for cmsg_level, cmsg_type, cmsg_data in ancdata:
                    if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_CREDS:
                        pid, uid, euid, gid = struct.unpack(
                            'iiii', cmsg_data[:struct.calcsize('iiii')])
                        self.parent.credentials = {
                            'pid': pid,
                            'uid': uid,
                            'euid': euid,
                            'gid': gid
                        }

                    if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS:
                        fds.fromstring(
                            cmsg_data[:len(cmsg_data) -
                                      (len(cmsg_data) % fds.itemsize)])

                self.parent.on_message(message, fds=fds)
            except OSError:
                break

        with contextlib.suppress(OSError):
            self.sock.close()

        if not self.terminated:
            self.closed()
Exemple #3
0
 def recv_udp(listener, bufsize):
     debug3('Accept UDP using socket_ext recvmsg.\n')
     srcip, data, adata, flags = listener.recvmsg((bufsize, ),
                                                  socket.CMSG_SPACE(24))
     dstip = None
     family = None
     for a in adata:
         if a.cmsg_level == socket.SOL_IP and a.cmsg_type == IP_ORIGDSTADDR:
             family, port = struct.unpack('=HH', a.cmsg_data[0:4])
             port = socket.htons(port)
             if family == socket.AF_INET:
                 start = 4
                 length = 4
             else:
                 raise Fatal("Unsupported socket type '%s'" % family)
             ip = socket.inet_ntop(family,
                                   a.cmsg_data[start:start + length])
             dstip = (ip, port)
             break
         elif a.cmsg_level == SOL_IPV6 and a.cmsg_type == IPV6_ORIGDSTADDR:
             family, port = struct.unpack('=HH', a.cmsg_data[0:4])
             port = socket.htons(port)
             if family == socket.AF_INET6:
                 start = 8
                 length = 16
             else:
                 raise Fatal("Unsupported socket type '%s'" % family)
             ip = socket.inet_ntop(family,
                                   a.cmsg_data[start:start + length])
             dstip = (ip, port)
             break
     return (srcip, dstip, data[0])
Exemple #4
0
def udp_server(src_ip, greeting, port):
    payload = bytes(greeting + '\n', 'utf-8')
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_IP, socket.IP_TRANSPARENT, 1)
    s.setsockopt(socket.SOL_IP, IP_RECVORIGDSTADDR, 1)
    s.bind(('127.0.0.1', port))
    print(f"[+] Bound to udp://127.0.0.1:{port}")

    while True:
        ancdata = s.recvmsg(0, socket.CMSG_SPACE(24))
        r_ip, r_port = ancdata[3]
        l_ip = s.getsockname()[0]
        l_port = get_src_port(ancdata[1])
        print(
            f"[ ]Connection from udp://{r_ip}:{r_port} to udp://{l_ip}:{l_port}"
        )

        s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s2.setsockopt(socket.IPPROTO_IP, socket.IP_TRANSPARENT, 1)
        s2.bind((src_ip, l_port))
        try:
            s2.sendto(payload, (r_ip, r_port))
        except socket.error:
            pass
        finally:
            s2.close()

    s.close()
Exemple #5
0
 def recvfds(sock, size):
     '''Receive an array of fds over an AF_UNIX socket.'''
     a = array.array('i')
     bytes_size = a.itemsize * size
     msg, ancdata, flags, addr = sock.recvmsg(1,
                                              socket.CMSG_SPACE(bytes_size))
     if not msg and not ancdata:
         raise EOFError
     try:
         if ACKNOWLEDGE:
             sock.send(b'A')
         if len(ancdata) != 1:
             raise RuntimeError('received %d items of ancdata' %
                                len(ancdata))
         cmsg_level, cmsg_type, cmsg_data = ancdata[0]
         if (cmsg_level == socket.SOL_SOCKET
                 and cmsg_type == socket.SCM_RIGHTS):
             if len(cmsg_data) % a.itemsize != 0:
                 raise ValueError
             a.frombytes(cmsg_data)
             if len(a) % 256 != msg[0]:
                 raise AssertionError(
                     "Len is {0:n} but msg[0] is {1!r}".format(
                         len(a), msg[0]))
             return list(a)
     except (ValueError, IndexError):
         pass
     raise RuntimeError('Invalid data received')
Exemple #6
0
 def recv_udp(listener, bufsize):
     debug3('Accept UDP python using recvmsg.')
     data, ancdata, _, srcip = listener.recvmsg(4096, socket.CMSG_SPACE(24))
     dstip = None
     family = None
     for cmsg_level, cmsg_type, cmsg_data in ancdata:
         if cmsg_level == socket.SOL_IP and cmsg_type == IP_ORIGDSTADDR:
             family, port = struct.unpack('=HH', cmsg_data[0:4])
             port = socket.htons(port)
             if family == socket.AF_INET:
                 start = 4
                 length = 4
             else:
                 raise Fatal("Unsupported socket type '%s'" % family)
             ip = socket.inet_ntop(family, cmsg_data[start:start + length])
             dstip = (ip, port)
             break
         elif cmsg_level == SOL_IPV6 and cmsg_type == IPV6_ORIGDSTADDR:
             family, port = struct.unpack('=HH', cmsg_data[0:4])
             port = socket.htons(port)
             if family == socket.AF_INET6:
                 start = 8
                 length = 16
             else:
                 raise Fatal("Unsupported socket type '%s'" % family)
             ip = socket.inet_ntop(family, cmsg_data[start:start + length])
             dstip = (ip, port)
             break
     return (srcip, dstip, data)
Exemple #7
0
    def read(self):
        buf, ancdata, _, addr = self._sock.recvmsg(512, socket.CMSG_SPACE(100))
        respond = self._get_cmsg_to(ancdata).encode('utf8')

        thread = threading.Thread(group=None,
                                  target=self.process,
                                  args=(buf, addr, respond))
        thread.start()
Exemple #8
0
 def get_request(self):
     iface_index = None
     data, ancdata, flags, client_addr = self.socket.recvmsg(
         self.max_packet_size,
         socket.CMSG_SPACE(ctypes.sizeof(ctypes.in6_pktinfo)))
     for anc in ancdata:
         if anc[0] == socket.IPPROTO_IPV6 and anc[1] == socket.IPV6_PKTINFO:
             _in6_pktinfo = ctypes.in6_pktinfo.from_buffer_copy(anc[2])
             iface_index = _in6_pktinfo.ipi6_ifindex
     return (data, self.socket, iface_index), client_addr
Exemple #9
0
def fds_buf_size():
    # If there may be file descriptors, we try to read 1 message at a time.
    # The reference implementation of D-Bus defaults to allowing 16 FDs per
    # message, and the Linux kernel currently allows 253 FDs per sendmsg()
    # call. So hopefully allowing 256 FDs per recvmsg() will always suffice.
    global _fds_buf_size_cache
    if _fds_buf_size_cache is None:
        maxfds = 256
        fd_size = array.array('i').itemsize
        _fds_buf_size_cache = socket.CMSG_SPACE(maxfds * fd_size)
    return _fds_buf_size_cache
Exemple #10
0
 def recv_udp(listener, bufsize):
     debug3('Accept UDP python using recvmsg.')
     data, ancdata, _, srcip = listener.recvmsg(4096, socket.CMSG_SPACE(4))
     dstip = None
     for cmsg_level, cmsg_type, cmsg_data in ancdata:
         if cmsg_level == socket.SOL_IP and cmsg_type == IP_RECVDSTADDR:
             port = 53
             ip = socket.inet_ntop(socket.AF_INET, cmsg_data[0:4])
             dstip = (ip, port)
             break
     return (srcip, dstip, data)
Exemple #11
0
 def recv_udp(listener, bufsize):
     debug3('Accept UDP using socket_ext recvmsg.')
     srcip, data, adata, _ = listener.recvmsg((bufsize, ),
                                              socket.CMSG_SPACE(4))
     dstip = None
     for a in adata:
         if a.cmsg_level == socket.SOL_IP and a.cmsg_type == IP_RECVDSTADDR:
             port = 53
             ip = socket.inet_ntop(socket.AF_INET, a.cmsg_data[0:4])
             dstip = (ip, port)
             break
     return (srcip, dstip, data[0])
Exemple #12
0
def listen(sock):
    message, ancillary_data, _, (address, _) = sock.recvmsg(4096, socket.CMSG_SPACE(24))

    port = None

    for cmsg_level, cmsg_type, cmsg_data in ancillary_data:
        if cmsg_level == socket.SOL_IP and cmsg_type == IP_ORIGDSTADDR:
            _, port = struct.unpack('=HH', cmsg_data[0:4])
            port = socket.htons(port)
            break

    return message, address, port
    def get_request(self):
        data, anc_data, _, client_addr = self.socket.recvmsg(
            self.max_packet_size, socket.CMSG_SPACE(65535))
        ifindex = None
        for anc_record in anc_data:
            (anc_level, anc_type, anc_datum) = anc_record
            # Check for IPV6_PKTINFO ancilliary data
            if anc_level == socket.IPPROTO_IPV6 and anc_type == socket.IPV6_PKTINFO:
                # Parse binary ancilliary data
                pktinfo = in6_pktinfo.from_buffer_copy(anc_datum)
                ifindex = pktinfo.ipi6_ifindex

        return (data, self.socket, ifindex), client_addr
Exemple #14
0
def retrieve_console_fd(sock):
    fds = array.array('i')
    conn, _ = sock.accept()
    sock.close()
    msg, ancdata, msg_flags, _addr = conn.recvmsg(
        16,
        socket.CMSG_SPACE(fds.itemsize),
        socket.MSG_CMSG_CLOEXEC,
    )
    cmsg_level, cmsg_type, cmsg_data = ancdata[0]
    assert cmsg_level == socket.SOL_SOCKET, cmsg_level
    assert cmsg_type == socket.SCM_RIGHTS, cmsg_type
    fds.frombytes(cmsg_data)
    return list(fds)[0]
Exemple #15
0
 def recv(self):
     try:
         fds = array.array("i")
         data, ancdata, msg_flags, address = self.connection.recvmsg(
             1024, socket.CMSG_SPACE(16 * fds.itemsize))
         for cmsg_level, cmsg_type, cmsg_data in ancdata:
             if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS:
                 fds.fromstring(cmsg_data[:len(cmsg_data) -
                                          len(cmsg_data) % fds.itemsize()])
         self.incoming_fds.extend(fds)
         if data:
             self.decode(data)
     except socket.error as e:
         if e.errno == 11:
             return
         raise
Exemple #16
0
    def __init__(
            self,
            iface_name: str,
            mtu: int,
            loop: typing.Optional[asyncio.AbstractEventLoop] = None) -> None:
        """
        CAN Classic/FD is selected automatically based on the MTU. It is not possible to use CAN FD with MTU of 8 bytes.

        :param iface_name: E.g., ``can0``.

        :param mtu: The maximum data field size in bytes. CAN FD is used if this value > 8, Classic CAN otherwise.
            This value must belong to Media.VALID_MTU_SET.

        :param loop: Deprecated.
        """
        self._mtu = int(mtu)
        if self._mtu not in self.VALID_MTU_SET:
            raise ValueError(
                f"Invalid MTU: {self._mtu} not in {self.VALID_MTU_SET}")
        if loop:
            warnings.warn("The loop argument is deprecated",
                          DeprecationWarning)

        self._iface_name = str(iface_name)
        self._is_fd = self._mtu > _NativeFrameDataCapacity.CAN_CLASSIC
        self._native_frame_data_capacity = int({
            False:
            _NativeFrameDataCapacity.CAN_CLASSIC,
            True:
            _NativeFrameDataCapacity.CAN_FD,
        }[self._is_fd])
        self._native_frame_size = _FRAME_HEADER_STRUCT.size + self._native_frame_data_capacity

        self._sock = _make_socket(iface_name, can_fd=self._is_fd)
        self._ctl_main, self._ctl_worker = socket.socketpair(
        )  # This is used for controlling the worker thread.
        self._closed = False
        self._maybe_thread: typing.Optional[threading.Thread] = None
        self._loopback_enabled = False

        self._ancillary_data_buffer_size = socket.CMSG_SPACE(
            _TIMEVAL_STRUCT.size)  # Used for recvmsg()

        super().__init__()
Exemple #17
0
def recv_fds(sock, msglen, maxfds, inheritable=False):
    '''
    Receives via a Unix domain socket a message of at most `msglen` bytes,
    with at most `maxfds` file descriptors in the ancillary data.  The file
    descriptors will be marked O_CLOEXEC unless inheritable is set to False.
    '''
    fds = array.array('i')
    msg, ancdata, msg_flags, _addr = sock.recvmsg(
        msglen, maxfds * socket.CMSG_SPACE(fds.itemsize),
        0 if inheritable else socket.MSG_CMSG_CLOEXEC,
    )
    assert not (msg_flags & socket.MSG_TRUNC), msg_flags
    assert not (msg_flags & socket.MSG_CTRUNC), msg_flags
    assert not (msg_flags & socket.MSG_ERRQUEUE), msg_flags
    for cmsg_level, cmsg_type, cmsg_data in ancdata:
        assert cmsg_level == socket.SOL_SOCKET, cmsg_level
        assert cmsg_type == socket.SCM_RIGHTS, cmsg_type
        assert len(cmsg_data) % fds.itemsize == 0, cmsg_data
        fds.frombytes(cmsg_data)
    return msg, list(fds)
Exemple #18
0
    def __init__(
            self,
            iface_name: str,
            mtu: int,
            loop: typing.Optional[asyncio.AbstractEventLoop] = None) -> None:
        """
        CAN Classic/FD is selected automatically based on the MTU. It is not possible to use CAN FD with MTU of 8 bytes.

        :param iface_name: E.g., ``can0``.

        :param mtu: The maximum data field size in bytes. CAN FD is used if this value > 8, Classic CAN otherwise.
            This value must belong to Media.VALID_MTU_SET.

        :param loop: The event loop to use. Defaults to :func:`asyncio.get_event_loop`.
        """
        self._mtu = int(mtu)
        if self._mtu not in self.VALID_MTU_SET:
            raise ValueError(
                f'Invalid MTU: {self._mtu} not in {self.VALID_MTU_SET}')

        self._iface_name = str(iface_name)
        self._loop = loop if loop is not None else asyncio.get_event_loop()

        self._is_fd = self._mtu > _NativeFrameDataCapacity.CAN_CLASSIC
        self._native_frame_data_capacity = int({
            False:
            _NativeFrameDataCapacity.CAN_CLASSIC,
            True:
            _NativeFrameDataCapacity.CAN_FD,
        }[self._is_fd])
        self._native_frame_size = _FRAME_HEADER_STRUCT.size + self._native_frame_data_capacity

        self._sock = _make_socket(iface_name, can_fd=self._is_fd)
        self._closed = False
        self._maybe_thread: typing.Optional[threading.Thread] = None
        self._loopback_enabled = False

        self._ancillary_data_buffer_size = socket.CMSG_SPACE(
            _TIMEVAL_STRUCT.size)  # Used for recvmsg()

        super(SocketCANMedia, self).__init__()
Exemple #19
0
 def _recv_loop(self):
     try:
         while self.connected:
             b = self._sock.recv(MIN_HEADER_SIZE, socket.MSG_PEEK)
             if not b:
                 raise TransportError()
             total_size, fields_size = get_sizes(RawData(b))
             if total_size > MAX_MESSAGE_LEN:
                 raise TooLongError('message too long: %d bytes' %
                                    total_size)
             raw = RawData(bytearray(total_size))
             view = raw.getbuffer()
             if self.unix_fds_enabled:
                 b = self._sock.recv(MIN_HEADER_SIZE + fields_size,
                                     socket.MSG_PEEK)
                 unix_fds_cnt = get_unix_fds_cnt(RawData(b))
             else:
                 unix_fds_cnt = 0
             if unix_fds_cnt:
                 fds = array.array('i')
                 cnt, anc, _, _ = self._sock.recvmsg_into(
                     [view], socket.CMSG_SPACE(unix_fds_cnt * fds.itemsize))
                 for cmsg_level, cmsg_type, cmsg_data in anc:
                     if (cmsg_level == socket.SOL_SOCKET
                             and cmsg_type == socket.SCM_RIGHTS):
                         fds.frombytes(
                             cmsg_data[:len(cmsg_data) -
                                       (len(cmsg_data) % fds.itemsize)])
                 raw.unix_fds = fds.tolist()
             else:
                 cnt = self._sock.recv_into(view)
             view.release()
             if not cnt:
                 raise TransportError()
             self._router.incoming(Message.from_bytes(raw))
     except Exception as ex:
         if self.connected:
             _logger.debug('recv loop', exc_info=True)
             self._set_error(ex)
             self.disconnect()
     _logger.debug('EXIT recv loop')
Exemple #20
0
    def receive(self, timeout=None):
        self._check_write_feedback()

        timeout = -1 if timeout is None else (timeout * 1000)

        if self._poll_rx.poll(timeout):
            ts_real = None
            ts_mono = None

            if NATIVE_SOCKETCAN:
                # Reading the frame together with timestamps in the ancillary data structures
                ancillary_len = 64  # Arbitrary value, must be large enough to accommodate all ancillary data
                packet_raw, ancdata, _flags, _addr = self.socket.recvmsg(
                    self.FRAME_SIZE, socket.CMSG_SPACE(ancillary_len))

                # Parsing the timestamps
                for cmsg_level, cmsg_type, cmsg_data in ancdata:
                    if cmsg_level == socket.SOL_SOCKET and cmsg_type == SO_TIMESTAMP:
                        sec, usec = struct.unpack(self.TIMEVAL_FORMAT,
                                                  cmsg_data)
                        ts_real = sec + usec * 1e-6
            else:
                packet_raw = self.socket.recv(self.FRAME_SIZE)

            # Parsing the frame
            can_id, can_dlc, can_data = struct.unpack(self.FRAME_FORMAT,
                                                      packet_raw)

            # TODO: receive timestamps directly from hardware
            # TODO: ...or at least obtain timestamps from the socket layer in local monotonic domain
            if ts_real and not ts_mono:
                ts_mono = self._convert_real_to_monotonic(ts_real)

            frame = CANFrame(can_id & CAN_EFF_MASK,
                             can_data[0:can_dlc],
                             bool(can_id & CAN_EFF_FLAG),
                             ts_monotonic=ts_mono,
                             ts_real=ts_real)
            self._rx_hook(frame)
            return frame
Exemple #21
0
    def __init__(self,
                 group: str,
                 port: int,
                 hop_limit: int,
                 max_buffer: int = 4096) -> None:
        self.group = group
        self.port = port
        self.hop_limit = hop_limit
        self.max_buffer = max_buffer

        # Look up multicast group address in name server and find out IP version of the first suitable target
        # and then get the address family of it (socket.AF_INET or socket.AF_INET6)
        connection_candidates = socket.getaddrinfo(  # type: ignore
            group, self.port, type=socket.SOCK_DGRAM)
        sock = None
        for connection_candidate in connection_candidates:
            address_family: socket.AddressFamily = connection_candidate[0]
            self.ip_version = 4 if address_family == socket.AF_INET else 6
            try:
                sock = self._create_socket(address_family)
            except OSError as error:
                log.info(
                    f"could not connect to the multicast IP network of candidate %s; reason: {error}",
                    connection_candidates,
                )
        if sock is not None:
            self._socket = sock
        else:
            raise RuntimeError("could not connect to a multicast IP network")

        # used in recv()
        self.received_timestamp_struct = "@ll"
        ancillary_data_size = struct.calcsize(self.received_timestamp_struct)
        self.received_ancillary_buffer_size = socket.CMSG_SPACE(
            ancillary_data_size)

        # used by send()
        self._send_destination = (self.group, self.port)
        self._last_send_timeout: Optional[float] = None
Exemple #22
0
    def read(self):
        buf, ancdata, _, addr = self._sock.recvmsg(512, socket.CMSG_SPACE(100))
        interface = self._get_cmsg_to(ancdata)

        try:
            query = Packet.parse(buf)
            answer, pool = self._handler.handle(interface, query)

            if not pool:
                return

            if answer.is_broadcast():
                logging.info('dhcp: got net broadcast on %s', interface)
                self.broadcast(answer, interface, addr[1])
            elif addr[0] == '0.0.0.0':
                logging.info('dhcp: got adr broadcast on %s', interface)
                addr = (socket.inet_ntoa(pool.broadcast), addr[1])
                self._queue.append((addr, answer))
            else:
                logging.info('dhcp: got unicast from %s', addr[0])
                self._queue.append((addr, answer))
        except Exception as e:
            traceback.print_exc()
Exemple #23
0
s.inet_ntoa(packed_ip)
# Преобразует 32-разрядный упакован­ный формат в строку IР-адреса 
# (только для адресов IPv4)

s.inet_pton(address_family, ip_string)
# Преобразует строку IР-адреса в упакованный двоичный формат,
# (и для адресов IPv4, и для адресов IPvб)

s.inet_ntop(address_family, packed_ip)
# Преобразует упакованный двоичный формат в строку IР-адреса,
# (и для адресов IPv4, и для адресов IPvб)

s.CMSG_LEN(length)
# 

s.CMSG_SPACE(length)
#

s.getdefaulttimeout()
# Возвращает значение по умолчанию тайм-аута сокета в секун­дах 
# (число с плавающей точкой)

s.setdefaulttimeout(timeout)
# задает значение по умолчанию тайм-аута сокета в секундах 
# (число с плавающей точкой)

s.sethostname(name)
# Задайте имя хоста машины. Это приведет к вызову OSError, если у 
# вас недостаточно прав.

s.if_nameindex()
Exemple #24
0
def main(argv=None):
    parser = argparse.ArgumentParser(description="Simple multihomed UDP server")
    parser.add_argument('-p', '--port', type=int, default=4242,
                        help="UDP port to be used (default: 4242)")
    parser.add_argument('-w', '--wait', action='store_true',
                        help="wait for connections instead of creating one")
    group = parser.add_mutually_exclusive_group()
    group.add_argument('-4', '--ipv4', action='store_true',
                       help="create an IPv4-only socket")
    group.add_argument('-6', '--ipv6', action='store_true',
                       help="create an IPv6-only socket")

    args = parser.parse_args(argv)

    # Compute local variables
    af = socket.AF_INET if args.ipv4 else socket.AF_INET6
    localaddr = '127.0.0.1' if args.ipv4 else '::1'
    anyaddr = '0.0.0.0' if args.ipv4 else '::'
    port = args.port if args.port > 0 else 4242

    # Create and configure socket for multihoming
    skserver = socket.socket(af, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    if not args.ipv6:
        if hasattr(socket, 'IP_PKTINFO'):
            skserver.setsockopt(socket.SOL_IP, socket.IP_PKTINFO, 1)
        elif hasattr(socket, 'IP_RECVDSTADDR'):
            skserver.setsockopt(socket.IPPROTO_IP, socket.IP_RECVDSTADDR, 1)
    if not args.ipv4:
        if hasattr(socket, 'IPV6_RECVPKTINFO'):
            skserver.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_RECVPKTINFO, 1)
        elif hasattr(socket, 'IPV6_RECVDSTADDR'):
            skserver.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_RECVDSTADDR, 1)
    if not args.ipv4:
        skserver.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, args.ipv6)

    # Listen
    if args.wait:
        listenaddr = anyaddr
    elif args.ipv6 or args.ipv4:
        listenaddr = localaddr
    else:
        # To protect dual-stack listen, bind the socket to the loopback interface
        listenaddr = anyaddr
        try:
            skserver.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, b'lo\0')
        except PermissionError as exc:
            logger.warning("Unable to bind to loopback interface: %s", exc)

    ainfos = socket.getaddrinfo(listenaddr, port, af, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    skserver.bind(ainfos[0][4])

    if args.wait:
        logger.info("Waiting for a connection on UDP port %d.", port)
    else:
        # Create a client socket, which uses IPv4-in-IPv6 if enabled
        clientaf = socket.AF_INET if not args.ipv6 else socket.AF_INET6
        clientdstaddr = '127.0.0.1' if not args.ipv6 else '::1'
        skclient = socket.socket(clientaf, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
        skclient.sendto(b'Hello, world!', (clientdstaddr, port))

    # Receive an incoming packet
    (msg, ancdata, _, clientaddrport) = skserver.recvmsg(1024, socket.CMSG_SPACE(100))
    assert args.wait or msg == b'Hello, world!'  # Check the socket channel
    dst_addr = None
    ifindex = None
    for cmsg_level, cmsg_type, cmsg_data in ancdata:
        if cmsg_level == socket.SOL_IP and hasattr(socket, 'IP_PKTINFO') and cmsg_type == socket.IP_PKTINFO:
            # struct in_pktinfo { int ipi_ifindex; struct in_addr ipi_spec_dst, ipi_addr; };
            assert len(cmsg_data) == 12
            dst_addr = socket.inet_ntop(socket.AF_INET, cmsg_data[4:8])
            ifindex = struct.unpack('I', cmsg_data[:4])[0]
        elif cmsg_level == socket.IPPROTO_IPV6 and hasattr(socket, 'IPV6_PKTINFO') and cmsg_type == socket.IPV6_PKTINFO:
            # struct in6_pktinfo { struct in6_addr ipi6_addr; int ipi_ifindex; };
            assert len(cmsg_data) == 20
            dst_addr = socket.inet_ntop(socket.AF_INET6, cmsg_data[:16])
            ifindex = struct.unpack('I', cmsg_data[16:20])[0]
        else:
            logger.warning("Unknown anciliary data: %s, %s, %r", cmsg_level, cmsg_type, cmsg_data)
        # TODO: decode IP_RECVDSTADDR/IPV6_RECVDSTADDR
    text = "Received UDP packet from {0[0]} port {0[1]}".format(clientaddrport)
    if dst_addr is not None:
        text += " to {} port {} interface {}".format(dst_addr, port, ifindex)
    logger.info(text)

    # Send back a reply with the same ancillary data
    skserver.sendmsg([b'Bye!\n'], ancdata, 0, clientaddrport)

    skserver.close()
    if not args.wait:
        skclient.close()
    return 0
Exemple #25
0
 def space(self):
     return socket.CMSG_SPACE(self._data_len)
        def handle_connection(self):
            self.conn.on_open()

            while True:
                try:
                    fds = array.array('i')
                    header, ancdata = xrecvmsg(
                        self.connfd, 8,
                        socket.CMSG_SPACE(MAXFDS * fds.itemsize) +
                        socket.CMSG_SPACE(CMSGCRED_SIZE))

                    if header == b'' or len(header) != 8:
                        if len(header) > 0:
                            self.server.logger.info(
                                'Short read (len {0})'.format(len(header)))
                        break

                    magic, length = struct.unpack('II', header)
                    if magic != 0xdeadbeef:
                        self.server.logger.info(
                            'Message with wrong magic dropped (magic {0:x})'.
                            format(magic))
                        break

                    msg, _ = xrecvmsg(self.connfd, length)
                    if msg == b'' or len(msg) != length:
                        self.server.logger.info(
                            'Message with wrong length dropped; closing connection'
                        )
                        break

                    for cmsg_level, cmsg_type, cmsg_data in ancdata:
                        if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_CREDS:
                            pid, uid, euid, gid = struct.unpack(
                                'iiii', cmsg_data[:struct.calcsize('iiii')])
                            self.client_address = ('unix', pid)
                            self.conn.credentials = {
                                'pid': pid,
                                'uid': uid,
                                'euid': euid,
                                'gid': gid
                            }

                        if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS:
                            fds.fromstring(
                                cmsg_data[:len(cmsg_data) -
                                          (len(cmsg_data) % fds.itemsize)])

                except (OSError, ValueError) as err:
                    if getattr(err, 'errno', None) == errno.EBADF:
                        # in gevent, shutdown() on a socket from other greenlets results in recv*() returning
                        # with EBADF.
                        break

                    self.server.logger.info(
                        'Receive failed: {0}; closing connection'.format(
                            str(err)),
                        exc_info=True)
                    break

                self.conn.on_message(msg, fds=fds)

            self.close()
Exemple #27
0
import errno  # EBADF
import logging  # getLogger
import os  # close, write
import socket  # CMSG_SPACE, SOL_SOCKET, SCM_RIGHTS, socketpair
import socketserver  # StreamRequestHandler
import struct  # calcsize, pack, unpack
import threading  # Thread
from pathlib import Path

import apkfoundry.container  # Container

_LOGGER = logging.getLogger(__name__)

NUM_FDS = 3
PASSFD_FMT = NUM_FDS * "i"
PASSFD_SIZE = socket.CMSG_SPACE(struct.calcsize(PASSFD_FMT))
RC_FMT = "i"
BUF_SIZE = 4096


def abuild_fetch(argv):
    expected_argv = (
        "-d",
        "/af/distfiles",
        ...,
    )

    if len(argv) != len(expected_argv):
        raise ValueError("apkfoundry: abuild-fetch: invalid usage")

    for arg, expected in zip(argv, expected_argv):