Skip to content

Commit 74155a3

Browse files
committed
fix(proxy): enforce deferred ask policy for non-TLS protocols
Non-MITM protocols (SSH, SMTP, plain HTTP, generic TCP) now check the deferred per-request policy before relaying. Without this, connections to non-TLS ports on ask destinations would pass through without any approval.
1 parent f33f84b commit 74155a3

1 file changed

Lines changed: 40 additions & 20 deletions

File tree

internal/proxy/server.go

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -319,14 +319,16 @@ func (r *policyRuleSet) Allow(ctx context.Context, req *socks5.Request) (context
319319
log.Printf("[ASK->DENY] %s:%d (no approval broker)", dest, port)
320320
} else {
321321
// Auto-allow the SOCKS5 CONNECT without prompting the user.
322-
// Approval happens per-request inside the MITM handler where
323-
// the HTTP method and path are known, producing a single
324-
// combined Telegram message per request instead of two
325-
// separate messages (connection + request).
322+
// For TLS connections: approval happens per-request inside the
323+
// MITM handler where the HTTP method and path are known.
324+
// For non-TLS connections (SSH, plain TCP): the checker is
325+
// attached but the direct-relay path in handleWithDetection
326+
// calls CheckAndConsume once before relaying, providing a
327+
// connection-level approval prompt.
326328
allowed = true
327329
effectiveVerdict = policy.Allow
328330
reason = "ask deferred to per-request"
329-
log.Printf("[ASK->DEFER] %s:%d (approval deferred to per-request)", dest, port)
331+
log.Printf("[ASK->DEFER] %s:%d (approval deferred to handler)", dest, port)
330332
}
331333
}
332334

@@ -1042,31 +1044,36 @@ func (s *Server) handleWithDetection(
10421044
return
10431045
}
10441046
case ProtoHTTP:
1045-
// Plain HTTP detected by byte sniffing. go-mitmproxy only parses
1046-
// TLS-intercepted traffic through CONNECT tunnels, so plain HTTP
1047-
// goes through direct relay without phantom replacement.
1048-
//
1049-
// Known gap: credentials bound to plain HTTP on non-standard ports
1050-
// will not be injected and phantom tokens will not be stripped.
1051-
// This is acceptable because (1) credential bindings almost always
1052-
// target HTTPS endpoints, and (2) the old goproxy-based path had
1053-
// the same limitation. A future fix could add a lightweight HTTP
1054-
// reverse proxy here or route plain HTTP through go-mitmproxy's
1055-
// non-TLS code path if it gains support.
1047+
// Plain HTTP: no MITM handler. Check connection-level policy
1048+
// before relaying if a checker was deferred from Allow().
1049+
if checker != nil {
1050+
if v, _ := checker.CheckAndConsume(fqdn, port); v != policy.Allow {
1051+
log.Printf("[DETECT-DENY] %s:%d plain HTTP blocked by deferred policy", fqdn, port)
1052+
return
1053+
}
1054+
}
10561055
relayDirect(peekConn, dialAddrs)
10571056
return
10581057
case ProtoSSH:
1058+
if checker != nil {
1059+
if v, _ := checker.CheckAndConsume(fqdn, port); v != policy.Allow {
1060+
log.Printf("[DETECT-DENY] %s:%d SSH blocked by deferred policy", fqdn, port)
1061+
return
1062+
}
1063+
}
10591064
if s.sshJump != nil && binding != nil {
1060-
// Pass nil for ready: SOCKS5 CONNECT already succeeded (see
1061-
// comment above), so the handler's readiness signal is unused.
1062-
// Both HandleConnection implementations guard with
1063-
// "if ready != nil" before sending.
10641065
if err := s.sshJump.HandleConnection(peekConn, dialAddrs, hostAddr, *binding, nil); err != nil {
10651066
log.Printf("[SSH] handler error for %s: %v", hostAddr, err)
10661067
}
10671068
return
10681069
}
10691070
case ProtoIMAP, ProtoSMTP:
1071+
if checker != nil {
1072+
if v, _ := checker.CheckAndConsume(fqdn, port); v != policy.Allow {
1073+
log.Printf("[DETECT-DENY] %s:%d %s blocked by deferred policy", fqdn, port, proto)
1074+
return
1075+
}
1076+
}
10701077
if s.mailProxy != nil && binding != nil {
10711078
if err := s.mailProxy.HandleConnection(peekConn, dialAddrs, hostAddr, *binding, proto, nil); err != nil {
10721079
log.Printf("[MAIL] handler error for %s: %v", hostAddr, err)
@@ -1082,10 +1089,23 @@ func (s *Server) handleWithDetection(
10821089
// can only route through the mail proxy and the upstream probe is wasted
10831090
// without a binding to inject.
10841091
if n == 0 && binding != nil && s.mailProxy != nil {
1092+
if checker != nil {
1093+
if v, _ := checker.CheckAndConsume(fqdn, port); v != policy.Allow {
1094+
log.Printf("[DETECT-DENY] %s:%d server-first blocked by deferred policy", fqdn, port)
1095+
return
1096+
}
1097+
}
10851098
s.handleServerFirstDetection(peekConn, binding, hostAddr, dialAddrs)
10861099
return
10871100
}
10881101

1102+
// Generic fallback: direct relay. Check deferred policy first.
1103+
if checker != nil {
1104+
if v, _ := checker.CheckAndConsume(fqdn, port); v != policy.Allow {
1105+
log.Printf("[DETECT-DENY] %s:%d blocked by deferred policy", fqdn, port)
1106+
return
1107+
}
1108+
}
10891109
relayDirect(peekConn, dialAddrs)
10901110
}
10911111

0 commit comments

Comments
 (0)