me.melchor9000.net.resolver.DNSResolverTest.java Source code

Java tutorial

Introduction

Here is the source code for me.melchor9000.net.resolver.DNSResolverTest.java

Source

/*
async-net: A basic asynchronous network library, based on netty
Copyright (C) 2017  melchor629 (melchor9000@gmail.com)
    
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package me.melchor9000.net.resolver;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import me.melchor9000.net.IOService;
import me.melchor9000.net.resolver.serverLookup.OracleJREServerProvider;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.*;

import static org.junit.Assert.*;

/**
 * Tests for {@link DNSResolver}
 */
public class DNSResolverTest {
    private static IOService service;
    private static DNSResolver resolver;

    @BeforeClass
    public static void setUp() {
        service = new IOService();
        resolver = new DNSResolver(service, new OracleJREServerProvider());
    }

    @AfterClass
    public static void tearDown() {
        resolver.close();
        service.cancel();
    }

    @Test
    public void deserializeCorrectly1() {
        //Obtained by `dig www.google.com`, the sent packet (Captured with Wireshark)
        ByteBuf buff = Unpooled.wrappedBuffer(new byte[] { 0x7c, (byte) 0x8d, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
                0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 });

        DNSMessage message = new DNSMessage();
        message.setId(0x7C8D);
        message.fromByteBuf(buff);

        assertEquals(0x7C8D, message.getId());
        assertFalse(message.isQueryOrResponse());
        assertEquals(0, message.getOpcode());
        assertFalse(message.isTruncated());
        assertTrue(message.isRecursionDesired());
        assertEquals(1, message.getCountQueries());
        assertEquals(0, message.getCountAnswers());
        assertEquals(0, message.getCountAuthorities());
        assertEquals(0, message.getCountAdditionals());

        DNSQuery query = message.getQueries().iterator().next();
        assertEquals("www.google.com", query.getName());
        assertEquals(DNSUtils.typeToInt("A"), query.getType());
        assertEquals(DNSUtils.classToInt("IN"), query.getClass_());
    }

    @Test
    public void deserializeCorrectly2() throws Exception {
        //Obtained randomly using Wireshark, is a response
        ByteBuf buff = Unpooled.wrappedBuffer(new byte[] { (byte) 0xbd, (byte) 0x87, (byte) 0x81, (byte) 0x80, 0x00,
                0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x65, 0x35, 0x31, 0x35, 0x33, 0x02, 0x65, 0x39,
                0x0a, 0x61, 0x6b, 0x61, 0x6d, 0x61, 0x69, 0x65, 0x64, 0x67, 0x65, 0x03, 0x6e, 0x65, 0x74, 0x00,
                0x00, 0x01, 0x00, 0x01, (byte) 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x13, 0x00,
                0x04, 0x02, 0x10, 0x27, 0x7c });

        DNSMessage message = new DNSMessage();
        message.setId(0xBD87);
        message.fromByteBuf(buff);

        assertEquals(0xBD87, message.getId());
        assertTrue(message.isQueryOrResponse());
        assertEquals(0, message.getOpcode());
        assertFalse(message.isAuthoritativeResponse());
        assertFalse(message.isTruncated());
        assertTrue(message.isRecursionDesired());
        assertTrue(message.isRecursionAvailable());
        assertEquals(1, message.getCountQueries());
        assertEquals(1, message.getCountAnswers());
        assertEquals(0, message.getCountAuthorities());
        assertEquals(0, message.getCountAdditionals());

        DNSQuery query = message.getQueries().iterator().next();
        assertEquals("e5153.e9.akamaiedge.net", query.getName());
        assertEquals(DNSUtils.typeToInt("A"), query.getType());
        assertEquals(DNSUtils.classToInt("IN"), query.getClass_());

        DNSResourceRecord record = message.getAnswers().iterator().next();
        assertEquals("e5153.e9.akamaiedge.net", record.getName());
        assertEquals(DNSUtils.typeToInt("A"), record.getType());
        assertEquals(DNSUtils.classToInt("IN"), record.getClass_());
        assertEquals(19, record.getTtl());

        DNSResourceData dataa = record.getData();
        assertEquals(DNSA.class, dataa.getClass());
        DNSA data = (DNSA) dataa;
        assertEquals(InetAddress.getByAddress(new byte[] { 2, 16, 39, 124 }), data.getAddress());
    }

