DnsPacketProxy { void handleDnsRequest(byte[] packetData) throws AdVpnThread.VpnNetworkException { IpPacket parsedPacket = null; try { parsedPacket = (IpPacket) IpSelector.newPacket(packetData, 0, packetData.length); } catch (Exception e) { Log.i(TAG, "handleDnsRequest: Discarding invalid IP packet", e); return; } UdpPacket parsedUdp; Packet udpPayload; try { parsedUdp = (UdpPacket) parsedPacket.getPayload(); udpPayload = parsedUdp.getPayload(); } catch (Exception e) { try { Log.i(TAG, "handleDnsRequest: Discarding unknown packet type " + parsedPacket.getHeader(), e); } catch (Exception e1) { Log.i(TAG, "handleDnsRequest: Discarding unknown packet type, could not log packet info", e1); } return; } InetAddress destAddr = translateDestinationAdress(parsedPacket); if (destAddr == null) return; if (udpPayload == null) { try { Log.i(TAG, "handleDnsRequest: Sending UDP packet without payload: " + parsedUdp); } catch (Exception e1) { Log.i(TAG, "handleDnsRequest: Sending UDP packet without payload"); } try { DatagramPacket outPacket = new DatagramPacket(new byte[0], 0, 0 , destAddr, parsedUdp.getHeader().getDstPort().valueAsInt()); eventLoop.forwardPacket(outPacket, null); } catch (Exception e) { Log.i(TAG, "handleDnsRequest: Could not send empty UDP packet", e); } return; } byte[] dnsRawData = udpPayload.getRawData(); Message dnsMsg; try { dnsMsg = new Message(dnsRawData); } catch (IOException e) { Log.i(TAG, "handleDnsRequest: Discarding non-DNS or invalid packet", e); return; } if (dnsMsg.getQuestion() == null) { Log.i(TAG, "handleDnsRequest: Discarding DNS packet with no query " + dnsMsg); return; } String dnsQueryName = dnsMsg.getQuestion().getName().toString(true); if (!ruleDatabase.isBlocked(dnsQueryName.toLowerCase(Locale.ENGLISH))) { Log.i(TAG, "handleDnsRequest: DNS Name " + dnsQueryName + " Allowed, sending to " + destAddr); DatagramPacket outPacket = new DatagramPacket(dnsRawData, 0, dnsRawData.length, destAddr, parsedUdp.getHeader().getDstPort().valueAsInt()); eventLoop.forwardPacket(outPacket, parsedPacket); } else { Log.i(TAG, "handleDnsRequest: DNS Name " + dnsQueryName + " Blocked!"); dnsMsg.getHeader().setFlag(Flags.QR); dnsMsg.getHeader().setRcode(Rcode.NOERROR); dnsMsg.addRecord(NEGATIVE_CACHE_SOA_RECORD, Section.AUTHORITY); handleDnsResponse(parsedPacket, dnsMsg.toWire()); } } DnsPacketProxy(EventLoop eventLoop, RuleDatabase database);  DnsPacketProxy(EventLoop eventLoop);   }
@Test public void testHandleDnsRequestNotIpPacket() throws Exception { dnsPacketProxy.handleDnsRequest(new byte[]{'f', 'o', 'o'}); assertNull(mockEventLoop.lastOutgoing); assertNull(mockEventLoop.lastResponse); }
@Test public void testHandleDnsRequestNotUdpPacket() throws Exception { TcpPacket.Builder payLoadBuilder = new TcpPacket.Builder() .srcPort(TcpPort.HTTP) .dstPort(TcpPort.HTTP) .srcAddr(InetAddress.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr(InetAddress.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder( new UnknownPacket.Builder() .rawData(new byte[0]) ); IpPacket ipOutPacket = new IpV4Packet.Builder() .version(IpVersion.IPV4) .tos(IpV4Rfc791Tos.newInstance((byte) 0)) .protocol(IpNumber.UDP) .srcAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder(payLoadBuilder) .build(); dnsPacketProxy.handleDnsRequest(ipOutPacket.getRawData()); assertNull(mockEventLoop.lastOutgoing); assertNull(mockEventLoop.lastResponse); }
@Test public void testHandleDnsRequestNotDnsPacket() throws Exception { UdpPacket.Builder payLoadBuilder = new UdpPacket.Builder() .srcPort(UdpPort.HTTP) .dstPort(UdpPort.HTTP) .srcAddr(InetAddress.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr(InetAddress.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder( new UnknownPacket.Builder() .rawData(new byte[]{1, 2, 3, 4, 5}) ); IpPacket ipOutPacket = new IpV4Packet.Builder() .version(IpVersion.IPV4) .tos(IpV4Rfc791Tos.newInstance((byte) 0)) .protocol(IpNumber.UDP) .srcAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder(payLoadBuilder) .build(); dnsPacketProxy.handleDnsRequest(ipOutPacket.getRawData()); assertNull(mockEventLoop.lastOutgoing); assertNull(mockEventLoop.lastResponse); }
@Test public void testHandleDnsRequestEmptyPacket() throws Exception { UdpPacket.Builder payLoadBuilder = new UdpPacket.Builder() .srcPort(UdpPort.DOMAIN) .dstPort(UdpPort.DOMAIN) .srcAddr(InetAddress.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr(InetAddress.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder( new UnknownPacket.Builder() .rawData(new byte[0]) ); IpPacket ipOutPacket = new IpV4Packet.Builder() .version(IpVersion.IPV4) .tos(IpV4Rfc791Tos.newInstance((byte) 0)) .protocol(IpNumber.UDP) .srcAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder(payLoadBuilder) .build(); dnsPacketProxy.handleDnsRequest(ipOutPacket.getRawData()); assertNotNull(mockEventLoop.lastOutgoing); assertEquals(0, mockEventLoop.lastOutgoing.getLength()); assertEquals(Inet4Address.getByAddress(new byte[]{8, 8, 8, 8}), mockEventLoop.lastOutgoing.getAddress()); assertNull(mockEventLoop.lastResponse); tinySetUp(); dnsPacketProxy.upstreamDnsServers.add(Inet4Address.getByAddress(new byte[]{1, 1, 1, 2})); dnsPacketProxy.handleDnsRequest(ipOutPacket.getRawData()); assertNull(mockEventLoop.lastOutgoing); assertNull(mockEventLoop.lastResponse); tinySetUp(); for (byte i = 2; i < 9; i++) dnsPacketProxy.upstreamDnsServers.add(Inet4Address.getByAddress(new byte[]{1, 1, 1, i})); dnsPacketProxy.handleDnsRequest(ipOutPacket.getRawData()); assertNotNull(mockEventLoop.lastOutgoing); assertEquals(0, mockEventLoop.lastOutgoing.getLength()); assertEquals(Inet4Address.getByAddress(new byte[]{1, 1, 1, 8}), mockEventLoop.lastOutgoing.getAddress()); assertNull(mockEventLoop.lastResponse); }
@Test public void testDnsQuery() throws Exception { Message message = Message.newQuery(new ARecord(new Name("notblocked.example.com."), 0x01, 3600, Inet4Address.getByAddress(new byte[]{0, 0, 0, 0}) )); UdpPacket.Builder payLoadBuilder = new UdpPacket.Builder() .srcPort(UdpPort.DOMAIN) .dstPort(UdpPort.DOMAIN) .srcAddr(InetAddress.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr(InetAddress.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder( new UnknownPacket.Builder() .rawData(message.toWire()) ); IpPacket ipOutPacket = new IpV4Packet.Builder() .version(IpVersion.IPV4) .tos(IpV4Rfc791Tos.newInstance((byte) 0)) .protocol(IpNumber.UDP) .srcAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder(payLoadBuilder) .build(); dnsPacketProxy.handleDnsRequest(ipOutPacket.getRawData()); assertNull(mockEventLoop.lastResponse); assertNotNull(mockEventLoop.lastOutgoing); assertEquals(Inet4Address.getByAddress(new byte[]{8, 8, 8, 8}), mockEventLoop.lastOutgoing.getAddress()); }
@Test public void testNoQueryDnsQuery() throws Exception { Message message = new Message(); UdpPacket.Builder payLoadBuilder = new UdpPacket.Builder() .srcPort(UdpPort.DOMAIN) .dstPort(UdpPort.DOMAIN) .srcAddr(InetAddress.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr(InetAddress.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder( new UnknownPacket.Builder() .rawData(message.toWire()) ); IpPacket ipOutPacket = new IpV4Packet.Builder() .version(IpVersion.IPV4) .tos(IpV4Rfc791Tos.newInstance((byte) 0)) .protocol(IpNumber.UDP) .srcAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder(payLoadBuilder) .build(); dnsPacketProxy.handleDnsRequest(ipOutPacket.getRawData()); assertNull(mockEventLoop.lastResponse); assertNull(mockEventLoop.lastOutgoing); dnsPacketProxy.handleDnsRequest(ipOutPacket.getRawData()); }
@Test public void testBlockedDnsQuery() throws Exception { Message message = Message.newQuery(new ARecord(new Name("blocked.example.com."), 0x01, 3600, Inet4Address.getByAddress(new byte[]{0, 0, 0, 0}) )); UdpPacket.Builder payLoadBuilder = new UdpPacket.Builder() .srcPort(UdpPort.DOMAIN) .dstPort(UdpPort.DOMAIN) .srcAddr(InetAddress.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr(InetAddress.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder( new UnknownPacket.Builder() .rawData(message.toWire()) ); IpPacket ipOutPacket = new IpV4Packet.Builder() .version(IpVersion.IPV4) .tos(IpV4Rfc791Tos.newInstance((byte) 0)) .protocol(IpNumber.UDP) .srcAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder(payLoadBuilder) .build(); dnsPacketProxy.handleDnsRequest(ipOutPacket.getRawData()); assertNotNull(mockEventLoop.lastResponse); assertNull(mockEventLoop.lastOutgoing); assertTrue(mockEventLoop.lastResponse instanceof IpPacket); assertTrue(mockEventLoop.lastResponse.getPayload() instanceof UdpPacket); Message responseMsg = new Message(mockEventLoop.lastResponse.getPayload().getPayload().getRawData()); assertEquals(NOERROR, responseMsg.getHeader().getRcode()); assertArrayEquals(new Record[] {}, responseMsg.getSectionArray(Section.ANSWER)); assertNotEquals(0, responseMsg.getSectionArray(Section.AUTHORITY).length); assertTrue(responseMsg.getSectionArray(Section.AUTHORITY)[0] instanceof SOARecord); assertTrue(responseMsg.getSectionArray(Section.AUTHORITY)[0].getTTL() > 0); }
@Test public void testBlockedInet6DnsQuery() throws Exception { Message message = Message.newQuery(new ARecord(new Name("blocked.example.com."), 0x01, 3600, Inet4Address.getByAddress(new byte[]{0, 0, 0, 0}) )); UdpPacket.Builder payLoadBuilder = new UdpPacket.Builder() .srcPort(UdpPort.DOMAIN) .dstPort(UdpPort.DOMAIN) .srcAddr((Inet6Address) Inet6Address.getByName("::0")) .dstAddr((Inet6Address) Inet6Address.getByName("::1")) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder( new UnknownPacket.Builder() .rawData(message.toWire()) ); IpPacket ipOutPacket = new IpV6Packet.Builder() .version(IpVersion.IPV6) .trafficClass(IpV6SimpleTrafficClass.newInstance((byte) 0)) .flowLabel(IpV6SimpleFlowLabel.newInstance(0)) .nextHeader(IpNumber.UDP) .srcAddr((Inet6Address) Inet6Address.getByName("::0")) .dstAddr((Inet6Address) Inet6Address.getByName("::1")) .correctLengthAtBuild(true) .payloadBuilder(payLoadBuilder) .build(); dnsPacketProxy.handleDnsRequest(ipOutPacket.getRawData()); assertNotNull(mockEventLoop.lastResponse); assertNull(mockEventLoop.lastOutgoing); assertTrue(mockEventLoop.lastResponse instanceof IpPacket); assertTrue(mockEventLoop.lastResponse.getPayload() instanceof UdpPacket); Message responseMsg = new Message(mockEventLoop.lastResponse.getPayload().getPayload().getRawData()); assertEquals(NOERROR, responseMsg.getHeader().getRcode()); assertArrayEquals(new Record[] {}, responseMsg.getSectionArray(Section.ANSWER)); assertNotEquals(0, responseMsg.getSectionArray(Section.AUTHORITY).length); assertTrue(responseMsg.getSectionArray(Section.AUTHORITY)[0] instanceof SOARecord); assertTrue(responseMsg.getSectionArray(Section.AUTHORITY)[0].getTTL() > 0); }