def testCrossProtocolCalls(self): """Tests that passing in the wrong family returns EAFNOSUPPORT.""" def CheckEAFNoSupport(function, *args): self.assertRaisesErrno(errno.EAFNOSUPPORT, function, *args) ipv6sockaddr = csocket.Sockaddr((net_test.IPV6_ADDR, 53)) # In order to check that IPv6 socket calls return EAFNOSUPPORT when passed # IPv4 socket address structures, we need to pass down a socket address # length argument that's at least sizeof(sockaddr_in6). Otherwise, the calls # will fail immediately with EINVAL because the passed-in socket length is # too short. So create a sockaddr_in that's as long as a sockaddr_in6. ipv4sockaddr = csocket.Sockaddr((net_test.IPV4_ADDR, 53)) ipv4sockaddr = csocket.SockaddrIn6( ipv4sockaddr.Pack() + "\x00" * (len(csocket.SockaddrIn6) - len(csocket.SockaddrIn))) s4 = net_test.IPv4PingSocket() s6 = net_test.IPv6PingSocket() # We can't just call s.connect(), s.bind() etc. with a tuple of the wrong # address family, because the Python implementation will just pass garbage # down to the kernel. So call the C functions directly. CheckEAFNoSupport(csocket.Bind, s4, ipv6sockaddr) CheckEAFNoSupport(csocket.Bind, s6, ipv4sockaddr) CheckEAFNoSupport(csocket.Connect, s4, ipv6sockaddr) CheckEAFNoSupport(csocket.Connect, s6, ipv4sockaddr) CheckEAFNoSupport(csocket.Sendmsg, s4, ipv6sockaddr, net_test.IPV4_PING, None, 0) CheckEAFNoSupport(csocket.Sendmsg, s6, ipv4sockaddr, net_test.IPV6_PING, None, 0)
def testIPv6MTU(self): """Tests IPV6_RECVERR and path MTU discovery on ping sockets. Relevant kernel commits: upstream net-next: dcb94b8 ipv6: fix endianness error in icmpv6_err """ s = net_test.IPv6PingSocket() s.setsockopt(net_test.SOL_IPV6, csocket.IPV6_DONTFRAG, 1) s.setsockopt(net_test.SOL_IPV6, csocket.IPV6_MTU_DISCOVER, 2) s.setsockopt(net_test.SOL_IPV6, net_test.IPV6_RECVERR, 1) s.connect((net_test.IPV6_ADDR, 55)) pkt = net_test.IPV6_PING + (PingReplyThread.LINK_MTU + 100) * "a" s.send(pkt) self.assertRaisesErrno(errno.EMSGSIZE, s.recv, 32768) data, addr, cmsg = csocket.Recvmsg(s, 4096, 1024, csocket.MSG_ERRQUEUE) # Compare the offending packet with the one we sent. To do this we need to # calculate the ident of the packet we sent and blank out the checksum of # the one we received. ident = struct.pack("!H", s.getsockname()[1]) pkt = pkt[:4] + ident + pkt[6:] data = data[:2] + "\x00\x00" + pkt[4:] self.assertEquals(pkt, data) # Check the address that the packet was sent to. # ... except in 4.1, where it just returns an AF_UNSPEC, like this: # recvmsg(9, {msg_name(0)={sa_family=AF_UNSPEC, # sa_data="\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}, # msg_iov(1)=[{"\x80\x00\x04\x6b\x00\xc4\x00\x03\x61\x61\x61\x61\x61\x61"..., 4096}], # msg_controllen=64, {cmsg_len=60, cmsg_level=SOL_IPV6, cmsg_type=, ...}, # msg_flags=MSG_ERRQUEUE}, MSG_ERRQUEUE) = 1232 if net_test.LINUX_VERSION != (4, 1, 0): self.assertEquals(csocket.Sockaddr(("2001:4860:4860::8888", 0)), addr) # Check the cmsg data, including the link MTU. mtu = PingReplyThread.LINK_MTU src = self.reply_threads[self.netid].INTERMEDIATE_IPV6 msglist = [(net_test.SOL_IPV6, net_test.IPV6_RECVERR, (csocket.SockExtendedErr( (errno.EMSGSIZE, csocket.SO_ORIGIN_ICMP6, ICMPV6_PKT_TOOBIG, 0, mtu, 0)), csocket.Sockaddr((src, 0))))] # IP[V6]_RECVERR in 3.10 appears to return incorrect data for the port. # The fix might have been in 676d236, but we don't have that in 3.10 and it # touches code all over the tree. Instead, just don't check the port. if net_test.LINUX_VERSION <= (3, 14, 0): msglist[0][2][1].port = cmsg[0][2][1].port self.assertEquals(msglist, cmsg)
def CheckRecvmsg(self, family, addr): s = self._BuildSocket(family, addr) if family == AF_INET: s.setsockopt(SOL_IP, csocket.IP_PKTINFO, 1) s.setsockopt(SOL_IP, csocket.IP_RECVTTL, 1) pktinfo_addr = inet_pton(AF_INET, addr) pktinfo = (SOL_IP, csocket.IP_PKTINFO, csocket.InPktinfo( (LOOPBACK_IFINDEX, pktinfo_addr, pktinfo_addr))) ttl = (SOL_IP, csocket.IP_TTL, 64) elif family == AF_INET6: s.setsockopt(SOL_IPV6, csocket.IPV6_RECVPKTINFO, 1) s.setsockopt(SOL_IPV6, csocket.IPV6_RECVHOPLIMIT, 1) pktinfo_addr = inet_pton(AF_INET6, addr) pktinfo = (SOL_IPV6, csocket.IPV6_PKTINFO, csocket.In6Pktinfo((pktinfo_addr, LOOPBACK_IFINDEX))) ttl = (SOL_IPV6, csocket.IPV6_HOPLIMIT, 64) addr = s.getsockname() sockaddr = csocket.Sockaddr(addr) s.sendto("foo", addr) data, addr, cmsg = csocket.Recvmsg(s, 4096, 1024, 0) self.assertEqual("foo", data) self.assertEqual(sockaddr, addr) self.assertEqual([pktinfo, ttl], cmsg) s.close()
def testAfUnspecBind(self): # Binding to AF_UNSPEC is treated as IPv4 if the address is 0.0.0.0. s4 = net_test.IPv4PingSocket() sockaddr = csocket.Sockaddr(("0.0.0.0", 12996)) sockaddr.family = AF_UNSPEC csocket.Bind(s4, sockaddr) self.assertEquals(("0.0.0.0", 12996), s4.getsockname()) # But not if the address is anything else. sockaddr = csocket.Sockaddr(("127.0.0.1", 58234)) sockaddr.family = AF_UNSPEC self.assertRaisesErrno(errno.EAFNOSUPPORT, csocket.Bind, s4, sockaddr) # This doesn't work for IPv6. s6 = net_test.IPv6PingSocket() sockaddr = csocket.Sockaddr(("::1", 58997)) sockaddr.family = AF_UNSPEC self.assertRaisesErrno(errno.EAFNOSUPPORT, csocket.Bind, s6, sockaddr)
def CheckRecvfrom(self, family, addr): s = self._BuildSocket(family, addr) addr = s.getsockname() sockaddr = csocket.Sockaddr(addr) s.sendto("foo", addr) data, addr = csocket.Recvfrom(s, 4096, 0) self.assertEqual("foo", data) self.assertEqual(sockaddr, addr) s.close()
def testPacketCount(self): self.map_fd = CreateMap(BPF_MAP_TYPE_HASH, 4, 4, 10) key = 0xf0f0 bpf_prog = BpfMov64Reg(BPF_REG_6, BPF_REG_1) bpf_prog += BpfLoadMapFd(self.map_fd, BPF_REG_1) bpf_prog += BpfMov64Imm(BPF_REG_7, key) bpf_prog += BpfStxMem(BPF_W, BPF_REG_10, BPF_REG_7, -4) bpf_prog += BpfMov64Reg(BPF_REG_8, BPF_REG_10) bpf_prog += BpfAlu64Imm(BPF_ADD, BPF_REG_8, -4) bpf_prog += BpfMov64Reg(BPF_REG_2, BPF_REG_8) bpf_prog += BpfFuncLookupMap() bpf_prog += BpfJumpImm(BPF_AND, BPF_REG_0, 0, 10) bpf_prog += BpfLoadMapFd(self.map_fd, BPF_REG_1) bpf_prog += BpfMov64Reg(BPF_REG_2, BPF_REG_8) bpf_prog += BpfStMem(BPF_W, BPF_REG_10, -8, 1) bpf_prog += BpfMov64Reg(BPF_REG_3, BPF_REG_10) bpf_prog += BpfAlu64Imm(BPF_ADD, BPF_REG_3, -8) bpf_prog += BpfMov64Imm(BPF_REG_4, 0) bpf_prog += BpfFuncUpdateMap() bpf_prog += BpfLdxMem(BPF_W, BPF_REG_0, BPF_REG_6, 0) bpf_prog += BpfExitInsn() bpf_prog += BpfMov64Reg(BPF_REG_2, BPF_REG_0) bpf_prog += BpfMov64Imm(BPF_REG_1, 1) bpf_prog += BpfRawInsn(BPF_STX | BPF_XADD | BPF_W, BPF_REG_2, BPF_REG_1, 0, 0) bpf_prog += BpfLdxMem(BPF_W, BPF_REG_0, BPF_REG_6, 0) bpf_prog += BpfExitInsn() insn_buff = ctypes.create_string_buffer(bpf_prog) # this program loaded is used to counting the packet transmitted through # a target socket. It will store the packet count into the eBPF map and we # will verify if the counting result is correct. self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SOCKET_FILTER, ctypes.addressof(insn_buff), len(insn_buff), BpfInsn._length) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) sock.settimeout(1) BpfProgAttachSocket(sock.fileno(), self.prog_fd) addr = "127.0.0.1" sock.bind((addr, 0)) addr = sock.getsockname() sockaddr = csocket.Sockaddr(addr) packet_count = 100 for i in xrange(packet_count): sock.sendto("foo", addr) data, retaddr = csocket.Recvfrom(sock, 4096, 0) self.assertEqual("foo", data) self.assertEqual(sockaddr, retaddr) self.assertEquals(LookupMap(self.map_fd, key).value, packet_count)
def SocketUDPLoopBack(packet_count, version, prog_fd): family = {4: socket.AF_INET, 6: socket.AF_INET6}[version] sock = socket.socket(family, socket.SOCK_DGRAM, 0) if prog_fd is not None: BpfProgAttachSocket(sock.fileno(), prog_fd) net_test.SetNonBlocking(sock) addr = {4: "127.0.0.1", 6: "::1"}[version] sock.bind((addr, 0)) addr = sock.getsockname() sockaddr = csocket.Sockaddr(addr) for i in xrange(packet_count): sock.sendto("foo", addr) data, retaddr = csocket.Recvfrom(sock, 4096, 0) assert "foo" == data assert sockaddr == retaddr return sock
def testProgLoad(self): bpf_prog = BpfMov64Reg(BPF_REG_6, BPF_REG_1) bpf_prog += BpfLdxMem(BPF_W, BPF_REG_0, BPF_REG_6, 0) bpf_prog += BpfExitInsn() insn_buff = ctypes.create_string_buffer(bpf_prog) # Load a program that does nothing except pass every packet it receives # It should not block the packet transmission otherwise the test fails. self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SOCKET_FILTER, ctypes.addressof(insn_buff), len(insn_buff), BpfInsn._length) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) sock.settimeout(1) BpfProgAttachSocket(sock.fileno(), self.prog_fd) addr = "127.0.0.1" sock.bind((addr, 0)) addr = sock.getsockname() sockaddr = csocket.Sockaddr(addr) sock.sendto("foo", addr) data, addr = csocket.Recvfrom(sock, 4096, 0) self.assertEqual("foo", data) self.assertEqual(sockaddr, addr)
def testAddDelSa(self): src4 = csocket.Sockaddr(("192.0.2.1", 0)) dst4 = csocket.Sockaddr(("192.0.2.2", 1)) self.pf_key.AddSa(src4, dst4, 0xdeadbeef, pf_key.SADB_TYPE_ESP, pf_key.IPSEC_MODE_TRANSPORT, 54321, pf_key.SADB_X_EALG_AESCBC, ENCRYPTION_KEY, pf_key.SADB_X_AALG_SHA2_256HMAC, ENCRYPTION_KEY) src6 = csocket.Sockaddr(("2001:db8::1", 0)) dst6 = csocket.Sockaddr(("2001:db8::2", 0)) self.pf_key.AddSa(src6, dst6, 0xbeefdead, pf_key.SADB_TYPE_ESP, pf_key.IPSEC_MODE_TRANSPORT, 12345, pf_key.SADB_X_EALG_AESCBC, ENCRYPTION_KEY, pf_key.SADB_X_AALG_SHA2_256HMAC, ENCRYPTION_KEY) sainfos = self.xfrm.DumpSaInfo() self.assertEquals(2, len(sainfos)) state4, attrs4 = [(s, a) for s, a in sainfos if s.family == AF_INET][0] state6, attrs6 = [(s, a) for s, a in sainfos if s.family == AF_INET6][0] pfkey_sainfos = self.pf_key.DumpSaInfo() self.assertEquals(2, len(pfkey_sainfos)) self.assertTrue( all(msg.satype == pf_key.SDB_TYPE_ESP) for msg, _ in pfkey_sainfos) self.assertEquals(xfrm.IPPROTO_ESP, state4.id.proto) self.assertEquals(xfrm.IPPROTO_ESP, state6.id.proto) self.assertEquals(54321, state4.reqid) self.assertEquals(12345, state6.reqid) self.assertEquals(0xdeadbeef, state4.id.spi) self.assertEquals(0xbeefdead, state6.id.spi) self.assertEquals(xfrm.PaddedAddress("192.0.2.1"), state4.saddr) self.assertEquals(xfrm.PaddedAddress("192.0.2.2"), state4.id.daddr) self.assertEquals(xfrm.PaddedAddress("2001:db8::1"), state6.saddr) self.assertEquals(xfrm.PaddedAddress("2001:db8::2"), state6.id.daddr) # The algorithm names are null-terminated, but after that contain garbage. # Kernel bug? aes_name = "cbc(aes)\x00" sha256_name = "hmac(sha256)\x00" self.assertTrue(attrs4["XFRMA_ALG_CRYPT"].name.startswith(aes_name)) self.assertTrue(attrs6["XFRMA_ALG_CRYPT"].name.startswith(aes_name)) self.assertTrue(attrs4["XFRMA_ALG_AUTH"].name.startswith(sha256_name)) self.assertTrue(attrs6["XFRMA_ALG_AUTH"].name.startswith(sha256_name)) self.assertEquals(256, attrs4["XFRMA_ALG_CRYPT"].key_len) self.assertEquals(256, attrs4["XFRMA_ALG_CRYPT"].key_len) self.assertEquals(256, attrs6["XFRMA_ALG_AUTH"].key_len) self.assertEquals(256, attrs6["XFRMA_ALG_AUTH"].key_len) self.assertEquals(256, attrs6["XFRMA_ALG_AUTH_TRUNC"].key_len) self.assertEquals(256, attrs6["XFRMA_ALG_AUTH_TRUNC"].key_len) self.assertEquals(128, attrs4["XFRMA_ALG_AUTH_TRUNC"].trunc_len) self.assertEquals(128, attrs4["XFRMA_ALG_AUTH_TRUNC"].trunc_len) self.pf_key.DelSa(src4, dst4, 0xdeadbeef, pf_key.SADB_TYPE_ESP) self.assertEquals(1, len(self.xfrm.DumpSaInfo())) self.pf_key.DelSa(src6, dst6, 0xbeefdead, pf_key.SADB_TYPE_ESP) self.assertEquals(0, len(self.xfrm.DumpSaInfo()))