Ejemplo n.º 1
0
    def test_enter(self, mock_cdll, mock_getpid):
        CLONE_NEWNET = 0x40000000
        FAKE_NETNS = 'fake-netns'
        FAKE_PID = random.randrange(100000)
        current_netns_fd = random.randrange(100000)
        target_netns_fd = random.randrange(100000)
        mock_getpid.return_value = FAKE_PID
        mock_cdll_obj = mock.MagicMock()
        mock_cdll.return_value = mock_cdll_obj
        expected_current_netns = '/proc/{pid}/ns/net'.format(pid=FAKE_PID)
        expected_target_netns = '/var/run/netns/{netns}'.format(
            netns=FAKE_NETNS)

        netns = network_namespace.NetworkNamespace(FAKE_NETNS)

        current_mock_open = self.useFixture(
            test_utils.OpenFixture(expected_current_netns)).mock_open
        current_mock_open.return_value = current_netns_fd

        target_mock_open = self.useFixture(
            test_utils.OpenFixture(expected_target_netns)).mock_open
        handle = target_mock_open()
        handle.fileno.return_value = target_netns_fd

        netns.__enter__()

        self.assertEqual(current_netns_fd, netns.current_netns_fd)
        netns.set_netns.assert_called_once_with(target_netns_fd, CLONE_NEWNET)
Ejemplo n.º 2
0
    def test_error_handler(self, mock_cdll, mock_get_errno):
        FAKE_NETNS = 'fake-netns'
        netns = network_namespace.NetworkNamespace(FAKE_NETNS)

        # Test result 0
        netns._error_handler(0, None, None)

        mock_get_errno.assert_not_called()

        # Test result -1
        mock_get_errno.reset_mock()

        self.assertRaises(OSError, netns._error_handler, -1, None, None)

        mock_get_errno.assert_called_once_with()
Ejemplo n.º 3
0
    def test_init(self, mock_cdll, mock_getpid):
        FAKE_NETNS = 'fake-netns'
        FAKE_PID = random.randrange(100000)
        mock_cdll_obj = mock.MagicMock()
        mock_cdll.return_value = mock_cdll_obj
        mock_getpid.return_value = FAKE_PID
        expected_current_netns = '/proc/{pid}/ns/net'.format(pid=FAKE_PID)
        expected_target_netns = '/var/run/netns/{netns}'.format(
            netns=FAKE_NETNS)

        netns = network_namespace.NetworkNamespace(FAKE_NETNS)

        self.assertEqual(expected_current_netns, netns.current_netns)
        self.assertEqual(expected_target_netns, netns.target_netns)
        self.assertEqual(mock_cdll_obj.setns, netns.set_netns)
        self.assertEqual(netns.set_netns.errcheck, netns._error_handler)
Ejemplo n.º 4
0
def garp(interface, ip_address, net_ns=None):
    """Sends a gratuitous ARP for ip_address on the interface.

    :param interface: The interface name to send the GARP on.
    :param ip_address: The IP address to advertise in the GARP.
    :param net_ns: The network namespace to send the GARP from.
    :returns: None
    """
    ARP_ETHERTYPE = 0x0806
    BROADCAST_MAC = b'\xff\xff\xff\xff\xff\xff'

    # Get a socket, optionally inside a network namespace
    garp_socket = None
    if net_ns:
        with network_namespace.NetworkNamespace(net_ns):
            garp_socket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
    else:
        garp_socket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)

    # Bind the socket with the ARP ethertype protocol
    garp_socket.bind((interface, ARP_ETHERTYPE))

    # Get the MAC address of the interface
    source_mac = garp_socket.getsockname()[4]

    garp_msg = [
        pack('!h', 1),  # Hardware type ethernet
        pack('!h', 0x0800),  # Protocol type IPv4
        pack('!B', 6),  # Hardware size
        pack('!B', 4),  # Protocol size
        pack('!h', 1),  # Opcode request
        source_mac,  # Sender MAC address
        socket.inet_aton(ip_address),  # Sender IP address
        BROADCAST_MAC,  # Target MAC address
        socket.inet_aton(ip_address)
    ]  # Target IP address

    garp_ethernet = [
        BROADCAST_MAC,  # Ethernet destination
        source_mac,  # Ethernet source
        pack('!h', ARP_ETHERTYPE),  # Ethernet type
        b''.join(garp_msg)
    ]  # The GARP message

    garp_socket.send(b''.join(garp_ethernet))
    garp_socket.close()
