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