]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/util/naming/dns/DnsBrowser.java
376c51edc4b1fbc0b53cb1f109d7d8fdf25186fc
[lgpl/argeo-commons.git] / org.argeo.util / src / org / argeo / util / naming / dns / DnsBrowser.java
1 package org.argeo.util.naming.dns;
2
3 import java.io.Closeable;
4 import java.io.IOException;
5 import java.io.PrintStream;
6 import java.util.ArrayList;
7 import java.util.Base64;
8 import java.util.Collections;
9 import java.util.Hashtable;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Objects;
13 import java.util.SortedSet;
14 import java.util.StringJoiner;
15 import java.util.TreeMap;
16 import java.util.TreeSet;
17
18 import javax.naming.Binding;
19 import javax.naming.Context;
20 import javax.naming.NameNotFoundException;
21 import javax.naming.NamingEnumeration;
22 import javax.naming.NamingException;
23 import javax.naming.directory.Attribute;
24 import javax.naming.directory.Attributes;
25 import javax.naming.directory.DirContext;
26 import javax.naming.directory.InitialDirContext;
27
28 public class DnsBrowser implements Closeable {
29 private final DirContext initialCtx;
30
31 public DnsBrowser() throws NamingException {
32 this(new ArrayList<>());
33 }
34
35 public DnsBrowser(List<String> dnsServerUrls) throws NamingException {
36 Objects.requireNonNull(dnsServerUrls);
37 Hashtable<String, Object> env = new Hashtable<>();
38 env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
39 if (!dnsServerUrls.isEmpty()) {
40 boolean specified = false;
41 StringJoiner providerUrl = new StringJoiner(" ");
42 for (String dnsUrl : dnsServerUrls) {
43 if (dnsUrl != null) {
44 providerUrl.add(dnsUrl);
45 specified = true;
46 }
47 }
48 if (specified)
49 env.put(Context.PROVIDER_URL, providerUrl.toString());
50 }
51 initialCtx = new InitialDirContext(env);
52 }
53
54 public Map<String, List<String>> getAllRecords(String name) throws NamingException {
55 Map<String, List<String>> res = new TreeMap<>();
56 Attributes attrs = initialCtx.getAttributes(name);
57 NamingEnumeration<String> ids = attrs.getIDs();
58 while (ids.hasMore()) {
59 String recordType = ids.next();
60 List<String> lst = new ArrayList<String>();
61 res.put(recordType, lst);
62 Attribute attr = attrs.get(recordType);
63 addValues(attr, lst);
64 }
65 return Collections.unmodifiableMap(res);
66 }
67
68 /**
69 * Return a single record (typically A, AAAA, etc. or null if not available.
70 * Will fail if multiple records.
71 */
72 public String getRecord(String name, String recordType) {
73 try {
74 Attributes attrs = initialCtx.getAttributes(name, new String[] { recordType });
75 if (attrs.size() == 0)
76 return null;
77 Attribute attr = attrs.get(recordType);
78 if (attr.size() > 1)
79 throw new IllegalArgumentException("Multiple record type " + recordType);
80 assert attr.size() != 0;
81 Object value = attr.get();
82 assert value != null;
83 return value.toString();
84 } catch (NameNotFoundException e) {
85 return null;
86 } catch (NamingException e) {
87 throw new IllegalStateException("Cannot get DNS entry " + recordType + " of " + name, e);
88 }
89 }
90
91 /**
92 * Return records of a given type.
93 */
94 public List<String> getRecords(String name, String recordType) throws NamingException {
95 List<String> res = new ArrayList<String>();
96 Attributes attrs = initialCtx.getAttributes(name, new String[] { recordType });
97 Attribute attr = attrs.get(recordType);
98 addValues(attr, res);
99 return res;
100 }
101
102 /** Ordered, with preferred first. */
103 public List<String> getSrvRecordsAsHosts(String name, boolean withPort) throws NamingException {
104 List<String> raw = getRecords(name, "SRV");
105 if (raw.size() == 0)
106 return null;
107 SortedSet<SrvRecord> res = new TreeSet<>();
108 for (int i = 0; i < raw.size(); i++) {
109 String record = raw.get(i);
110 String[] arr = record.split(" ");
111 Integer priority = Integer.parseInt(arr[0]);
112 Integer weight = Integer.parseInt(arr[1]);
113 Integer port = Integer.parseInt(arr[2]);
114 String hostname = arr[3];
115 SrvRecord order = new SrvRecord(priority, weight, port, hostname);
116 res.add(order);
117 }
118 List<String> lst = new ArrayList<>();
119 for (SrvRecord order : res) {
120 lst.add(order.toHost(withPort));
121 }
122 return Collections.unmodifiableList(lst);
123 }
124
125 private void addValues(Attribute attr, List<String> lst) throws NamingException {
126 NamingEnumeration<?> values = attr.getAll();
127 while (values.hasMore()) {
128 Object value = values.next();
129 if (value != null) {
130 if (value instanceof byte[]) {
131 String str = Base64.getEncoder().encodeToString((byte[]) value);
132 lst.add(str);
133 } else
134 lst.add(value.toString());
135 }
136 }
137
138 }
139
140 public List<String> listEntries(String name) throws NamingException {
141 List<String> res = new ArrayList<String>();
142 NamingEnumeration<Binding> ne = initialCtx.listBindings(name);
143 while (ne.hasMore()) {
144 Binding b = ne.next();
145 res.add(b.getName());
146 }
147 return Collections.unmodifiableList(res);
148 }
149
150 @Override
151 public void close() throws IOException {
152 destroy();
153 }
154
155 public void destroy() {
156 try {
157 initialCtx.close();
158 } catch (NamingException e) {
159 // silent
160 }
161 }
162
163 public static void main(String[] args) {
164 if (args.length == 0) {
165 printUsage(System.err);
166 System.exit(1);
167 }
168 try (DnsBrowser dnsBrowser = new DnsBrowser()) {
169 String hostname = args[0];
170 String recordType = args.length > 1 ? args[1] : "A";
171 if (recordType.equals("*")) {
172 Map<String, List<String>> records = dnsBrowser.getAllRecords(hostname);
173 for (String type : records.keySet()) {
174 for (String record : records.get(type)) {
175 String typeLabel;
176 if ("44".equals(type))
177 typeLabel = "SSHFP";
178 else if ("46".equals(type))
179 typeLabel = "RRSIG";
180 else if ("48".equals(type))
181 typeLabel = "DNSKEY";
182 else
183 typeLabel = type;
184 System.out.println(typeLabel + "\t" + record);
185 }
186 }
187 } else {
188 System.out.println(dnsBrowser.getRecord(hostname, recordType));
189 }
190
191 } catch (Exception e) {
192 e.printStackTrace();
193 }
194 }
195
196 public static void printUsage(PrintStream out) {
197 out.println("java org.argeo.naming.DnsBrowser <hostname> [<record type> | *]");
198 }
199
200 }