Skip to content

Commit 54a1bc6

Browse files
author
Joseph Harnish
committed
Initial load
1 parent 3a5e746 commit 54a1bc6

File tree

4 files changed

+260
-1
lines changed

4 files changed

+260
-1
lines changed

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,20 @@
22
A Web interface to DNS.
33

44

5-
This is a quick implimentation to be the opposite side of: https://github.com/wrouesnel/dns-over-https-proxy
5+
This is a quick implementation to be the opposite side of: https://github.com/wrouesnel/dns-over-https-proxy
66

77
You should be able to run this on a virtual instance where ever. Or any CDN or Freedom advocate can run it.
88

9+
This is a work in progress. I used the basic TLS webserver from Go. PRs and updates welcome.
10+
11+
/etc/dnsproxy.yaml
12+
13+
```
14+
dnsserver: 8.8.8.8
15+
dnsport: 53
16+
listenport: 8415
17+
sslkeypath:
18+
sslcrtpath:
19+
```
20+
21+
It currently has no logging. Will probably add that shortly.

config.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package main
2+
3+
import (
4+
"gopkg.in/yaml.v1"
5+
"io/ioutil"
6+
"log"
7+
"os"
8+
)
9+
10+
type Config struct {
11+
DNSServer string
12+
DNSPort string
13+
ListenPort string
14+
SSLKeyPath string
15+
SSLCrtPath string
16+
}
17+
18+
func LoadConfig(path string) *Config {
19+
20+
temp := new(Config)
21+
file, err := ioutil.ReadFile(path)
22+
if err != nil {
23+
log.Println("open config: ", err)
24+
os.Exit(1)
25+
}
26+
27+
if err = yaml.Unmarshal(file, temp); err != nil {
28+
log.Println("parse config: ", err)
29+
os.Exit(1)
30+
}
31+
return temp
32+
}

https-dns-proxy.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"github.com/miekg/dns"
7+
"log"
8+
"net"
9+
"net/http"
10+
"strconv"
11+
)
12+
13+
type QuestionRec struct {
14+
Name string `json:"name"`
15+
Type int `json:"type"`
16+
}
17+
18+
type ResponseRecord struct {
19+
AD bool `json:"AD"`
20+
Additional []interface{} `json:"Additional"`
21+
Answer []dns.RR
22+
CD bool `json:"CD"`
23+
Question QuestionRec `json:"Question"`
24+
RA bool `json:"RA"`
25+
RD bool `json:"RD"`
26+
Status int `json:"Status"`
27+
TC bool `json:"TC"`
28+
EdnsClientSubnet string `json:"edns_client_subnet"`
29+
Comment string `json:"Comment"`
30+
}
31+
32+
func ResolveDNS(w http.ResponseWriter, req *http.Request) {
33+
w.Header().Set("Content-Type", "application/json")
34+
recname := req.URL.Query().Get("name")
35+
rectype := req.URL.Query().Get("type")
36+
//FIXME add dnssec info
37+
//recdnssec := req.URL.Query().Get("dnssec")
38+
39+
c := new(dns.Client)
40+
m := new(dns.Msg)
41+
rectypeint, err := strconv.Atoi(rectype)
42+
if err != nil {
43+
rectypeint = 255
44+
}
45+
myquestion := QuestionRec{
46+
Name: recname,
47+
Type: rectypeint,
48+
}
49+
m.SetQuestion(dns.Fqdn(recname), uint16(rectypeint))
50+
m.RecursionDesired = true
51+
r, _, err := c.Exchange(m, net.JoinHostPort(config.DNSServer, config.DNSPort))
52+
if r == nil {
53+
log.Fatalf("*** error: %s\n", err.Error())
54+
http.Error(w, err.Error(), http.StatusInternalServerError)
55+
}
56+
57+
status := 0
58+
if r.Rcode != dns.RcodeSuccess {
59+
log.Fatalf(" *** invalid answer name %s after A query for %s\n", recname, recname)
60+
status = 1
61+
62+
}
63+
64+
//FIXME make all fields updated
65+
responsejson := ResponseRecord{
66+
AD: false,
67+
CD: false,
68+
Answer: r.Answer,
69+
Question: myquestion,
70+
Status: status,
71+
TC: false,
72+
RD: true,
73+
RA: true,
74+
}
75+
76+
jsonoutbyte, err := json.Marshal(responsejson)
77+
if err != nil {
78+
fmt.Println("Error")
79+
http.Error(w, err.Error(), http.StatusInternalServerError)
80+
} else {
81+
w.Write(jsonoutbyte)
82+
}
83+
}
84+
85+
func ResolveDNSHTML(w http.ResponseWriter, req *http.Request) {
86+
fmt.Fprint(w, PageHTML)
87+
}
88+
89+
func redirect(w http.ResponseWriter, r *http.Request) {
90+
91+
http.Redirect(w, r, "/query", 301)
92+
}
93+
94+
var config = LoadConfig("/etc/dnsproxy.yaml")
95+
96+
func main() {
97+
98+
http.HandleFunc("/", redirect)
99+
http.HandleFunc("/query", ResolveDNSHTML)
100+
http.HandleFunc("/resolve", ResolveDNS)
101+
if config.SSLKeyPath != "" {
102+
err := http.ListenAndServeTLS(":"+config.ListenPort, config.SSLCrtPath, config.SSLKeyPath, nil)
103+
if err != nil {
104+
log.Fatal("ListenAndServeTLS: ", err)
105+
}
106+
} else {
107+
err := http.ListenAndServe(":"+config.ListenPort, nil)
108+
109+
if err != nil {
110+
log.Fatal("ListenAndServe: ", err)
111+
}
112+
113+
}
114+
}

