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

前端之家收集整理的这篇文章主要介绍了Go语言Ubuntu下打印网络请求报文信息前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
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, 50) // 未处理的事务

  transactionList []metric.Transaction = make([]metric.Transaction, 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,}
            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()
  }
}

猜你在找的Ubuntu相关文章