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.
go-mitmproxy/web/message.go

301 lines
6.3 KiB
Go

package web
import (
"bytes"
"encoding/binary"
"encoding/json"
"errors"
2 years ago
"github.com/lqqyt2423/go-mitmproxy/proxy"
uuid "github.com/satori/go.uuid"
2 years ago
log "github.com/sirupsen/logrus"
)
// message:
// type: 0/1/2/3/4/5
// 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 = 2
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
}
2 years ago
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
2 years ago
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 {
2 years ago
req := new(proxy.Request)
err := json.Unmarshal(headerContent, req)
if err != nil {
return nil
}
req.Body = bodyContent
msg.request = req
} else if mType == messageTypeChangeResponse {
2 years ago
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
}
}