pr review changes

This commit is contained in:
Quentin McGaw
2026-06-11 00:16:32 +00:00
parent 69b4e5c584
commit d28744e06d
8 changed files with 54 additions and 13 deletions
+4
View File
@@ -63,6 +63,10 @@ jobs:
-v "$(pwd)/coverage.txt:/tmp/gobuild/coverage.txt" \ -v "$(pwd)/coverage.txt:/tmp/gobuild/coverage.txt" \
test-container test-container
- name: Run integration tests in test container
run: |
docker run --rm --entrypoint "go test -tags=integration ./internal/restrictednet" test-container
- name: Verify dev cross platform compatibility - name: Verify dev cross platform compatibility
run: docker build --target xcompile . run: docker build --target xcompile .
+1 -1
View File
@@ -3,7 +3,7 @@
// to develop this project. // to develop this project.
"files.eol": "\n", "files.eol": "\n",
"editor.formatOnSave": true, "editor.formatOnSave": true,
"go.buildTags": "linux", "go.buildTags": "linux,integration",
"go.toolsEnvVars": { "go.toolsEnvVars": {
"CGO_ENABLED": "0" "CGO_ENABLED": "0"
}, },
+2 -1
View File
@@ -41,7 +41,8 @@ func New(settings Settings) *Client {
} }
// OpenHTTPSByHostname opens an https connection through the firewall, // OpenHTTPSByHostname opens an https connection through the firewall,
// valid for up to one second, to the hostname which in the format `host:port`. // to the hostname which in the format `host:port`. The returned cleanup
// function must be called to remove the temporary firewall rule and close connections.
// It first resolves the domain in hostname using DNS over HTTPS and then opens // It first resolves the domain in hostname using DNS over HTTPS and then opens
// the restricted HTTPS connection to the resolved IP. // the restricted HTTPS connection to the resolved IP.
func (c *Client) OpenHTTPSByHostname(ctx context.Context, hostname string) ( func (c *Client) OpenHTTPSByHostname(ctx context.Context, hostname string) (
+2
View File
@@ -16,6 +16,8 @@ import (
) )
// OpenHTTPS opens temporary restrictive firewall output for one HTTPS destination. // OpenHTTPS opens temporary restrictive firewall output for one HTTPS destination.
// The returned [*http.Client] must be used sequentially only, and each request must
// have its response body fully read/discarded and then closed.
// The returned cleanup function must be called to remove the temporary firewall rule and close connections. // The returned cleanup function must be called to remove the temporary firewall rule and close connections.
func (c *Client) OpenHTTPS(ctx context.Context, destinationTLSName string, destinationAddrPort netip.AddrPort, func (c *Client) OpenHTTPS(ctx context.Context, destinationTLSName string, destinationAddrPort netip.AddrPort,
) (httpClient *http.Client, cleanup func() error, err error) { ) (httpClient *http.Client, cleanup func() error, err error) {
+15 -8
View File
@@ -1,8 +1,11 @@
//go:build integration
package restrictednet package restrictednet
import ( import (
"context" "context"
"fmt" "fmt"
"io"
"net/http" "net/http"
"net/netip" "net/netip"
"testing" "testing"
@@ -94,16 +97,20 @@ func Test_Client_OpenHTTPS(t *testing.T) {
require.NotNil(t, httpClient) require.NotNil(t, httpClient)
require.NotNil(t, cleanup) require.NotNil(t, cleanup)
request, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://"+destinationTLSName, nil) const requests = 2
require.NoError(t, err)
response, err := httpClient.Do(request) for range requests {
require.NoError(t, err) request, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://"+destinationTLSName, nil)
t.Cleanup(func() { require.NoError(t, err)
_ = response.Body.Close()
})
assert.Equal(t, http.StatusOK, response.StatusCode) response, err := httpClient.Do(request)
require.NoError(t, err)
_, err = io.Copy(io.Discard, response.Body)
require.NoError(t, err)
err = response.Body.Close()
require.NoError(t, err)
assert.Equal(t, http.StatusOK, response.StatusCode)
}
err = cleanup() err = cleanup()
require.NoError(t, err) require.NoError(t, err)
+27 -2
View File
@@ -9,6 +9,7 @@ import (
"net/http" "net/http"
"net/netip" "net/netip"
"net/url" "net/url"
"strconv"
"github.com/miekg/dns" "github.com/miekg/dns"
) )
@@ -76,8 +77,16 @@ func (c *Client) resolveOneQuestionType(ctx context.Context,
dohServerIPs = append(dohServerIPs, dohServer.IPv4...) dohServerIPs = append(dohServerIPs, dohServer.IPv4...)
for _, dohServerIP := range dohServerIPs { for _, dohServerIP := range dohServerIPs {
const defaultDoHPort = 443 const defaultDoHPort uint16 = 443
dohServerAddrPort := netip.AddrPortFrom(dohServerIP, defaultDoHPort) port := defaultDoHPort
if portStr := dohURL.Port(); portStr != "" {
port, err = parseDestinationPort(portStr)
if err != nil {
errs = append(errs, fmt.Errorf("parsing DoH server port: %w", err))
continue
}
}
dohServerAddrPort := netip.AddrPortFrom(dohServerIP, port)
responseMessage, err := c.doHQuery(ctx, queryWire, dohURL, dohServerAddrPort) responseMessage, err := c.doHQuery(ctx, queryWire, dohURL, dohServerAddrPort)
switch { switch {
case err != nil: case err != nil:
@@ -178,3 +187,19 @@ func answersToNetipAddrs(message *dns.Msg) (addresses []netip.Addr) {
} }
return addresses return addresses
} }
func parseDestinationPort(portStr string) (port uint16, err error) {
portUint, err := strconv.ParseUint(portStr, 10, 16)
if err != nil {
return 0, err
}
const maxPortUint = 65535
switch {
case portUint == 0:
return 0, errors.New("port cannot be 0")
case portUint > maxPortUint:
return 0, fmt.Errorf("port cannot be greater than %d", maxPortUint)
}
return uint16(portUint), nil
}
+2
View File
@@ -1,3 +1,5 @@
//go:build integration
package restrictednet package restrictednet
import ( import (
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build unix //go:build !windows
package restrictednet package restrictednet