Go语言Ubuntu下打印网络请求报文信息

来源:互联网 发布:前瞻网数据 编辑:程序博客网 时间:2024/06/05 15:59
package mainimport (  "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()  }}
0 0
原创粉丝点击