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, 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
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ithouse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值