1 /*
2  * This file is a part of DNSViz, a tool suite for DNS/DNSSEC monitoring,
3  * analysis, and visualization.
4  * Created by Casey Deccio (casey@deccio.net)
5  *
6  * Copyright 2016 VeriSign, Inc.
7  *
8  * DNSViz is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * DNSViz is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with DNSViz.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 package net.dnsviz.lookingglass;
23 
24 import java.io.IOException;
25 import java.io.PrintWriter;
26 import java.io.StringWriter;
27 import java.net.InetAddress;
28 import java.net.UnknownHostException;
29 
30 import org.json.JSONArray;
31 import org.json.JSONObject;
32 import org.json.JSONException;
33 
34 import net.dnsviz.transport.DNSQueryTransportHandler;
35 import net.dnsviz.transport.DNSQueryTransportHandlerTCP;
36 import net.dnsviz.transport.DNSQueryTransportHandlerUDP;
37 import net.dnsviz.transport.DNSQueryTransportManager;
38 import net.dnsviz.util.Base64Decoder;
39 import net.dnsviz.util.Base64Encoder;
40 import net.dnsviz.websocket.WebSocketClient;
41 
42 public class DNSLookingGlass {
DNSLookingGlass()43 	public DNSLookingGlass() {
44 	}
45 
getDNSQueryTransportHandlers(JSONObject obj)46 	protected DNSQueryTransportHandler [] getDNSQueryTransportHandlers(JSONObject obj) throws JSONException, UnknownHostException {
47 		DNSQueryTransportHandler [] ret;
48 		JSONArray requests;
49 		String [] vers;
50 		String src;
51 		int sport;
52 		JSONObject reqObj;
53 
54 		vers = Double.toString(obj.getDouble("version")).split("\\.");
55 		if (Integer.parseInt(vers[0]) != 1 || Integer.parseInt(vers[1]) > 0) {
56 			throw new JSONException("Version of JSON input is invalid");
57 		}
58 
59 		requests = obj.getJSONArray("requests");
60 		ret = new DNSQueryTransportHandler [requests.length()];
61 		for (int i = 0; i < requests.length(); i++) {
62 			reqObj = requests.getJSONObject(i);
63 			if (reqObj.has("src")) {
64 				src = reqObj.getString("src");
65 			} else {
66 				src = null;
67 			}
68 			if (reqObj.has("sport")) {
69 				sport = reqObj.getInt("sport");
70 			} else {
71 				sport = 0;
72 			}
73 			ret[i] = getDNSQueryTransportHandler(reqObj.getString("req"), reqObj.getString("dst"), reqObj.getInt("dport"), src, sport, reqObj.getLong("timeout"), reqObj.getBoolean("tcp"));
74 		}
75 		return ret;
76 	}
77 
getEncodedResponses(DNSQueryTransportHandler [] qths)78 	protected JSONObject getEncodedResponses(DNSQueryTransportHandler [] qths) {
79 		JSONObject ret;
80 		JSONObject response;
81 
82 		JSONArray responses = new JSONArray();
83 		for (int i = 0; i < qths.length; i++) {
84 			response = new JSONObject();
85 			response.put("res", qths[i].getEncodedResponse());
86 			if (qths[i].getError() != null) {
87 				response.put("err", qths[i].getError());
88 				if (qths[i].getErrno() != null) {
89 					response.put("errno", qths[i].getErrno());
90 				}
91 			}
92 			if (qths[i].getSource() != null) {
93 				response.put("src", qths[i].getSource().getHostAddress());
94 			} else {
95 				response.put("src", (String)null);
96 			}
97 			if (qths[i].getSPort() != 0) {
98 				response.put("sport", qths[i].getSPort());
99 			} else {
100 				response.put("sport", (String)null);
101 			}
102 			response.put("time_elapsed", qths[i].timeElapsed());
103 			responses.put(response);
104 		}
105 
106 		ret = new JSONObject();
107 		ret.put("version", "1.0");
108 		ret.put("responses", responses);
109 		return ret;
110 	}
111 
getDNSQueryTransportHandler(String req, String dst, int dport, String src, int sport, long timeout, boolean tcp)112 	public DNSQueryTransportHandler getDNSQueryTransportHandler(String req, String dst, int dport, String src, int sport, long timeout, boolean tcp) throws UnknownHostException {
113 		Base64Decoder d = new Base64Decoder();
114 		byte [] byteReq = d.decode(req.getBytes());
115 		InetAddress srcAddr = null;
116 		InetAddress dstAddr = null;
117 		if (dst != null) {
118 			dstAddr = InetAddress.getByName(dst);
119 		}
120 		if (src != null) {
121 			srcAddr = InetAddress.getByName(src);
122 		}
123 		if (tcp) {
124 			return new DNSQueryTransportHandlerTCP(byteReq, dstAddr, dport, srcAddr, sport, timeout);
125 		} else {
126 			return new DNSQueryTransportHandlerUDP(byteReq, dstAddr, dport, srcAddr, sport, timeout);
127 		}
128 	}
129 
executeQueries(DNSQueryTransportHandler [] qths)130 	public void executeQueries(DNSQueryTransportHandler [] qths) throws IOException {
131 		int i;
132 		DNSQueryTransportManager qtm = new DNSQueryTransportManager();
133 		qtm.query(qths);
134 		for (i = 0; i < qths.length; i++) {
135 			qths[i].finalize();
136 		}
137 	}
138 
interact(WebSocketClient ws)139 	protected void interact(WebSocketClient ws) throws IOException {
140 		byte [] input;
141 		while ((input = ws.read()).length > 0) {
142 			ws.write(run(new String(input)).getBytes());
143 		}
144 	}
145 
run(String json)146 	public String run(String json) {
147 		JSONObject ret;
148 		try {
149 			DNSQueryTransportHandler [] qths = getDNSQueryTransportHandlers(new JSONObject(json));
150 			executeQueries(qths);
151 			return getEncodedResponses(qths).toString();
152 		} catch (Exception ex) {
153 			ret = new JSONObject();
154 			ret.put("version", "1.0");
155 			ret.put("error", getErrorTrace(ex));
156 			return ret.toString();
157 		}
158 	}
159 
getErrorTrace(Exception err)160 	protected String getErrorTrace(Exception err) {
161 		StringWriter sw = new StringWriter();
162 		PrintWriter pw = new PrintWriter(sw);
163 		err.printStackTrace(pw);
164 		return sw.toString();
165 	}
166 
main(String [] args)167 	public static void main(String [] args) throws IOException {
168 		WebSocketClient ws = new WebSocketClient(args[0], Integer.parseInt(args[1]), args[2], args[3]);
169 		DNSLookingGlass lg = new DNSLookingGlass();
170 		lg.interact(ws);
171 	}
172 }
173