完善 HTTP 处理逻辑,优化请求解析和认证流程

This commit is contained in:
2025-03-03 10:15:48 +08:00
parent d8c8b22123
commit cc0b74c5c2
3 changed files with 144 additions and 25 deletions

View File

@@ -6,6 +6,7 @@ import (
"net"
"proxy-server/pkg/utils"
"proxy-server/server/fwd/core"
"proxy-server/server/fwd/http"
"proxy-server/server/fwd/socks"
"strconv"
"time"
@@ -98,9 +99,16 @@ func (s *Server) acceptHttp(ls net.Listener) error {
}
go func() {
err := s.processHttp(conn)
user, err := http.Process(s.ctx, conn)
if err != nil {
slog.Error("dispatcher http process error", "err", err)
utils.Close(conn)
return
}
select {
case <-s.ctx.Done():
utils.Close(user)
case s.Conn <- user:
}
}()
}
@@ -121,7 +129,7 @@ func (s *Server) acceptSocks(ls net.Listener) error {
}
go func() {
conn, err := socks.Process(s.ctx, conn)
user, err := socks.Process(s.ctx, conn)
if err != nil {
slog.Error("处理 socks 连接失败", "err", err)
utils.Close(conn)
@@ -129,16 +137,12 @@ func (s *Server) acceptSocks(ls net.Listener) error {
}
select {
case <-s.ctx.Done():
utils.Close(conn)
case s.Conn <- conn:
utils.Close(user)
case s.Conn <- user:
}
}()
}
}
func (s *Server) processHttp(conn net.Conn) error {
return nil
}
type Conn struct {
}

View File

@@ -3,8 +3,11 @@ package http
import (
"bufio"
"context"
"encoding/base64"
"io"
"net"
"net/textproto"
"net/url"
"proxy-server/server/fwd/core"
"strings"
@@ -12,6 +15,12 @@ import (
)
type Request struct {
conn net.Conn
reader *bufio.Reader
method string
uri string
proto string
headers *textproto.MIMEHeader
auth *core.AuthContext
dest *core.FwdAddr
}
@@ -25,38 +34,143 @@ func Process(ctx context.Context, conn net.Conn) (*core.Conn, error) {
if err != nil {
return nil, err
}
parts := strings.Split(line, " ")
parts := strings.Fields(line)
if len(parts) != 3 {
return nil, errors.New("invalid http request")
return nil, errors.New("无效的 http 请求")
}
var req Request
// 请求头
headers, err := textReader.ReadMIMEHeader()
if err != nil {
return nil, errors.Wrap(err, "解析请求头失败")
}
// 验证账号
authInfo := headers.Get("Proxy-Authorization")
var auth *core.AuthContext
if authInfo == "" {
auth, err = core.CheckIp(conn)
if err != nil {
return nil, errors.Wrap(err, "验证账号失败")
}
} else {
authParts := strings.Split(authInfo, " ")
if len(authParts) != 2 {
return nil, errors.New("无效的 Proxy-Authorization")
}
if authParts[0] != "Basic" {
return nil, errors.New("不支持的认证方式")
}
authBytes, err := base64.URLEncoding.DecodeString(authParts[1])
if err != nil {
return nil, errors.Wrap(err, "解码认证信息失败")
}
authPair := strings.Split(string(authBytes), ":")
auth, err = core.CheckPass(conn, authPair[0], authPair[1])
}
// 获取 Host
host := headers.Get("Host")
if host == "" {
return nil, errors.New("无效的 Host")
}
if !strings.Contains(host, ":") {
host += ":80"
}
addr, err := net.ResolveTCPAddr("tcp", host)
if err != nil {
return nil, errors.Wrap(err, "解析 Host 失败")
}
request := &Request{
conn: conn,
reader: reader,
method: parts[0],
uri: parts[1],
proto: parts[2],
headers: &headers,
dest: &core.FwdAddr{
IP: addr.IP,
Port: addr.Port,
Domain: host,
},
auth: auth,
}
var user *core.Conn
if parts[0] == "CONNECT" {
req, err = processHttps(ctx, textReader)
user, err = processHttps(ctx, request)
if err != nil {
return nil, err
}
} else {
req, err = processHttp(ctx, textReader)
user, err = processHttp(ctx, request)
if err != nil {
return nil, err
}
}
return user, nil
}
func processHttps(ctx context.Context, req *Request) (*core.Conn, error) {
// 响应 CONNECT
_, err := req.conn.Write([]byte("HTTP/1.1 200 Connection Established\r\n\r\n"))
if err != nil {
return nil, errors.Wrap(err, "响应 CONNECT 失败")
}
return &core.Conn{
Conn: conn,
Reader: reader,
Tag: conn.RemoteAddr().String() + "_" + conn.LocalAddr().String(),
Protocol: "http",
Conn: req.conn,
Reader: req.reader,
Tag: req.conn.RemoteAddr().String() + "_" + req.conn.LocalAddr().String(),
Protocol: "https",
Dest: req.dest,
Auth: req.auth,
}, nil
}
func processHttps(ctx context.Context, reader *textproto.Reader) (Request, error) {
panic("not implemented")
func processHttp(ctx context.Context, req *Request) (*core.Conn, error) {
// 修改请求头
rawUrl, err := url.Parse(req.uri)
if err != nil {
return nil, errors.Wrap(err, "解析请求地址失败")
}
rawUrl.Scheme = ""
rawUrl.Host = ""
req.uri = rawUrl.String()
req.headers.Del("Proxy-Authorization")
// 构造请求
sb := strings.Builder{}
sb.WriteString(req.method)
sb.WriteString(" ")
sb.WriteString(req.uri)
sb.WriteString(" ")
sb.WriteString(req.proto)
sb.WriteString("\r\n")
for k, v := range *req.headers {
sb.WriteString(k)
sb.WriteString(": ")
sb.WriteString(strings.Join(v, ","))
sb.WriteString("\r\n")
}
func processHttp(ctx context.Context, reader *textproto.Reader) (Request, error) {
panic("not implemented")
sb.WriteString("\r\n")
mReader := io.MultiReader(strings.NewReader(sb.String()), req.conn)
newReader := bufio.NewReader(mReader)
return &core.Conn{
Conn: req.conn,
Reader: newReader,
Tag: req.conn.RemoteAddr().String() + "_" + req.conn.LocalAddr().String(),
Protocol: "http",
Dest: req.dest,
Auth: req.auth,
}, nil
}

View File

@@ -81,6 +81,7 @@ func initLog() {
writer := colorable.NewColorable(os.Stdout)
logger := slog.New(tint.NewHandler(writer, &tint.Options{
Level: slog.LevelDebug,
TimeFormat: time.RFC3339,
ReplaceAttr: func(_ []string, attr slog.Attr) slog.Attr {
err, ok := attr.Value.Any().(error)
if !ok {