完善 HTTP 处理逻辑,优化请求解析和认证流程
This commit is contained in:
@@ -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 {
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
func processHttp(ctx context.Context, reader *textproto.Reader) (Request, error) {
|
||||
panic("not implemented")
|
||||
// 修改请求头
|
||||
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")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user