Example #1
0
// TCPDataDump provides text debugging information for all the TCP packets in d.
// A result that returns with an error may still have partial information up to
// the packet that caused the error.
func TCPDataDump(d []*pkt.Packet) ([]string, error) {
	var tcpHdr *pkt.TcpHdr
	var ipHdr pkt.InetProtoHdr
	var ok bool
	pl := make([]string, len(d))
	for i := range d {
		ipHdr, ok = d[i].Headers[pkt.NetworkLayer].(pkt.InetProtoHdr)
		if !ok || ipHdr == nil {
			return pl, ErrNetworkLayerHeader
		}
		tcpHdr, ok = d[i].Headers[pkt.TransportLayer].(*pkt.TcpHdr)
		if !ok || tcpHdr == nil {
			return pl, ErrTransportLayerHeader
		}
		pl[i] = fmt.Sprintf("%d %d->%d %d %d %d %#x %d %d",
			d[i].Time.UnixNano(),
			tcpHdr.Source,
			tcpHdr.Dest,
			tcpHdr.Seq,
			tcpHdr.AckSeq,
			tcpHdr.Doff,
			tcpHdr.Flags,
			tcpHdr.Window,
			tcpHdr.PayloadLen(ipHdr.PL()))
	}
	return pl, nil
}
Example #2
0
// getBytes returns the total number of bytes from the IP payload length
// for a given range of packets where s is a valid TCP sequence number for the
// beginning of the range and e is a valid TCP sequence number for the end of the
// range.  The pm map is used to lookup packets for every sequence number in the
// range s to e; this map should be obtained as part of a TCPFlow.
func getBytes(s, e uint32, pm map[uint32]*pkt.Packet) (uint32, error) {
	var (
		ip  pkt.InetProtoHdr // IP header - to access the IP payload length
		tcp *pkt.TcpHdr      // TCP header - to gather per-packet TCP data
		ok  bool             // caste success indicator
		seq uint32           // the expected sequence number
		b   uint32           // total number of bytes
		pl  uint32           // TCP payload length
		p   *pkt.Packet
	)
	seq = s
	for {
		if seq > e {
			break
		}
		p, ok = pm[seq]
		if !ok || p == nil {
			if seq == e {
				//TODO(gavaletz) Hack for last AcKSeq in a trace.
				break
			}
			return b, ErrTCPSeqMissing
		}
		tcp, ok = p.Headers[pkt.TransportLayer].(*pkt.TcpHdr)
		if !ok || tcp == nil {
			return b, ErrTransportLayerHeader
		}
		ip, ok = p.Headers[pkt.NetworkLayer].(pkt.InetProtoHdr)
		if !ok || ip == nil {
			return b, ErrNetworkLayerHeader
		}
		pl = uint32(tcp.PayloadLen(ip.PL()))
		b += pl
		if pl < 1 {
			return b, ErrTCPSeqMissing
		}
		seq += pl
	}
	return b, nil
}
Example #3
0
// Analysis computes the aggregate packet-level data for a TCPFlow.  This does
// not take into account packets that may have been dropped by the pcap trace
// and the analysis of such traces will be less accurate than those without any
// missing packets.
func TCPFlowAnalysis(d []*pkt.Packet, t *TCPTuple) (*TCPFlowStats, error) {
	var (
		ip           pkt.InetProtoHdr // IP header - to access the IP payload length
		tcp          *pkt.TcpHdr      // TCP header - to gather per-packet tcp data
		ok           bool             // caste success indicator
		pl           uint16           // TCP payload length
		srcSeq       uint32           // the expected Dst sequence number
		dstSeq       uint32           // the expected Dst sequence number
		srcAck       uint32           // the last Src ACK sequence number
		dstAck       uint32           // the last Dst ACK sequence number
		srcDupAckCnt int              // count of Src ACK duplicates
		dstDupAckCnt int              // count of Dst ACK duplicates
	)
	fs := &TCPFlowStats{}           // accumulation of stats
	srcLoss := make(map[uint32]int) // accumulation of Src losses
	dstLoss := make(map[uint32]int) // accumulation of Dst losses
	for i := range d {
		ip, ok = d[i].Headers[pkt.NetworkLayer].(pkt.InetProtoHdr)
		if !ok || ip == nil {
			return fs, ErrNetworkLayerHeader
		}
		tcp, ok = d[i].Headers[pkt.TransportLayer].(*pkt.TcpHdr)
		if !ok || tcp == nil {
			return fs, ErrTransportLayerHeader
		}
		pl = tcp.PayloadLen(ip.PL())
		if int(tcp.Source) == t.Src.Port {
			if tcp.AckSeq > srcAck {
				srcAck = tcp.AckSeq
				srcDupAckCnt = 0
			} else if tcp.AckSeq == srcAck {
				srcDupAckCnt++
				fs.SrcDupAck++
				if srcDupAckCnt == 3 && srcAck != dstSeq {
					dstLoss[srcAck] = i
				}
			}
			if tcp.Seq >= srcSeq {
				srcSeq = tcp.Seq + uint32(pl)
			} else {
				_, ok = srcLoss[tcp.Seq]
				if ok {
					fs.SrcLoss++
					fs.SrcLossBytes += uint32(pl)
					delete(srcLoss, tcp.Seq)
				} else {
					if dstDupAckCnt < 3 {
						fs.SrcOrder++
					} else {
						fs.SrcOther++
					}
				}
			}
		} else {
			if tcp.AckSeq > dstAck {
				dstAck = tcp.AckSeq
				dstDupAckCnt = 0
			} else if tcp.AckSeq == dstAck {
				dstDupAckCnt++
				fs.DstDupAck++
				if dstDupAckCnt == 3 && dstAck != srcSeq {
					srcLoss[dstAck] = i
				}
			}
			if tcp.Seq >= dstSeq {
				dstSeq = tcp.Seq + uint32(pl)
			} else {
				_, ok = dstLoss[tcp.Seq]
				if ok {
					fs.DstLoss++
					fs.DstLossBytes += uint32(pl)
					delete(dstLoss, tcp.Seq)
				} else {
					if srcDupAckCnt < 3 {
						fs.DstOrder++
					} else {
						fs.DstOther++
					}
				}
			}
		}
	}
	fs.DstOther += len(dstLoss)
	fs.SrcOther += len(srcLoss)
	return fs, nil
}