    @Test
    public void serializeCorrectly1() throws Exception {
        ByteBuf buff = Unpooled.buffer(100);

        DNSMessage message = new DNSMessage();
        message.setId(0xDEAD);
        message.setQueryOrResponse(false);
        message.setOpcode((byte) 0);
        message.setAuthoritativeResponse(false);
        message.setTruncated(false);
        message.setRecursionDesired(true);

        DNSQuery query1 = new DNSQuery();
        query1.setClass("IN");
        query1.setType("A");
        query1.setName("melchor9000.me");

        DNSQuery query2 = new DNSQuery();
        query2.setClass("IN");
        query2.setType("AAAA");
        query2.setName("melchor9000.me");

        message.addQuery(query1);
        message.addQuery(query2);

        assertEquals(52, message.byteBufSize());
        message.toByteBuf(buff);

        byte data[] = new byte[message.byteBufSize()];
        buff.readBytes(data);

        assertEquals(0, buff.readableBytes());
        assertArrayEquals(
                new byte[] { (byte) 0xDE, (byte) 0xAD, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //message (12)
                        0x0B, 109, 101, 108, 99, 104, 111, 114, 57, 48, 48, 48, //melchor9000 (12)
                        0x02, 109, 101, //me (3)
                        0x00, // \0 (1)
                        0x00, 0x01, 0x00, 0x01, //A IN (4)
                        0x0B, 109, 101, 108, 99, 104, 111, 114, 57, 48, 48, 48, //melchor9000 (12)
                        0x02, 109, 101, //me (3)
                        0x00, // \0 (1)
                        0x00, 0x1C, 0x00, 0x01 //A IN (4)
                }, data);
    }

    @Test
    public void serializeCorrectly2() throws Exception {
        ByteBuf buff = Unpooled.buffer(160);

        DNSMessage message = new DNSMessage();
        message.setId(0xDEAD);
        message.setQueryOrResponse(false);
        message.setOpcode((byte) 0);
        message.setAuthoritativeResponse(false);
        message.setTruncated(false);
        message.setRecursionDesired(true);

        buff.writerIndex(99);
        DNSA a = new DNSA(buff);
        DNSAAAA aaaa = new DNSAAAA(buff);
        DNSMX mx = new DNSMX(buff);
        buff.clear();

        a.setAddress(192, 168, 1, 101);
        aaaa.setAddress((Inet6Address) Inet6Address.getByName("fd6b:587e:77a::c85:7e1b:1a5e:7fd1"));
        mx.setExchange("mbp-de-melchor.local");
        mx.setPreference(1);

        DNSResourceRecord recordA = new DNSResourceRecord();
        recordA.setName("mbp-de-melchor.local");
        recordA.setType(1);
        recordA.setClass(1);
        recordA.setTtl(123);
        recordA.setData(a);

        DNSResourceRecord recordAAAA = new DNSResourceRecord();
        recordAAAA.setName("mbp-de-melchor.local");
        recordAAAA.setType("AAAA");
        recordAAAA.setClass(1);
        recordAAAA.setTtl(123);
        recordAAAA.setData(aaaa);

        DNSResourceRecord recordMX = new DNSResourceRecord();
        recordMX.setName("mbp-de-melchor.local");
        recordMX.setType("MX");
        recordMX.setClass(1);
        recordMX.setTtl(123);
        recordMX.setData(mx);

        message.addAnswer(recordA);
        message.addAnswer(recordAAAA);
        message.addAnswer(recordMX);

        assertEquals(12 + (12 + 20 + 4) + (12 + 20 + 16) + (12 + 20 + 24), message.byteBufSize());

        byte data[] = new byte[message.byteBufSize()];
        message.toByteBuf(buff);
        buff.readBytes(data);

        assertEquals(0, buff.readableBytes());
        assertArrayEquals(
                new byte[] { (byte) 0xDE, (byte) 0xAD, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,

                        0x0E, 0x6d, 0x62, 0x70, 0x2d, 0x64, 0x65, 0x2d, 0x6d, 0x65, 0x6c, 0x63, 0x68, 0x6f, 0x72,
                        0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7B,
                        0x00, 0x04, (byte) 192, (byte) 168, 1, 101,

                        0x0E, 0x6d, 0x62, 0x70, 0x2d, 0x64, 0x65, 0x2d, 0x6d, 0x65, 0x6c, 0x63, 0x68, 0x6f, 0x72,
                        0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x00, 0x00, 0x1C, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7B,
                        0x00, 0x10, (byte) 0xfd, 0x6b, 0x58, 0x7e, 0x07, 0x7a, 0x00, 0x00, 0x0c, (byte) 0x085, 0x7e,
                        0x1b, 0x1a, 0x5e, 0x7f, (byte) 0xd1,

                        0x0E, 0x6d, 0x62, 0x70, 0x2d, 0x64, 0x65, 0x2d, 0x6d, 0x65, 0x6c, 0x63, 0x68, 0x6f, 0x72,
                        0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7B,
                        0x00, 0x18, 0x00, 0x01, 0x0E, 0x6d, 0x62, 0x70, 0x2d, 0x64, 0x65, 0x2d, 0x6d, 0x65, 0x6c,
                        0x63, 0x68, 0x6f, 0x72, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x00, },
                data);
    }