webpage.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package main
2+
3+
const PageHTML = `
4+
<html lang=en>
5+
<head>
6+
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
7+
<title>HTTP(s) DNS lookup</title>
8+
<script language="JavaScript">
9+
// http://stackoverflow.com/questions/12460378/how-to-get-json-from-url-in-javascript
10+
var getJSON = function(url, callback) {
11+
var xhr = new XMLHttpRequest();
12+
xhr.open('GET', url, true);
13+
xhr.responseType = 'json';
14+
xhr.onload = function() {
15+
var status = xhr.status;
16+
if (status == 200) {
17+
callback(null, xhr.response);
18+
} else {
19+
callback(status);
20+
}
21+
};
22+
xhr.send();
23+
};
24+
// http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
25+
function getParameterByName(name, url) {
26+
if (!url) url = window.location.href;
27+
name = name.replace(/[\[\]]/g, "\\$&");
28+
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
29+
results = regex.exec(url);
30+
if (!results) return null;
31+
if (!results[2]) return '';
32+
return decodeURIComponent(results[2].replace(/\+/g, " "));
33+
}
34+
35+
function ResolveName() {
36+
var name = document.getElementById('name').value;
37+
var types = document.getElementsByName('type');
38+
var i;
39+
var mytype = 255
40+
for (i=0; i < types.length; i++){
41+
if (types[i].checked == true){
42+
mytype = types[i].value;
43+
}
44+
}
45+
var hosturl = window.location.host;
46+
var protocol = window.location.protocol;
47+
var prefixurl = protocol + "//" + hosturl
48+
document.getElementById("directurl").innerHTML = '<a href="'+ prefixurl + '/resolve?name=' + name + '&type=' + mytype + '">' + prefixurl + '/resolve?name=' + name + '&type=' + mytype + '</a><br>';
49+
getJSON('/resolve?name=' + name,
50+
function(err, data) {
51+
if (err != null) {
52+
alert('Something went wrong: ' + err);
53+
} else {
54+
document.getElementById("json").innerHTML = JSON.stringify(data, undefined, 2);
55+
}
56+
});
57+
}
58+
function loadURL() {
59+
var myname = getParameterByName("name")
60+
var mytype = getParameterByName("type")
61+
document.getElementById("name").value = myname;
62+
document.getElementById("type-" + mytype).checked = true;
63+
var hosturl = window.location.host;
64+
var protocol = window.location.protocol;
65+
var prefixurl = protocol + "//" + hosturl
66+
document.getElementById("directurl").innerHTML = '<a href="'+ prefixurl + '/resolve?name=' + myname + '&type=' + mytype + '">' + prefixurl + '/resolve?name=' + myname + '&type=' + mytype + '</a><br>';
67+
getJSON('/resolve?name=' + myname + '&type=' + mytype,
68+
function(err, data) {
69+
if (err != null) {
70+
alert('failed to query');
71+
} else {
72+
document.getElementById("json").innerHTML = JSON.stringify(data, undefined, 2);
73+
}
74+
})
75+
}
76+
77+
</script>
78+
</head>
79+
<body onload="loadURL()">
80+
<form>
81+
<table width=100% bgcolor="#808080">
82+
<tr><td>DNS Lookup</td><td><input type="text" name="name" id="name"></td><td><input type="button" name="lookup" value="Resolve" OnClick=ResolveName()></td></tr>
83+
</table>
84+
<table>
85+
<tr>
86+
<td><input type="radio" name="type" id="type-1" value="1"> A </td>
87+
<td><input type="radio" name="type" id="type-28" value="28"> AAAA </td>
88+
<td><input type="radio" name="type" id="type-5" value="5"> CNAME </td>
89+
<td><input type="radio" name="type" id="type-15" value="15"> MX </td>
90+
<td><input type="radio" name="type" id="type-255" value="255" checked> ANY </td>
91+
</tr>
92+
</table>
93+
</form>
94+
<hr>
95+
Results:<br>
96+
<pre id="json"></pre>
97+
Short cut URL: <p id="directurl"></p>
98+
</body>
99+
</html>
100+
`

0 commit comments

Comments
 (0)