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