Skip to content

Commit 4a5fa1e

Browse files
tmp commit: seems working
1 parent 1599be1 commit 4a5fa1e

File tree

2 files changed

+169
-16
lines changed

2 files changed

+169
-16
lines changed

e2e_tests/boundary_integration_test.go

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,9 @@ func TestBoundaryIntegration(t *testing.T) {
134134
})
135135

136136
// Test blocked domain (from inside the jail)
137-
t.Run("BlockedDomainTest", func(t *testing.T) {
137+
t.Run("HTTPBlockedDomainTest", func(t *testing.T) {
138138
// Run curl directly in the namespace using ip netns exec
139-
curlCmd := exec.Command("sudo", "sudo", "nsenter", "-t", pid, "-n", "--",
139+
curlCmd := exec.Command("sudo", "nsenter", "-t", pid, "-n", "--",
140140
"curl", "-s", "http://example.com")
141141

142142
// Capture stderr separately
@@ -150,6 +150,101 @@ func TestBoundaryIntegration(t *testing.T) {
150150
require.Contains(t, string(output), "Request Blocked by Boundary")
151151
})
152152

153+
// Test blocked domain (from inside the jail)
154+
t.Run("HTTPSBlockedDomainTest", func(t *testing.T) {
155+
_, _, _, _, configDir := util.GetUserInfo()
156+
certPath := fmt.Sprintf("%v/ca-cert.pem", configDir)
157+
158+
// Run curl directly in the namespace using ip netns exec
159+
curlCmd := exec.Command("sudo", "nsenter", "-t", pid, "-n", "--",
160+
"env", fmt.Sprintf("SSL_CERT_FILE=%v", certPath), "curl", "-s", "https://example.com")
161+
162+
// Capture stderr separately
163+
var stderr bytes.Buffer
164+
curlCmd.Stderr = &stderr
165+
output, err := curlCmd.Output()
166+
167+
if err != nil {
168+
t.Fatalf("curl command failed: %v, stderr: %s, output: %s", err, stderr.String(), string(output))
169+
}
170+
require.Contains(t, string(output), "Request Blocked by Boundary")
171+
})
172+
173+
// Gracefully close process, call cleanup methods
174+
err = boundaryCmd.Process.Signal(os.Interrupt)
175+
require.NoError(t, err, "Failed to interrupt boundary process")
176+
time.Sleep(time.Second * 1)
177+
178+
// Clean up
179+
cancel() // This will terminate the boundary process
180+
err = boundaryCmd.Wait() // Wait for process to finish
181+
if err != nil {
182+
t.Logf("Boundary process finished with error: %v", err)
183+
}
184+
185+
// Clean up binary
186+
err = os.Remove("/tmp/boundary-test")
187+
require.NoError(t, err, "Failed to remove /tmp/boundary-test")
188+
}
189+
190+
func TestBoundaryIntegration2(t *testing.T) {
191+
// Find project root by looking for go.mod file
192+
projectRoot := findProjectRoot(t)
193+
194+
// Build the boundary binary
195+
buildCmd := exec.Command("go", "build", "-o", "/tmp/boundary-test", "./cmd/...")
196+
buildCmd.Dir = projectRoot
197+
err := buildCmd.Run()
198+
require.NoError(t, err, "Failed to build boundary binary")
199+
200+
// Create context for boundary process
201+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
202+
defer cancel()
203+
204+
// Start boundary process with sudo
205+
boundaryCmd := exec.CommandContext(ctx, "/tmp/boundary-test",
206+
"--allow", "example.com",
207+
"--log-level", "debug",
208+
"--", "/bin/bash", "-c", "/usr/bin/sleep 10 && /usr/bin/echo 'Test completed'")
209+
210+
boundaryCmd.Stdin = os.Stdin
211+
boundaryCmd.Stdout = os.Stdout
212+
boundaryCmd.Stderr = os.Stderr
213+
214+
// Start the process
215+
err = boundaryCmd.Start()
216+
require.NoError(t, err, "Failed to start boundary process")
217+
218+
// Give boundary time to start
219+
time.Sleep(2 * time.Second)
220+
221+
pidInt := getChildProcessPID(t)
222+
pid := fmt.Sprintf("%v", pidInt)
223+
224+
// Test HTTPS request through boundary (from inside the jail)
225+
t.Run("HTTPSRequestThroughBoundary", func(t *testing.T) {
226+
_, _, _, _, configDir := util.GetUserInfo()
227+
certPath := fmt.Sprintf("%v/ca-cert.pem", configDir)
228+
229+
// Run curl directly in the namespace using ip netns exec
230+
curlCmd := exec.Command("sudo", "nsenter", "-t", pid, "-n", "--",
231+
"env", fmt.Sprintf("SSL_CERT_FILE=%v", certPath), "curl", "-s", "https://example.com")
232+
233+
// Capture stderr separately
234+
var stderr bytes.Buffer
235+
curlCmd.Stderr = &stderr
236+
output, err := curlCmd.Output()
237+
238+
if err != nil {
239+
t.Fatalf("curl command failed: %v, stderr: %s, output: %s", err, stderr.String(), string(output))
240+
}
241+
242+
// Verify response contains expected content
243+
expectedResponse := `<!doctype html><html lang="en"><head><title>Example Domain</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>body{background:#eee;width:60vw;margin:15vh auto;font-family:system-ui,sans-serif}h1{font-size:1.5em}div{opacity:0.8}a:link,a:visited{color:#348}</style><body><div><h1>Example Domain</h1><p>This domain is for use in documentation examples without needing permission. Avoid use in operations.<p><a href="https://iana.org/domains/example">Learn more</a></div></body></html>
244+
`
245+
require.Equal(t, expectedResponse, string(output))
246+
})
247+
153248
// Gracefully close process, call cleanup methods
154249
err = boundaryCmd.Process.Signal(os.Interrupt)
155250
require.NoError(t, err, "Failed to interrupt boundary process")

proxy/proxy.go

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package proxy
22

33
import (
44
"bufio"
5+
"bytes"
56
"crypto/tls"
67
"errors"
78
"fmt"
@@ -10,8 +11,11 @@ import (
1011
"log/slog"
1112
"net"
1213
"net/http"
14+
"net/url"
15+
"strconv"
1316
"strings"
1417
"sync/atomic"
18+
"time"
1519

1620
"github.com/coder/boundary/audit"
1721
"github.com/coder/boundary/rules"
@@ -115,7 +119,18 @@ func (p *Server) isStopped() bool {
115119
}
116120

117121
func (p *Server) handleConnectionWithTLSDetection(conn net.Conn) {
118-
defer conn.Close()
122+
//defer func() {
123+
// time.Sleep(time.Millisecond * 500)
124+
// _ = time.Sleep
125+
//
126+
// err := conn.Close()
127+
// if err != nil {
128+
// p.logger.Error("Failed to close connection", "error", err)
129+
// }
130+
//
131+
// p.logger.Debug("Successfully closed connection")
132+
//}()
133+
_ = time.Sleep
119134

120135
// Detect protocol using TLS handshake detection
121136
conn, isTLS := p.isTLSConnection(conn)
@@ -208,6 +223,22 @@ func (p *Server) handleTLSConnection(conn net.Conn) {
208223
log.Printf(" Host: %s", req.Host)
209224
log.Printf(" User-Agent: %s", req.Header.Get("User-Agent"))
210225

226+
// Check if request should be allowed
227+
result := p.ruleEngine.Evaluate(req.Method, req.Host)
228+
229+
// Audit the request
230+
//p.auditor.AuditRequest(audit.Request{
231+
// Method: req.Method,
232+
// URL: req.URL.String(),
233+
// Allowed: result.Allowed,
234+
// Rule: result.Rule,
235+
//})
236+
237+
if !result.Allowed {
238+
p.writeBlockedResponse(tlsConn, req)
239+
return
240+
}
241+
211242
// Forward HTTPS request to destination
212243
p.forwardHTTPSRequest(tlsConn, req)
213244
}
@@ -249,40 +280,67 @@ func (p *Server) forwardHTTPRequest(conn net.Conn, req *http.Request) {
249280
func (p *Server) forwardHTTPSRequest(conn net.Conn, req *http.Request) {
250281
// Create HTTP client
251282
client := &http.Client{
252-
Transport: &http.Transport{
253-
TLSClientConfig: &tls.Config{
254-
InsecureSkipVerify: true, // For demo purposes
255-
},
256-
},
257283
CheckRedirect: func(req *http.Request, via []*http.Request) error {
258284
return http.ErrUseLastResponse // Don't follow redirects
259285
},
260286
}
261287

262-
req.RequestURI = ""
263-
264288
// Set the scheme if it's missing
265289
if req.URL.Scheme == "" {
266290
req.URL.Scheme = "https"
267291
}
268292

269-
// Set the host if it's missing
270-
if req.URL.Host == "" {
271-
req.URL.Host = req.Host
293+
// Create a new request to the target server
294+
targetURL := &url.URL{
295+
Scheme: req.URL.Scheme,
296+
Host: req.Host,
297+
Path: req.URL.Path,
298+
RawQuery: req.URL.RawQuery,
299+
}
300+
newReq, err := http.NewRequest(req.Method, targetURL.String(), nil)
301+
if err != nil {
302+
panic(err)
303+
}
304+
305+
// Copy headers
306+
for name, values := range req.Header {
307+
// Skip connection-specific headers
308+
if strings.ToLower(name) == "connection" || strings.ToLower(name) == "proxy-connection" {
309+
continue
310+
}
311+
for _, value := range values {
312+
newReq.Header.Add(name, value)
313+
}
272314
}
273315

274316
// Make request to destination
275-
resp, err := client.Do(req)
317+
resp, err := client.Do(newReq)
276318
if err != nil {
277319
log.Printf("Failed to forward HTTPS request: %v", err)
278320
return
279321
}
280-
defer resp.Body.Close()
281322

282323
log.Printf("🔒 HTTPS Response: %d %s", resp.StatusCode, resp.Status)
283324

325+
bodyBytes, err := io.ReadAll(resp.Body)
326+
if err != nil {
327+
panic(err)
328+
}
329+
resp.Header.Add("Content-Length", strconv.Itoa(len(bodyBytes)))
330+
resp.ContentLength = int64(len(bodyBytes))
331+
err = resp.Body.Close()
332+
if err != nil {
333+
log.Printf("Failed to close HTTP response body: %v", err)
334+
}
335+
resp.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
336+
284337
// Copy response back to client
285-
resp.Write(conn)
338+
err = resp.Write(conn)
339+
if err != nil {
340+
log.Printf("Failed to forward HTTPS request: %v", err)
341+
}
342+
343+
log.Printf("Successfuly wrote to connection")
286344
}
287345

288346
func (p *Server) writeBlockedResponse(conn net.Conn, req *http.Request) {

0 commit comments

Comments
 (0)