aboutsummaryrefslogtreecommitdiffstats
path: root/libs/minidns/src/main/java/de/measite/minidns/Question.java
blob: 3b2fa1a1355a55025c3241260cd647cd9e4979f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package de.measite.minidns;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;

import de.measite.minidns.Record.CLASS;
import de.measite.minidns.Record.TYPE;
import de.measite.minidns.util.NameUtil;

/**
 * A DNS question (request).
 */
public class Question {

    /**
     * The question string (e.g. "measite.de").
     */
    private final String name;

    /**
     * The question type (e.g. A).
     */
    private final TYPE type;

    /**
     * The question class (usually IN / internet).
     */
    private final CLASS clazz;

    /**
     * UnicastQueries have the highest bit of the CLASS field set to 1.
     */
    private final boolean unicastQuery;

    /**
     * Cache for the serialized object.
     */
    private byte[] byteArray;

    /**
     * Create a dns question for the given name/type/class.
     * @param name The name e.g. "measite.de".
     * @param type The type, e.g. A.
     * @param clazz The class, usually IN (internet).
     */
    public Question(String name, TYPE type, CLASS clazz, boolean unicastQuery) {
        this.name = name;
        this.type = type;
        this.clazz = clazz;
        this.unicastQuery = unicastQuery;
    }

    /**
     * Create a dns question for the given name/type/class.
     * @param name The name e.g. "measite.de".
     * @param type The type, e.g. A.
     * @param clazz The class, usually IN (internet).
     */
    public Question(String name, TYPE type, CLASS clazz) {
        this(name, type, clazz, false);
    }

    /**
     * Create a dns question for the given name/type/IN (internet class).
     * @param name The name e.g. "measite.de".
     * @param type The type, e.g. A.
     */
    public Question(String name, TYPE type) {
        this(name, type, CLASS.IN);
    }

    /**
     * Retrieve the type of this question.
     * @return The type.
     */
    public TYPE getType() {
        return type;
    }

    /**
     * Retrieve the class of this dns question (usually internet).
     * @return The class of this dns question.
     */
    public CLASS getClazz() {
        return clazz;
    }

    /**
     * Retrieve the name of this dns question (e.g. "measite.de").
     * @return The name of this dns question.
     */
    public String getName() {
        return name;
    }

    /**
     * Parse a byte array and rebuild the dns question from it.
     * @param dis The input stream.
     * @param data The plain data (for dns name references).
     * @return The parsed dns question.
     * @throws IOException On errors (read outside of packet).
     */
    public static Question parse(DataInputStream dis, byte[] data) throws IOException {
        String name = NameUtil.parse(dis, data);
        TYPE type = TYPE.getType(dis.readUnsignedShort());
        CLASS clazz = CLASS.getClass(dis.readUnsignedShort());
        return new Question (name, type, clazz);
    }

    /**
     * Generate a binary paket for this dns question.
     * @return The dns question.
     */
    public byte[] toByteArray() {
        if (byteArray == null) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
            DataOutputStream dos = new DataOutputStream(baos);

            try {
                dos.write(NameUtil.toByteArray(this.name));
                dos.writeShort(type.getValue());
                dos.writeShort(clazz.getValue() | (unicastQuery ? (1 << 15) : 0));
                dos.flush();
            } catch (IOException e) {
                // Should never happen
                throw new IllegalStateException(e);
            }
            byteArray = baos.toByteArray();
        }
        return byteArray;
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(toByteArray());
    }

    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof Question)) {
            return false;
        }
        byte t[] = toByteArray();
        byte o[] = ((Question)other).toByteArray();
        return Arrays.equals(t, o);
    }

    @Override
    public String toString() {
        return "Question/" + clazz + "/" + type + ": " + name;
    }
}