package main
import (
"time"
"github.com/google/gopacket/pcap"
"log"
"fmt"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"strings"
"vprobe/rawtransaction"
"sync"
"encoding/json"
"vprobe/metric"
"strconv"
)
var (
device string = "eth1"
snapshot_len int32 = 1024
promiscuous bool = false
timeout time.Duration = 30 * time.Second
//handle *pcap.Handle
localAddress string
errorNumber int = 0
channel chan bool = make(chan bool)
lock = &sync.RWMutex{}
// Metrics到ops-agent的上报周期(30s)或其他值,可配置,范围为1-60s
// ops-agent到kafka的上报周期以分钟为粒度,可配置,范围为1-5分钟
noresp int = 30000 // 指标上报周期为30秒,即30000毫秒
requestList []rawtransaction.RequestIdentification = make([]rawtransaction.RequestIdentification, 0, 50) // 30个元素,预留20个元素
rawTransactions []rawtransaction.Transaction = make([]rawtransaction.Transaction, 0, 50) // 未处理的事务
transactionList []metric.Transaction = make([]metric.Transaction, 0, 50) // 经过处理的事务
)
func main() {
// 查找设备
devices, err := pcap.FindAllDevs()
if err != nil {
log.Fatal(err)
}
MainThread:
for _, dev := range devices {
if strings.EqualFold(dev.Name, device) {
for _, address := range dev.Addresses {
// 获取到了本地IP
localAddress = address.IP.To4().String()
break MainThread
}
}
}
go capturePacket()
go submitTrans()
go formMetrics()
<-channel
}
/**
* 抓取报文
*/
func capturePacket() {
// 实时监控
handle, err: = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
if err != nil {
log.Fatal(err)
}
defer handle.Close()
// 设置过滤80==========================80端口
var filter string = "tcp and port 80"
err = handle.SetBPFFilter(filter)
if err != nil {
log.Fatal(err)
}
fmt.Println("Only capturing TCP port 80 packets.")
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
for packet := range packetSource.Packets() {
// 直接打印抓到的数据包
//fmt.Println(packet)
// 打印解析之后的数据包信息
printPacketInfo(packet)
}
channel <- true
}
/**
* 解析报文
*/
func printPacketInfo(packet gopacket.Packet) {
ipLayer := packet.Layer(layers.LayerTypeIPv4)
if ipLayer != nil {
// 包含IP包
ip, _ := ipLayer.(*layers.IPv4)
tcpLayer := packet.Layer(layers.LayerTypeTCP)
if tcpLayer != nil {
// 包含TCP包
tcp, _ := tcpLayer.(*layers.TCP)
applicationLayer := packet.ApplicationLayer()
if applicationLayer != nil {
payload := string(applicationLayer.Payload())
if strings.Contains(payload, "HTTP") {
//fmt.Printf("源IP地址:%s -----目的IP地址:%s\n", ip.SrcIP, ip.DstIP)
//fmt.Printf("源端口:%d --------目的端口:%d\n", tcp.SrcPort, tcp.DstPort)
// 时间戳
timestamp := int(packet.Metadata().Timestamp.Unix())
//fmt.Println("时间戳:" + timestamp)
// 报文内容
//packetContent := packet.Data()
//fmt.Println("报文内容:" + string(packetContent))
// 报文总长度
//packetLength := packet.Metadata().CaptureLength
//fmt.Println("报文长度:" + strconv.Itoa(packetLength))
//fmt.Println("协议类型: ", ip.Protocol)
lock.Lock()
if strings.EqualFold(localAddress, ip.SrcIP.String()) {
// 这个包代表的是HTTP请求,添加到请求列表
iden := ip.SrcIP.String() + tcp.SrcPort.String() + ip.DstIP.String() + tcp.DstPort.String()
reqiden := rawtransaction.RequestIdentification{
timestamp,
-1,
iden,
false,
0,
}
requestList = append(requestList, reqiden)
} else {
// 这个包代表的是HTTP响应,查看是否有请求与其对应
iden := ip.DstIP.String() + tcp.DstPort.String() + ip.SrcIP.String() + tcp.SrcPort.String()
for i, _ := range requestList {
if strings.EqualFold(requestList[i].Identification, iden) {
// 那么这个响应就是请求reqiden的
if timestamp - requestList[i].Timestamp > noresp {
// 超时了,形成异常事务。在这里,不去修改这个请求,说明这个请求在规定的时间内没有收到响应
} else {
// 没有超时,形成正常事务,请求时间戳,响应时间戳,响应码
contents := strings.Split(payload, " ")
if len(contents) >=2 {
code, err := strconv.Atoi(contents[1])
if err == nil {
// 没有错误,可以获取响应码
requestList[i].Modify = true
requestList[i].RespTimestamp = timestamp
requestList[i].Code = code
} else {
// 没有获取到响应码
}
}
}
} else {
// 这是只有响应,没有请求与之对应,暂时先不管?
}
}
}
lock.Unlock()
}
}
}
}
}
/**
* 每隔30秒就将这30秒之内产生的原始请求进行解析,形成“事务”,缓存到“事务”列表
*/
func submitTrans() {
c := time.Tick(30 * time.Second)
for _ = range c {
lock.Lock()
// 用一个临时变量来记住请求,减少锁的持有时间
tempRequestList := requestList
requestList = requestList[:0]
lock.Unlock()
for _, reqiden := range tempRequestList{
if reqiden.Modify {
// 该请求是被修改过了的,也就是说有响应
rawtra := rawtransaction.Transaction {
rawtransaction.Request{reqiden.Timestamp},
rawtransaction.Response{reqiden.RespTimestamp, reqiden.Code},
}
rawTransactions = append(rawTransactions, rawtra)
} else {
// 异常事务+1
errorNumber++
}
}
}
}
/**
* 每隔5分钟就将这5分钟之内收集到的“事务”形成一个“记录”
*/
func formMetrics() {
c := time.Tick(300 * time.Second)
for _ = range c {
for _, rawTransaction := range rawTransactions {
transaction := metric.Transaction{
rawTransaction.Request.Timestamp,
rawTransaction.Response.Timestamp - rawTransaction.Request.Timestamp,
rawTransaction.Response.Code,
}
transactionList = append(transactionList, transaction)
}
metric := metric.Metric{
len(transactionList),
transactionList,
errorNumber,
}
// 把“记录”打印出来
metricJson, _ := json.Marshal(metric)
fmt.Println(string(metricJson))
//操作之后,清空requestList和rawTransactions
lock.Lock()
transactionList = transactionList[:0]
rawTransactions = rawTransactions[:0]
errorNumber = 0
lock.Unlock()
}
}
Go语言Ubuntu下打印网络请求报文信息
最新推荐文章于 2024-08-07 09:51:58 发布