@@ -5,10 +5,12 @@ import (
55 "crypto/tls"
66 "errors"
77 "fmt"
8+ "io"
89 "log"
910 "log/slog"
1011 "net"
1112 "net/http"
13+ "strings"
1214 "sync/atomic"
1315
1416 "github.com/coder/boundary/audit"
@@ -163,6 +165,22 @@ func (p *Server) handleHTTPConnection(conn net.Conn) {
163165 log .Printf (" Host: %s" , req .Host )
164166 log .Printf (" User-Agent: %s" , req .Header .Get ("User-Agent" ))
165167
168+ // Check if request should be allowed
169+ result := p .ruleEngine .Evaluate (req .Method , req .Host )
170+
171+ // Audit the request
172+ //p.auditor.AuditRequest(audit.Request{
173+ // Method: req.Method,
174+ // URL: req.URL.String(),
175+ // Allowed: result.Allowed,
176+ // Rule: result.Rule,
177+ //})
178+
179+ if ! result .Allowed {
180+ p .writeBlockedResponse (conn , req )
181+ return
182+ }
183+
166184 // Forward HTTP request to destination
167185 p .forwardHTTPRequest (conn , req )
168186}
@@ -267,6 +285,48 @@ func (p *Server) forwardHTTPSRequest(conn net.Conn, req *http.Request) {
267285 resp .Write (conn )
268286}
269287
288+ func (p * Server ) writeBlockedResponse (conn net.Conn , req * http.Request ) {
289+ // Create a response object
290+ resp := & http.Response {
291+ Status : "403 Forbidden" ,
292+ StatusCode : http .StatusForbidden ,
293+ Proto : "HTTP/1.1" ,
294+ ProtoMajor : 1 ,
295+ ProtoMinor : 1 ,
296+ Header : make (http.Header ),
297+ Body : nil ,
298+ ContentLength : 0 ,
299+ }
300+
301+ // Set headers
302+ resp .Header .Set ("Content-Type" , "text/plain" )
303+
304+ // Create the response body
305+ host := req .URL .Host
306+ if host == "" {
307+ host = req .Host
308+ }
309+
310+ body := fmt .Sprintf (`🚫 Request Blocked by Boundary
311+
312+ Request: %s %s
313+ Host: %s
314+
315+ To allow this request, restart boundary with:
316+ --allow "%s" # Allow all methods to this host
317+ --allow "%s %s" # Allow only %s requests to this host
318+
319+ For more help: https://github.com/coder/boundary
320+ ` ,
321+ req .Method , req .URL .Path , host , host , req .Method , host , req .Method )
322+
323+ resp .Body = io .NopCloser (strings .NewReader (body ))
324+ resp .ContentLength = int64 (len (body ))
325+
326+ // Write to connection
327+ resp .Write (conn )
328+ }
329+
270330// connectionWrapper lets us "unread" the peeked byte
271331type connectionWrapper struct {
272332 net.Conn
0 commit comments