osbase/socksproxy: implement hostname addresses

This is required by quite a few clients, like Chrome. Implement it for
better usability of our userspace network while debugging.

Change-Id: I5db16d3702800b79f88d11c132ce8f7469839ec4
Reviewed-on: https://review.monogon.dev/c/monogon/+/3842
Tested-by: Jenkins CI
Reviewed-by: Leopold Schabel <leo@monogon.tech>
diff --git a/osbase/socksproxy/protocol.go b/osbase/socksproxy/protocol.go
index 0d5d133..698d324 100644
--- a/osbase/socksproxy/protocol.go
+++ b/osbase/socksproxy/protocol.go
@@ -115,9 +115,13 @@
 	}
 
 	var addrBytes []byte
+	var hostnameBytes []byte
 	switch header.Atyp {
 	case 1:
 		addrBytes = make([]byte, 4)
+	case 3:
+		// Variable-length string to resolve
+		addrBytes = make([]byte, 1)
 	case 4:
 		addrBytes = make([]byte, 16)
 	default:
@@ -127,20 +131,30 @@
 		return nil, fmt.Errorf("when reading address: %w", err)
 	}
 
+	// Handle domain name addressing, required by for example Chrome
+	if header.Atyp == 3 {
+		hostnameBytes = make([]byte, addrBytes[0])
+		if _, err := io.ReadFull(r, hostnameBytes); err != nil {
+			return nil, fmt.Errorf("when reading address: %w", err)
+		}
+	}
+
 	var port uint16
 	if err := binary.Read(r, binary.BigEndian, &port); err != nil {
 		return nil, fmt.Errorf("when reading port: %w", err)
 	}
 
 	return &connectRequest{
-		address: addrBytes,
-		port:    port,
+		address:  addrBytes,
+		hostname: string(hostnameBytes),
+		port:     port,
 	}, nil
 }
 
 type connectRequest struct {
-	address net.IP
-	port    uint16
+	address  net.IP
+	hostname string
+	port     uint16
 }
 
 // Reply is an RFC1928 6. “Replies” reply field value. It's returned to the