You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
301 lines
6.3 KiB
Go
301 lines
6.3 KiB
Go
package web
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"errors"
|
|
|
|
"github.com/lqqyt2423/go-mitmproxy/proxy"
|
|
uuid "github.com/satori/go.uuid"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// message:
|
|
|
|
// type: 0/1/2/3/4
|
|
// messageFlow
|
|
// version 1 byte + type 1 byte + id 36 byte + waitIntercept 1 byte + content left bytes
|
|
|
|
// type: 11/12/13/14
|
|
// messageEdit
|
|
// version 1 byte + type 1 byte + id 36 byte + header len 4 byte + header content bytes + body len 4 byte + [body content bytes]
|
|
|
|
// type: 21
|
|
// messageMeta
|
|
// version 1 byte + type 1 byte + content left bytes
|
|
|
|
const messageVersion = 1
|
|
|
|
type messageType byte
|
|
|
|
const (
|
|
messageTypeConn messageType = 0
|
|
messageTypeConnClose messageType = 5
|
|
messageTypeRequest messageType = 1
|
|
messageTypeRequestBody messageType = 2
|
|
messageTypeResponse messageType = 3
|
|
messageTypeResponseBody messageType = 4
|
|
|
|
messageTypeChangeRequest messageType = 11
|
|
messageTypeChangeResponse messageType = 12
|
|
messageTypeDropRequest messageType = 13
|
|
messageTypeDropResponse messageType = 14
|
|
|
|
messageTypeChangeBreakPointRules messageType = 21
|
|
)
|
|
|
|
var allMessageTypes = []messageType{
|
|
messageTypeConn,
|
|
messageTypeConnClose,
|
|
messageTypeRequest,
|
|
messageTypeRequestBody,
|
|
messageTypeResponse,
|
|
messageTypeResponseBody,
|
|
messageTypeChangeRequest,
|
|
messageTypeChangeResponse,
|
|
messageTypeDropRequest,
|
|
messageTypeDropResponse,
|
|
messageTypeChangeBreakPointRules,
|
|
}
|
|
|
|
func validMessageType(t byte) bool {
|
|
for _, v := range allMessageTypes {
|
|
if t == byte(v) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type message interface {
|
|
bytes() []byte
|
|
}
|
|
|
|
type messageFlow struct {
|
|
mType messageType
|
|
id uuid.UUID
|
|
waitIntercept byte
|
|
content []byte
|
|
}
|
|
|
|
func newMessageFlow(mType messageType, f *proxy.Flow) *messageFlow {
|
|
var content []byte
|
|
var err error = nil
|
|
|
|
if mType == messageTypeConn {
|
|
content, err = json.Marshal(f.ConnContext)
|
|
} else if mType == messageTypeRequest {
|
|
m := make(map[string]interface{})
|
|
m["request"] = f.Request
|
|
m["connId"] = f.ConnContext.Id().String()
|
|
content, err = json.Marshal(m)
|
|
} else if mType == messageTypeRequestBody {
|
|
content = f.Request.Body
|
|
} else if mType == messageTypeResponse {
|
|
content, err = json.Marshal(f.Response)
|
|
} else if mType == messageTypeResponseBody {
|
|
content, err = f.Response.DecodedBody()
|
|
} else {
|
|
panic(errors.New("invalid message type"))
|
|
}
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
id := f.Id
|
|
if mType == messageTypeConn {
|
|
id = f.ConnContext.Id()
|
|
}
|
|
|
|
return &messageFlow{
|
|
mType: mType,
|
|
id: id,
|
|
content: content,
|
|
}
|
|
}
|
|
|
|
func newMessageConnClose(connCtx *proxy.ConnContext) *messageFlow {
|
|
return &messageFlow{
|
|
mType: messageTypeConnClose,
|
|
id: connCtx.Id(),
|
|
}
|
|
}
|
|
|
|
func (m *messageFlow) bytes() []byte {
|
|
buf := bytes.NewBuffer(make([]byte, 0))
|
|
buf.WriteByte(byte(messageVersion))
|
|
buf.WriteByte(byte(m.mType))
|
|
buf.WriteString(m.id.String()) // len: 36
|
|
buf.WriteByte(m.waitIntercept)
|
|
buf.Write(m.content)
|
|
return buf.Bytes()
|
|
}
|
|
|
|
type messageEdit struct {
|
|
mType messageType
|
|
id uuid.UUID
|
|
request *proxy.Request
|
|
response *proxy.Response
|
|
}
|
|
|
|
func parseMessageEdit(data []byte) *messageEdit {
|
|
// 2 + 36
|
|
if len(data) < 38 {
|
|
return nil
|
|
}
|
|
|
|
mType := (messageType)(data[1])
|
|
|
|
id, err := uuid.FromString(string(data[2:38]))
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
msg := &messageEdit{
|
|
mType: mType,
|
|
id: id,
|
|
}
|
|
|
|
if mType == messageTypeDropRequest || mType == messageTypeDropResponse {
|
|
return msg
|
|
}
|
|
|
|
// 2 + 36 + 4 + 4
|
|
if len(data) < 46 {
|
|
return nil
|
|
}
|
|
|
|
hl := (int)(binary.BigEndian.Uint32(data[38:42]))
|
|
if 42+hl+4 > len(data) {
|
|
return nil
|
|
}
|
|
headerContent := data[42 : 42+hl]
|
|
|
|
bl := (int)(binary.BigEndian.Uint32(data[42+hl : 42+hl+4]))
|
|
if 42+hl+4+bl != len(data) {
|
|
return nil
|
|
}
|
|
bodyContent := data[42+hl+4:]
|
|
|
|
if mType == messageTypeChangeRequest {
|
|
req := new(proxy.Request)
|
|
err := json.Unmarshal(headerContent, req)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
req.Body = bodyContent
|
|
msg.request = req
|
|
} else if mType == messageTypeChangeResponse {
|
|
res := new(proxy.Response)
|
|
err := json.Unmarshal(headerContent, res)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
res.Body = bodyContent
|
|
msg.response = res
|
|
} else {
|
|
return nil
|
|
}
|
|
|
|
return msg
|
|
}
|
|
|
|
func (m *messageEdit) bytes() []byte {
|
|
buf := bytes.NewBuffer(make([]byte, 0))
|
|
buf.WriteByte(byte(messageVersion))
|
|
buf.WriteByte(byte(m.mType))
|
|
buf.WriteString(m.id.String()) // len: 36
|
|
|
|
if m.mType == messageTypeChangeRequest {
|
|
headerContent, err := json.Marshal(m.request)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
hl := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(hl, (uint32)(len(headerContent)))
|
|
buf.Write(hl)
|
|
|
|
bodyContent := m.request.Body
|
|
bl := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(bl, (uint32)(len(bodyContent)))
|
|
buf.Write(bl)
|
|
buf.Write(bodyContent)
|
|
} else if m.mType == messageTypeChangeResponse {
|
|
headerContent, err := json.Marshal(m.response)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
hl := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(hl, (uint32)(len(headerContent)))
|
|
buf.Write(hl)
|
|
|
|
bodyContent := m.response.Body
|
|
bl := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(bl, (uint32)(len(bodyContent)))
|
|
buf.Write(bl)
|
|
buf.Write(bodyContent)
|
|
}
|
|
|
|
return buf.Bytes()
|
|
}
|
|
|
|
type messageMeta struct {
|
|
mType messageType
|
|
breakPointRules []*breakPointRule
|
|
}
|
|
|
|
func parseMessageMeta(data []byte) *messageMeta {
|
|
content := data[2:]
|
|
rules := make([]*breakPointRule, 0)
|
|
err := json.Unmarshal(content, &rules)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
return &messageMeta{
|
|
mType: messageType(data[1]),
|
|
breakPointRules: rules,
|
|
}
|
|
}
|
|
|
|
func (m *messageMeta) bytes() []byte {
|
|
buf := bytes.NewBuffer(make([]byte, 0))
|
|
buf.WriteByte(byte(messageVersion))
|
|
buf.WriteByte(byte(m.mType))
|
|
|
|
content, err := json.Marshal(m.breakPointRules)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
buf.Write(content)
|
|
|
|
return buf.Bytes()
|
|
}
|
|
|
|
func parseMessage(data []byte) message {
|
|
if len(data) < 2 {
|
|
return nil
|
|
}
|
|
|
|
if data[0] != messageVersion {
|
|
return nil
|
|
}
|
|
|
|
if !validMessageType(data[1]) {
|
|
return nil
|
|
}
|
|
|
|
mType := (messageType)(data[1])
|
|
|
|
if mType == messageTypeChangeRequest || mType == messageTypeChangeResponse || mType == messageTypeDropRequest || mType == messageTypeDropResponse {
|
|
return parseMessageEdit(data)
|
|
} else if mType == messageTypeChangeBreakPointRules {
|
|
return parseMessageMeta(data)
|
|
} else {
|
|
log.Warnf("invalid message type %v", mType)
|
|
return nil
|
|
}
|
|
}
|