From f532e6353b23256ae27b6a18b11e18c0a0b5c082 Mon Sep 17 00:00:00 2001 From: insanity Date: Sun, 12 Aug 2018 19:46:46 +0900 Subject: [PATCH] init --- Gopkg.lock | 15 + Gopkg.toml | 34 + meta/MetaCollectionItem.go | 16 + meta/MetaCollectionItemMapping.go | 14 + meta/MetaCrawler.go | 14 + meta/MetaCrawlerContainer.go | 14 + meta/MetaCrawlerInputItem.go | 14 + meta/MetaCrawlerMapping.go | 16 + meta/MetaCryptoType.go | 98 ++ meta/MetaDisplayItem.go | 14 + meta/MetaDisplayItemCategory.go | 14 + meta/MetaDisplayItemMapping.go | 20 + meta/MetaHistoryType.go | 14 + meta/MetaIPType.go | 47 + meta/MetaInfraType.go | 50 ++ meta/MetaInputType.go | 14 + meta/MetaItemUnit.go | 15 + meta/MetaMemberStatus.go | 53 ++ meta/MetaNoAuthProbeStatus.go | 50 ++ meta/MetaPortType.go | 47 + meta/MetaProbeStatus.go | 47 + meta/MetaSensorDisplayItem.go | 18 + meta/MetaSensorItem.go | 14 + meta/MetaSensorItemKey.go | 19 + meta/MetaSensorItemType.go | 14 + meta/MetaSensorItemUnit.go | 15 + meta/MetaSensorStatus.go | 14 + meta/MetaTargetHostType.go | 36 + meta/MetaTargetServiceType.go | 36 + meta/MetaTargetType.go | 16 + meta/MetaTargetZoneType.go | 39 + scan/DiscoverHost.go | 16 + scan/DiscoverPort.go | 28 + scan/DiscoverService.go | 5 + scan/DiscoverZone.go | 7 + scan/Host.go | 17 + scan/Port.go | 20 + scan/Service.go | 16 + scan/Zone.go | 20 + util/timestamp.go | 42 + vendor/github.com/google/gopacket/.gitignore | 38 + .../google/gopacket/.travis.gofmt.sh | 7 + .../google/gopacket/.travis.golint.sh | 25 + .../google/gopacket/.travis.govet.sh | 10 + vendor/github.com/google/gopacket/.travis.yml | 14 + vendor/github.com/google/gopacket/AUTHORS | 46 + .../google/gopacket/CONTRIBUTING.md | 215 +++++ vendor/github.com/google/gopacket/LICENSE | 28 + vendor/github.com/google/gopacket/README.md | 10 + vendor/github.com/google/gopacket/base.go | 178 ++++ vendor/github.com/google/gopacket/decode.go | 157 ++++ vendor/github.com/google/gopacket/doc.go | 365 ++++++++ vendor/github.com/google/gopacket/flows.go | 236 +++++ vendor/github.com/google/gopacket/gc | 278 ++++++ .../github.com/google/gopacket/layerclass.go | 107 +++ .../github.com/google/gopacket/layertype.go | 111 +++ vendor/github.com/google/gopacket/packet.go | 838 ++++++++++++++++++ vendor/github.com/google/gopacket/parser.go | 198 +++++ vendor/github.com/google/gopacket/writer.go | 213 +++++ 59 files changed, 4086 insertions(+) create mode 100644 Gopkg.lock create mode 100644 Gopkg.toml create mode 100644 meta/MetaCollectionItem.go create mode 100644 meta/MetaCollectionItemMapping.go create mode 100644 meta/MetaCrawler.go create mode 100644 meta/MetaCrawlerContainer.go create mode 100644 meta/MetaCrawlerInputItem.go create mode 100644 meta/MetaCrawlerMapping.go create mode 100644 meta/MetaCryptoType.go create mode 100644 meta/MetaDisplayItem.go create mode 100644 meta/MetaDisplayItemCategory.go create mode 100644 meta/MetaDisplayItemMapping.go create mode 100644 meta/MetaHistoryType.go create mode 100644 meta/MetaIPType.go create mode 100644 meta/MetaInfraType.go create mode 100644 meta/MetaInputType.go create mode 100644 meta/MetaItemUnit.go create mode 100644 meta/MetaMemberStatus.go create mode 100644 meta/MetaNoAuthProbeStatus.go create mode 100644 meta/MetaPortType.go create mode 100644 meta/MetaProbeStatus.go create mode 100644 meta/MetaSensorDisplayItem.go create mode 100644 meta/MetaSensorItem.go create mode 100644 meta/MetaSensorItemKey.go create mode 100644 meta/MetaSensorItemType.go create mode 100644 meta/MetaSensorItemUnit.go create mode 100644 meta/MetaSensorStatus.go create mode 100644 meta/MetaTargetHostType.go create mode 100644 meta/MetaTargetServiceType.go create mode 100644 meta/MetaTargetType.go create mode 100644 meta/MetaTargetZoneType.go create mode 100644 scan/DiscoverHost.go create mode 100644 scan/DiscoverPort.go create mode 100644 scan/DiscoverService.go create mode 100644 scan/DiscoverZone.go create mode 100644 scan/Host.go create mode 100644 scan/Port.go create mode 100644 scan/Service.go create mode 100644 scan/Zone.go create mode 100644 util/timestamp.go create mode 100644 vendor/github.com/google/gopacket/.gitignore create mode 100644 vendor/github.com/google/gopacket/.travis.gofmt.sh create mode 100644 vendor/github.com/google/gopacket/.travis.golint.sh create mode 100644 vendor/github.com/google/gopacket/.travis.govet.sh create mode 100644 vendor/github.com/google/gopacket/.travis.yml create mode 100644 vendor/github.com/google/gopacket/AUTHORS create mode 100644 vendor/github.com/google/gopacket/CONTRIBUTING.md create mode 100644 vendor/github.com/google/gopacket/LICENSE create mode 100644 vendor/github.com/google/gopacket/README.md create mode 100644 vendor/github.com/google/gopacket/base.go create mode 100644 vendor/github.com/google/gopacket/decode.go create mode 100644 vendor/github.com/google/gopacket/doc.go create mode 100644 vendor/github.com/google/gopacket/flows.go create mode 100644 vendor/github.com/google/gopacket/gc create mode 100644 vendor/github.com/google/gopacket/layerclass.go create mode 100644 vendor/github.com/google/gopacket/layertype.go create mode 100644 vendor/github.com/google/gopacket/packet.go create mode 100644 vendor/github.com/google/gopacket/parser.go create mode 100644 vendor/github.com/google/gopacket/writer.go diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000..551a0ca --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,15 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/google/gopacket" + packages = ["."] + revision = "11c65f1ca9081dfea43b4f9643f5c155583b73ba" + version = "v1.1.14" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "355ee061c527e073afa8c024489befb54aeaa19e316b5805db73a9fe25c66bd4" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 0000000..090e272 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,34 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/google/gopacket" + version = "1.1.14" + +[prune] + go-tests = true + unused-packages = true diff --git a/meta/MetaCollectionItem.go b/meta/MetaCollectionItem.go new file mode 100644 index 0000000..cc4d8de --- /dev/null +++ b/meta/MetaCollectionItem.go @@ -0,0 +1,16 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaCollectionItem struct { + ID json.Number `json:"id,Number,omitempty"` + Key string `json:"key,omitempty"` + Item string `json:"item,omitempty"` + ItemClass string `json:"itemClass,omitempty"` + MetaItemUnit *MetaItemUnit `json:"metaItemUnit,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaCollectionItemMapping.go b/meta/MetaCollectionItemMapping.go new file mode 100644 index 0000000..b9fca8f --- /dev/null +++ b/meta/MetaCollectionItemMapping.go @@ -0,0 +1,14 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaCollectionItemMapping struct { + ID json.Number `json:"id,Number,omitempty"` + MetaDisplayItemMapping *MetaDisplayItemMapping `json:"metaDisplayItemMapping,omitempty"` + MetaCollectionItem *MetaCollectionItem `json:"metaCollectionItem,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaCrawler.go b/meta/MetaCrawler.go new file mode 100644 index 0000000..8912044 --- /dev/null +++ b/meta/MetaCrawler.go @@ -0,0 +1,14 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaCrawler struct { + ID json.Number `json:"id,Number,omitempty"` + Name string `json:"name,omitempty"` + Key string `json:"key,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaCrawlerContainer.go b/meta/MetaCrawlerContainer.go new file mode 100644 index 0000000..b3db49b --- /dev/null +++ b/meta/MetaCrawlerContainer.go @@ -0,0 +1,14 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaCrawlerContainer struct { + ID json.Number `json:"id,Number,omitempty"` + Name string `json:"name,omitempty"` + Key string `json:"key,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaCrawlerInputItem.go b/meta/MetaCrawlerInputItem.go new file mode 100644 index 0000000..0c25bc5 --- /dev/null +++ b/meta/MetaCrawlerInputItem.go @@ -0,0 +1,14 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaCrawlerInputItem struct { + ID json.Number `json:"id,Number,omitempty"` + MetaInputType *MetaInputType `json:"metaInputType,omitempty"` + Key string `json:"key,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaCrawlerMapping.go b/meta/MetaCrawlerMapping.go new file mode 100644 index 0000000..15d727a --- /dev/null +++ b/meta/MetaCrawlerMapping.go @@ -0,0 +1,16 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaCrawlerMapping struct { + ID json.Number `json:"id,Number,omitempty"` + MetaTargetType *MetaTargetType `json:"metaTargetType,Number,omitempty"` + MetaCrawler *MetaCrawler `json:"metaCrawler,omitempty"` + DefaultInterval json.Number `json:"defaultInterval,omitempty"` + IsDefault bool `json:"isDefault,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaCryptoType.go b/meta/MetaCryptoType.go new file mode 100644 index 0000000..17d74ba --- /dev/null +++ b/meta/MetaCryptoType.go @@ -0,0 +1,98 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaCryptoType struct { + ID json.Number `json:"id,Number,omitempty"` + Name string `json:"name,omitempty"` + Key string `json:"key,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} + +type MetaCryptoTypeEnum int + +const ( + MetaCryptoTypeEnumNONE MetaCryptoTypeEnum = iota + 1 + MetaCryptoTypeEnumUNKNOWN + MetaCryptoTypeEnumAES + MetaCryptoTypeEnumCIPHER + MetaCryptoTypeEnumDES + MetaCryptoTypeEnumDSA + MetaCryptoTypeEnumECDSA + MetaCryptoTypeEnumELLIPTIC + MetaCryptoTypeEnumHMAC + MetaCryptoTypeEnumMD5 + MetaCryptoTypeEnumRAND + MetaCryptoTypeEnumRC4 + MetaCryptoTypeEnumRSA + MetaCryptoTypeEnumSHA1 + MetaCryptoTypeEnumSHA256 + MetaCryptoTypeEnumSUBTLE + MetaCryptoTypeEnumTLS + MetaCryptoTypeEnumX509 + MetaCryptoTypeEnumPKIX +) + +var ( + metaCryptoTypeEnumID = map[MetaCryptoTypeEnum]string{ + MetaCryptoTypeEnumNONE: "NONE", + MetaCryptoTypeEnumUNKNOWN: "UNKNOWN", + MetaCryptoTypeEnumAES: "AES", + MetaCryptoTypeEnumCIPHER: "CIPHER", + MetaCryptoTypeEnumDES: "DES", + MetaCryptoTypeEnumDSA: "DSA", + MetaCryptoTypeEnumECDSA: "ECDSA", + MetaCryptoTypeEnumELLIPTIC: "ELLIPTIC", + MetaCryptoTypeEnumHMAC: "HMAC", + MetaCryptoTypeEnumMD5: "MD5", + MetaCryptoTypeEnumRAND: "RAND", + MetaCryptoTypeEnumRC4: "RC4", + MetaCryptoTypeEnumRSA: "RSA", + MetaCryptoTypeEnumSHA1: "SHA1", + MetaCryptoTypeEnumSHA256: "SHA256", + MetaCryptoTypeEnumSUBTLE: "SUBTLE", + MetaCryptoTypeEnumTLS: "TLS", + MetaCryptoTypeEnumX509: "X509", + MetaCryptoTypeEnumPKIX: "PKIX", + } + + metaCryptoTypeEnumKey = map[string]MetaCryptoTypeEnum{ + "NONE": MetaCryptoTypeEnumNONE, + "UNKNOWN": MetaCryptoTypeEnumUNKNOWN, + "AES": MetaCryptoTypeEnumAES, + "CIPHER": MetaCryptoTypeEnumCIPHER, + "DES": MetaCryptoTypeEnumDES, + "DSA": MetaCryptoTypeEnumDSA, + "ECDSA": MetaCryptoTypeEnumECDSA, + "ELLIPTIC": MetaCryptoTypeEnumELLIPTIC, + "HMAC": MetaCryptoTypeEnumHMAC, + "MD5": MetaCryptoTypeEnumMD5, + "RAND": MetaCryptoTypeEnumRAND, + "RC4": MetaCryptoTypeEnumRC4, + "RSA": MetaCryptoTypeEnumRSA, + "SHA1": MetaCryptoTypeEnumSHA1, + "SHA256": MetaCryptoTypeEnumSHA256, + "SUBTLE": MetaCryptoTypeEnumSUBTLE, + "TLS": MetaCryptoTypeEnumTLS, + "X509": MetaCryptoTypeEnumX509, + "PKIX": MetaCryptoTypeEnumPKIX, + } +) + +func (e MetaCryptoTypeEnum) String() string { + return metaCryptoTypeEnumID[e] +} + +func ToMetaCryptoTypeEnum(v *MetaCryptoType) MetaCryptoTypeEnum { + return metaCryptoTypeEnumKey[v.Key] +} + +func ToMetaCryptoType(v MetaCryptoTypeEnum) *MetaCryptoType { + return &MetaCryptoType{ + Key: metaCryptoTypeEnumID[v], + } +} diff --git a/meta/MetaDisplayItem.go b/meta/MetaDisplayItem.go new file mode 100644 index 0000000..6865423 --- /dev/null +++ b/meta/MetaDisplayItem.go @@ -0,0 +1,14 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaDisplayItem struct { + ID json.Number `json:"id,Number,omitempty"` + Name string `json:"name,omitempty"` + Key string `json:"key,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaDisplayItemCategory.go b/meta/MetaDisplayItemCategory.go new file mode 100644 index 0000000..add321b --- /dev/null +++ b/meta/MetaDisplayItemCategory.go @@ -0,0 +1,14 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaDisplayItemCategory struct { + ID json.Number `json:"id,Number,omitempty"` + Name string `json:"name,omitempty"` + Key string `json:"key,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaDisplayItemMapping.go b/meta/MetaDisplayItemMapping.go new file mode 100644 index 0000000..68ccf88 --- /dev/null +++ b/meta/MetaDisplayItemMapping.go @@ -0,0 +1,20 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaDisplayItemMapping struct { + ID json.Number `json:"id,Number,omitempty"` + MetaDisplayItem *MetaDisplayItem `json:"metaDisplayItem,omitempty"` + MetaCrawlerMapping *MetaCrawlerMapping `json:"metaCrawlerMapping,omitempty"` + MetaItemUnit *MetaItemUnit `json:"metaItemUnit,omitempty"` + MetaDisplayItemCategory *MetaDisplayItemCategory `json:"metaDisplayItemCategory,omitempty"` + IsDefault bool `json:"isDefault,omitempty"` + Formula string `json:"formula,omitempty"` + Priority json.Number `json:"priority,omitempty"` + IsRequired bool `json:"isRequired,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaHistoryType.go b/meta/MetaHistoryType.go new file mode 100644 index 0000000..99803cf --- /dev/null +++ b/meta/MetaHistoryType.go @@ -0,0 +1,14 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaHistoryType struct { + ID json.Number `json:"id,Number,omitempty"` + Name string `json:"name,omitempty"` + Key string `json:"key,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaIPType.go b/meta/MetaIPType.go new file mode 100644 index 0000000..d3ef688 --- /dev/null +++ b/meta/MetaIPType.go @@ -0,0 +1,47 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaIPType struct { + ID json.Number `json:"id,Number,omitempty"` + Name string `json:"name,omitempty"` + Key string `json:"key,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} + +type MetaIPTypeEnum int + +const ( + MetaIPTypeEnumV4 MetaIPTypeEnum = iota + 1 + MetaIPTypeEnumV6 +) + +var ( + metaIPTypeEnumID = map[MetaIPTypeEnum]string{ + MetaIPTypeEnumV4: "V4", + MetaIPTypeEnumV6: "V6", + } + + metaIPTypeEnumKey = map[string]MetaIPTypeEnum{ + "V4": MetaIPTypeEnumV4, + "V6": MetaIPTypeEnumV6, + } +) + +func (e MetaIPTypeEnum) String() string { + return metaIPTypeEnumID[e] +} + +func ToMetaIPTypeEnum(v *MetaIPType) MetaIPTypeEnum { + return metaIPTypeEnumKey[v.Key] +} + +func ToMetaIPType(v MetaIPTypeEnum) *MetaIPType { + return &MetaIPType{ + Key: metaIPTypeEnumID[v], + } +} diff --git a/meta/MetaInfraType.go b/meta/MetaInfraType.go new file mode 100644 index 0000000..d54ca13 --- /dev/null +++ b/meta/MetaInfraType.go @@ -0,0 +1,50 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaInfraType struct { + ID json.Number `json:"id,Number,omitempty"` + Key string `json:"key,omitempty"` + Name string `json:"name,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} + +type MetaInfraTypeEnum int + +const ( + MetaInfraTypeEnumZONE MetaInfraTypeEnum = iota + 1 + MetaInfraTypeEnumHOST + MetaInfraTypeEnumService +) + +var ( + metaInfraTypeEnumID = map[MetaInfraTypeEnum]string{ + MetaInfraTypeEnumZONE: "ZONE", + MetaInfraTypeEnumHOST: "HOST", + MetaInfraTypeEnumService: "SERVICE", + } + + metaInfraTypeEnumKey = map[string]MetaInfraTypeEnum{ + "ZONE": MetaInfraTypeEnumZONE, + "HOST": MetaInfraTypeEnumHOST, + "SERVICE": MetaInfraTypeEnumService, + } +) + +func (e MetaInfraTypeEnum) String() string { + return metaInfraTypeEnumID[e] +} + +func ToMetaInfraTypeEnum(v *MetaInfraType) MetaInfraTypeEnum { + return metaInfraTypeEnumKey[v.Key] +} + +func ToMetaInfraType(v MetaInfraTypeEnum) *MetaInfraType { + return &MetaInfraType{ + Key: metaInfraTypeEnumID[v], + } +} diff --git a/meta/MetaInputType.go b/meta/MetaInputType.go new file mode 100644 index 0000000..dd27144 --- /dev/null +++ b/meta/MetaInputType.go @@ -0,0 +1,14 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaInputType struct { + ID json.Number `json:"id,Number,omitempty"` + Name string `json:"name,omitempty"` + Key string `json:"key,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaItemUnit.go b/meta/MetaItemUnit.go new file mode 100644 index 0000000..4f9148c --- /dev/null +++ b/meta/MetaItemUnit.go @@ -0,0 +1,15 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaItemUnit struct { + ID json.Number `json:"id,Number,omitempty"` + Key string `json:"key,omitempty"` + Unit string `json:"unit,omitempty"` + Mark string `json:"mark,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaMemberStatus.go b/meta/MetaMemberStatus.go new file mode 100644 index 0000000..f9cae47 --- /dev/null +++ b/meta/MetaMemberStatus.go @@ -0,0 +1,53 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaMemberStatus struct { + ID json.Number `json:"id,Number,omitempty"` + Name string `json:"name,omitempty"` + Key string `json:"key,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} + +type MetaMemberStatusEnum int + +const ( + MetaMemberStatusEnumNOAUTH MetaMemberStatusEnum = iota + 1 + MetaMemberStatusEnumNORMAL + MetaMemberStatusEnumDORMANCY + MetaMemberStatusEnumWITHDRAWAL +) + +var ( + metaMemberStatusEnumID = map[MetaMemberStatusEnum]string{ + MetaMemberStatusEnumNOAUTH: "NOAUTH", + MetaMemberStatusEnumNORMAL: "NORMAL", + MetaMemberStatusEnumDORMANCY: "DORMANCY", + MetaMemberStatusEnumWITHDRAWAL: "WITHDRAWAL", + } + + metaMemberStatusEnumKey = map[string]MetaMemberStatusEnum{ + "NOAUTH": MetaMemberStatusEnumNOAUTH, + "NORMAL": MetaMemberStatusEnumNORMAL, + "DORMANCY": MetaMemberStatusEnumDORMANCY, + "WITHDRAWAL": MetaMemberStatusEnumWITHDRAWAL, + } +) + +func (e MetaMemberStatusEnum) String() string { + return metaMemberStatusEnumID[e] +} + +func ToMetaMemberStatusEnum(v *MetaMemberStatus) MetaMemberStatusEnum { + return metaMemberStatusEnumKey[v.Key] +} + +func ToMetaMemberStatus(v MetaMemberStatusEnum) *MetaMemberStatus { + return &MetaMemberStatus{ + Key: metaMemberStatusEnumID[v], + } +} diff --git a/meta/MetaNoAuthProbeStatus.go b/meta/MetaNoAuthProbeStatus.go new file mode 100644 index 0000000..e46c399 --- /dev/null +++ b/meta/MetaNoAuthProbeStatus.go @@ -0,0 +1,50 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaNoAuthProbeStatus struct { + ID json.Number `json:"id,Number,omitempty"` + Key string `json:"key,omitempty"` + Name string `json:"name,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} + +type MetaNoAuthProbeStatusEnum int + +const ( + MetaNoAuthProbeStatusEnumACCEPT MetaNoAuthProbeStatusEnum = iota + 1 + MetaNoAuthProbeStatusEnumDENY + MetaNoAuthProbeStatusEnumPROCESSING +) + +var ( + metaNoAuthProbeStatusEnumID = map[MetaNoAuthProbeStatusEnum]string{ + MetaNoAuthProbeStatusEnumACCEPT: "ACCEPT", + MetaNoAuthProbeStatusEnumDENY: "DENY", + MetaNoAuthProbeStatusEnumPROCESSING: "PROCESSING", + } + + metaNoAuthProbeStatusEnumKey = map[string]MetaNoAuthProbeStatusEnum{ + "ACCEPT": MetaNoAuthProbeStatusEnumACCEPT, + "DENY": MetaNoAuthProbeStatusEnumDENY, + "PROCESSING": MetaNoAuthProbeStatusEnumPROCESSING, + } +) + +func (e MetaNoAuthProbeStatusEnum) String() string { + return metaNoAuthProbeStatusEnumID[e] +} + +func ToMetaNoAuthProbeStatusEnum(v *MetaNoAuthProbeStatus) MetaNoAuthProbeStatusEnum { + return metaNoAuthProbeStatusEnumKey[v.Key] +} + +func ToMetaNoAuthProbeStatus(v MetaNoAuthProbeStatusEnum) *MetaNoAuthProbeStatus { + return &MetaNoAuthProbeStatus{ + Key: metaNoAuthProbeStatusEnumID[v], + } +} diff --git a/meta/MetaPortType.go b/meta/MetaPortType.go new file mode 100644 index 0000000..86d3f86 --- /dev/null +++ b/meta/MetaPortType.go @@ -0,0 +1,47 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaPortType struct { + ID json.Number `json:"id,Number,omitempty"` + Name string `json:"name,omitempty"` + Key string `json:"key,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} + +type MetaPortTypeEnum int + +const ( + MetaPortTypeEnumTCP MetaPortTypeEnum = iota + 1 + MetaPortTypeEnumUDP +) + +var ( + metaPortTypeEnumID = map[MetaPortTypeEnum]string{ + MetaPortTypeEnumTCP: "TCP", + MetaPortTypeEnumUDP: "UDP", + } + + metaPortTypeEnumKey = map[string]MetaPortTypeEnum{ + "TCP": MetaPortTypeEnumTCP, + "UDP": MetaPortTypeEnumUDP, + } +) + +func (e MetaPortTypeEnum) String() string { + return metaPortTypeEnumID[e] +} + +func ToMetaPortTypeEnum(v *MetaPortType) MetaPortTypeEnum { + return metaPortTypeEnumKey[v.Key] +} + +func ToMetaPortType(v MetaPortTypeEnum) *MetaPortType { + return &MetaPortType{ + Key: metaPortTypeEnumID[v], + } +} diff --git a/meta/MetaProbeStatus.go b/meta/MetaProbeStatus.go new file mode 100644 index 0000000..f0af3fb --- /dev/null +++ b/meta/MetaProbeStatus.go @@ -0,0 +1,47 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaProbeStatus struct { + ID json.Number `json:"id,Number,omitempty"` + Name string `json:"name,omitempty"` + Key string `json:"key,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} + +type MetaProbeStatusEnum int + +const ( + MetaProbeStatusEnumINITIAL MetaProbeStatusEnum = iota + 1 + MetaProbeStatusEnumNORMAL +) + +var ( + metaProbeStatusEnumID = map[MetaProbeStatusEnum]string{ + MetaProbeStatusEnumINITIAL: "INITIAL", + MetaProbeStatusEnumNORMAL: "NORMAL", + } + + metaProbeStatusEnumKey = map[string]MetaProbeStatusEnum{ + "INITIAL": MetaProbeStatusEnumINITIAL, + "NORMAL": MetaProbeStatusEnumNORMAL, + } +) + +func (e MetaProbeStatusEnum) String() string { + return metaProbeStatusEnumID[e] +} + +func ToMetaProbeStatusEnum(v *MetaProbeStatus) MetaProbeStatusEnum { + return metaProbeStatusEnumKey[v.Key] +} + +func ToMetaProbeStatus(v MetaProbeStatusEnum) *MetaProbeStatus { + return &MetaProbeStatus{ + Key: metaProbeStatusEnumID[v], + } +} diff --git a/meta/MetaSensorDisplayItem.go b/meta/MetaSensorDisplayItem.go new file mode 100644 index 0000000..e6a1d5c --- /dev/null +++ b/meta/MetaSensorDisplayItem.go @@ -0,0 +1,18 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaSensorDisplayItem struct { + ID json.Number `json:"id,Number,omitempty"` + Key string `json:"key,omitempty"` + Name string `json:"name,omitempty"` + IsDefault bool `json:"isDefault,omitempty"` + MetaCrawler *MetaCrawler `json:"metaCrawler,omitempty"` + MetaSensorItemUnit *MetaSensorItemUnit `json:"metaSensorItemUnit,omitempty"` + MetaSensorItemType *MetaSensorItemType `json:"metaSensorItemType,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaSensorItem.go b/meta/MetaSensorItem.go new file mode 100644 index 0000000..f97c2fe --- /dev/null +++ b/meta/MetaSensorItem.go @@ -0,0 +1,14 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaSensorItem struct { + ID json.Number `json:"id,Number,omitempty"` + Key string `json:"key,omitempty"` + Name string `json:"name,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaSensorItemKey.go b/meta/MetaSensorItemKey.go new file mode 100644 index 0000000..1e62f56 --- /dev/null +++ b/meta/MetaSensorItemKey.go @@ -0,0 +1,19 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaSensorItemKey struct { + ID json.Number `json:"id,Number,omitempty"` + Key string `json:"key,omitempty"` + Name string `json:"name,omitempty"` + Froms string `json:"froms,omitempty"` + Option string `json:"option,omitempty"` + MetaSensorItem *MetaSensorItem `json:"metaSensorItem,omitempty"` + MetaCrawler *MetaCrawler `json:"metaCrawler,omitempty"` + MetaSensorItemUnit *MetaSensorItemUnit `json:"metaSensorItemUnit,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaSensorItemType.go b/meta/MetaSensorItemType.go new file mode 100644 index 0000000..ef671ae --- /dev/null +++ b/meta/MetaSensorItemType.go @@ -0,0 +1,14 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaSensorItemType struct { + ID json.Number `json:"id,Number,omitempty"` + Name string `json:"name,omitempty"` + Key string `json:"key,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaSensorItemUnit.go b/meta/MetaSensorItemUnit.go new file mode 100644 index 0000000..4fb069d --- /dev/null +++ b/meta/MetaSensorItemUnit.go @@ -0,0 +1,15 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaSensorItemUnit struct { + ID json.Number `json:"id,Number,omitempty"` + Key string `json:"key,omitempty"` + Unit string `json:"unit,omitempty"` + Mark string `json:"mark,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaSensorStatus.go b/meta/MetaSensorStatus.go new file mode 100644 index 0000000..db8bcff --- /dev/null +++ b/meta/MetaSensorStatus.go @@ -0,0 +1,14 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaSensorStatus struct { + ID json.Number `json:"id,Number,omitempty"` + Key string `json:"key,omitempty"` + Name string `json:"name,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaTargetHostType.go b/meta/MetaTargetHostType.go new file mode 100644 index 0000000..974a6aa --- /dev/null +++ b/meta/MetaTargetHostType.go @@ -0,0 +1,36 @@ +package meta + +type MetaTargetHostType struct { + MetaTargetType +} + +type MetaTargetHostTypeEnum int + +const ( + MetaTargetHostTypeEnumUNKNOWN MetaTargetHostTypeEnum = iota + 1 +) + +var ( + metaTargetHostTypeEnumID = map[MetaTargetHostTypeEnum]string{ + MetaTargetHostTypeEnumUNKNOWN: "UNKNOWN", + } + + metaTargetHostTypeEnumKey = map[string]MetaTargetHostTypeEnum{ + "UNKNOWN": MetaTargetHostTypeEnumUNKNOWN, + } +) + +func (e MetaTargetHostTypeEnum) String() string { + return metaTargetHostTypeEnumID[e] +} + +func ToMetaTargetHostTypeEnum(v *MetaTargetHostType) MetaTargetHostTypeEnum { + return metaTargetHostTypeEnumKey[v.Key] +} + +func ToMetaTargetHostType(v MetaTargetHostTypeEnum) *MetaTargetHostType { + m := &MetaTargetHostType{} + m.Key = metaTargetHostTypeEnumID[v] + + return m +} diff --git a/meta/MetaTargetServiceType.go b/meta/MetaTargetServiceType.go new file mode 100644 index 0000000..6276079 --- /dev/null +++ b/meta/MetaTargetServiceType.go @@ -0,0 +1,36 @@ +package meta + +type MetaTargetServiceType struct { + MetaTargetType +} + +type MetaTargetServiceTypeEnum int + +const ( + MetaTargetServiceTypeEnumUNKNOWN MetaTargetServiceTypeEnum = iota + 1 +) + +var ( + metaTargetServiceTypeEnumID = map[MetaTargetServiceTypeEnum]string{ + MetaTargetServiceTypeEnumUNKNOWN: "UNKNOWN", + } + + metaTargetServiceTypeEnumKey = map[string]MetaTargetServiceTypeEnum{ + "UNKNOWN": MetaTargetServiceTypeEnumUNKNOWN, + } +) + +func (e MetaTargetServiceTypeEnum) String() string { + return metaTargetServiceTypeEnumID[e] +} + +func ToMetaTargetServiceTypeEnum(v *MetaTargetServiceType) MetaTargetServiceTypeEnum { + return metaTargetServiceTypeEnumKey[v.Key] +} + +func ToMetaTargetServiceType(v MetaTargetServiceTypeEnum) *MetaTargetServiceType { + m := &MetaTargetServiceType{} + m.Key = metaTargetServiceTypeEnumID[v] + + return m +} diff --git a/meta/MetaTargetType.go b/meta/MetaTargetType.go new file mode 100644 index 0000000..8262a79 --- /dev/null +++ b/meta/MetaTargetType.go @@ -0,0 +1,16 @@ +package meta + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/util" +) + +type MetaTargetType struct { + ID json.Number `json:"id,Number,omitempty"` + MetaInfraType *MetaInfraType `json:"metaInfraType,omitempty"` + Key string `json:"key,omitempty"` + Name string `json:"name,omitempty"` + IsSupported bool `json:"isSupported,omitempty"` + CreateDate *util.Timestamp `json:"createDate,omitempty"` +} diff --git a/meta/MetaTargetZoneType.go b/meta/MetaTargetZoneType.go new file mode 100644 index 0000000..77af1ba --- /dev/null +++ b/meta/MetaTargetZoneType.go @@ -0,0 +1,39 @@ +package meta + +type MetaTargetZoneType struct { + MetaTargetType +} + +type MetaTargetZoneTypeEnum int + +const ( + MetaTargetZoneTypeEnumUNKNOWN MetaTargetZoneTypeEnum = iota + 1 + MetaTargetZoneTypeEnumZONE +) + +var ( + metaTargetZoneTypeEnumID = map[MetaTargetZoneTypeEnum]string{ + MetaTargetZoneTypeEnumUNKNOWN: "UNKNOWN", + MetaTargetZoneTypeEnumZONE: "ZONE", + } + + metaTargetZoneTypeEnumKey = map[string]MetaTargetZoneTypeEnum{ + "UNKNOWN": MetaTargetZoneTypeEnumUNKNOWN, + "ZONE": MetaTargetZoneTypeEnumZONE, + } +) + +func (e MetaTargetZoneTypeEnum) String() string { + return metaTargetZoneTypeEnumID[e] +} + +func ToMetaTargetZoneTypeEnum(v *MetaTargetZoneType) MetaTargetZoneTypeEnum { + return metaTargetZoneTypeEnumKey[v.Key] +} + +func ToMetaTargetZoneType(v MetaTargetZoneTypeEnum) *MetaTargetZoneType { + m := &MetaTargetZoneType{} + m.Key = metaTargetZoneTypeEnumID[v] + + return m +} diff --git a/scan/DiscoverHost.go b/scan/DiscoverHost.go new file mode 100644 index 0000000..18c2a0d --- /dev/null +++ b/scan/DiscoverHost.go @@ -0,0 +1,16 @@ +package discovery + +import ( + "git.loafle.net/overflow/model/meta" +) + +type DiscoverHost struct { + MetaIPType *meta.MetaIPType `json:"metaIPType,omitempty"` + + FirstScanRange string `json:"firstScanRange,omitempty"` + LastScanRange string `json:"lastScanRange,omitempty"` + ExcludeHosts []string `json:"excludeHosts,omitempty"` + IncludeHosts []string `json:"includeHosts,omitempty"` + + DiscoverPort *DiscoverPort `json:"discoverPort,omitempty"` +} diff --git a/scan/DiscoverPort.go b/scan/DiscoverPort.go new file mode 100644 index 0000000..8e7e37f --- /dev/null +++ b/scan/DiscoverPort.go @@ -0,0 +1,28 @@ +package discovery + +type DiscoverPort struct { + FirstScanRange int `json:"firstScanRange,omitempty"` + LastScanRange int `json:"lastScanRange,omitempty"` + ExcludePorts []int `json:"excludePorts,omitempty"` + + IncludeTCP bool `json:"includeTCP,omitempty"` + IncludeUDP bool `json:"includeUDP,omitempty"` + + DiscoverService *DiscoverService `json:"discoverService,omitempty"` +} + +func (dp *DiscoverPort) Contains(port int) bool { + if dp.FirstScanRange > port { + return false + } + if dp.LastScanRange < port { + return false + } + for _, p := range dp.ExcludePorts { + if p == port { + return false + } + } + + return true +} diff --git a/scan/DiscoverService.go b/scan/DiscoverService.go new file mode 100644 index 0000000..5b32960 --- /dev/null +++ b/scan/DiscoverService.go @@ -0,0 +1,5 @@ +package discovery + +type DiscoverService struct { + IncludeServices []string `json:"includeServices,omitempty"` +} diff --git a/scan/DiscoverZone.go b/scan/DiscoverZone.go new file mode 100644 index 0000000..73b078e --- /dev/null +++ b/scan/DiscoverZone.go @@ -0,0 +1,7 @@ +package discovery + +type DiscoverZone struct { + ExcludePatterns []string `json:"excludePatterns,omitempty"` + + DiscoverHost *DiscoverHost `json:"discoverHost,omitempty"` +} diff --git a/scan/Host.go b/scan/Host.go new file mode 100644 index 0000000..d92d8d0 --- /dev/null +++ b/scan/Host.go @@ -0,0 +1,17 @@ +package discovery + +import ( + "git.loafle.net/overflow/model/meta" + "git.loafle.net/overflow/model/util" +) + +type Host struct { + MetaIPType *meta.MetaIPType `json:"metaIPType,omitempty"` + Address string `json:"address,omitempty"` + Mac string `json:"mac,omitempty"` + + Zone *Zone `json:"zone,omitempty"` + PortList []*Port `json:"portList,omitempty"` + + DiscoveredDate *util.Timestamp `json:"discoveredDate,omitempty"` +} diff --git a/scan/Port.go b/scan/Port.go new file mode 100644 index 0000000..f25df95 --- /dev/null +++ b/scan/Port.go @@ -0,0 +1,20 @@ +package discovery + +import ( + "encoding/json" + + "git.loafle.net/overflow/model/meta" + "git.loafle.net/overflow/model/util" + "github.com/google/gopacket" +) + +type Port struct { + MetaPortType *meta.MetaPortType `json:"metaPortType,omitempty"` + PortNumber json.Number `json:"portNumber,omitempty"` + DiscoveredDate *util.Timestamp `json:"discoveredDate,omitempty"` + + Host *Host `json:"host,omitempty"` + ServiceList []*Service `json:"serviceList,omitempty"` + + UDPLayer gopacket.Layer `json:"-"` +} diff --git a/scan/Service.go b/scan/Service.go new file mode 100644 index 0000000..764628a --- /dev/null +++ b/scan/Service.go @@ -0,0 +1,16 @@ +package discovery + +import ( + "git.loafle.net/overflow/model/meta" + "git.loafle.net/overflow/model/util" +) + +type Service struct { + MetaCryptoType *meta.MetaCryptoType `json:"metaCryptoType,omitempty"` + Key string `json:"key,omitempty"` + Description string `json:"description,omitempty"` + + Port *Port `json:"port,omitempty"` + + DiscoveredDate *util.Timestamp `json:"discoveredDate,omitempty"` +} diff --git a/scan/Zone.go b/scan/Zone.go new file mode 100644 index 0000000..4033b18 --- /dev/null +++ b/scan/Zone.go @@ -0,0 +1,20 @@ +package discovery + +import ( + "sync" + + "git.loafle.net/overflow/model/meta" + "git.loafle.net/overflow/model/util" +) + +type Zone struct { + Network string `json:"network,omitempty"` + Iface string `json:"iface,omitempty"` + MetaIPType *meta.MetaIPType `json:"metaIPType,omitempty"` + Address string `json:"address,omitempty"` + Mac string `json:"mac,omitempty"` + + DiscoveredDate *util.Timestamp `json:"discoveredDate,omitempty"` + + mtx sync.RWMutex `json:"-"` +} diff --git a/util/timestamp.go b/util/timestamp.go new file mode 100644 index 0000000..623f64a --- /dev/null +++ b/util/timestamp.go @@ -0,0 +1,42 @@ +package util + +import ( + "fmt" + "strconv" + "time" +) + +type Timestamp time.Time + +func (t Timestamp) MarshalJSON() ([]byte, error) { + ts := time.Time(t).Unix() + stamp := fmt.Sprint(ts * 1000) + return []byte(stamp), nil +} + +func (t *Timestamp) UnmarshalJSON(b []byte) error { + ts, err := strconv.Atoi(string(b)) + if err != nil { + return err + } + *t = Timestamp(time.Unix(int64(ts)/1000, 0)) + + return nil +} + +func (t Timestamp) String() string { + return time.Time(t).String() +} + +func Now() Timestamp { + return Timestamp(time.Now()) +} + +func NowPtr() *Timestamp { + n := Now() + return &n +} + +func Date(year int, month time.Month, day int) Timestamp { + return Timestamp(time.Date(year, month, day, 0, 0, 0, 0, time.UTC)) +} diff --git a/vendor/github.com/google/gopacket/.gitignore b/vendor/github.com/google/gopacket/.gitignore new file mode 100644 index 0000000..149266f --- /dev/null +++ b/vendor/github.com/google/gopacket/.gitignore @@ -0,0 +1,38 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +#* +*~ + +# examples binaries +examples/synscan/synscan +examples/pfdump/pfdump +examples/pcapdump/pcapdump +examples/httpassembly/httpassembly +examples/statsassembly/statsassembly +examples/arpscan/arpscan +examples/bidirectional/bidirectional +examples/bytediff/bytediff +examples/reassemblydump/reassemblydump +layers/gen +macs/gen +pcap/pcap_tester diff --git a/vendor/github.com/google/gopacket/.travis.gofmt.sh b/vendor/github.com/google/gopacket/.travis.gofmt.sh new file mode 100644 index 0000000..e341a1c --- /dev/null +++ b/vendor/github.com/google/gopacket/.travis.gofmt.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +cd "$(dirname $0)" +if [ -n "$(go fmt ./...)" ]; then + echo "Go code is not formatted, run 'go fmt github.com/google/stenographer/...'" >&2 + exit 1 +fi diff --git a/vendor/github.com/google/gopacket/.travis.golint.sh b/vendor/github.com/google/gopacket/.travis.golint.sh new file mode 100644 index 0000000..ed74c65 --- /dev/null +++ b/vendor/github.com/google/gopacket/.travis.golint.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +cd "$(dirname $0)" + +go get github.com/golang/lint/golint +DIRS=". tcpassembly tcpassembly/tcpreader ip4defrag reassembly macs pcapgo pcap afpacket pfring routing" +# Add subdirectories here as we clean up golint on each. +for subdir in $DIRS; do + pushd $subdir + if golint | + grep -v CannotSetRFMon | # pcap exported error name + grep -v DataLost | # tcpassembly/tcpreader exported error name + grep .; then + exit 1 + fi + popd +done + +pushd layers +for file in $(cat .linted); do + if golint $file | grep .; then + exit 1 + fi +done +popd diff --git a/vendor/github.com/google/gopacket/.travis.govet.sh b/vendor/github.com/google/gopacket/.travis.govet.sh new file mode 100644 index 0000000..52ad084 --- /dev/null +++ b/vendor/github.com/google/gopacket/.travis.govet.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +cd "$(dirname $0)" +DIRS=". layers pcap pcapgo pfring tcpassembly tcpassembly/tcpreader routing ip4defrag bytediff macs" +set -e +for subdir in $DIRS; do + pushd $subdir + go vet + popd +done diff --git a/vendor/github.com/google/gopacket/.travis.yml b/vendor/github.com/google/gopacket/.travis.yml new file mode 100644 index 0000000..7d73126 --- /dev/null +++ b/vendor/github.com/google/gopacket/.travis.yml @@ -0,0 +1,14 @@ +language: go +install: + - go get github.com/google/gopacket + - go get github.com/google/gopacket/layers + - go get github.com/google/gopacket/tcpassembly + - go get github.com/google/gopacket/reassembly +script: + - go test github.com/google/gopacket + - go test github.com/google/gopacket/layers + - go test github.com/google/gopacket/tcpassembly + - go test github.com/google/gopacket/reassembly + - ./.travis.gofmt.sh + - ./.travis.govet.sh + - ./.travis.golint.sh diff --git a/vendor/github.com/google/gopacket/AUTHORS b/vendor/github.com/google/gopacket/AUTHORS new file mode 100644 index 0000000..eba34f0 --- /dev/null +++ b/vendor/github.com/google/gopacket/AUTHORS @@ -0,0 +1,46 @@ +AUTHORS AND MAINTAINERS: + +MAIN DEVELOPERS: +Graeme Connell + +AUTHORS: +Nigel Tao +Cole Mickens +Ben Daglish +Luis Martinez +Remco Verhoef +Hiroaki Kawai +Lukas Lueg +Laurent Hausermann +Bill Green + +CONTRIBUTORS: +Attila Oláh +Vittus Mikiassen +Matthias Radestock +Matthew Sackman +Loic Prylli +Alexandre Fiori +Adrian Tam +Satoshi Matsumoto +David Stainton +Jesse Ward +Kane Mathers + +----------------------------------------------- +FORKED FROM github.com/akrennmair/gopcap +ALL THE FOLLOWING ARE FOR THAT PROJECT + +MAIN DEVELOPERS: +Andreas Krennmair + +CONTRIBUTORS: +Andrea Nall +Daniel Arndt +Dustin Sallings +Graeme Connell +Guillaume Savary +Mark Smith +Miek Gieben +Mike Bell +Trevor Strohman diff --git a/vendor/github.com/google/gopacket/CONTRIBUTING.md b/vendor/github.com/google/gopacket/CONTRIBUTING.md new file mode 100644 index 0000000..99ab7a2 --- /dev/null +++ b/vendor/github.com/google/gopacket/CONTRIBUTING.md @@ -0,0 +1,215 @@ +Contributing To gopacket +======================== + +So you've got some code and you'd like it to be part of gopacket... wonderful! +We're happy to accept contributions, whether they're fixes to old protocols, new +protocols entirely, or anything else you think would improve the gopacket +library. This document is designed to help you to do just that. + +The first section deals with the plumbing: how to actually get a change +submitted. + +The second section deals with coding style... Go is great in that it +has a uniform style implemented by 'go fmt', but there's still some decisions +we've made that go above and beyond, and if you follow them, they won't come up +in your code review. + +The third section deals with some of the implementation decisions we've made, +which may help you to understand the current code and which we may ask you to +conform to (or provide compelling reasons for ignoring). + +Overall, we hope this document will help you to understand our system and write +great code which fits in, and help us to turn around on your code review quickly +so the code can make it into the master branch as quickly as possible. + + +How To Submit Code +------------------ + +We use github.com's Pull Request feature to receive code contributions from +external contributors. See +https://help.github.com/articles/creating-a-pull-request/ for details on +how to create a request. + +Also, there's a local script `gc` in the base directory of GoPacket that +runs a local set of checks, which should give you relatively high confidence +that your pull won't fail github pull checks. + +```sh +go get github.com/google/gopacket +cd $GOROOT/src/pkg/github.com/google/gopacket +git checkout -b # create a new branch to work from +... code code code ... +./gc # Run this to do local commits, it performs a number of checks +``` + +To sum up: + +* DO + + Pull down the latest version. + + Make a feature-specific branch. + + Code using the style and methods discussed in the rest of this document. + + Use the ./gc command to do local commits or check correctness. + + Push your new feature branch up to github.com, as a pull request. + + Handle comments and requests from reviewers, pushing new commits up to + your feature branch as problems are addressed. + + Put interesting comments and discussions into commit comments. +* DON'T + + Push to someone else's branch without their permission. + + +Coding Style +------------ + +* Go code must be run through `go fmt`, `go vet`, and `golint` +* Follow http://golang.org/doc/effective_go.html as much as possible. + + In particular, http://golang.org/doc/effective_go.html#mixed-caps. Enums + should be be CamelCase, with acronyms capitalized (TCPSourcePort, vs. + TcpSourcePort or TCP_SOURCE_PORT). +* Bonus points for giving enum types a String() field. +* Any exported types or functions should have commentary + (http://golang.org/doc/effective_go.html#commentary) + + +Coding Methods And Implementation Notes +--------------------------------------- + +### Error Handling + +Many times, you'll be decoding a protocol and run across something bad, a packet +corruption or the like. How do you handle this? First off, ALWAYS report the +error. You can do this either by returning the error from the decode() function +(most common), or if you're up for it you can implement and add an ErrorLayer +through the packet builder (the first method is a simple shortcut that does +exactly this, then stops any future decoding). + +Often, you'll already have decode some part of your protocol by the time you hit +your error. Use your own discretion to determine whether the stuff you've +already decoded should be returned to the caller or not: + +```go +func decodeMyProtocol(data []byte, p gopacket.PacketBuilder) error { + prot := &MyProtocol{} + if len(data) < 10 { + // This error occurred before we did ANYTHING, so there's nothing in my + // protocol that the caller could possibly want. Just return the error. + return fmt.Errorf("Length %d less than 10", len(data)) + } + prot.ImportantField1 = data[:5] + prot.ImportantField2 = data[5:10] + // At this point, we've already got enough information in 'prot' to + // warrant returning it to the caller, so we'll add it now. + p.AddLayer(prot) + if len(data) < 15 { + // We encountered an error later in the packet, but the caller already + // has the important info we've gleaned so far. + return fmt.Errorf("Length %d less than 15", len(data)) + } + prot.ImportantField3 = data[10:15] + return nil // We've already added the layer, we can just return success. +} +``` + +In general, our code follows the approach of returning the first error it +encounters. In general, we don't trust any bytes after the first error we see. + +### What Is A Layer? + +The definition of a layer is up to the discretion of the coder. It should be +something important enough that it's actually useful to the caller (IE: every +TLV value should probably NOT be a layer). However, it can be more granular +than a single protocol... IPv6 and SCTP both implement many layers to handle the +various parts of the protocol. Use your best judgement, and prepare to defend +your decisions during code review. ;) + +### Performance + +We strive to make gopacket as fast as possible while still providing lots of +features. In general, this means: + +* Focus performance tuning on common protocols (IP4/6, TCP, etc), and optimize + others on an as-needed basis (tons of MPLS on your network? Time to optimize + MPLS!) +* Use fast operations. See the toplevel benchmark_test for benchmarks of some + of Go's underlying features and types. +* Test your performance changes! You should use the ./gc script's --benchmark + flag to submit any performance-related changes. Use pcap/gopacket_benchmark + to test your change against a PCAP file based on your traffic patterns. +* Don't be TOO hacky. Sometimes, removing an unused struct from a field causes + a huge performance hit, due to the way that Go currently handles its segmented + stack... don't be afraid to clean it up anyway. We'll trust the Go compiler + to get good enough over time to handle this. Also, this type of + compiler-specific optimization is very fragile; someone adding a field to an + entirely different struct elsewhere in the codebase could reverse any gains + you might achieve by aligning your allocations. +* Try to minimize memory allocations. If possible, use []byte to reference + pieces of the input, instead of using string, which requires copying the bytes + into a new memory allocation. +* Think hard about what should be evaluated lazily vs. not. In general, a + layer's struct should almost exactly mirror the layer's frame. Anything + that's more interesting should be a function. This may not always be + possible, but it's a good rule of thumb. +* Don't fear micro-optimizations. With the above in mind, we welcome + micro-optimizations that we think will have positive/neutral impacts on the + majority of workloads. A prime example of this is pre-allocating certain + structs within a larger one: + +```go +type MyProtocol struct { + // Most packets have 1-4 of VeryCommon, so we preallocate it here. + initialAllocation [4]uint32 + VeryCommon []uint32 +} + +func decodeMyProtocol(data []byte, p gopacket.PacketBuilder) error { + prot := &MyProtocol{} + prot.VeryCommon = proto.initialAllocation[:0] + for len(data) > 4 { + field := binary.BigEndian.Uint32(data[:4]) + data = data[4:] + // Since we're using the underlying initialAllocation, we won't need to + // allocate new memory for the following append unless we more than 16 + // bytes of data, which should be the uncommon case. + prot.VeryCommon = append(prot.VeryCommon, field) + } + p.AddLayer(prot) + if len(data) > 0 { + return fmt.Errorf("MyProtocol packet has %d bytes left after decoding", len(data)) + } + return nil +} +``` + +### Slices And Data + +If you're pulling a slice from the data you're decoding, don't copy it. Just +use the slice itself. + +```go +type MyProtocol struct { + A, B net.IP +} +func decodeMyProtocol(data []byte, p gopacket.PacketBuilder) error { + p.AddLayer(&MyProtocol{ + A: data[:4], + B: data[4:8], + }) + return nil +} +``` + +The caller has already agreed, by using this library, that they won't modify the +set of bytes they pass in to the decoder, or the library has already copied the +set of bytes to a read-only location. See DecodeOptions.NoCopy for more +information. + +### Enums/Types + +If a protocol has an integer field (uint8, uint16, etc) with a couple of known +values that mean something special, make it a type. This allows us to do really +nice things like adding a String() function to them, so we can more easily +display those to users. Check out layers/enums.go for one example, as well as +layers/icmp.go for layer-specific enums. + +When naming things, try for descriptiveness over suscinctness. For example, +choose DNSResponseRecord over DNSRR. diff --git a/vendor/github.com/google/gopacket/LICENSE b/vendor/github.com/google/gopacket/LICENSE new file mode 100644 index 0000000..2100d52 --- /dev/null +++ b/vendor/github.com/google/gopacket/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2012 Google, Inc. All rights reserved. +Copyright (c) 2009-2011 Andreas Krennmair. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Andreas Krennmair, Google, nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/google/gopacket/README.md b/vendor/github.com/google/gopacket/README.md new file mode 100644 index 0000000..f71854c --- /dev/null +++ b/vendor/github.com/google/gopacket/README.md @@ -0,0 +1,10 @@ +# GoPacket + +This library provides packet decoding capabilities for Go. +See [godoc](https://godoc.org/github.com/google/gopacket) for more details. + +[![Build Status](https://travis-ci.org/google/gopacket.svg?branch=master)](https://travis-ci.org/google/gopacket) +[![GoDoc](https://godoc.org/github.com/google/gopacket?status.svg)](https://godoc.org/github.com/google/gopacket) + +Originally forked from the gopcap project written by Andreas +Krennmair (http://github.com/akrennmair/gopcap). diff --git a/vendor/github.com/google/gopacket/base.go b/vendor/github.com/google/gopacket/base.go new file mode 100644 index 0000000..797b55f --- /dev/null +++ b/vendor/github.com/google/gopacket/base.go @@ -0,0 +1,178 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "fmt" +) + +// Layer represents a single decoded packet layer (using either the +// OSI or TCP/IP definition of a layer). When decoding, a packet's data is +// broken up into a number of layers. The caller may call LayerType() to +// figure out which type of layer they've received from the packet. Optionally, +// they may then use a type assertion to get the actual layer type for deep +// inspection of the data. +type Layer interface { + // LayerType is the gopacket type for this layer. + LayerType() LayerType + // LayerContents returns the set of bytes that make up this layer. + LayerContents() []byte + // LayerPayload returns the set of bytes contained within this layer, not + // including the layer itself. + LayerPayload() []byte +} + +// Payload is a Layer containing the payload of a packet. The definition of +// what constitutes the payload of a packet depends on previous layers; for +// TCP and UDP, we stop decoding above layer 4 and return the remaining +// bytes as a Payload. Payload is an ApplicationLayer. +type Payload []byte + +// LayerType returns LayerTypePayload +func (p Payload) LayerType() LayerType { return LayerTypePayload } + +// LayerContents returns the bytes making up this layer. +func (p Payload) LayerContents() []byte { return []byte(p) } + +// LayerPayload returns the payload within this layer. +func (p Payload) LayerPayload() []byte { return nil } + +// Payload returns this layer as bytes. +func (p Payload) Payload() []byte { return []byte(p) } + +// String implements fmt.Stringer. +func (p Payload) String() string { return fmt.Sprintf("%d byte(s)", len(p)) } + +// GoString implements fmt.GoStringer. +func (p Payload) GoString() string { return LongBytesGoString([]byte(p)) } + +// CanDecode implements DecodingLayer. +func (p Payload) CanDecode() LayerClass { return LayerTypePayload } + +// NextLayerType implements DecodingLayer. +func (p Payload) NextLayerType() LayerType { return LayerTypeZero } + +// DecodeFromBytes implements DecodingLayer. +func (p *Payload) DecodeFromBytes(data []byte, df DecodeFeedback) error { + *p = Payload(data) + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (p Payload) SerializeTo(b SerializeBuffer, opts SerializeOptions) error { + bytes, err := b.PrependBytes(len(p)) + if err != nil { + return err + } + copy(bytes, p) + return nil +} + +// decodePayload decodes data by returning it all in a Payload layer. +func decodePayload(data []byte, p PacketBuilder) error { + payload := &Payload{} + if err := payload.DecodeFromBytes(data, p); err != nil { + return nil + } + p.AddLayer(payload) + p.SetApplicationLayer(payload) + return nil +} + +// Fragment is a Layer containing a fragment of a larger frame, used by layers +// like IPv4 and IPv6 that allow for fragmentation of their payloads. +type Fragment []byte + +// LayerType returns LayerTypeFragment +func (p *Fragment) LayerType() LayerType { return LayerTypeFragment } + +// LayerContents implements Layer. +func (p *Fragment) LayerContents() []byte { return []byte(*p) } + +// LayerPayload implements Layer. +func (p *Fragment) LayerPayload() []byte { return nil } + +// Payload returns this layer as a byte slice. +func (p *Fragment) Payload() []byte { return []byte(*p) } + +// String implements fmt.Stringer. +func (p *Fragment) String() string { return fmt.Sprintf("%d byte(s)", len(*p)) } + +// CanDecode implements DecodingLayer. +func (p *Fragment) CanDecode() LayerClass { return LayerTypeFragment } + +// NextLayerType implements DecodingLayer. +func (p *Fragment) NextLayerType() LayerType { return LayerTypeZero } + +// DecodeFromBytes implements DecodingLayer. +func (p *Fragment) DecodeFromBytes(data []byte, df DecodeFeedback) error { + *p = Fragment(data) + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (p *Fragment) SerializeTo(b SerializeBuffer, opts SerializeOptions) error { + bytes, err := b.PrependBytes(len(*p)) + if err != nil { + return err + } + copy(bytes, *p) + return nil +} + +// decodeFragment decodes data by returning it all in a Fragment layer. +func decodeFragment(data []byte, p PacketBuilder) error { + payload := &Fragment{} + if err := payload.DecodeFromBytes(data, p); err != nil { + return nil + } + p.AddLayer(payload) + p.SetApplicationLayer(payload) + return nil +} + +// These layers correspond to Internet Protocol Suite (TCP/IP) layers, and their +// corresponding OSI layers, as best as possible. + +// LinkLayer is the packet layer corresponding to TCP/IP layer 1 (OSI layer 2) +type LinkLayer interface { + Layer + LinkFlow() Flow +} + +// NetworkLayer is the packet layer corresponding to TCP/IP layer 2 (OSI +// layer 3) +type NetworkLayer interface { + Layer + NetworkFlow() Flow +} + +// TransportLayer is the packet layer corresponding to the TCP/IP layer 3 (OSI +// layer 4) +type TransportLayer interface { + Layer + TransportFlow() Flow +} + +// ApplicationLayer is the packet layer corresponding to the TCP/IP layer 4 (OSI +// layer 7), also known as the packet payload. +type ApplicationLayer interface { + Layer + Payload() []byte +} + +// ErrorLayer is a packet layer created when decoding of the packet has failed. +// Its payload is all the bytes that we were unable to decode, and the returned +// error details why the decoding failed. +type ErrorLayer interface { + Layer + Error() error +} diff --git a/vendor/github.com/google/gopacket/decode.go b/vendor/github.com/google/gopacket/decode.go new file mode 100644 index 0000000..2633f84 --- /dev/null +++ b/vendor/github.com/google/gopacket/decode.go @@ -0,0 +1,157 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "errors" +) + +// DecodeFeedback is used by DecodingLayer layers to provide decoding metadata. +type DecodeFeedback interface { + // SetTruncated should be called if during decoding you notice that a packet + // is shorter than internal layer variables (HeaderLength, or the like) say it + // should be. It sets packet.Metadata().Truncated. + SetTruncated() +} + +type nilDecodeFeedback struct{} + +func (nilDecodeFeedback) SetTruncated() {} + +// NilDecodeFeedback implements DecodeFeedback by doing nothing. +var NilDecodeFeedback DecodeFeedback = nilDecodeFeedback{} + +// PacketBuilder is used by layer decoders to store the layers they've decoded, +// and to defer future decoding via NextDecoder. +// Typically, the pattern for use is: +// func (m *myDecoder) Decode(data []byte, p PacketBuilder) error { +// if myLayer, err := myDecodingLogic(data); err != nil { +// return err +// } else { +// p.AddLayer(myLayer) +// } +// // maybe do this, if myLayer is a LinkLayer +// p.SetLinkLayer(myLayer) +// return p.NextDecoder(nextDecoder) +// } +type PacketBuilder interface { + DecodeFeedback + // AddLayer should be called by a decoder immediately upon successful + // decoding of a layer. + AddLayer(l Layer) + // The following functions set the various specific layers in the final + // packet. Note that if many layers call SetX, the first call is kept and all + // other calls are ignored. + SetLinkLayer(LinkLayer) + SetNetworkLayer(NetworkLayer) + SetTransportLayer(TransportLayer) + SetApplicationLayer(ApplicationLayer) + SetErrorLayer(ErrorLayer) + // NextDecoder should be called by a decoder when they're done decoding a + // packet layer but not done with decoding the entire packet. The next + // decoder will be called to decode the last AddLayer's LayerPayload. + // Because of this, NextDecoder must only be called once all other + // PacketBuilder calls have been made. Set*Layer and AddLayer calls after + // NextDecoder calls will behave incorrectly. + NextDecoder(next Decoder) error + // DumpPacketData is used solely for decoding. If you come across an error + // you need to diagnose while processing a packet, call this and your packet's + // data will be dumped to stderr so you can create a test. This should never + // be called from a production decoder. + DumpPacketData() + // DecodeOptions returns the decode options + DecodeOptions() *DecodeOptions +} + +// Decoder is an interface for logic to decode a packet layer. Users may +// implement a Decoder to handle their own strange packet types, or may use one +// of the many decoders available in the 'layers' subpackage to decode things +// for them. +type Decoder interface { + // Decode decodes the bytes of a packet, sending decoded values and other + // information to PacketBuilder, and returning an error if unsuccessful. See + // the PacketBuilder documentation for more details. + Decode([]byte, PacketBuilder) error +} + +// DecodeFunc wraps a function to make it a Decoder. +type DecodeFunc func([]byte, PacketBuilder) error + +// Decode implements Decoder by calling itself. +func (d DecodeFunc) Decode(data []byte, p PacketBuilder) error { + // function, call thyself. + return d(data, p) +} + +// DecodePayload is a Decoder that returns a Payload layer containing all +// remaining bytes. +var DecodePayload Decoder = DecodeFunc(decodePayload) + +// DecodeUnknown is a Decoder that returns an Unknown layer containing all +// remaining bytes, useful if you run up against a layer that you're unable to +// decode yet. This layer is considered an ErrorLayer. +var DecodeUnknown Decoder = DecodeFunc(decodeUnknown) + +// DecodeFragment is a Decoder that returns a Fragment layer containing all +// remaining bytes. +var DecodeFragment Decoder = DecodeFunc(decodeFragment) + +// LayerTypeZero is an invalid layer type, but can be used to determine whether +// layer type has actually been set correctly. +var LayerTypeZero = RegisterLayerType(0, LayerTypeMetadata{Name: "Unknown", Decoder: DecodeUnknown}) + +// LayerTypeDecodeFailure is the layer type for the default error layer. +var LayerTypeDecodeFailure = RegisterLayerType(1, LayerTypeMetadata{Name: "DecodeFailure", Decoder: DecodeUnknown}) + +// LayerTypePayload is the layer type for a payload that we don't try to decode +// but treat as a success, IE: an application-level payload. +var LayerTypePayload = RegisterLayerType(2, LayerTypeMetadata{Name: "Payload", Decoder: DecodePayload}) + +// LayerTypeFragment is the layer type for a fragment of a layer transported +// by an underlying layer that supports fragmentation. +var LayerTypeFragment = RegisterLayerType(3, LayerTypeMetadata{Name: "Fragment", Decoder: DecodeFragment}) + +// DecodeFailure is a packet layer created if decoding of the packet data failed +// for some reason. It implements ErrorLayer. LayerContents will be the entire +// set of bytes that failed to parse, and Error will return the reason parsing +// failed. +type DecodeFailure struct { + data []byte + err error + stack []byte +} + +// Error returns the error encountered during decoding. +func (d *DecodeFailure) Error() error { return d.err } + +// LayerContents implements Layer. +func (d *DecodeFailure) LayerContents() []byte { return d.data } + +// LayerPayload implements Layer. +func (d *DecodeFailure) LayerPayload() []byte { return nil } + +// String implements fmt.Stringer. +func (d *DecodeFailure) String() string { + return "Packet decoding error: " + d.Error().Error() +} + +// Dump implements Dumper. +func (d *DecodeFailure) Dump() (s string) { + if d.stack != nil { + s = string(d.stack) + } + return +} + +// LayerType returns LayerTypeDecodeFailure +func (d *DecodeFailure) LayerType() LayerType { return LayerTypeDecodeFailure } + +// decodeUnknown "decodes" unsupported data types by returning an error. +// This decoder will thus always return a DecodeFailure layer. +func decodeUnknown(data []byte, p PacketBuilder) error { + return errors.New("Layer type not currently supported") +} diff --git a/vendor/github.com/google/gopacket/doc.go b/vendor/github.com/google/gopacket/doc.go new file mode 100644 index 0000000..6198940 --- /dev/null +++ b/vendor/github.com/google/gopacket/doc.go @@ -0,0 +1,365 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +/* +Package gopacket provides packet decoding for the Go language. + +gopacket contains many sub-packages with additional functionality you may find +useful, including: + + * layers: You'll probably use this every time. This contains of the logic + built into gopacket for decoding packet protocols. Note that all example + code below assumes that you have imported both gopacket and + gopacket/layers. + * pcap: C bindings to use libpcap to read packets off the wire. + * pfring: C bindings to use PF_RING to read packets off the wire. + * afpacket: C bindings for Linux's AF_PACKET to read packets off the wire. + * tcpassembly: TCP stream reassembly + +Also, if you're looking to dive right into code, see the examples subdirectory +for numerous simple binaries built using gopacket libraries. + +Basic Usage + +gopacket takes in packet data as a []byte and decodes it into a packet with +a non-zero number of "layers". Each layer corresponds to a protocol +within the bytes. Once a packet has been decoded, the layers of the packet +can be requested from the packet. + + // Decode a packet + packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Default) + // Get the TCP layer from this packet + if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil { + fmt.Println("This is a TCP packet!") + // Get actual TCP data from this layer + tcp, _ := tcpLayer.(*layers.TCP) + fmt.Printf("From src port %d to dst port %d\n", tcp.SrcPort, tcp.DstPort) + } + // Iterate over all layers, printing out each layer type + for _, layer := range packet.Layers() { + fmt.Println("PACKET LAYER:", layer.LayerType()) + } + +Packets can be decoded from a number of starting points. Many of our base +types implement Decoder, which allow us to decode packets for which +we don't have full data. + + // Decode an ethernet packet + ethP := gopacket.NewPacket(p1, layers.LayerTypeEthernet, gopacket.Default) + // Decode an IPv6 header and everything it contains + ipP := gopacket.NewPacket(p2, layers.LayerTypeIPv6, gopacket.Default) + // Decode a TCP header and its payload + tcpP := gopacket.NewPacket(p3, layers.LayerTypeTCP, gopacket.Default) + + +Reading Packets From A Source + +Most of the time, you won't just have a []byte of packet data lying around. +Instead, you'll want to read packets in from somewhere (file, interface, etc) +and process them. To do that, you'll want to build a PacketSource. + +First, you'll need to construct an object that implements the PacketDataSource +interface. There are implementations of this interface bundled with gopacket +in the gopacket/pcap and gopacket/pfring subpackages... see their documentation +for more information on their usage. Once you have a PacketDataSource, you can +pass it into NewPacketSource, along with a Decoder of your choice, to create +a PacketSource. + +Once you have a PacketSource, you can read packets from it in multiple ways. +See the docs for PacketSource for more details. The easiest method is the +Packets function, which returns a channel, then asynchronously writes new +packets into that channel, closing the channel if the packetSource hits an +end-of-file. + + packetSource := ... // construct using pcap or pfring + for packet := range packetSource.Packets() { + handlePacket(packet) // do something with each packet + } + +You can change the decoding options of the packetSource by setting fields in +packetSource.DecodeOptions... see the following sections for more details. + + +Lazy Decoding + +gopacket optionally decodes packet data lazily, meaning it +only decodes a packet layer when it needs to handle a function call. + + // Create a packet, but don't actually decode anything yet + packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Lazy) + // Now, decode the packet up to the first IPv4 layer found but no further. + // If no IPv4 layer was found, the whole packet will be decoded looking for + // it. + ip4 := packet.Layer(layers.LayerTypeIPv4) + // Decode all layers and return them. The layers up to the first IPv4 layer + // are already decoded, and will not require decoding a second time. + layers := packet.Layers() + +Lazily-decoded packets are not concurrency-safe. Since layers have not all been +decoded, each call to Layer() or Layers() has the potential to mutate the packet +in order to decode the next layer. If a packet is used +in multiple goroutines concurrently, don't use gopacket.Lazy. Then gopacket +will decode the packet fully, and all future function calls won't mutate the +object. + + +NoCopy Decoding + +By default, gopacket will copy the slice passed to NewPacket and store the +copy within the packet, so future mutations to the bytes underlying the slice +don't affect the packet and its layers. If you can guarantee that the +underlying slice bytes won't be changed, you can use NoCopy to tell +gopacket.NewPacket, and it'll use the passed-in slice itself. + + // This channel returns new byte slices, each of which points to a new + // memory location that's guaranteed immutable for the duration of the + // packet. + for data := range myByteSliceChannel { + p := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy) + doSomethingWithPacket(p) + } + +The fastest method of decoding is to use both Lazy and NoCopy, but note from +the many caveats above that for some implementations either or both may be +dangerous. + + +Pointers To Known Layers + +During decoding, certain layers are stored in the packet as well-known +layer types. For example, IPv4 and IPv6 are both considered NetworkLayer +layers, while TCP and UDP are both TransportLayer layers. We support 4 +layers, corresponding to the 4 layers of the TCP/IP layering scheme (roughly +anagalous to layers 2, 3, 4, and 7 of the OSI model). To access these, +you can use the packet.LinkLayer, packet.NetworkLayer, +packet.TransportLayer, and packet.ApplicationLayer functions. Each of +these functions returns a corresponding interface +(gopacket.{Link,Network,Transport,Application}Layer). The first three +provide methods for getting src/dst addresses for that particular layer, +while the final layer provides a Payload function to get payload data. +This is helpful, for example, to get payloads for all packets regardless +of their underlying data type: + + // Get packets from some source + for packet := range someSource { + if app := packet.ApplicationLayer(); app != nil { + if strings.Contains(string(app.Payload()), "magic string") { + fmt.Println("Found magic string in a packet!") + } + } + } + +A particularly useful layer is ErrorLayer, which is set whenever there's +an error parsing part of the packet. + + packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Default) + if err := packet.ErrorLayer(); err != nil { + fmt.Println("Error decoding some part of the packet:", err) + } + +Note that we don't return an error from NewPacket because we may have decoded +a number of layers successfully before running into our erroneous layer. You +may still be able to get your Ethernet and IPv4 layers correctly, even if +your TCP layer is malformed. + + +Flow And Endpoint + +gopacket has two useful objects, Flow and Endpoint, for communicating in a protocol +independent manner the fact that a packet is coming from A and going to B. +The general layer types LinkLayer, NetworkLayer, and TransportLayer all provide +methods for extracting their flow information, without worrying about the type +of the underlying Layer. + +A Flow is a simple object made up of a set of two Endpoints, one source and one +destination. It details the sender and receiver of the Layer of the Packet. + +An Endpoint is a hashable representation of a source or destination. For +example, for LayerTypeIPv4, an Endpoint contains the IP address bytes for a v4 +IP packet. A Flow can be broken into Endpoints, and Endpoints can be combined +into Flows: + + packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Lazy) + netFlow := packet.NetworkLayer().NetworkFlow() + src, dst := netFlow.Endpoints() + reverseFlow := gopacket.NewFlow(dst, src) + +Both Endpoint and Flow objects can be used as map keys, and the equality +operator can compare them, so you can easily group together all packets +based on endpoint criteria: + + flows := map[gopacket.Endpoint]chan gopacket.Packet + packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Lazy) + // Send all TCP packets to channels based on their destination port. + if tcp := packet.Layer(layers.LayerTypeTCP); tcp != nil { + flows[tcp.TransportFlow().Dst()] <- packet + } + // Look for all packets with the same source and destination network address + if net := packet.NetworkLayer(); net != nil { + src, dst := net.NetworkFlow().Endpoints() + if src == dst { + fmt.Println("Fishy packet has same network source and dst: %s", src) + } + } + // Find all packets coming from UDP port 1000 to UDP port 500 + interestingFlow := gopacket.NewFlow(layers.NewUDPPortEndpoint(1000), layers.NewUDPPortEndpoint(500)) + if t := packet.NetworkLayer(); t != nil && t.TransportFlow() == interestingFlow { + fmt.Println("Found that UDP flow I was looking for!") + } + +For load-balancing purposes, both Flow and Endpoint have FastHash() functions, +which provide quick, non-cryptographic hashes of their contents. Of particular +importance is the fact that Flow FastHash() is symmetric: A->B will have the same +hash as B->A. An example usage could be: + + channels := [8]chan gopacket.Packet + for i := 0; i < 8; i++ { + channels[i] = make(chan gopacket.Packet) + go packetHandler(channels[i]) + } + for packet := range getPackets() { + if net := packet.NetworkLayer(); net != nil { + channels[int(net.NetworkFlow().FastHash()) & 0x7] <- packet + } + } + +This allows us to split up a packet stream while still making sure that each +stream sees all packets for a flow (and its bidirectional opposite). + + +Implementing Your Own Decoder + +If your network has some strange encapsulation, you can implement your own +decoder. In this example, we handle Ethernet packets which are encapsulated +in a 4-byte header. + + // Create a layer type, should be unique and high, so it doesn't conflict, + // giving it a name and a decoder to use. + var MyLayerType = gopacket.RegisterLayerType(12345, gopacket.LayerTypeMetadata{Name: "MyLayerType", Decoder: gopacket.DecodeFunc(decodeMyLayer)}) + + // Implement my layer + type MyLayer struct { + StrangeHeader []byte + payload []byte + } + func (m MyLayer) LayerType() gopacket.LayerType { return MyLayerType } + func (m MyLayer) LayerContents() []byte { return m.StrangeHeader } + func (m MyLayer) LayerPayload() []byte { return m.payload } + + // Now implement a decoder... this one strips off the first 4 bytes of the + // packet. + func decodeMyLayer(data []byte, p gopacket.PacketBuilder) error { + // Create my layer + p.AddLayer(&MyLayer{data[:4], data[4:]}) + // Determine how to handle the rest of the packet + return p.NextDecoder(layers.LayerTypeEthernet) + } + + // Finally, decode your packets: + p := gopacket.NewPacket(data, MyLayerType, gopacket.Lazy) + +See the docs for Decoder and PacketBuilder for more details on how coding +decoders works, or look at RegisterLayerType and RegisterEndpointType to see how +to add layer/endpoint types to gopacket. + + +Fast Decoding With DecodingLayerParser + +TLDR: DecodingLayerParser takes about 10% of the time as NewPacket to decode +packet data, but only for known packet stacks. + +Basic decoding using gopacket.NewPacket or PacketSource.Packets is somewhat slow +due to its need to allocate a new packet and every respective layer. It's very +versatile and can handle all known layer types, but sometimes you really only +care about a specific set of layers regardless, so that versatility is wasted. + +DecodingLayerParser avoids memory allocation altogether by decoding packet +layers directly into preallocated objects, which you can then reference to get +the packet's information. A quick example: + + func main() { + var eth layers.Ethernet + var ip4 layers.IPv4 + var ip6 layers.IPv6 + var tcp layers.TCP + parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, ð, &ip4, &ip6, &tcp) + decoded := []gopacket.LayerType{} + for packetData := range somehowGetPacketData() { + err := parser.DecodeLayers(packetData, &decoded) + for _, layerType := range decoded { + switch layerType { + case layers.LayerTypeIPv6: + fmt.Println(" IP6 ", ip6.SrcIP, ip6.DstIP) + case layers.LayerTypeIPv4: + fmt.Println(" IP4 ", ip4.SrcIP, ip4.DstIP) + } + } + } + } + +The important thing to note here is that the parser is modifying the passed in +layers (eth, ip4, ip6, tcp) instead of allocating new ones, thus greatly +speeding up the decoding process. It's even branching based on layer type... +it'll handle an (eth, ip4, tcp) or (eth, ip6, tcp) stack. However, it won't +handle any other type... since no other decoders were passed in, an (eth, ip4, +udp) stack will stop decoding after ip4, and only pass back [LayerTypeEthernet, +LayerTypeIPv4] through the 'decoded' slice (along with an error saying it can't +decode a UDP packet). + +Unfortunately, not all layers can be used by DecodingLayerParser... only those +implementing the DecodingLayer interface are usable. Also, it's possible to +create DecodingLayers that are not themselves Layers... see +layers.IPv6ExtensionSkipper for an example of this. + + +Creating Packet Data + +As well as offering the ability to decode packet data, gopacket will allow you +to create packets from scratch, as well. A number of gopacket layers implement +the SerializableLayer interface; these layers can be serialized to a []byte in +the following manner: + + ip := &layers.IPv4{ + SrcIP: net.IP{1, 2, 3, 4}, + DstIP: net.IP{5, 6, 7, 8}, + // etc... + } + buf := gopacket.NewSerializeBuffer() + opts := gopacket.SerializeOptions{} // See SerializeOptions for more details. + err := ip.SerializeTo(&buf, opts) + if err != nil { panic(err) } + fmt.Println(buf.Bytes()) // prints out a byte slice containing the serialized IPv4 layer. + +SerializeTo PREPENDS the given layer onto the SerializeBuffer, and they treat +the current buffer's Bytes() slice as the payload of the serializing layer. +Therefore, you can serialize an entire packet by serializing a set of layers in +reverse order (Payload, then TCP, then IP, then Ethernet, for example). The +SerializeBuffer's SerializeLayers function is a helper that does exactly that. + +To generate a (empty and useless, because no fields are set) +Ethernet(IPv4(TCP(Payload))) packet, for example, you can run: + + buf := gopacket.NewSerializeBuffer() + opts := gopacket.SerializeOptions{} + gopacket.SerializeLayers(buf, opts, + &layers.Ethernet{}, + &layers.IPv4{}, + &layers.TCP{}, + gopacket.Payload([]byte{1, 2, 3, 4})) + packetData := buf.Bytes() + +A Final Note + +If you use gopacket, you'll almost definitely want to make sure gopacket/layers +is imported, since when imported it sets all the LayerType variables and fills +in a lot of interesting variables/maps (DecodersByLayerName, etc). Therefore, +it's recommended that even if you don't use any layers functions directly, you still import with: + + import ( + _ "github.com/google/gopacket/layers" + ) +*/ +package gopacket diff --git a/vendor/github.com/google/gopacket/flows.go b/vendor/github.com/google/gopacket/flows.go new file mode 100644 index 0000000..7203ead --- /dev/null +++ b/vendor/github.com/google/gopacket/flows.go @@ -0,0 +1,236 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "bytes" + "fmt" + "strconv" +) + +// MaxEndpointSize determines the maximum size in bytes of an endpoint address. +// +// Endpoints/Flows have a problem: They need to be hashable. Therefore, they +// can't use a byte slice. The two obvious choices are to use a string or a +// byte array. Strings work great, but string creation requires memory +// allocation, which can be slow. Arrays work great, but have a fixed size. We +// originally used the former, now we've switched to the latter. Use of a fixed +// byte-array doubles the speed of constructing a flow (due to not needing to +// allocate). This is a huge increase... too much for us to pass up. +// +// The end result of this, though, is that an endpoint/flow can't be created +// using more than MaxEndpointSize bytes per address. +const MaxEndpointSize = 16 + +// Endpoint is the set of bytes used to address packets at various layers. +// See LinkLayer, NetworkLayer, and TransportLayer specifications. +// Endpoints are usable as map keys. +type Endpoint struct { + typ EndpointType + len int + raw [MaxEndpointSize]byte +} + +// EndpointType returns the endpoint type associated with this endpoint. +func (a Endpoint) EndpointType() EndpointType { return a.typ } + +// Raw returns the raw bytes of this endpoint. These aren't human-readable +// most of the time, but they are faster than calling String. +func (a Endpoint) Raw() []byte { return a.raw[:a.len] } + +// LessThan provides a stable ordering for all endpoints. It sorts first based +// on the EndpointType of an endpoint, then based on the raw bytes of that +// endpoint. +// +// For some endpoints, the actual comparison may not make sense, however this +// ordering does provide useful information for most Endpoint types. +// Ordering is based first on endpoint type, then on raw endpoint bytes. +// Endpoint bytes are sorted lexigraphically. +func (a Endpoint) LessThan(b Endpoint) bool { + return a.typ < b.typ || (a.typ == b.typ && bytes.Compare(a.raw[:a.len], b.raw[:b.len]) < 0) +} + +// fnvHash is used by our FastHash functions, and implements the FNV hash +// created by Glenn Fowler, Landon Curt Noll, and Phong Vo. +// See http://isthe.com/chongo/tech/comp/fnv/. +func fnvHash(s []byte) (h uint64) { + h = fnvBasis + for i := 0; i < len(s); i++ { + h ^= uint64(s[i]) + h *= fnvPrime + } + return +} + +const fnvBasis = 14695981039346656037 +const fnvPrime = 1099511628211 + +// FastHash provides a quick hashing function for an endpoint, useful if you'd +// like to split up endpoints by modulos or other load-balancing techniques. +// It uses a variant of Fowler-Noll-Vo hashing. +// +// The output of FastHash is not guaranteed to remain the same through future +// code revisions, so should not be used to key values in persistent storage. +func (a Endpoint) FastHash() (h uint64) { + h = fnvHash(a.raw[:a.len]) + h ^= uint64(a.typ) + h *= fnvPrime + return +} + +// NewEndpoint creates a new Endpoint object. +// +// The size of raw must be less than MaxEndpointSize, otherwise this function +// will panic. +func NewEndpoint(typ EndpointType, raw []byte) (e Endpoint) { + e.len = len(raw) + if e.len > MaxEndpointSize { + panic("raw byte length greater than MaxEndpointSize") + } + e.typ = typ + copy(e.raw[:], raw) + return +} + +// EndpointTypeMetadata is used to register a new endpoint type. +type EndpointTypeMetadata struct { + // Name is the string returned by an EndpointType's String function. + Name string + // Formatter is called from an Endpoint's String function to format the raw + // bytes in an Endpoint into a human-readable string. + Formatter func([]byte) string +} + +// EndpointType is the type of a gopacket Endpoint. This type determines how +// the bytes stored in the endpoint should be interpreted. +type EndpointType int64 + +var endpointTypes = map[EndpointType]EndpointTypeMetadata{} + +// RegisterEndpointType creates a new EndpointType and registers it globally. +// It MUST be passed a unique number, or it will panic. Numbers 0-999 are +// reserved for gopacket's use. +func RegisterEndpointType(num int, meta EndpointTypeMetadata) EndpointType { + t := EndpointType(num) + if _, ok := endpointTypes[t]; ok { + panic("Endpoint type number already in use") + } + endpointTypes[t] = meta + return t +} + +func (e EndpointType) String() string { + if t, ok := endpointTypes[e]; ok { + return t.Name + } + return strconv.Itoa(int(e)) +} + +func (a Endpoint) String() string { + if t, ok := endpointTypes[a.typ]; ok && t.Formatter != nil { + return t.Formatter(a.raw[:a.len]) + } + return fmt.Sprintf("%v:%v", a.typ, a.raw) +} + +// Flow represents the direction of traffic for a packet layer, as a source and destination Endpoint. +// Flows are usable as map keys. +type Flow struct { + typ EndpointType + slen, dlen int + src, dst [MaxEndpointSize]byte +} + +// FlowFromEndpoints creates a new flow by pasting together two endpoints. +// The endpoints must have the same EndpointType, or this function will return +// an error. +func FlowFromEndpoints(src, dst Endpoint) (_ Flow, err error) { + if src.typ != dst.typ { + err = fmt.Errorf("Mismatched endpoint types: %v->%v", src.typ, dst.typ) + return + } + return Flow{src.typ, src.len, dst.len, src.raw, dst.raw}, nil +} + +// FastHash provides a quick hashing function for a flow, useful if you'd +// like to split up flows by modulos or other load-balancing techniques. +// It uses a variant of Fowler-Noll-Vo hashing, and is guaranteed to collide +// with its reverse flow. IE: the flow A->B will have the same hash as the flow +// B->A. +// +// The output of FastHash is not guaranteed to remain the same through future +// code revisions, so should not be used to key values in persistent storage. +func (f Flow) FastHash() (h uint64) { + // This combination must be commutative. We don't use ^, since that would + // give the same hash for all A->A flows. + h = fnvHash(f.src[:f.slen]) + fnvHash(f.dst[:f.dlen]) + h ^= uint64(f.typ) + h *= fnvPrime + return +} + +// String returns a human-readable representation of this flow, in the form +// "Src->Dst" +func (f Flow) String() string { + s, d := f.Endpoints() + return fmt.Sprintf("%v->%v", s, d) +} + +// EndpointType returns the EndpointType for this Flow. +func (f Flow) EndpointType() EndpointType { + return f.typ +} + +// Endpoints returns the two Endpoints for this flow. +func (f Flow) Endpoints() (src, dst Endpoint) { + return Endpoint{f.typ, f.slen, f.src}, Endpoint{f.typ, f.dlen, f.dst} +} + +// Src returns the source Endpoint for this flow. +func (f Flow) Src() (src Endpoint) { + src, _ = f.Endpoints() + return +} + +// Dst returns the destination Endpoint for this flow. +func (f Flow) Dst() (dst Endpoint) { + _, dst = f.Endpoints() + return +} + +// Reverse returns a new flow with endpoints reversed. +func (f Flow) Reverse() Flow { + return Flow{f.typ, f.dlen, f.slen, f.dst, f.src} +} + +// NewFlow creates a new flow. +// +// src and dst must have length <= MaxEndpointSize, otherwise NewFlow will +// panic. +func NewFlow(t EndpointType, src, dst []byte) (f Flow) { + f.slen = len(src) + f.dlen = len(dst) + if f.slen > MaxEndpointSize || f.dlen > MaxEndpointSize { + panic("flow raw byte length greater than MaxEndpointSize") + } + f.typ = t + copy(f.src[:], src) + copy(f.dst[:], dst) + return +} + +// EndpointInvalid is an endpoint type used for invalid endpoints, IE endpoints +// that are specified incorrectly during creation. +var EndpointInvalid = RegisterEndpointType(0, EndpointTypeMetadata{Name: "invalid", Formatter: func(b []byte) string { + return fmt.Sprintf("%v", b) +}}) + +// InvalidEndpoint is a singleton Endpoint of type EndpointInvalid. +var InvalidEndpoint = NewEndpoint(EndpointInvalid, nil) + +// InvalidFlow is a singleton Flow of type EndpointInvalid. +var InvalidFlow = NewFlow(EndpointInvalid, nil, nil) diff --git a/vendor/github.com/google/gopacket/gc b/vendor/github.com/google/gopacket/gc new file mode 100644 index 0000000..57bcdee --- /dev/null +++ b/vendor/github.com/google/gopacket/gc @@ -0,0 +1,278 @@ +#!/bin/bash +# Copyright 2012 Google, Inc. All rights reserved. + +# This script provides a simple way to run benchmarks against previous code and +# keep a log of how benchmarks change over time. When used with the --benchmark +# flag, it runs benchmarks from the current code and from the last commit run +# with --benchmark, then stores the results in the git commit description. We +# rerun the old benchmarks along with the new ones, since there's no guarantee +# that git commits will happen on the same machine, so machine differences could +# cause wildly inaccurate results. +# +# If you're making changes to 'gopacket' which could cause performance changes, +# you may be requested to use this commit script to make sure your changes don't +# have large detrimental effects (or to show off how awesome your performance +# improvements are). +# +# If not run with the --benchmark flag, this script is still very useful... it +# makes sure all the correct go formatting, building, and testing work as +# expected. + +function Usage { + cat < + +--benchmark: Run benchmark comparisons against last benchmark'd commit +--root: Run tests that require root priviledges +--gen: Generate code for MACs/ports by pulling down external data + +Note, some 'git commit' flags are necessary, if all else fails, pass in -a +EOF + exit 1 +} + +BENCH="" +GEN="" +ROOT="" +while [ ! -z "$1" ]; do + case "$1" in + "--benchmark") + BENCH="$2" + shift + shift + ;; + "--gen") + GEN="yes" + shift + ;; + "--root") + ROOT="yes" + shift + ;; + "--help") + Usage + ;; + "-h") + Usage + ;; + "help") + Usage + ;; + *) + break + ;; + esac +done + +function Root { + if [ ! -z "$ROOT" ]; then + local exec="$1" + # Some folks (like me) keep source code in places inaccessible by root (like + # NFS), so to make sure things run smoothly we copy them to a /tmp location. + local tmpfile="$(mktemp -t gopacket_XXXXXXXX)" + echo "Running root test executable $exec as $tmpfile" + cp "$exec" "$tmpfile" + chmod a+x "$tmpfile" + shift + sudo "$tmpfile" "$@" + fi +} + +if [ "$#" -eq "0" ]; then + Usage +fi + +cd $(dirname $0) + +# Check for copyright notices. +for filename in $(find ./ -type f -name '*.go'); do + if ! head -n 1 "$filename" | grep -q Copyright; then + echo "File '$filename' may not have copyright notice" + exit 1 + fi +done + +set -e +set -x + +if [ ! -z "$ROOT" ]; then + echo "Running SUDO to get root priviledges for root tests" + sudo echo "have root" +fi + +if [ ! -z "$GEN" ]; then + pushd macs + go run gen.go | gofmt > valid_mac_prefixes.go + popd + pushd layers + go run gen.go | gofmt > iana_ports.go + popd +fi + +# Make sure everything is formatted, compiles, and tests pass. +go fmt ./... +go test -i ./... 2>/dev/null >/dev/null || true +go test +go build +pushd examples/bytediff +go build +popd +if [ -f /usr/include/pcap.h ]; then + pushd pcap + go test ./... + go build ./... + go build pcap_tester.go + Root pcap_tester --mode=basic + Root pcap_tester --mode=filtered + Root pcap_tester --mode=timestamp || echo "You might not support timestamp sources" + popd + pushd examples/pcapdump + go build + popd + pushd examples/arpscan + go build + popd + pushd examples/bidirectional + go build + popd + pushd examples/synscan + go build + popd + pushd examples/httpassembly + go build + popd + pushd examples/statsassembly + go build + popd +fi +pushd macs +go test ./... +gofmt -w gen.go +go build gen.go +popd +pushd tcpassembly +go test ./... +popd +pushd reassembly +go test ./... +popd +pushd layers +gofmt -w gen.go +go build gen.go +go test ./... +popd +pushd pcapgo +go test ./... +go build ./... +popd +if [ -f /usr/include/linux/if_packet.h ]; then + if grep -q TPACKET_V3 /usr/include/linux/if_packet.h; then + pushd afpacket + go build ./... + go test ./... + popd + fi +fi +if [ -f /usr/include/pfring.h ]; then + pushd pfring + go test ./... + go build ./... + popd + pushd examples/pfdump + go build + popd +fi + +for travis_script in `ls .travis.*.sh`; do + ./$travis_script +done + +# Run our initial commit +git commit "$@" + +if [ -z "$BENCH" ]; then + set +x + echo "We're not benchmarking and we've committed... we're done!" + exit +fi + +### If we get here, we want to run benchmarks from current commit, and compare +### then to benchmarks from the last --benchmark commit. + +# Get our current branch. +BRANCH="$(git branch | grep '^*' | awk '{print $2}')" + +# File we're going to build our commit description in. +COMMIT_FILE="$(mktemp /tmp/tmp.XXXXXXXX)" + +# Add the word "BENCH" to the start of the git commit. +echo -n "BENCH " > $COMMIT_FILE + +# Get the current description... there must be an easier way. +git log -n 1 | grep '^ ' | sed 's/^ //' >> $COMMIT_FILE + +# Get the commit sha for the last benchmark commit +PREV=$(git log -n 1 --grep='BENCHMARK_MARKER_DO_NOT_CHANGE' | head -n 1 | awk '{print $2}') + +## Run current benchmarks + +cat >> $COMMIT_FILE <&1 | tee -a $COMMIT_FILE +pushd layers +go test --test.bench="$BENCH" 2>&1 | tee -a $COMMIT_FILE +popd +cat >> $COMMIT_FILE <&1 | tee -a $COMMIT_FILE +fi + + + +## Reset to last benchmark commit, run benchmarks + +git checkout $PREV + +cat >> $COMMIT_FILE <&1 | tee -a $COMMIT_FILE +pushd layers +go test --test.bench="$BENCH" 2>&1 | tee -a $COMMIT_FILE +popd +cat >> $COMMIT_FILE <&1 | tee -a $COMMIT_FILE +fi + + + +## Reset back to the most recent commit, edit the commit message by appending +## benchmark results. +git checkout $BRANCH +git commit --amend -F $COMMIT_FILE diff --git a/vendor/github.com/google/gopacket/layerclass.go b/vendor/github.com/google/gopacket/layerclass.go new file mode 100644 index 0000000..775cd09 --- /dev/null +++ b/vendor/github.com/google/gopacket/layerclass.go @@ -0,0 +1,107 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +// LayerClass is a set of LayerTypes, used for grabbing one of a number of +// different types from a packet. +type LayerClass interface { + // Contains returns true if the given layer type should be considered part + // of this layer class. + Contains(LayerType) bool + // LayerTypes returns the set of all layer types in this layer class. + // Note that this may not be a fast operation on all LayerClass + // implementations. + LayerTypes() []LayerType +} + +// Contains implements LayerClass. +func (l LayerType) Contains(a LayerType) bool { + return l == a +} + +// LayerTypes implements LayerClass. +func (l LayerType) LayerTypes() []LayerType { + return []LayerType{l} +} + +// LayerClassSlice implements a LayerClass with a slice. +type LayerClassSlice []bool + +// Contains returns true if the given layer type should be considered part +// of this layer class. +func (s LayerClassSlice) Contains(t LayerType) bool { + return int(t) < len(s) && s[t] +} + +// LayerTypes returns all layer types in this LayerClassSlice. +// Because of LayerClassSlice's implementation, this could be quite slow. +func (s LayerClassSlice) LayerTypes() (all []LayerType) { + for i := 0; i < len(s); i++ { + if s[i] { + all = append(all, LayerType(i)) + } + } + return +} + +// NewLayerClassSlice creates a new LayerClassSlice by creating a slice of +// size max(types) and setting slice[t] to true for each type t. Note, if +// you implement your own LayerType and give it a high value, this WILL create +// a very large slice. +func NewLayerClassSlice(types []LayerType) LayerClassSlice { + var max LayerType + for _, typ := range types { + if typ > max { + max = typ + } + } + t := make([]bool, int(max+1)) + for _, typ := range types { + t[typ] = true + } + return t +} + +// LayerClassMap implements a LayerClass with a map. +type LayerClassMap map[LayerType]bool + +// Contains returns true if the given layer type should be considered part +// of this layer class. +func (m LayerClassMap) Contains(t LayerType) bool { + return m[t] +} + +// LayerTypes returns all layer types in this LayerClassMap. +func (m LayerClassMap) LayerTypes() (all []LayerType) { + for t := range m { + all = append(all, t) + } + return +} + +// NewLayerClassMap creates a LayerClassMap and sets map[t] to true for each +// type in types. +func NewLayerClassMap(types []LayerType) LayerClassMap { + m := LayerClassMap{} + for _, typ := range types { + m[typ] = true + } + return m +} + +// NewLayerClass creates a LayerClass, attempting to be smart about which type +// it creates based on which types are passed in. +func NewLayerClass(types []LayerType) LayerClass { + for _, typ := range types { + if typ > maxLayerType { + // NewLayerClassSlice could create a very large object, so instead create + // a map. + return NewLayerClassMap(types) + } + } + return NewLayerClassSlice(types) +} diff --git a/vendor/github.com/google/gopacket/layertype.go b/vendor/github.com/google/gopacket/layertype.go new file mode 100644 index 0000000..3abfee1 --- /dev/null +++ b/vendor/github.com/google/gopacket/layertype.go @@ -0,0 +1,111 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "fmt" + "strconv" +) + +// LayerType is a unique identifier for each type of layer. This enumeration +// does not match with any externally available numbering scheme... it's solely +// usable/useful within this library as a means for requesting layer types +// (see Packet.Layer) and determining which types of layers have been decoded. +// +// New LayerTypes may be created by calling gopacket.RegisterLayerType. +type LayerType int64 + +// LayerTypeMetadata contains metadata associated with each LayerType. +type LayerTypeMetadata struct { + // Name is the string returned by each layer type's String method. + Name string + // Decoder is the decoder to use when the layer type is passed in as a + // Decoder. + Decoder Decoder +} + +type layerTypeMetadata struct { + inUse bool + LayerTypeMetadata +} + +// DecodersByLayerName maps layer names to decoders for those layers. +// This allows users to specify decoders by name to a program and have that +// program pick the correct decoder accordingly. +var DecodersByLayerName = map[string]Decoder{} + +const maxLayerType = 2000 + +var ltMeta [maxLayerType]layerTypeMetadata +var ltMetaMap = map[LayerType]layerTypeMetadata{} + +// RegisterLayerType creates a new layer type and registers it globally. +// The number passed in must be unique, or a runtime panic will occur. Numbers +// 0-999 are reserved for the gopacket library. Numbers 1000-1999 should be +// used for common application-specific types, and are very fast. Any other +// number (negative or >= 2000) may be used for uncommon application-specific +// types, and are somewhat slower (they require a map lookup over an array +// index). +func RegisterLayerType(num int, meta LayerTypeMetadata) LayerType { + if 0 <= num && num < maxLayerType { + if ltMeta[num].inUse { + panic("Layer type already exists") + } + } else { + if ltMetaMap[LayerType(num)].inUse { + panic("Layer type already exists") + } + } + return OverrideLayerType(num, meta) +} + +// OverrideLayerType acts like RegisterLayerType, except that if the layer type +// has already been registered, it overrides the metadata with the passed-in +// metadata intead of panicing. +func OverrideLayerType(num int, meta LayerTypeMetadata) LayerType { + if 0 <= num && num < maxLayerType { + ltMeta[num] = layerTypeMetadata{ + inUse: true, + LayerTypeMetadata: meta, + } + } else { + ltMetaMap[LayerType(num)] = layerTypeMetadata{ + inUse: true, + LayerTypeMetadata: meta, + } + } + DecodersByLayerName[meta.Name] = meta.Decoder + return LayerType(num) +} + +// Decode decodes the given data using the decoder registered with the layer +// type. +func (t LayerType) Decode(data []byte, c PacketBuilder) error { + var d Decoder + if 0 <= int(t) && int(t) < maxLayerType { + d = ltMeta[int(t)].Decoder + } else { + d = ltMetaMap[t].Decoder + } + if d != nil { + return d.Decode(data, c) + } + return fmt.Errorf("Layer type %v has no associated decoder", t) +} + +// String returns the string associated with this layer type. +func (t LayerType) String() (s string) { + if 0 <= int(t) && int(t) < maxLayerType { + s = ltMeta[int(t)].Name + } else { + s = ltMetaMap[t].Name + } + if s == "" { + s = strconv.Itoa(int(t)) + } + return +} diff --git a/vendor/github.com/google/gopacket/packet.go b/vendor/github.com/google/gopacket/packet.go new file mode 100644 index 0000000..76b62d8 --- /dev/null +++ b/vendor/github.com/google/gopacket/packet.go @@ -0,0 +1,838 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "bytes" + "encoding/hex" + "errors" + "fmt" + "io" + "os" + "reflect" + "runtime/debug" + "strings" + "time" +) + +// CaptureInfo provides standardized information about a packet captured off +// the wire or read from a file. +type CaptureInfo struct { + // Timestamp is the time the packet was captured, if that is known. + Timestamp time.Time + // CaptureLength is the total number of bytes read off of the wire. + CaptureLength int + // Length is the size of the original packet. Should always be >= + // CaptureLength. + Length int + // InterfaceIndex + InterfaceIndex int +} + +// PacketMetadata contains metadata for a packet. +type PacketMetadata struct { + CaptureInfo + // Truncated is true if packet decoding logic detects that there are fewer + // bytes in the packet than are detailed in various headers (for example, if + // the number of bytes in the IPv4 contents/payload is less than IPv4.Length). + // This is also set automatically for packets captured off the wire if + // CaptureInfo.CaptureLength < CaptureInfo.Length. + Truncated bool +} + +// Packet is the primary object used by gopacket. Packets are created by a +// Decoder's Decode call. A packet is made up of a set of Data, which +// is broken into a number of Layers as it is decoded. +type Packet interface { + //// Functions for outputting the packet as a human-readable string: + //// ------------------------------------------------------------------ + // String returns a human-readable string representation of the packet. + // It uses LayerString on each layer to output the layer. + String() string + // Dump returns a verbose human-readable string representation of the packet, + // including a hex dump of all layers. It uses LayerDump on each layer to + // output the layer. + Dump() string + + //// Functions for accessing arbitrary packet layers: + //// ------------------------------------------------------------------ + // Layers returns all layers in this packet, computing them as necessary + Layers() []Layer + // Layer returns the first layer in this packet of the given type, or nil + Layer(LayerType) Layer + // LayerClass returns the first layer in this packet of the given class, + // or nil. + LayerClass(LayerClass) Layer + + //// Functions for accessing specific types of packet layers. These functions + //// return the first layer of each type found within the packet. + //// ------------------------------------------------------------------ + // LinkLayer returns the first link layer in the packet + LinkLayer() LinkLayer + // NetworkLayer returns the first network layer in the packet + NetworkLayer() NetworkLayer + // TransportLayer returns the first transport layer in the packet + TransportLayer() TransportLayer + // ApplicationLayer returns the first application layer in the packet + ApplicationLayer() ApplicationLayer + // ErrorLayer is particularly useful, since it returns nil if the packet + // was fully decoded successfully, and non-nil if an error was encountered + // in decoding and the packet was only partially decoded. Thus, its output + // can be used to determine if the entire packet was able to be decoded. + ErrorLayer() ErrorLayer + + //// Functions for accessing data specific to the packet: + //// ------------------------------------------------------------------ + // Data returns the set of bytes that make up this entire packet. + Data() []byte + // Metadata returns packet metadata associated with this packet. + Metadata() *PacketMetadata +} + +// packet contains all the information we need to fulfill the Packet interface, +// and its two "subclasses" (yes, no such thing in Go, bear with me), +// eagerPacket and lazyPacket, provide eager and lazy decoding logic around the +// various functions needed to access this information. +type packet struct { + // data contains the entire packet data for a packet + data []byte + // initialLayers is space for an initial set of layers already created inside + // the packet. + initialLayers [6]Layer + // layers contains each layer we've already decoded + layers []Layer + // last is the last layer added to the packet + last Layer + // metadata is the PacketMetadata for this packet + metadata PacketMetadata + + decodeOptions DecodeOptions + + // Pointers to the various important layers + link LinkLayer + network NetworkLayer + transport TransportLayer + application ApplicationLayer + failure ErrorLayer +} + +func (p *packet) SetTruncated() { + p.metadata.Truncated = true +} + +func (p *packet) SetLinkLayer(l LinkLayer) { + if p.link == nil { + p.link = l + } +} + +func (p *packet) SetNetworkLayer(l NetworkLayer) { + if p.network == nil { + p.network = l + } +} + +func (p *packet) SetTransportLayer(l TransportLayer) { + if p.transport == nil { + p.transport = l + } +} + +func (p *packet) SetApplicationLayer(l ApplicationLayer) { + if p.application == nil { + p.application = l + } +} + +func (p *packet) SetErrorLayer(l ErrorLayer) { + if p.failure == nil { + p.failure = l + } +} + +func (p *packet) AddLayer(l Layer) { + p.layers = append(p.layers, l) + p.last = l +} + +func (p *packet) DumpPacketData() { + fmt.Fprint(os.Stderr, p.packetDump()) + os.Stderr.Sync() +} + +func (p *packet) Metadata() *PacketMetadata { + return &p.metadata +} + +func (p *packet) Data() []byte { + return p.data +} + +func (p *packet) DecodeOptions() *DecodeOptions { + return &p.decodeOptions +} + +func (p *packet) addFinalDecodeError(err error, stack []byte) { + fail := &DecodeFailure{err: err, stack: stack} + if p.last == nil { + fail.data = p.data + } else { + fail.data = p.last.LayerPayload() + } + p.AddLayer(fail) + p.SetErrorLayer(fail) +} + +func (p *packet) recoverDecodeError() { + if !p.decodeOptions.SkipDecodeRecovery { + if r := recover(); r != nil { + p.addFinalDecodeError(fmt.Errorf("%v", r), debug.Stack()) + } + } +} + +// LayerString outputs an individual layer as a string. The layer is output +// in a single line, with no trailing newline. This function is specifically +// designed to do the right thing for most layers... it follows the following +// rules: +// * If the Layer has a String function, just output that. +// * Otherwise, output all exported fields in the layer, recursing into +// exported slices and structs. +// NOTE: This is NOT THE SAME AS fmt's "%#v". %#v will output both exported +// and unexported fields... many times packet layers contain unexported stuff +// that would just mess up the output of the layer, see for example the +// Payload layer and it's internal 'data' field, which contains a large byte +// array that would really mess up formatting. +func LayerString(l Layer) string { + return fmt.Sprintf("%v\t%s", l.LayerType(), layerString(reflect.ValueOf(l), false, false)) +} + +// Dumper dumps verbose information on a value. If a layer type implements +// Dumper, then its LayerDump() string will include the results in its output. +type Dumper interface { + Dump() string +} + +// LayerDump outputs a very verbose string representation of a layer. Its +// output is a concatenation of LayerString(l) and hex.Dump(l.LayerContents()). +// It contains newlines and ends with a newline. +func LayerDump(l Layer) string { + var b bytes.Buffer + b.WriteString(LayerString(l)) + b.WriteByte('\n') + if d, ok := l.(Dumper); ok { + dump := d.Dump() + if dump != "" { + b.WriteString(dump) + if dump[len(dump)-1] != '\n' { + b.WriteByte('\n') + } + } + } + b.WriteString(hex.Dump(l.LayerContents())) + return b.String() +} + +// layerString outputs, recursively, a layer in a "smart" way. See docs for +// LayerString for more details. +// +// Params: +// i - value to write out +// anonymous: if we're currently recursing an anonymous member of a struct +// writeSpace: if we've already written a value in a struct, and need to +// write a space before writing more. This happens when we write various +// anonymous values, and need to keep writing more. +func layerString(v reflect.Value, anonymous bool, writeSpace bool) string { + // Let String() functions take precedence. + if v.CanInterface() { + if s, ok := v.Interface().(fmt.Stringer); ok { + return s.String() + } + } + // Reflect, and spit out all the exported fields as key=value. + switch v.Type().Kind() { + case reflect.Interface, reflect.Ptr: + if v.IsNil() { + return "nil" + } + r := v.Elem() + return layerString(r, anonymous, writeSpace) + case reflect.Struct: + var b bytes.Buffer + typ := v.Type() + if !anonymous { + b.WriteByte('{') + } + for i := 0; i < v.NumField(); i++ { + // Check if this is upper-case. + ftype := typ.Field(i) + f := v.Field(i) + if ftype.Anonymous { + anonStr := layerString(f, true, writeSpace) + writeSpace = writeSpace || anonStr != "" + b.WriteString(anonStr) + } else if ftype.PkgPath == "" { // exported + if writeSpace { + b.WriteByte(' ') + } + writeSpace = true + fmt.Fprintf(&b, "%s=%s", typ.Field(i).Name, layerString(f, false, writeSpace)) + } + } + if !anonymous { + b.WriteByte('}') + } + return b.String() + case reflect.Slice: + var b bytes.Buffer + b.WriteByte('[') + if v.Len() > 4 { + fmt.Fprintf(&b, "..%d..", v.Len()) + } else { + for j := 0; j < v.Len(); j++ { + if j != 0 { + b.WriteString(", ") + } + b.WriteString(layerString(v.Index(j), false, false)) + } + } + b.WriteByte(']') + return b.String() + } + return fmt.Sprintf("%v", v.Interface()) +} + +const ( + longBytesLength = 128 +) + +// LongBytesGoString returns a string representation of the byte slice shortened +// using the format '{ ... ( bytes)}' if it +// exceeds a predetermined length. Can be used to avoid filling the display with +// very long byte strings. +func LongBytesGoString(buf []byte) string { + if len(buf) < longBytesLength { + return fmt.Sprintf("%#v", buf) + } + s := fmt.Sprintf("%#v", buf[:longBytesLength-1]) + s = strings.TrimSuffix(s, "}") + return fmt.Sprintf("%s ... (%d bytes)}", s, len(buf)) +} + +func baseLayerString(value reflect.Value) string { + t := value.Type() + content := value.Field(0) + c := make([]byte, content.Len()) + for i := range c { + c[i] = byte(content.Index(i).Uint()) + } + payload := value.Field(1) + p := make([]byte, payload.Len()) + for i := range p { + p[i] = byte(payload.Index(i).Uint()) + } + return fmt.Sprintf("%s{Contents:%s, Payload:%s}", t.String(), + LongBytesGoString(c), + LongBytesGoString(p)) +} + +func layerGoString(i interface{}, b *bytes.Buffer) { + if s, ok := i.(fmt.GoStringer); ok { + b.WriteString(s.GoString()) + return + } + + var v reflect.Value + var ok bool + if v, ok = i.(reflect.Value); !ok { + v = reflect.ValueOf(i) + } + switch v.Kind() { + case reflect.Ptr, reflect.Interface: + if v.Kind() == reflect.Ptr { + b.WriteByte('&') + } + layerGoString(v.Elem().Interface(), b) + case reflect.Struct: + t := v.Type() + b.WriteString(t.String()) + b.WriteByte('{') + for i := 0; i < v.NumField(); i++ { + if i > 0 { + b.WriteString(", ") + } + if t.Field(i).Name == "BaseLayer" { + fmt.Fprintf(b, "BaseLayer:%s", baseLayerString(v.Field(i))) + } else if v.Field(i).Kind() == reflect.Struct { + fmt.Fprintf(b, "%s:", t.Field(i).Name) + layerGoString(v.Field(i), b) + } else if v.Field(i).Kind() == reflect.Ptr { + b.WriteByte('&') + layerGoString(v.Field(i), b) + } else { + fmt.Fprintf(b, "%s:%#v", t.Field(i).Name, v.Field(i)) + } + } + b.WriteByte('}') + default: + fmt.Fprintf(b, "%#v", i) + } +} + +// LayerGoString returns a representation of the layer in Go syntax, +// taking care to shorten "very long" BaseLayer byte slices +func LayerGoString(l Layer) string { + b := new(bytes.Buffer) + layerGoString(l, b) + return b.String() +} + +func (p *packet) packetString() string { + var b bytes.Buffer + fmt.Fprintf(&b, "PACKET: %d bytes", len(p.Data())) + if p.metadata.Truncated { + b.WriteString(", truncated") + } + if p.metadata.Length > 0 { + fmt.Fprintf(&b, ", wire length %d cap length %d", p.metadata.Length, p.metadata.CaptureLength) + } + if !p.metadata.Timestamp.IsZero() { + fmt.Fprintf(&b, " @ %v", p.metadata.Timestamp) + } + b.WriteByte('\n') + for i, l := range p.layers { + fmt.Fprintf(&b, "- Layer %d (%02d bytes) = %s\n", i+1, len(l.LayerContents()), LayerString(l)) + } + return b.String() +} + +func (p *packet) packetDump() string { + var b bytes.Buffer + fmt.Fprintf(&b, "-- FULL PACKET DATA (%d bytes) ------------------------------------\n%s", len(p.data), hex.Dump(p.data)) + for i, l := range p.layers { + fmt.Fprintf(&b, "--- Layer %d ---\n%s", i+1, LayerDump(l)) + } + return b.String() +} + +// eagerPacket is a packet implementation that does eager decoding. Upon +// initial construction, it decodes all the layers it can from packet data. +// eagerPacket implements Packet and PacketBuilder. +type eagerPacket struct { + packet +} + +var errNilDecoder = errors.New("NextDecoder passed nil decoder, probably an unsupported decode type") + +func (p *eagerPacket) NextDecoder(next Decoder) error { + if next == nil { + return errNilDecoder + } + if p.last == nil { + return errors.New("NextDecoder called, but no layers added yet") + } + d := p.last.LayerPayload() + if len(d) == 0 { + return nil + } + // Since we're eager, immediately call the next decoder. + return next.Decode(d, p) +} +func (p *eagerPacket) initialDecode(dec Decoder) { + defer p.recoverDecodeError() + err := dec.Decode(p.data, p) + if err != nil { + p.addFinalDecodeError(err, nil) + } +} +func (p *eagerPacket) LinkLayer() LinkLayer { + return p.link +} +func (p *eagerPacket) NetworkLayer() NetworkLayer { + return p.network +} +func (p *eagerPacket) TransportLayer() TransportLayer { + return p.transport +} +func (p *eagerPacket) ApplicationLayer() ApplicationLayer { + return p.application +} +func (p *eagerPacket) ErrorLayer() ErrorLayer { + return p.failure +} +func (p *eagerPacket) Layers() []Layer { + return p.layers +} +func (p *eagerPacket) Layer(t LayerType) Layer { + for _, l := range p.layers { + if l.LayerType() == t { + return l + } + } + return nil +} +func (p *eagerPacket) LayerClass(lc LayerClass) Layer { + for _, l := range p.layers { + if lc.Contains(l.LayerType()) { + return l + } + } + return nil +} +func (p *eagerPacket) String() string { return p.packetString() } +func (p *eagerPacket) Dump() string { return p.packetDump() } + +// lazyPacket does lazy decoding on its packet data. On construction it does +// no initial decoding. For each function call, it decodes only as many layers +// as are necessary to compute the return value for that function. +// lazyPacket implements Packet and PacketBuilder. +type lazyPacket struct { + packet + next Decoder +} + +func (p *lazyPacket) NextDecoder(next Decoder) error { + if next == nil { + return errNilDecoder + } + p.next = next + return nil +} +func (p *lazyPacket) decodeNextLayer() { + if p.next == nil { + return + } + d := p.data + if p.last != nil { + d = p.last.LayerPayload() + } + next := p.next + p.next = nil + // We've just set p.next to nil, so if we see we have no data, this should be + // the final call we get to decodeNextLayer if we return here. + if len(d) == 0 { + return + } + defer p.recoverDecodeError() + err := next.Decode(d, p) + if err != nil { + p.addFinalDecodeError(err, nil) + } +} +func (p *lazyPacket) LinkLayer() LinkLayer { + for p.link == nil && p.next != nil { + p.decodeNextLayer() + } + return p.link +} +func (p *lazyPacket) NetworkLayer() NetworkLayer { + for p.network == nil && p.next != nil { + p.decodeNextLayer() + } + return p.network +} +func (p *lazyPacket) TransportLayer() TransportLayer { + for p.transport == nil && p.next != nil { + p.decodeNextLayer() + } + return p.transport +} +func (p *lazyPacket) ApplicationLayer() ApplicationLayer { + for p.application == nil && p.next != nil { + p.decodeNextLayer() + } + return p.application +} +func (p *lazyPacket) ErrorLayer() ErrorLayer { + for p.failure == nil && p.next != nil { + p.decodeNextLayer() + } + return p.failure +} +func (p *lazyPacket) Layers() []Layer { + for p.next != nil { + p.decodeNextLayer() + } + return p.layers +} +func (p *lazyPacket) Layer(t LayerType) Layer { + for _, l := range p.layers { + if l.LayerType() == t { + return l + } + } + numLayers := len(p.layers) + for p.next != nil { + p.decodeNextLayer() + for _, l := range p.layers[numLayers:] { + if l.LayerType() == t { + return l + } + } + numLayers = len(p.layers) + } + return nil +} +func (p *lazyPacket) LayerClass(lc LayerClass) Layer { + for _, l := range p.layers { + if lc.Contains(l.LayerType()) { + return l + } + } + numLayers := len(p.layers) + for p.next != nil { + p.decodeNextLayer() + for _, l := range p.layers[numLayers:] { + if lc.Contains(l.LayerType()) { + return l + } + } + numLayers = len(p.layers) + } + return nil +} +func (p *lazyPacket) String() string { p.Layers(); return p.packetString() } +func (p *lazyPacket) Dump() string { p.Layers(); return p.packetDump() } + +// DecodeOptions tells gopacket how to decode a packet. +type DecodeOptions struct { + // Lazy decoding decodes the minimum number of layers needed to return data + // for a packet at each function call. Be careful using this with concurrent + // packet processors, as each call to packet.* could mutate the packet, and + // two concurrent function calls could interact poorly. + Lazy bool + // NoCopy decoding doesn't copy its input buffer into storage that's owned by + // the packet. If you can guarantee that the bytes underlying the slice + // passed into NewPacket aren't going to be modified, this can be faster. If + // there's any chance that those bytes WILL be changed, this will invalidate + // your packets. + NoCopy bool + // SkipDecodeRecovery skips over panic recovery during packet decoding. + // Normally, when packets decode, if a panic occurs, that panic is captured + // by a recover(), and a DecodeFailure layer is added to the packet detailing + // the issue. If this flag is set, panics are instead allowed to continue up + // the stack. + SkipDecodeRecovery bool + // DecodeStreamsAsDatagrams enables routing of application-level layers in the TCP + // decoder. If true, we should try to decode layers after TCP in single packets. + // This is disabled by default because the reassembly package drives the decoding + // of TCP payload data after reassembly. + DecodeStreamsAsDatagrams bool +} + +// Default decoding provides the safest (but slowest) method for decoding +// packets. It eagerly processes all layers (so it's concurrency-safe) and it +// copies its input buffer upon creation of the packet (so the packet remains +// valid if the underlying slice is modified. Both of these take time, +// though, so beware. If you can guarantee that the packet will only be used +// by one goroutine at a time, set Lazy decoding. If you can guarantee that +// the underlying slice won't change, set NoCopy decoding. +var Default = DecodeOptions{} + +// Lazy is a DecodeOptions with just Lazy set. +var Lazy = DecodeOptions{Lazy: true} + +// NoCopy is a DecodeOptions with just NoCopy set. +var NoCopy = DecodeOptions{NoCopy: true} + +// DecodeStreamsAsDatagrams is a DecodeOptions with just DecodeStreamsAsDatagrams set. +var DecodeStreamsAsDatagrams = DecodeOptions{DecodeStreamsAsDatagrams: true} + +// NewPacket creates a new Packet object from a set of bytes. The +// firstLayerDecoder tells it how to interpret the first layer from the bytes, +// future layers will be generated from that first layer automatically. +func NewPacket(data []byte, firstLayerDecoder Decoder, options DecodeOptions) Packet { + if !options.NoCopy { + dataCopy := make([]byte, len(data)) + copy(dataCopy, data) + data = dataCopy + } + if options.Lazy { + p := &lazyPacket{ + packet: packet{data: data, decodeOptions: options}, + next: firstLayerDecoder, + } + p.layers = p.initialLayers[:0] + // Crazy craziness: + // If the following return statemet is REMOVED, and Lazy is FALSE, then + // eager packet processing becomes 17% FASTER. No, there is no logical + // explanation for this. However, it's such a hacky micro-optimization that + // we really can't rely on it. It appears to have to do with the size the + // compiler guesses for this function's stack space, since one symptom is + // that with the return statement in place, we more than double calls to + // runtime.morestack/runtime.lessstack. We'll hope the compiler gets better + // over time and we get this optimization for free. Until then, we'll have + // to live with slower packet processing. + return p + } + p := &eagerPacket{ + packet: packet{data: data, decodeOptions: options}, + } + p.layers = p.initialLayers[:0] + p.initialDecode(firstLayerDecoder) + return p +} + +// PacketDataSource is an interface for some source of packet data. Users may +// create their own implementations, or use the existing implementations in +// gopacket/pcap (libpcap, allows reading from live interfaces or from +// pcap files) or gopacket/pfring (PF_RING, allows reading from live +// interfaces). +type PacketDataSource interface { + // ReadPacketData returns the next packet available from this data source. + // It returns: + // data: The bytes of an individual packet. + // ci: Metadata about the capture + // err: An error encountered while reading packet data. If err != nil, + // then data/ci will be ignored. + ReadPacketData() (data []byte, ci CaptureInfo, err error) +} + +// ConcatFinitePacketDataSources returns a PacketDataSource that wraps a set +// of internal PacketDataSources, each of which will stop with io.EOF after +// reading a finite number of packets. The returned PacketDataSource will +// return all packets from the first finite source, followed by all packets from +// the second, etc. Once all finite sources have returned io.EOF, the returned +// source will as well. +func ConcatFinitePacketDataSources(pds ...PacketDataSource) PacketDataSource { + c := concat(pds) + return &c +} + +type concat []PacketDataSource + +func (c *concat) ReadPacketData() (data []byte, ci CaptureInfo, err error) { + for len(*c) > 0 { + data, ci, err = (*c)[0].ReadPacketData() + if err == io.EOF { + *c = (*c)[1:] + continue + } + return + } + return nil, CaptureInfo{}, io.EOF +} + +// ZeroCopyPacketDataSource is an interface to pull packet data from sources +// that allow data to be returned without copying to a user-controlled buffer. +// It's very similar to PacketDataSource, except that the caller must be more +// careful in how the returned buffer is handled. +type ZeroCopyPacketDataSource interface { + // ZeroCopyReadPacketData returns the next packet available from this data source. + // It returns: + // data: The bytes of an individual packet. Unlike with + // PacketDataSource's ReadPacketData, the slice returned here points + // to a buffer owned by the data source. In particular, the bytes in + // this buffer may be changed by future calls to + // ZeroCopyReadPacketData. Do not use the returned buffer after + // subsequent ZeroCopyReadPacketData calls. + // ci: Metadata about the capture + // err: An error encountered while reading packet data. If err != nil, + // then data/ci will be ignored. + ZeroCopyReadPacketData() (data []byte, ci CaptureInfo, err error) +} + +// PacketSource reads in packets from a PacketDataSource, decodes them, and +// returns them. +// +// There are currently two different methods for reading packets in through +// a PacketSource: +// +// Reading With Packets Function +// +// This method is the most convenient and easiest to code, but lacks +// flexibility. Packets returns a 'chan Packet', then asynchronously writes +// packets into that channel. Packets uses a blocking channel, and closes +// it if an io.EOF is returned by the underlying PacketDataSource. All other +// PacketDataSource errors are ignored and discarded. +// for packet := range packetSource.Packets() { +// ... +// } +// +// Reading With NextPacket Function +// +// This method is the most flexible, and exposes errors that may be +// encountered by the underlying PacketDataSource. It's also the fastest +// in a tight loop, since it doesn't have the overhead of a channel +// read/write. However, it requires the user to handle errors, most +// importantly the io.EOF error in cases where packets are being read from +// a file. +// for { +// packet, err := packetSource.NextPacket() +// if err == io.EOF { +// break +// } else if err != nil { +// log.Println("Error:", err) +// continue +// } +// handlePacket(packet) // Do something with each packet. +// } +type PacketSource struct { + source PacketDataSource + decoder Decoder + // DecodeOptions is the set of options to use for decoding each piece + // of packet data. This can/should be changed by the user to reflect the + // way packets should be decoded. + DecodeOptions + c chan Packet +} + +// NewPacketSource creates a packet data source. +func NewPacketSource(source PacketDataSource, decoder Decoder) *PacketSource { + return &PacketSource{ + source: source, + decoder: decoder, + } +} + +// NextPacket returns the next decoded packet from the PacketSource. On error, +// it returns a nil packet and a non-nil error. +func (p *PacketSource) NextPacket() (Packet, error) { + data, ci, err := p.source.ReadPacketData() + if err != nil { + return nil, err + } + packet := NewPacket(data, p.decoder, p.DecodeOptions) + m := packet.Metadata() + m.CaptureInfo = ci + m.Truncated = m.Truncated || ci.CaptureLength < ci.Length + return packet, nil +} + +// packetsToChannel reads in all packets from the packet source and sends them +// to the given channel. When it receives an error, it ignores it. When it +// receives an io.EOF, it closes the channel. +func (p *PacketSource) packetsToChannel() { + defer close(p.c) + for { + packet, err := p.NextPacket() + if err == io.EOF { + return + } else if err == nil { + p.c <- packet + } + } +} + +// Packets returns a channel of packets, allowing easy iterating over +// packets. Packets will be asynchronously read in from the underlying +// PacketDataSource and written to the returned channel. If the underlying +// PacketDataSource returns an io.EOF error, the channel will be closed. +// If any other error is encountered, it is ignored. +// +// for packet := range packetSource.Packets() { +// handlePacket(packet) // Do something with each packet. +// } +// +// If called more than once, returns the same channel. +func (p *PacketSource) Packets() chan Packet { + if p.c == nil { + p.c = make(chan Packet, 1000) + go p.packetsToChannel() + } + return p.c +} diff --git a/vendor/github.com/google/gopacket/parser.go b/vendor/github.com/google/gopacket/parser.go new file mode 100644 index 0000000..f786834 --- /dev/null +++ b/vendor/github.com/google/gopacket/parser.go @@ -0,0 +1,198 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "fmt" +) + +// DecodingLayer is an interface for packet layers that can decode themselves. +// +// The important part of DecodingLayer is that they decode themselves in-place. +// Calling DecodeFromBytes on a DecodingLayer totally resets the entire layer to +// the new state defined by the data passed in. A returned error leaves the +// DecodingLayer in an unknown intermediate state, thus its fields should not be +// trusted. +// +// Because the DecodingLayer is resetting its own fields, a call to +// DecodeFromBytes should normally not require any memory allocation. +type DecodingLayer interface { + // DecodeFromBytes resets the internal state of this layer to the state + // defined by the passed-in bytes. Slices in the DecodingLayer may + // reference the passed-in data, so care should be taken to copy it + // first should later modification of data be required before the + // DecodingLayer is discarded. + DecodeFromBytes(data []byte, df DecodeFeedback) error + // CanDecode returns the set of LayerTypes this DecodingLayer can + // decode. For Layers that are also DecodingLayers, this will most + // often be that Layer's LayerType(). + CanDecode() LayerClass + // NextLayerType returns the LayerType which should be used to decode + // the LayerPayload. + NextLayerType() LayerType + // LayerPayload is the set of bytes remaining to decode after a call to + // DecodeFromBytes. + LayerPayload() []byte +} + +// DecodingLayerParser parses a given set of layer types. See DecodeLayers for +// more information on how DecodingLayerParser should be used. +type DecodingLayerParser struct { + // DecodingLayerParserOptions is the set of options available to the + // user to define the parser's behavior. + DecodingLayerParserOptions + first LayerType + decoders map[LayerType]DecodingLayer + df DecodeFeedback + // Truncated is set when a decode layer detects that the packet has been + // truncated. + Truncated bool +} + +// AddDecodingLayer adds a decoding layer to the parser. This adds support for +// the decoding layer's CanDecode layers to the parser... should they be +// encountered, they'll be parsed. +func (l *DecodingLayerParser) AddDecodingLayer(d DecodingLayer) { + for _, typ := range d.CanDecode().LayerTypes() { + l.decoders[typ] = d + } +} + +// SetTruncated is used by DecodingLayers to set the Truncated boolean in the +// DecodingLayerParser. Users should simply read Truncated after calling +// DecodeLayers. +func (l *DecodingLayerParser) SetTruncated() { + l.Truncated = true +} + +// NewDecodingLayerParser creates a new DecodingLayerParser and adds in all +// of the given DecodingLayers with AddDecodingLayer. +// +// Each call to DecodeLayers will attempt to decode the given bytes first by +// treating them as a 'first'-type layer, then by using NextLayerType on +// subsequently decoded layers to find the next relevant decoder. Should a +// deoder not be available for the layer type returned by NextLayerType, +// decoding will stop. +func NewDecodingLayerParser(first LayerType, decoders ...DecodingLayer) *DecodingLayerParser { + dlp := &DecodingLayerParser{ + decoders: make(map[LayerType]DecodingLayer), + first: first, + } + dlp.df = dlp // Cast this once to the interface + for _, d := range decoders { + dlp.AddDecodingLayer(d) + } + return dlp +} + +// DecodeLayers decodes as many layers as possible from the given data. It +// initially treats the data as layer type 'typ', then uses NextLayerType on +// each subsequent decoded layer until it gets to a layer type it doesn't know +// how to parse. +// +// For each layer successfully decoded, DecodeLayers appends the layer type to +// the decoded slice. DecodeLayers truncates the 'decoded' slice initially, so +// there's no need to empty it yourself. +// +// This decoding method is about an order of magnitude faster than packet +// decoding, because it only decodes known layers that have already been +// allocated. This means it doesn't need to allocate each layer it returns... +// instead it overwrites the layers that already exist. +// +// Example usage: +// func main() { +// var eth layers.Ethernet +// var ip4 layers.IPv4 +// var ip6 layers.IPv6 +// var tcp layers.TCP +// var udp layers.UDP +// var payload gopacket.Payload +// parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, ð, &ip4, &ip6, &tcp, &udp, &payload) +// var source gopacket.PacketDataSource = getMyDataSource() +// decodedLayers := make([]gopacket.LayerType, 0, 10) +// for { +// data, _, err := source.ReadPacketData() +// if err == nil { +// fmt.Println("Error reading packet data: ", err) +// continue +// } +// fmt.Println("Decoding packet") +// err = parser.DecodeLayers(data, &decodedLayers) +// for _, typ := range decodedLayers { +// fmt.Println(" Successfully decoded layer type", typ) +// switch typ { +// case layers.LayerTypeEthernet: +// fmt.Println(" Eth ", eth.SrcMAC, eth.DstMAC) +// case layers.LayerTypeIPv4: +// fmt.Println(" IP4 ", ip4.SrcIP, ip4.DstIP) +// case layers.LayerTypeIPv6: +// fmt.Println(" IP6 ", ip6.SrcIP, ip6.DstIP) +// case layers.LayerTypeTCP: +// fmt.Println(" TCP ", tcp.SrcPort, tcp.DstPort) +// case layers.LayerTypeUDP: +// fmt.Println(" UDP ", udp.SrcPort, udp.DstPort) +// } +// } +// if decodedLayers.Truncated { +// fmt.Println(" Packet has been truncated") +// } +// if err != nil { +// fmt.Println(" Error encountered:", err) +// } +// } +// } +// +// If DecodeLayers is unable to decode the next layer type, it will return the +// error UnsupportedLayerType. +func (l *DecodingLayerParser) DecodeLayers(data []byte, decoded *[]LayerType) (err error) { + l.Truncated = false + if !l.IgnorePanic { + defer panicToError(&err) + } + typ := l.first + *decoded = (*decoded)[:0] // Truncated decoded layers. + for len(data) > 0 { + decoder, ok := l.decoders[typ] + if !ok { + return UnsupportedLayerType(typ) + } else if err = decoder.DecodeFromBytes(data, l.df); err != nil { + return err + } + *decoded = append(*decoded, typ) + typ = decoder.NextLayerType() + data = decoder.LayerPayload() + } + return nil +} + +// UnsupportedLayerType is returned by DecodingLayerParser if DecodeLayers +// encounters a layer type that the DecodingLayerParser has no decoder for. +type UnsupportedLayerType LayerType + +// Error implements the error interface, returning a string to say that the +// given layer type is unsupported. +func (e UnsupportedLayerType) Error() string { + return fmt.Sprintf("No decoder for layer type %v", LayerType(e)) +} + +func panicToError(e *error) { + if r := recover(); r != nil { + *e = fmt.Errorf("panic: %v", r) + } +} + +// DecodingLayerParserOptions provides options to affect the behavior of a given +// DecodingLayerParser. +type DecodingLayerParserOptions struct { + // IgnorePanic determines whether a DecodingLayerParser should stop + // panics on its own (by returning them as an error from DecodeLayers) + // or should allow them to raise up the stack. Handling errors does add + // latency to the process of decoding layers, but is much safer for + // callers. IgnorePanic defaults to false, thus if the caller does + // nothing decode panics will be returned as errors. + IgnorePanic bool +} diff --git a/vendor/github.com/google/gopacket/writer.go b/vendor/github.com/google/gopacket/writer.go new file mode 100644 index 0000000..9e85a92 --- /dev/null +++ b/vendor/github.com/google/gopacket/writer.go @@ -0,0 +1,213 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "fmt" +) + +// SerializableLayer allows its implementations to be written out as a set of bytes, +// so those bytes may be sent on the wire or otherwise used by the caller. +// SerializableLayer is implemented by certain Layer types, and can be encoded to +// bytes using the LayerWriter object. +type SerializableLayer interface { + // SerializeTo writes this layer to a slice, growing that slice if necessary + // to make it fit the layer's data. + // Args: + // b: SerializeBuffer to write this layer on to. When called, b.Bytes() + // is the payload this layer should wrap, if any. Note that this + // layer can either prepend itself (common), append itself + // (uncommon), or both (sometimes padding or footers are required at + // the end of packet data). It's also possible (though probably very + // rarely needed) to overwrite any bytes in the current payload. + // After this call, b.Bytes() should return the byte encoding of + // this layer wrapping the original b.Bytes() payload. + // opts: options to use while writing out data. + // Returns: + // error if a problem was encountered during encoding. If an error is + // returned, the bytes in data should be considered invalidated, and + // not used. + // + // SerializeTo calls SHOULD entirely ignore LayerContents and + // LayerPayload. It just serializes based on struct fields, neither + // modifying nor using contents/payload. + SerializeTo(b SerializeBuffer, opts SerializeOptions) error +} + +// SerializeOptions provides options for behaviors that SerializableLayers may want to +// implement. +type SerializeOptions struct { + // FixLengths determines whether, during serialization, layers should fix + // the values for any length field that depends on the payload. + FixLengths bool + // ComputeChecksums determines whether, during serialization, layers + // should recompute checksums based on their payloads. + ComputeChecksums bool +} + +// SerializeBuffer is a helper used by gopacket for writing out packet layers. +// SerializeBuffer starts off as an empty []byte. Subsequent calls to PrependBytes +// return byte slices before the current Bytes(), AppendBytes returns byte +// slices after. +// +// Byte slices returned by PrependBytes/AppendBytes are NOT zero'd out, so if +// you want to make sure they're all zeros, set them as such. +// +// SerializeBuffer is specifically designed to handle packet writing, where unlike +// with normal writes it's easier to start writing at the inner-most layer and +// work out, meaning that we often need to prepend bytes. This runs counter to +// typical writes to byte slices using append(), where we only write at the end +// of the buffer. +// +// It can be reused via Clear. Note, however, that a Clear call will invalidate the +// byte slices returned by any previous Bytes() call (the same buffer is +// reused). +// +// 1) Reusing a write buffer is generally much faster than creating a new one, +// and with the default implementation it avoids additional memory allocations. +// 2) If a byte slice from a previous Bytes() call will continue to be used, +// it's better to create a new SerializeBuffer. +// +// The Clear method is specifically designed to minimize memory allocations for +// similar later workloads on the SerializeBuffer. IE: if you make a set of +// Prepend/Append calls, then clear, then make the same calls with the same +// sizes, the second round (and all future similar rounds) shouldn't allocate +// any new memory. +type SerializeBuffer interface { + // Bytes returns the contiguous set of bytes collected so far by Prepend/Append + // calls. The slice returned by Bytes will be modified by future Clear calls, + // so if you're planning on clearing this SerializeBuffer, you may want to copy + // Bytes somewhere safe first. + Bytes() []byte + // PrependBytes returns a set of bytes which prepends the current bytes in this + // buffer. These bytes start in an indeterminate state, so they should be + // overwritten by the caller. The caller must only call PrependBytes if they + // know they're going to immediately overwrite all bytes returned. + PrependBytes(num int) ([]byte, error) + // AppendBytes returns a set of bytes which appends the current bytes in this + // buffer. These bytes start in an indeterminate state, so they should be + // overwritten by the caller. The caller must only call AppendBytes if they + // know they're going to immediately overwrite all bytes returned. + AppendBytes(num int) ([]byte, error) + // Clear resets the SerializeBuffer to a new, empty buffer. After a call to clear, + // the byte slice returned by any previous call to Bytes() for this buffer + // should be considered invalidated. + Clear() error +} + +type serializeBuffer struct { + data []byte + start int + prepended, appended int +} + +// NewSerializeBuffer creates a new instance of the default implementation of +// the SerializeBuffer interface. +func NewSerializeBuffer() SerializeBuffer { + return &serializeBuffer{} +} + +// NewSerializeBufferExpectedSize creates a new buffer for serialization, optimized for an +// expected number of bytes prepended/appended. This tends to decrease the +// number of memory allocations made by the buffer during writes. +func NewSerializeBufferExpectedSize(expectedPrependLength, expectedAppendLength int) SerializeBuffer { + return &serializeBuffer{ + data: make([]byte, expectedPrependLength, expectedPrependLength+expectedAppendLength), + start: expectedPrependLength, + prepended: expectedPrependLength, + appended: expectedAppendLength, + } +} + +func (w *serializeBuffer) Bytes() []byte { + return w.data[w.start:] +} + +func (w *serializeBuffer) PrependBytes(num int) ([]byte, error) { + if num < 0 { + panic("num < 0") + } + if w.start < num { + toPrepend := w.prepended + if toPrepend < num { + toPrepend = num + } + w.prepended += toPrepend + length := cap(w.data) + toPrepend + newData := make([]byte, length) + newStart := w.start + toPrepend + copy(newData[newStart:], w.data[w.start:]) + w.start = newStart + w.data = newData[:toPrepend+len(w.data)] + } + w.start -= num + return w.data[w.start : w.start+num], nil +} + +func (w *serializeBuffer) AppendBytes(num int) ([]byte, error) { + if num < 0 { + panic("num < 0") + } + initialLength := len(w.data) + if cap(w.data)-initialLength < num { + toAppend := w.appended + if toAppend < num { + toAppend = num + } + w.appended += toAppend + newData := make([]byte, cap(w.data)+toAppend) + copy(newData[w.start:], w.data[w.start:]) + w.data = newData[:initialLength] + } + // Grow the buffer. We know it'll be under capacity given above. + w.data = w.data[:initialLength+num] + return w.data[initialLength:], nil +} + +func (w *serializeBuffer) Clear() error { + w.start = w.prepended + w.data = w.data[:w.start] + return nil +} + +// SerializeLayers clears the given write buffer, then writes all layers into it so +// they correctly wrap each other. Note that by clearing the buffer, it +// invalidates all slices previously returned by w.Bytes() +// +// Example: +// buf := gopacket.NewSerializeBuffer() +// opts := gopacket.SerializeOptions{} +// gopacket.SerializeLayers(buf, opts, a, b, c) +// firstPayload := buf.Bytes() // contains byte representation of a(b(c)) +// gopacket.SerializeLayers(buf, opts, d, e, f) +// secondPayload := buf.Bytes() // contains byte representation of d(e(f)). firstPayload is now invalidated, since the SerializeLayers call Clears buf. +func SerializeLayers(w SerializeBuffer, opts SerializeOptions, layers ...SerializableLayer) error { + w.Clear() + for i := len(layers) - 1; i >= 0; i-- { + layer := layers[i] + err := layer.SerializeTo(w, opts) + if err != nil { + return err + } + } + return nil +} + +// SerializePacket is a convenience function that calls SerializeLayers +// on packet's Layers(). +// It returns an error if one of the packet layers is not a SerializebleLayer. +func SerializePacket(buf SerializeBuffer, opts SerializeOptions, packet Packet) error { + sls := []SerializableLayer{} + for _, layer := range packet.Layers() { + sl, ok := layer.(SerializableLayer) + if !ok { + return fmt.Errorf("layer %s is not serializable", layer.LayerType().String()) + } + sls = append(sls, sl) + } + return SerializeLayers(buf, opts, sls...) +}