Browse Source

pass username to inbound.User.Email in http/socks server

tnextday 6 years ago
parent
commit
ad3bcd2c07
3 changed files with 26 additions and 11 deletions
  1. 5 1
      proxy/http/server.go
  2. 18 10
      proxy/socks/protocol.go
  3. 3 0
      proxy/socks/server.go

+ 5 - 1
proxy/http/server.go

@@ -85,7 +85,8 @@ type readerOnly struct {
 }
 
 func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {
-	if inbound := session.InboundFromContext(ctx); inbound != nil {
+	inbound := session.InboundFromContext(ctx)
+	if inbound != nil {
 		inbound.User = &protocol.MemoryUser{
 			Level: s.config.UserLevel,
 		}
@@ -112,6 +113,9 @@ Start:
 		if !ok || !s.config.HasAccount(user, pass) {
 			return common.Error2(conn.Write([]byte("HTTP/1.1 407 Proxy Authentication Required\r\nProxy-Authenticate: Basic realm=\"proxy\"\r\n\r\n")))
 		}
+		if inbound != nil {
+			inbound.User.Email = user
+		}
 	}
 
 	newError("request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]").WriteToLog(session.ExportIDToError(ctx))

+ 18 - 10
proxy/socks/protocol.go

@@ -94,12 +94,12 @@ func (s *ServerSession) handshake4(cmd byte, reader io.Reader, writer io.Writer)
 	}
 }
 
-func (s *ServerSession) auth5(nMethod byte, reader io.Reader, writer io.Writer) error {
+func (s *ServerSession) auth5(nMethod byte, reader io.Reader, writer io.Writer) (username string, err error) {
 	buffer := buf.StackNew()
 	defer buffer.Release()
 
-	if _, err := buffer.ReadFullFrom(reader, int32(nMethod)); err != nil {
-		return newError("failed to read auth methods").Base(err)
+	if _, err = buffer.ReadFullFrom(reader, int32(nMethod)); err != nil {
+		return "", newError("failed to read auth methods").Base(err)
 	}
 
 	var expectedAuth byte = authNotRequired
@@ -109,34 +109,39 @@ func (s *ServerSession) auth5(nMethod byte, reader io.Reader, writer io.Writer)
 
 	if !hasAuthMethod(expectedAuth, buffer.BytesRange(0, int32(nMethod))) {
 		writeSocks5AuthenticationResponse(writer, socks5Version, authNoMatchingMethod) // nolint: errcheck
-		return newError("no matching auth method")
+		return "", newError("no matching auth method")
 	}
 
 	if err := writeSocks5AuthenticationResponse(writer, socks5Version, expectedAuth); err != nil {
-		return newError("failed to write auth response").Base(err)
+		return "", newError("failed to write auth response").Base(err)
 	}
 
 	if expectedAuth == authPassword {
 		username, password, err := ReadUsernamePassword(reader)
 		if err != nil {
-			return newError("failed to read username and password for authentication").Base(err)
+			return "", newError("failed to read username and password for authentication").Base(err)
 		}
 
 		if !s.config.HasAccount(username, password) {
 			writeSocks5AuthenticationResponse(writer, 0x01, 0xFF) // nolint: errcheck
-			return newError("invalid username or password")
+			return "", newError("invalid username or password")
 		}
 
 		if err := writeSocks5AuthenticationResponse(writer, 0x01, 0x00); err != nil {
-			return newError("failed to write auth response").Base(err)
+			return "", newError("failed to write auth response").Base(err)
 		}
+		return username, nil
 	}
 
-	return nil
+	return "", nil
 }
 
 func (s *ServerSession) handshake5(nMethod byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
-	if err := s.auth5(nMethod, reader, writer); err != nil {
+	var (
+		username string
+		err      error
+	)
+	if username, err = s.auth5(nMethod, reader, writer); err != nil {
 		return nil, err
 	}
 
@@ -152,6 +157,9 @@ func (s *ServerSession) handshake5(nMethod byte, reader io.Reader, writer io.Wri
 	}
 
 	request := new(protocol.RequestHeader)
+	if username != "" {
+		request.User = &protocol.MemoryUser{Email: username}
+	}
 	switch cmd {
 	case cmdTCPConnect, cmdTorResolve, cmdTorResolvePTR:
 		// We don't have a solution for Tor case now. Simply treat it as connect command.

+ 3 - 0
proxy/socks/server.go

@@ -108,6 +108,9 @@ func (s *Server) processTCP(ctx context.Context, conn internet.Connection, dispa
 		}
 		return newError("failed to read request").Base(err)
 	}
+	if request.User != nil {
+		inbound.User.Email = request.User.Email
+	}
 
 	if err := conn.SetReadDeadline(time.Time{}); err != nil {
 		newError("failed to clear deadline").Base(err).WriteToLog(session.ExportIDToError(ctx))