    @Test
    public void resolvesNameIPv4() throws Exception {
        Set<InetAddress> addresses = toSet(resolver.resolveV4("melchor9000.me"));
        assertEquals("Must have 2 entries for melchor9000.me", 2, addresses.size());
        assertTrue("192.30.252.153 is not inside", addresses
                .contains(InetAddress.getByAddress(new byte[] { (byte) 192, 30, (byte) 252, (byte) 153 })));
        assertTrue("192.30.252.154 is not inside", addresses
                .contains(InetAddress.getByAddress(new byte[] { (byte) 192, 30, (byte) 252, (byte) 154 })));
    }

    @Test
    public void resolvesCachesRequestsIPv4() {
        Set<InetAddress> ad1 = toSet(resolver.resolveV4("www.google.com")); //Resolve
        Set<InetAddress> ad2 = toSet(DNSResolverCache.getAddressesIPv4("www.google.com")); //Get from cach

        assertEquals("Addresses must be equals", ad1, ad2);
    }

    @Test
    public void resolvesNameIPv6() throws Exception {
        Set<InetAddress> addresses = toSet(resolver.resolveV6("bandaancha.eu"));
        assertEquals("Must have 1 entry for bandaancha.eu", 1, addresses.size());
        assertTrue("2001:470:1f20:49::2 is not inside", addresses.contains(InetAddress.getByAddress(new byte[] {
                0x20, 0x01, 0x04, 0x70, 0x1f, 0x20, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 })));
    }

    @Test
    public void resolvesCachesRequestsIPv6() {
        Set<InetAddress> ad1 = toSet(resolver.resolveV6("www.google.com")); //Resolve
        Set<InetAddress> ad2 = toSet(DNSResolverCache.getAddressesIPv6("www.google.com")); //Get from cach

        assertEquals("Addresses must be equals", ad1, ad2);
    }

    /*@Test(expected = UnknownHostException.class)
    public void notResolvesUnknownHost() {
    resolver.resolve("abc123zxy987q.net");
    }*/

    @Test
    public void shouldResolveHostWithIPv4AndIPv6() {
        Set<InetAddress> addresses = toSet(resolver.resolve("www.facebook.com"));
        assertTrue("www.facebook.com should resolve at least 2 addresses", addresses.size() >= 2);

        Inet4Address ip4 = null;
        Inet6Address ip6 = null;
        for (InetAddress address : addresses) {
            if (address instanceof Inet4Address)
                ip4 = (Inet4Address) address;
            if (address instanceof Inet6Address)
                ip6 = (Inet6Address) address;
        }

        assertNotNull("Must be one IPv4", ip4);
        assertNotNull("Must be one IPv6", ip6);
    }

    private <T> Set<T> toSet(Iterable<T> iterable) {
        Set<T> set = new HashSet<>();
        for (T o : iterable) {
            set.add(o);
        }
        return set;
    }
}