aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs/conversations/utils/DNSHelper.java
blob: 79a8c85433aa5d52a59c25fa71095109fc57fc07 (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
package eu.siacs.conversations.utils;

import de.measite.minidns.Client;
import de.measite.minidns.DNSMessage;
import de.measite.minidns.Record;
import de.measite.minidns.Record.TYPE;
import de.measite.minidns.Record.CLASS;
import de.measite.minidns.record.SRV;
import de.measite.minidns.record.Data;
import de.measite.minidns.util.NameUtil;

import java.io.IOException;
import java.net.InetAddress;
import java.util.TreeSet;
import java.util.regex.Pattern;

import de.thedevstack.android.logcat.Logging;
import de.thedevstack.conversationsplus.dto.SrvRecord;

import eu.siacs.conversations.Config;
import eu.siacs.conversations.xmpp.jid.Jid;

public class DNSHelper {
    private static final String CLIENT_SRV_PREFIX = "_xmpp-client._tcp.";
    private static final Pattern PATTERN_IPV4 = Pattern.compile("\\A(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
    private static final Pattern PATTERN_IPV6_HEX4DECCOMPRESSED = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::((?:[0-9A-Fa-f]{1,4}:)*)(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
    private static final Pattern PATTERN_IPV6_6HEX4DEC = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}:){6,6})(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
    private static final Pattern PATTERN_IPV6_HEXCOMPRESSED = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)\\z");
    private static final Pattern PATTERN_IPV6 = Pattern.compile("\\A(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\\z");

	protected static Client client = new Client();

    /**
     * Queries the SRV record for the server JID.
     * This method uses all available Domain Name Servers.
     * @param jid the server JID
     * @return TreeSet with SrvRecords. If no SRV record is found for JID an empty TreeSet is returned.
     */
    public static final TreeSet<SrvRecord> querySrvRecord(Jid jid) {
        String host = jid.getDomainpart();
        String dns[] = client.findDNS();
        TreeSet<SrvRecord> result = new TreeSet<>();

        if (dns != null) {
            for (String dnsserver : dns) {
                result = querySrvRecord(host, dnsserver);
                if (!result.isEmpty()) {
                    break;
                }
            }
        }

        return result;
    }

    /**
     * Queries the SRV record for an host from the given Domain Name Server.
     * @param host the host to query for
     * @param dnsserver the DNS to query on
     * @return TreeSet with SrvRecords.
     */
    private static final TreeSet<SrvRecord> querySrvRecord(String host, String dnsserver) {
        TreeSet<SrvRecord> result = new TreeSet<>();
        try {
            InetAddress dnsServerAddress = InetAddress.getByName(dnsserver);
            String qname = CLIENT_SRV_PREFIX + host;
            DNSMessage message = client.query(qname, TYPE.SRV, CLASS.IN, dnsServerAddress.getHostAddress());
            Record[] rrset = message.getAnswers();
            for (Record rr : rrset) {
                Data d = rr.getPayload();
                if (d instanceof SRV && NameUtil.idnEquals(qname, rr.getName())) {
                    SRV srv = (SRV) d;
                    SrvRecord srvRecord = new SrvRecord(srv.getPriority(), srv.getName(), srv.getPort());
                    result.add(srvRecord);
                }
            }
        } catch (IOException e) {
            Logging.d("dns", "Error while retrieving SRV record for '" + host + "' from DNS '" + dnsserver + "': " + e.getMessage());
        }
        return result;
    }

    /**
     * Checks whether the given server is an IP address or not.
     * The following patterns are treated as valid IP addresses:
     * <ul>
     *     <li>{@link #PATTERN_IPV4}</li>
     *     <li>{@link #PATTERN_IPV6}</li>
     *     <li>{@link #PATTERN_IPV6_6HEX4DEC}</li>
     *     <li>{@link #PATTERN_IPV6_HEX4DECCOMPRESSED}</li>
     *     <li>{@link #PATTERN_IPV6_HEXCOMPRESSED}</li>
     * </ul>
     * @param server the string to check
     * @return <code>true</code> if one of the patterns is matched <code>false</code> otherwise
     */
	public static boolean isIp(final String server) {
		return PATTERN_IPV4.matcher(server).matches()
				|| PATTERN_IPV6.matcher(server).matches()
				|| PATTERN_IPV6_6HEX4DEC.matcher(server).matches()
				|| PATTERN_IPV6_HEX4DECCOMPRESSED.matcher(server).matches()
				|| PATTERN_IPV6_HEXCOMPRESSED.matcher(server).matches();
	}
}