Compare commits
No commits in common. 'master' and 'nghttp2' have entirely different histories.
@ -1,59 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type httpclient struct {
|
||||
Net string
|
||||
Timeout time.Duration
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
func (c *httpclient) Exchange(msg *dns.Msg, upstream string) (*dns.Msg, int, error) {
|
||||
data, err := msg.Pack()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", upstream, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", dnsMsgType)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), c.Timeout)
|
||||
defer cancel()
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
resp, err := c.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, 0, fmt.Errorf("http error %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
data, err = io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
m := new(dns.Msg)
|
||||
if err = m.Unpack(data); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return m, 0, nil
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
module github.com/fangdingjun/gdns
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/fangdingjun/go-log/v5 v5.0.0
|
||||
github.com/fangdingjun/protolistener v0.0.0-20210804081554-626e6590d6e7
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||
github.com/miekg/dns v1.1.43
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/pires/go-proxyproto v0.6.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
@ -1,51 +0,0 @@
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/fangdingjun/go-log/v5 v5.0.0 h1:vdh9Bk9C4ZFL6KoO6rII73zQIyaLf7hFdBvucO/ckiE=
|
||||
github.com/fangdingjun/go-log/v5 v5.0.0/go.mod h1:V012Oxo0/pSbccX4OFSp9MJglXwNsZo2ByBBorr7zzM=
|
||||
github.com/fangdingjun/protolistener v0.0.0-20210804081554-626e6590d6e7 h1:z5NlLvUNbGZxQhtUZELvIorAqpDmcIhGQXE5GdO7+5I=
|
||||
github.com/fangdingjun/protolistener v0.0.0-20210804081554-626e6590d6e7/go.mod h1:ljbjhI4fVrT5GwMu1iBhWTZwLJSqsXKwKlGKas5GudM=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/pires/go-proxyproto v0.6.0/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
|
||||
github.com/pires/go-proxyproto v0.6.1 h1:EBupykFmo22SDjv4fQVQd2J9NOoLPmyZA/15ldOGkPw=
|
||||
github.com/pires/go-proxyproto v0.6.1/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
|
||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
@ -1,56 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
log "github.com/fangdingjun/go-log/v5"
|
||||
)
|
||||
|
||||
type logHandler struct {
|
||||
status int
|
||||
w http.ResponseWriter
|
||||
size int
|
||||
}
|
||||
|
||||
func (lh *logHandler) WriteHeader(status int) {
|
||||
lh.status = status
|
||||
lh.w.WriteHeader(status)
|
||||
}
|
||||
|
||||
func (lh *logHandler) Write(buf []byte) (int, error) {
|
||||
lh.size += len(buf)
|
||||
return lh.w.Write(buf)
|
||||
}
|
||||
|
||||
func (lh *logHandler) Header() http.Header {
|
||||
return lh.w.Header()
|
||||
}
|
||||
|
||||
func (lh *logHandler) Status() int {
|
||||
if lh.status != 0 {
|
||||
return lh.status
|
||||
}
|
||||
return 200
|
||||
}
|
||||
|
||||
var _ http.ResponseWriter = &logHandler{}
|
||||
|
||||
// LogHandler is a log middleware
|
||||
// record request log
|
||||
func LogHandler(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Error(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
log.Infof("\"%s - %s %s %s\" - %d %d \"%s\"",
|
||||
r.RemoteAddr, r.Method, r.RequestURI, r.Proto, 500, 0, r.UserAgent())
|
||||
}
|
||||
}()
|
||||
|
||||
lh := &logHandler{w: w}
|
||||
handler.ServeHTTP(lh, r)
|
||||
log.Infof("\"%s - %s %s %s\" - %d %d \"%s\"",
|
||||
r.RemoteAddr, r.Method, r.RequestURI, r.Proto, lh.Status(), lh.size, r.UserAgent())
|
||||
})
|
||||
}
|
@ -1,66 +1,83 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"crypto/tls"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
log "github.com/fangdingjun/go-log/v5"
|
||||
"github.com/fangdingjun/go-log"
|
||||
"github.com/fangdingjun/nghttp2-go"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
const dnsMsgType = "application/dns-message"
|
||||
|
||||
func (srv *server) handleHTTPReq(w http.ResponseWriter, r *http.Request) {
|
||||
/*
|
||||
ctype := r.Header.Get("content-type")
|
||||
if !strings.HasPrefix(ctype, dnsMsgType) {
|
||||
log.Errorf("request type %s, require %s", ctype, dnsMsgType)
|
||||
http.Error(w, "dns message is required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
*/
|
||||
func (srv *server) handleHTTPSConn(c net.Conn) {
|
||||
defer c.Close()
|
||||
tlsconn := c.(*tls.Conn)
|
||||
if err := tlsconn.Handshake(); err != nil {
|
||||
log.Errorln("handshake", err)
|
||||
return
|
||||
}
|
||||
state := tlsconn.ConnectionState()
|
||||
if state.NegotiatedProtocol != "h2" {
|
||||
log.Errorln("http2 is needed")
|
||||
return
|
||||
}
|
||||
h2conn, err := nghttp2.Server(tlsconn, srv)
|
||||
if err != nil {
|
||||
log.Errorf("create http2 error: %s", err)
|
||||
return
|
||||
}
|
||||
h2conn.Run()
|
||||
}
|
||||
|
||||
if r.ContentLength < 10 {
|
||||
log.Errorf("message is too small, %v", r.ContentLength)
|
||||
http.Error(w, "message is too small", http.StatusBadRequest)
|
||||
func (srv *server) handleHTTP2Req(w http.ResponseWriter, r *http.Request) {
|
||||
ctype := r.Header.Get("content-type")
|
||||
if ctype != "application/dns-message" {
|
||||
http.Error(w, "dns message is required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(r.Body)
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
log.Errorln("read request body", err)
|
||||
http.Error(w, "read request failed", http.StatusBadRequest)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
msg := new(dns.Msg)
|
||||
if err := msg.Unpack(data); err != nil {
|
||||
log.Errorln("parse dns message", err)
|
||||
http.Error(w, "parse dns message error", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
m, err := getResponseFromUpstream(msg, srv.upstreams)
|
||||
if err != nil {
|
||||
log.Debugln("query", msg.Question[0].String(), "timeout")
|
||||
http.Error(w, "query upstream server failed", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
for _, a := range m.Answer {
|
||||
log.Debugln("result", a.String())
|
||||
reply := false
|
||||
for _, up := range srv.upstreams {
|
||||
log.Debugf("from %s query upstream %s", r.RemoteAddr, up.String())
|
||||
log.Debugln("query", msg.Question[0].String())
|
||||
m, err := queryUpstream(msg, up)
|
||||
if err == nil {
|
||||
w.Header().Set("content-type", "application/dns-message")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
for _, a := range m.Answer {
|
||||
log.Debugln("result", a.String())
|
||||
}
|
||||
d, _ := m.Pack()
|
||||
w.Write(d)
|
||||
reply = true
|
||||
break
|
||||
} else {
|
||||
log.Errorf("https query upstream %s", err)
|
||||
}
|
||||
}
|
||||
w.Header().Set("content-type", dnsMsgType)
|
||||
d, _ := m.Pack()
|
||||
if _, err := w.Write(d); err != nil {
|
||||
log.Errorln(err)
|
||||
if !reply {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.RequestURI != srv.addr.Path {
|
||||
http.Error(w, "Path not found", http.StatusNotFound)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
srv.handleHTTPReq(w, r)
|
||||
srv.handleHTTP2Req(w, r)
|
||||
}
|
||||
|
Loading…
Reference in New Issue