Skip to content

Commit

Permalink
replace net/http with fastHTTP for better performance
Browse files Browse the repository at this point in the history
  • Loading branch information
uoosef committed Nov 23, 2023
1 parent c45aede commit 2bf0e98
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 34 deletions.
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ go 1.21.1

require (
github.com/miekg/dns v1.1.57
github.com/valyala/fasthttp v1.51.0
golang.org/x/time v0.4.0
)

require (
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/klauspost/compress v1.17.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
Expand Down
72 changes: 38 additions & 34 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
"github.com/miekg/dns"
"github.com/valyala/fasthttp"
"golang.org/x/time/rate"
"io"
"log"
Expand Down Expand Up @@ -77,31 +78,6 @@ func processDNSQuery(query []byte) ([]byte, error) {
return msg.Pack()
}

// handleDoHRequest processes the DoH request with rate limiting.
func handleDoHRequest(limiter *rate.Limiter) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if !limiter.Allow() {
http.Error(w, "Rate limit exceeded", http.StatusTooManyRequests)
return
}

body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request body", http.StatusInternalServerError)
return
}

dnsResponse, err := processDNSQuery(body)
if err != nil {
http.Error(w, "Failed to pack DNS response", http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "application/dns-message")
w.Write(dnsResponse)
}
}

// handleDoTConnection handles a single DoT connection.
func handleDoTConnection(conn net.Conn, limiter *rate.Limiter) {
defer conn.Close()
Expand Down Expand Up @@ -210,13 +186,13 @@ type readOnlyConn struct {
}

func (conn readOnlyConn) Read(p []byte) (int, error) { return conn.reader.Read(p) }
func (conn readOnlyConn) Write(p []byte) (int, error) { return 0, io.ErrClosedPipe }
func (conn readOnlyConn) Write(_ []byte) (int, error) { return 0, io.ErrClosedPipe }
func (conn readOnlyConn) Close() error { return conn.Close() }
func (conn readOnlyConn) LocalAddr() net.Addr { return nil }
func (conn readOnlyConn) RemoteAddr() net.Addr { return nil }
func (conn readOnlyConn) SetDeadline(t time.Time) error { return nil }
func (conn readOnlyConn) SetReadDeadline(t time.Time) error { return nil }
func (conn readOnlyConn) SetWriteDeadline(t time.Time) error { return nil }
func (conn readOnlyConn) SetDeadline(t time.Time) error { return conn.SetDeadline(t) }
func (conn readOnlyConn) SetReadDeadline(t time.Time) error { return conn.SetReadDeadline(t) }
func (conn readOnlyConn) SetWriteDeadline(t time.Time) error { return conn.SetWriteDeadline(t) }

func readClientHello(reader io.Reader) (*tls.ClientHelloInfo, error) {
var hello *tls.ClientHelloInfo
Expand Down Expand Up @@ -298,16 +274,44 @@ func handleConnection(clientConn net.Conn) {
wg.Wait()
}

func runDOHServer(limiter *rate.Limiter) {
http.HandleFunc("/dns-query", handleDoHRequest(limiter))
// handleDoHRequest processes the DoH request with rate limiting using fasthttp.
func handleDoHRequest(ctx *fasthttp.RequestCtx, limiter *rate.Limiter) {
if !limiter.Allow() {
ctx.Error("Rate limit exceeded", fasthttp.StatusTooManyRequests)
return
}

body := ctx.PostBody()

dnsResponse, err := processDNSQuery(body)
if err != nil {
ctx.Error("Failed to process DNS query", fasthttp.StatusInternalServerError)
return
}

ctx.SetContentType("application/dns-message")
ctx.SetStatusCode(fasthttp.StatusOK)
ctx.Write(dnsResponse)
}

server := &http.Server{
Addr: "127.0.0.1:8080",
// runDOHServer starts the DNS-over-HTTPS server using fasthttp.
func runDOHServer(limiter *rate.Limiter) {
server := &fasthttp.Server{
Handler: func(ctx *fasthttp.RequestCtx) {
switch string(ctx.Path()) {
case "/dns-query":
handleDoHRequest(ctx, limiter)
default:
ctx.Error("Unsupported path", fasthttp.StatusNotFound)
}
},
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
}

log.Println(server.ListenAndServe())
if err := server.ListenAndServe("127.0.0.1:8080"); err != nil {
log.Fatalf("Error in DoH Server: %s", err)
}
}

func main() {
Expand Down

0 comments on commit 2bf0e98

Please sign in to comment.