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