// 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 }
// 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 }
// 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 }