-
Notifications
You must be signed in to change notification settings - Fork 2
/
doh.go
111 lines (87 loc) · 1.95 KB
/
doh.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package hnsquery
import (
"bytes"
"context"
"encoding/binary"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"time"
)
type dohConn struct {
endpoint *url.URL
http *http.Client
body *io.Reader
ctx context.Context
deadline time.Time
}
func (d *dohConn) Read(b []byte) (n int, err error) {
if d.body == nil {
return 0, io.ErrClosedPipe
}
return (*d.body).Read(b)
}
func (d *dohConn) Write(b []byte) (n int, err error) {
if d.body != nil {
return 0, io.ErrClosedPipe
}
if len(b) < 2 {
return 0, fmt.Errorf("bad message")
}
// trim length
b = b[2:]
ctx := d.ctx
if !d.deadline.IsZero() {
var cancel context.CancelFunc
ctx, cancel = context.WithDeadline(d.ctx, d.deadline)
defer cancel()
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, d.endpoint.String(), bytes.NewBuffer(b))
if err != nil {
return 0, fmt.Errorf("failed making http request: %v", err)
}
req.Header.Add("Content-Type", "application/dns-message")
req.Host = d.endpoint.Host
resp, err := d.http.Do(req)
if err != nil {
return 0, fmt.Errorf("failed reading http response: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return 0, fmt.Errorf("failed with http status code %d", resp.StatusCode)
}
buf, err := ioutil.ReadAll(resp.Body)
if err != nil {
return 0, fmt.Errorf("failed reading response: %v", err)
}
msg := make([]byte, 2+len(buf))
binary.BigEndian.PutUint16(msg, uint16(len(buf)))
copy(msg[2:], buf)
reader := io.Reader(bytes.NewReader(msg))
d.body = &reader
return len(b), nil
}
func (d *dohConn) Close() error {
return nil
}
func (d *dohConn) LocalAddr() net.Addr {
return nil
}
func (d *dohConn) RemoteAddr() net.Addr {
return nil
}
func (d *dohConn) SetDeadline(t time.Time) error {
d.deadline = t
return nil
}
func (d *dohConn) SetReadDeadline(t time.Time) error {
d.deadline = t
return nil
}
func (d *dohConn) SetWriteDeadline(t time.Time) error {
d.deadline = t
return nil
}