Updated docs

This commit is contained in:
Leonid Bugaev
2013-06-20 18:43:31 +06:00
parent 35f2f71199
commit 28702cd503
4 changed files with 48 additions and 23 deletions
+2 -1
View File
@@ -40,10 +40,11 @@ func Run() {
log.Fatal("Connection error", err)
}
// Sniffing traffic from given port
// Sniffing traffic from given address
listener := RAWTCPListen(Settings.address, Settings.port)
for {
// Receiving TCPMessage object
m := listener.Receive()
if Settings.verbose {
+33 -13
View File
@@ -6,17 +6,23 @@ import (
"net"
)
// Capture traffic from socket using RAW_SOCKET's
// http://en.wikipedia.org/wiki/Raw_socket
//
// RAW_SOCKET allow you listen for traffic on any port (e.g. sniffing) because they operate on IP level.
// Ports is TCP feature, same as flow control, reliable transmission and etc.
// Since we can't use default TCP libraries RAWTCPLitener implements own TCP layer
// TCP packets is parsed using tcp_packet.go, and flow control is managed by tcp_message.go
type RAWTCPListener struct {
messages []*TCPMessage // buffer of TCPMessages waiting to be send
c_packets chan *TCPPacket
c_messages chan *TCPMessage
c_messages chan *TCPMessage // Messages ready to be send to client
c_add_message chan *TCPMessage
c_del_message chan *TCPMessage
c_del_message chan *TCPMessage // Used for notifications about completed or expired messages
addr string
port int
addr string // IP to listen
port int // Port to listen
}
func RAWTCPListen(addr string, port int) (listener *RAWTCPListener) {
@@ -24,14 +30,13 @@ func RAWTCPListen(addr string, port int) (listener *RAWTCPListener) {
listener.c_packets = make(chan *TCPPacket)
listener.c_messages = make(chan *TCPMessage)
listener.c_add_message = make(chan *TCPMessage)
listener.c_del_message = make(chan *TCPMessage)
listener.addr = addr
listener.port = port
go listener.listen()
go listener.readTCPPackets()
go listener.readRAWSocket()
return
}
@@ -39,21 +44,23 @@ func RAWTCPListen(addr string, port int) (listener *RAWTCPListener) {
func (t *RAWTCPListener) listen() {
for {
select {
// If message ready for deletion it means that its also complete or expired by timeout
case message := <-t.c_del_message:
t.deleteMessage(message)
Debug("Deleted")
t.c_messages <- message
// We need to use channgels to process each packet to avoid data races
case packet := <-t.c_packets:
t.processTCPPacket(packet)
Debug("Processed")
}
}
}
// Deleting messages that came from t.c_del_message channel
func (t *RAWTCPListener) deleteMessage(message *TCPMessage) bool {
var idx int = -1
// Searching for given message in messages buffer
for i, m := range t.messages {
if m.Ack == message.Ack {
idx = i
@@ -65,14 +72,17 @@ func (t *RAWTCPListener) deleteMessage(message *TCPMessage) bool {
return false
}
// Delete element from array
// Note: that this version for arrays that consist of pointers
// https://code.google.com/p/go-wiki/wiki/SliceTricks
copy(t.messages[idx:], t.messages[idx+1:])
t.messages[len(t.messages)-1] = nil // or the zero value of T
t.messages[len(t.messages)-1] = nil // Ensure that value will be garbage-collected.
t.messages = t.messages[:len(t.messages)-1]
return true
}
func (t *RAWTCPListener) readTCPPackets() {
func (t *RAWTCPListener) readRAWSocket() {
conn, e := net.ListenPacket("ip4:tcp", t.addr)
defer conn.Close()
@@ -80,9 +90,10 @@ func (t *RAWTCPListener) readTCPPackets() {
log.Fatal(e)
}
buf := make([]byte, 1500*2)
buf := make([]byte, 4096)
for {
// Note: ReadFrom receive messages without IP header
n, _, err := conn.ReadFrom(buf)
if err != nil {
@@ -90,20 +101,24 @@ func (t *RAWTCPListener) readTCPPackets() {
}
if n > 0 {
// To avoid full packet parsing every time, we manually parsing values needed for packet filtering
// http://en.wikipedia.org/wiki/Transmission_Control_Protocol
dest_port := binary.BigEndian.Uint16(buf[2:4])
// Because RAW_SOCKET can't be bound to port, we have to control it by ourself
if int(dest_port) == t.port {
// Check TCPPacket code for more description
flags := binary.BigEndian.Uint16(buf[12:14]) & 0x1FF
f_psh := (flags & TCP_PSH) != 0
// We need only packets with data inside
// TCP PSH flag indicate that client should push data to buffer
// TCP PSH flag indicate that packet have data inside
if f_psh {
// We should create new buffer because go slices is pointers. So buffer data shoud be immutable.
new_buf := make([]byte, n)
copy(new_buf, buf[:n])
// To avoid socket locking processing packet in new goroutine
go func(buf []byte) {
packet := NewTCPPacket(new_buf)
t.c_packets <- packet
@@ -114,10 +129,13 @@ func (t *RAWTCPListener) readTCPPackets() {
}
}
// Trying to add packet to existing message or creating new message
//
// For TCP message unique id is Acknowledgment number (see tcp_packet.go)
func (t *RAWTCPListener) processTCPPacket(packet *TCPPacket) {
var message *TCPMessage
// Searching for message with same Ack
for _, msg := range t.messages {
if msg.Ack == packet.Ack {
message = msg
@@ -126,12 +144,14 @@ func (t *RAWTCPListener) processTCPPacket(packet *TCPPacket) {
}
if message == nil {
// We sending c_del_message channel, so message object can communicate with Listener and notify it if message completed
message = NewTCPMessage(packet.Ack, t.c_del_message)
Debug("Adding message")
t.messages = append(t.messages, message)
}
// Adding packet to message
message.c_packets <- packet
}
+12 -9
View File
@@ -12,12 +12,12 @@ const MSG_EXPIRE = 200 * time.Millisecond
//
// Each TCP Packet have 2 ids: acknowledgement - message_id, and sequence - packet_id
// Message can be compiled from unique packets with same message_id which sorted by sequence
// Message is received if we did't receive any packets for 200ms OR if we received packet with "fin" flag
// Message is received if we did't receive any packets for 200ms
type TCPMessage struct {
Ack uint32 // Message ID
packets []*TCPPacket
timer *time.Timer
timer *time.Timer // Used for expire check
expired bool
@@ -32,21 +32,22 @@ func NewTCPMessage(Ack uint32, c_del chan *TCPMessage) (msg *TCPMessage) {
msg.c_packets = make(chan *TCPPacket)
msg.c_closing = make(chan int)
msg.c_del_message = c_del
msg.c_del_message = c_del // used for notifying that message completed or expired
// Every time we receive packet we reset this timer
msg.timer = time.AfterFunc(MSG_EXPIRE, msg.Timeout)
go msg.ListenPackets()
go msg.listen()
return
}
func (t *TCPMessage) ListenPackets() {
func (t *TCPMessage) listen() {
for {
select {
case <-t.c_closing:
close(t.c_packets)
return
return // Stop loop if message completed/expired
case packet := <-t.c_packets:
t.AddPacket(packet)
}
@@ -54,8 +55,8 @@ func (t *TCPMessage) ListenPackets() {
}
func (t *TCPMessage) Timeout() {
t.c_closing <- 1
t.c_del_message <- t
t.c_closing <- 1 // Notify to stop listen loop and close channel
t.c_del_message <- t // Notify RAWListener that message is ready to be send to replay server
}
// Sort packets in right orders and return message content
@@ -77,7 +78,8 @@ func (t *TCPMessage) Bytes() (output []byte) {
return
}
// Add packet to the message
// Add packet to the message and ensure packet uniquiness
// TCP allows that packet can be re-send multiple times
func (t *TCPMessage) AddPacket(packet *TCPPacket) {
if t.expired {
Debug("Adding packet to expired message")
@@ -99,5 +101,6 @@ func (t *TCPMessage) AddPacket(packet *TCPPacket) {
t.packets = append(t.packets, packet)
}
// Reset message timeout timer
t.timer.Reset(MSG_EXPIRE)
}
+1
View File
@@ -41,6 +41,7 @@ func NewRequestFactory() (factory *RequestFactory) {
func (f *RequestFactory) sendRequest(host *ForwardHost, request *http.Request) {
client := &http.Client{}
// Change HOST of original request
URL := host.Url + request.URL.Path + "?" + request.URL.RawQuery
request.RequestURI = ""