| 226 | } |
| 227 | |
| 228 | func (s *ProxyHandler) ServeHTTP(wr http.ResponseWriter, req *http.Request) { |
| 229 | if originator, isLoopback := s.isLoopback(req); isLoopback { |
| 230 | s.logger.Critical("Loopback tunnel detected: %s is an outbound "+ |
| 231 | "address for another request from %s", req.RemoteAddr, originator) |
| 232 | http.Error(wr, auth.BAD_REQ_MSG, http.StatusBadRequest) |
| 233 | return |
| 234 | } |
| 235 | |
| 236 | if s.directResponse != nil && isDirectRequest(req) { |
| 237 | s.reject(s.directResponse, wr, req) |
| 238 | return |
| 239 | } |
| 240 | |
| 241 | ctx := req.Context() |
| 242 | username, ok := s.auth.Validate(ctx, wr, req) |
| 243 | localAddr := getLocalAddr(req.Context()) |
| 244 | s.logger.Info("Request: %v => %v %q %v %v %v", req.RemoteAddr, localAddr, username, req.Proto, req.Method, req.URL) |
| 245 | |
| 246 | if !ok { |
| 247 | return |
| 248 | } |
| 249 | |
| 250 | if (req.URL.Host == "" || req.URL.Scheme == "" && req.Method != "CONNECT") && req.ProtoMajor < 2 || |
| 251 | req.Host == "" && req.ProtoMajor == 2 { |
| 252 | http.Error(wr, auth.BAD_REQ_MSG, http.StatusBadRequest) |
| 253 | return |
| 254 | } |
| 255 | |
| 256 | var ipHints *string |
| 257 | if s.userIPHints { |
| 258 | hintValues := req.Header.Values(HintsHeaderName) |
| 259 | if len(hintValues) > 0 { |
| 260 | req.Header.Del(HintsHeaderName) |
| 261 | ipHints = &hintValues[0] |
| 262 | } |
| 263 | } |
| 264 | ctx = ddto.BoundDialerParamsToContext(ctx, ipHints, trimAddrPort(localAddr)) |
| 265 | ctx = ddto.FilterParamsToContext(ctx, req, username) |
| 266 | req = req.WithContext(ctx) |
| 267 | delHopHeaders(req.Header) |
| 268 | switch req.Method { |
| 269 | case "CONNECT": |
| 270 | s.HandleTunnel(wr, req, username) |
| 271 | case "GETRANDOM": |
| 272 | s.HandleGetRandom(wr, req, username) |
| 273 | default: |
| 274 | s.HandleRequest(wr, req, username) |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | func (s *ProxyHandler) rejectAccess(wr http.ResponseWriter, req *http.Request) { |
| 279 | if s.accessReject == nil { |