Ejemplo n.º 5
0
    def test_exit(self, mock_cdll, mock_getpid):
        CLONE_NEWNET = 0x40000000
        FAKE_NETNS = 'fake-netns'
        FAKE_PID = random.randrange(100000)
        current_netns_fileno = random.randrange(100000)
        mock_getpid.return_value = FAKE_PID
        mock_cdll_obj = mock.MagicMock()
        mock_cdll.return_value = mock_cdll_obj
        mock_current_netns_fd = mock.MagicMock()
        mock_current_netns_fd.fileno.return_value = current_netns_fileno

        netns = network_namespace.NetworkNamespace(FAKE_NETNS)

        netns.current_netns_fd = mock_current_netns_fd

        netns.__exit__()

        netns.set_netns.assert_called_once_with(current_netns_fileno,
                                                CLONE_NEWNET)
        mock_current_netns_fd.close.assert_called_once_with()
Ejemplo n.º 6
0
def neighbor_advertisement(interface, ip_address, net_ns=None):
    """Sends a unsolicited neighbor advertisement for an ip on the interface.

    :param interface: The interface name to send the GARP on.
    :param ip_address: The IP address to advertise in the GARP.
    :param net_ns: The network namespace to send the GARP from.
    :returns: None
    """
    ALL_NODES_ADDR = 'ff02::1'
    SIOCGIFHWADDR = 0x8927

    # Get a socket, optionally inside a network namespace
    na_socket = None
    if net_ns:
        with network_namespace.NetworkNamespace(net_ns):
            na_socket = socket.socket(
                socket.AF_INET6, socket.SOCK_RAW,
                socket.getprotobyname(constants.IPV6_ICMP))
    else:
        na_socket = socket.socket(socket.AF_INET6, socket.SOCK_RAW,
                                  socket.getprotobyname(constants.IPV6_ICMP))

    # Per RFC 4861 section 4.4, the hop limit should be 255
    na_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, 255)

    # Bind the socket with the source address
    na_socket.bind((ip_address, 0))

    # Get the byte representation of the MAC address of the interface
    # Note: You can't use getsockname() to get the MAC on this type of socket
    source_mac = fcntl.ioctl(na_socket.fileno(), SIOCGIFHWADDR,
                             pack('256s', bytes(interface, 'utf-8')))[18:24]

    # Get the byte representation of the source IP address
    source_ip_bytes = socket.inet_pton(socket.AF_INET6, ip_address)

    icmpv6_na_msg_prefix = [
        pack('!B', 136),  # ICMP Type Neighbor Advertisement
        pack('!B', 0)
    ]  # ICMP Code
    icmpv6_na_msg_postfix = [
        pack('!I', 0xa0000000),  # Flags (Router, Override)
        source_ip_bytes,  # Target address
        pack('!B', 2),  # ICMPv6 option type target link-layer address
        pack('!B', 1),  # ICMPv6 option length
        source_mac
    ]  # ICMPv6 option link-layer address

    # Calculate the ICMPv6 checksum
    icmpv6_pseudo_header = [
        source_ip_bytes,  # Source IP address
        socket.inet_pton(socket.AF_INET6, ALL_NODES_ADDR),  # Destination IP
        pack('!I', 58),  # IPv6 next header (ICMPv6)
        pack('!h', 32)
    ]  # IPv6 payload length
    icmpv6_tmp_chksum = pack('!H', 0)  # Checksum are zeros for calculation
    tmp_chksum_msg = b''.join(icmpv6_pseudo_header + icmpv6_na_msg_prefix +
                              [icmpv6_tmp_chksum] + icmpv6_pseudo_header)
    checksum = pack('!H', calculate_icmpv6_checksum(tmp_chksum_msg))

    # Build the ICMPv6 unsolicitated neighbor advertisement
    icmpv6_msg = b''.join(icmpv6_na_msg_prefix + [checksum] +
                          icmpv6_na_msg_postfix)

    na_socket.sendto(icmpv6_msg, (ALL_NODES_ADDR, 0, 0, 0))
    na_socket.close()