[VOL-3610] implementing a fake DHCP server within BBSim
Change-Id: If291a0ca7f78909c3713ef0e6831e381304fc2c9
diff --git a/Makefile b/Makefile
index c96ffeb..1d84999 100644
--- a/Makefile
+++ b/Makefile
@@ -30,22 +30,12 @@
GO = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") -v gocache:/.cache -v gocache-${VOLTHA_TOOLS_VERSION}:/go/pkg voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-golang go
GO_SH = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") -v gocache:/.cache -v gocache-${VOLTHA_TOOLS_VERSION}:/go/pkg voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-golang sh -c '
-BBSIM_BUILDER = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") -v gocache:/.cache -v gocache-${VOLTHA_TOOLS_VERSION}:/go/pkg bbsim-builder go
GO_JUNIT_REPORT = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app -i voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-go-junit-report go-junit-report
GOCOVER_COBERTURA = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app -i voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-gocover-cobertura gocover-cobertura
-BBSIM_LINTER = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") -v gocache:/.cache -v gocache-${VOLTHA_TOOLS_VERSION}:/go/pkg bbsim-linter:${VOLTHA_TOOLS_VERSION}-golangci-lint golangci-lint
+GOLANGCI_LINT = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") -v gocache:/.cache -v gocache-${VOLTHA_TOOLS_VERSION}:/go/pkg voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-golangci-lint golangci-lint
HADOLINT = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-hadolint hadolint
PROTOC = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") -v gocache-${VOLTHA_TOOLS_VERSION}:/go/pkg voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-protoc protoc
-builder:
- @docker build -t bbsim-builder:latest -f build/ci/builder.Dockerfile build/ci/
-
-linter:
- # since this repo depends on C libs (libpcap), they are first added into a local container
- @[[ "$(docker images -q bbsim-linter:${VOLTHA_TOOLS_VERSION}-golangci-lint 2> /dev/null)" != "" ]] || \
- docker build --build-arg=VOLTHA_TOOLS_VERSION=${VOLTHA_TOOLS_VERSION} -t bbsim-linter:${VOLTHA_TOOLS_VERSION}-golangci-lint -f build/ci/linter.Dockerfile build/ci/
-
-
# Public targets
all: help
@@ -77,19 +67,20 @@
lint: lint-mod lint-dockerfile
-sca: linter
+sca:
@rm -rf ./sca-report
@mkdir -p ./sca-report
@echo "Running static code analysis..."
- @${BBSIM_LINTER} run --deadline=4m --out-format junit-xml ./... | tee ./sca-report/sca-report.xml
+ @${GOLANGCI_LINT} run --deadline=4m --out-format junit-xml ./... | tee ./sca-report/sca-report.xml
@echo ""
@echo "Static code analysis OK"
test: docs-lint test-unit test-bbr
-test-unit: clean local-omci-sim builder # @HELP Execute unit tests
+test-unit: clean local-omci-sim # @HELP Execute unit tests
+ @echo "Running unit tests..."
@mkdir -p ./tests/results
- @${BBSIM_BUILDER} test -mod=vendor -v -coverprofile ./tests/results/go-test-coverage.out -covermode count ./... 2>&1 | tee ./tests/results/go-test-results.out ;\
+ @${GO} test -mod=vendor -v -coverprofile ./tests/results/go-test-coverage.out -covermode count ./... 2>&1 | tee ./tests/results/go-test-results.out ;\
RETURN=$$? ;\
${GO_JUNIT_REPORT} < ./tests/results/go-test-results.out > ./tests/results/go-test-results.xml ;\
${GOCOVER_COBERTURA} < ./tests/results/go-test-coverage.out > ./tests/results/go-test-coverage.xml ;\
@@ -141,18 +132,18 @@
RELEASE_BBSIM_NAME ?= bbsim
RELEASE_BBSIMCTL_NAME ?= bbsimctl
-release-bbr: builder
+release-bbr:
@echo "$(RELEASE_BBR_NAME)-linux-amd64"
- @${BBSIM_BUILDER} build -mod vendor \
+ @${GO} build -mod vendor \
-ldflags "-w -X main.buildTime=$(shell date +%Y/%m/%d-%H:%M:%S) \
-X main.commitHash=$(shell git log --pretty=format:%H -n 1) \
-X main.gitStatus=${GIT_STATUS} \
-X main.version=${VERSION}" \
-o "$(RELEASE_DIR)/$(RELEASE_BBR_NAME)-linux-amd64" ./cmd/bbr
-release-bbsim: builder
+release-bbsim:
@echo "$(RELEASE_BBSIM_NAME)-linux-amd64"
- @${BBSIM_BUILDER} build -mod vendor \
+ @${GO} build -mod vendor \
-ldflags "-w -X main.buildTime=$(shell date +%Y/%m/%d-%H:%M:%S) \
-X main.commitHash=$(shell git log --pretty=format:%H -n 1) \
-X main.gitStatus=${GIT_STATUS} \
diff --git a/VERSION b/VERSION
index f0bb29e..88c5fb8 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.3.0
+1.4.0
diff --git a/build/ci/builder.Dockerfile b/build/ci/builder.Dockerfile
deleted file mode 100644
index 94ab871..0000000
--- a/build/ci/builder.Dockerfile
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright 2020-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-FROM golang:1.13.8-stretch
-
-RUN apt-get update && apt-get install -y \
- build-essential libpcap-dev && \
- mkdir -m 777 /.cache /go/pkg
-
-ENV CGO_ENABLED=1
-
-WORKDIR /app
\ No newline at end of file
diff --git a/build/ci/linter.Dockerfile b/build/ci/linter.Dockerfile
deleted file mode 100644
index bc3274a..0000000
--- a/build/ci/linter.Dockerfile
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2020-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-ARG VOLTHA_TOOLS_VERSION
-FROM voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-golangci-lint
-
-# install repo-specific C dependencies
-RUN apk add --no-cache build-base libpcap-dev
diff --git a/build/package/Dockerfile b/build/package/Dockerfile
index ae3b919..ba3954c 100644
--- a/build/package/Dockerfile
+++ b/build/package/Dockerfile
@@ -17,8 +17,6 @@
# builder parent
FROM golang:1.13.8-stretch as builder
-RUN apt-get update && apt-get install -y build-essential=12.3 libpcap-dev=1.8.1-3 --no-install-recommends
-
ENV CGO_ENABLED=1
WORKDIR /app
@@ -41,29 +39,28 @@
# runtime parent
FROM ubuntu:18.04
-
-# runtime prereqs
-# the symlink on libpcap is because both alpine and debian come with 1.8.x, but
-# debian symlinks it to 0.8 for historical reasons:
-# https://packages.debian.org/stretch/libpcap0.8-dev
-RUN apt-get update \
- && apt-get install -y libpcap-dev=1.8.1-6ubuntu1.18.04.1 isc-dhcp-server=4.3.5-3ubuntu7.1 \
- network-manager=1.10.6-2ubuntu1.4 tcpdump=4.9.3-0ubuntu0.18.04.1 --no-install-recommends \
- && apt-get clean \
- && rm -rf /var/lib/apt/lists/* \
- && ln -s /usr/lib/libpcap.so.1.8.1 /usr/lib/libpcap.so.0.9
-
-COPY ./configs/dhcpd.conf /etc/dhcp/
-RUN mv /usr/sbin/dhcpd /usr/local/bin/ \
-&& mv /sbin/dhclient /usr/local/bin/ \
-&& touch /var/lib/dhcp/dhcpd.leases
-
WORKDIR /app
COPY --from=builder /app/bbsim /app/bbsim
COPY --from=builder /app/bbsimctl /usr/bin/bbsimctl
-RUN mv /usr/sbin/tcpdump /usr/bin/tcpdump
+COPY ./configs/ ./configs/
RUN chmod a+x /app/bbsim
RUN chmod a+x /usr/bin/bbsimctl
-COPY ./configs/ ./configs/
RUN bbsimctl completion bash >> "$HOME/.bashrc"
CMD [ "/app/bbsim" ]
+
+# Label image
+ARG org_label_schema_version=unknown
+ARG org_label_schema_vcs_url=unknown
+ARG org_label_schema_vcs_ref=unknown
+ARG org_label_schema_build_date=unknown
+ARG org_opencord_vcs_commit_date=unknown
+ARG org_opencord_vcs_dirty=unknown
+
+LABEL org.label-schema.schema-version=1.0 \
+ org.label-schema.name=voltha-rw-core \
+ org.label-schema.version=$org_label_schema_version \
+ org.label-schema.vcs-url=$org_label_schema_vcs_url \
+ org.label-schema.vcs-ref=$org_label_schema_vcs_ref \
+ org.label-schema.build-date=$org_label_schema_build_date \
+ org.opencord.vcs-commit-date=$org_opencord_vcs_commit_date \
+ org.opencord.vcs-dirty=$org_opencord_vcs_dirty
diff --git a/configs/dhcpd.conf b/configs/dhcpd.conf
deleted file mode 100644
index 9a480fe..0000000
--- a/configs/dhcpd.conf
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Sample configuration file for ISC dhcpd for Debian
-#
-
-ddns-update-style none;
-
-option domain-name "example.org";
-# option domain-name-servers ns1.example.org, ns2.example.org;
-
-default-lease-time 600;
-max-lease-time 7200;
-
-# This is a very basic subnet declaration.
-subnet 192.168.0.0 netmask 255.255.0.0 {
- range 192.168.0.1 192.168.253.254;
- option routers 192.168.254.254;
-}
\ No newline at end of file
diff --git a/internal/bbsim/devices/nni.go b/internal/bbsim/devices/nni.go
index fe092e8..32fffaa 100644
--- a/internal/bbsim/devices/nni.go
+++ b/internal/bbsim/devices/nni.go
@@ -17,68 +17,42 @@
package devices
import (
- "bytes"
"encoding/hex"
- "os/exec"
-
"github.com/google/gopacket"
- "github.com/google/gopacket/pcap"
"github.com/looplab/fsm"
"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
- "github.com/opencord/bbsim/internal/bbsim/types"
+ "github.com/opencord/voltha-protos/v4/go/openolt"
log "github.com/sirupsen/logrus"
)
-var (
- nniLogger = log.WithFields(log.Fields{"module": "NNI"})
- dhcpServerIp = "192.168.254.1"
-)
-
-type Executor interface {
- Command(name string, arg ...string) Runnable
-}
-
-type DefaultExecutor struct{}
-
-func (d DefaultExecutor) Command(name string, arg ...string) Runnable {
- return exec.Command(name, arg...)
-}
-
-type Runnable interface {
- Run() error
-}
-
-var executor = DefaultExecutor{}
+var nniLogger = log.WithFields(log.Fields{"module": "NNI"})
type NniPort struct {
// BBSIM Internals
- ID uint32
- nniVeth string
- upstreamVeth string
- PacketCount uint64
+ ID uint32
+ Olt *OltDevice
// PON Attributes
- OperState *fsm.FSM
- Type string
+ OperState *fsm.FSM
+ Type string
+ PacketCount uint64 // dummy value for the stats
}
func CreateNNI(olt *OltDevice) (NniPort, error) {
nniPort := NniPort{
- ID: uint32(0),
- nniVeth: "nni",
- upstreamVeth: "upstream",
+ ID: uint32(0),
OperState: getOperStateFSM(func(e *fsm.Event) {
oltLogger.Debugf("Changing NNI OperState from %s to %s", e.Src, e.Dst)
}),
Type: "nni",
+ Olt: olt,
}
- _ = createNNIPair(executor, olt, &nniPort)
+
return nniPort, nil
}
-// sendNniPacket will send a packet out of the NNI interface.
-// We will send upstream only DHCP packets and drop anything else
-func (n *NniPort) sendNniPacket(packet gopacket.Packet) error {
+// handleNniPacket will send a packet to a fake DHCP server implementation
+func (n *NniPort) handleNniPacket(packet gopacket.Packet) error {
isDhcp := packetHandlers.IsDhcpPacket(packet)
isLldp := packetHandlers.IsLldpPacket(packet)
@@ -90,152 +64,33 @@
}
if isDhcp {
- packet, err := packetHandlers.PopDoubleTag(packet)
+
+ // get a response packet from the DHCP server
+ pkt, err := n.Olt.dhcpServer.HandleServerPacket(packet)
if err != nil {
nniLogger.WithFields(log.Fields{
- "packet": packet,
- }).Errorf("Can't remove double tags from packet: %v", err)
+ "SourcePkt": hex.EncodeToString(packet.Data()),
+ "Err": err,
+ }).Error("DHCP Server can't handle packet")
return err
}
- handle, err := getVethHandler(n.nniVeth)
- if err != nil {
+ // send packetIndication to VOLTHA
+ data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
+ IntfType: "nni",
+ IntfId: n.ID,
+ Pkt: pkt.Data()}}
+ if err := n.Olt.OpenoltStream.Send(&openolt.Indication{Data: data}); err != nil {
+ oltLogger.WithFields(log.Fields{
+ "IntfType": data.PktInd.IntfType,
+ "IntfId": n.ID,
+ "Pkt": hex.EncodeToString(pkt.Data()),
+ }).Errorf("Fail to send PktInd indication: %v", err)
return err
}
-
- err = handle.WritePacketData(packet.Data())
- if err != nil {
- nniLogger.WithFields(log.Fields{
- "packet": packet,
- }).Errorf("Failed to send packet out of the NNI: %s", err)
- return err
- }
-
- nniLogger.WithFields(log.Fields{
- "packet": hex.EncodeToString(packet.Data()),
- }).Trace("Sent packet out of NNI")
} else if isLldp {
// TODO rework this when BBSim supports data-plane packets
nniLogger.Trace("Received LLDP Packet, ignoring it")
}
return nil
}
-
-//createNNIBridge will create a veth bridge to fake the connection between the NNI port
-//and something upstream, in this case a DHCP server.
-//It is also responsible to start the DHCP server itself
-func createNNIPair(executor Executor, olt *OltDevice, nniPort *NniPort) error {
-
- if err := executor.Command("ip", "link", "add", nniPort.nniVeth, "type", "veth", "peer", "name", nniPort.upstreamVeth).Run(); err != nil {
- nniLogger.Errorf("Couldn't create veth pair between %s and %s", nniPort.nniVeth, nniPort.upstreamVeth)
- return err
- }
-
- if err := setVethUp(executor, nniPort.nniVeth); err != nil {
- return err
- }
-
- if err := setVethUp(executor, nniPort.upstreamVeth); err != nil {
- return err
- }
-
- // TODO should be moved out of this function in case there are multiple NNI interfaces.
- // Only one DHCP server should be running and listening on all NNI interfaces
- if err := startDHCPServer(nniPort.upstreamVeth, dhcpServerIp); err != nil {
- return err
- }
-
- return nil
-}
-
-// NewVethChan returns a new channel for receiving packets over the NNI interface
-func (n *NniPort) NewVethChan() (chan *types.PacketMsg, *pcap.Handle, error) {
- ch, handle, err := listenOnVeth(n.nniVeth)
- if err != nil {
- return nil, nil, err
- }
- return ch, handle, err
-}
-
-// setVethUp is responsible to activate a virtual interface
-func setVethUp(executor Executor, vethName string) error {
- if err := executor.Command("ip", "link", "set", vethName, "up").Run(); err != nil {
- nniLogger.Errorf("Couldn't change interface %s state to up: %v", vethName, err)
- return err
- }
- return nil
-}
-
-var startDHCPServer = func(upstreamVeth string, dhcpServerIp string) error {
- // TODO the DHCP server should support multiple interfaces
- if err := exec.Command("ip", "addr", "add", dhcpServerIp, "dev", upstreamVeth).Run(); err != nil {
- nniLogger.Errorf("Couldn't assing ip %s to interface %s: %v", dhcpServerIp, upstreamVeth, err)
- return err
- }
-
- if err := setVethUp(executor, upstreamVeth); err != nil {
- return err
- }
-
- dhcp := "/usr/local/bin/dhcpd"
- conf := "/etc/dhcp/dhcpd.conf" // copied in the container from configs/dhcpd.conf
- logfile := "/tmp/dhcplog"
- var stderr bytes.Buffer
- cmd := exec.Command(dhcp, "-cf", conf, upstreamVeth, "-tf", logfile, "-4")
- cmd.Stderr = &stderr
- err := cmd.Run()
- if err != nil {
- nniLogger.Errorf("Fail to start DHCP Server: %s, %s", err, stderr.String())
- return err
- }
- nniLogger.Info("Successfully activated DHCP Server")
- return nil
-}
-
-func getVethHandler(vethName string) (*pcap.Handle, error) {
- var (
- device = vethName
- snapshotLen int32 = 1518
- promiscuous = false
- timeout = pcap.BlockForever
- )
- handle, err := pcap.OpenLive(device, snapshotLen, promiscuous, timeout)
- if err != nil {
- nniLogger.Errorf("Can't retrieve handler for interface %s", vethName)
- return nil, err
- }
- return handle, nil
-}
-
-var listenOnVeth = func(vethName string) (chan *types.PacketMsg, *pcap.Handle, error) {
-
- handle, err := getVethHandler(vethName)
- if err != nil {
- return nil, nil, err
- }
-
- channel := make(chan *types.PacketMsg, 1024)
-
- go func() {
- nniLogger.Info("Start listening on NNI for packets")
- packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
- for packet := range packetSource.Packets() {
-
- if !packetHandlers.IsIncomingPacket(packet) {
- nniLogger.Tracef("Ignoring packet as it's going out")
- continue
- }
-
- nniLogger.WithFields(log.Fields{
- "packet": packet.Dump(),
- }).Tracef("Received packet on NNI Port")
- pkt := types.PacketMsg{
- Pkt: packet,
- }
- channel <- &pkt
- }
- nniLogger.Info("Stop listening on NNI for packets")
- }()
-
- return channel, handle, nil
-}
diff --git a/internal/bbsim/devices/nni_test.go b/internal/bbsim/devices/nni_test.go
index 9ee945e..4f93bb8 100644
--- a/internal/bbsim/devices/nni_test.go
+++ b/internal/bbsim/devices/nni_test.go
@@ -19,88 +19,82 @@
import (
"errors"
- "github.com/google/gopacket/pcap"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/opencord/voltha-protos/v4/go/openolt"
+ "github.com/stretchr/testify/assert"
"testing"
-
- "github.com/opencord/bbsim/internal/bbsim/types"
- "gotest.tools/assert"
)
-func TestSetVethUpSuccess(t *testing.T) {
- spy := &ExecutorSpy{
- Calls: make(map[int][]string),
+func TestCreateNNI(t *testing.T) {
+ olt := OltDevice{
+ ID: 0,
}
- err := setVethUp(spy, "test_veth")
- assert.Equal(t, spy.CommandCallCount, 1)
- assert.Equal(t, spy.Calls[1][2], "test_veth")
- assert.Equal(t, err, nil)
+ nni, err := CreateNNI(&olt)
+
+ assert.Nil(t, err)
+ assert.Equal(t, "nni", nni.Type)
+ assert.Equal(t, uint32(0), nni.ID)
+ assert.Equal(t, "down", nni.OperState.Current())
}
-func TestSetVethUpFail(t *testing.T) {
- spy := &ExecutorSpy{
- failRun: true,
- Calls: make(map[int][]string),
+func TestSendNniPacket(t *testing.T) {
+
+ stream := &mockStream{
+ CallCount: 0,
+ Calls: make(map[int]*openolt.Indication),
+ fail: false,
+ channel: make(chan int, 10),
}
- err := setVethUp(spy, "test_veth")
- assert.Equal(t, spy.CommandCallCount, 1)
- assert.Equal(t, err.Error(), "fake-error")
+
+ dhcpServer := &mockDhcpServer{
+ callCount: 0,
+ fail: false,
+ }
+
+ nni := NniPort{
+ Olt: &OltDevice{
+ OpenoltStream: stream,
+ dhcpServer: dhcpServer,
+ },
+ ID: 12,
+ }
+
+ // the DHCP server is mocked, so we don't really care about the packet we send in
+ pkt := createTestDhcpPacket(t)
+ err := nni.handleNniPacket(pkt)
+ assert.Nil(t, err)
+ assert.Equal(t, stream.CallCount, 1)
+ indication := stream.Calls[1].GetPktInd()
+ assert.Equal(t, "nni", indication.IntfType)
+ assert.Equal(t, nni.ID, indication.IntfId)
+ assert.Equal(t, pkt.Data(), indication.Pkt)
}
-func TestCreateNNIPair(t *testing.T) {
-
- startDHCPServerCalled := false
- _startDHCPServer := startDHCPServer
- defer func() { startDHCPServer = _startDHCPServer }()
- startDHCPServer = func(upstreamVeth string, dhcpServerIp string) error {
- startDHCPServerCalled = true
- return nil
- }
-
- listenOnVethCalled := false
- _listenOnVeth := listenOnVeth
- defer func() { listenOnVeth = _listenOnVeth }()
- listenOnVeth = func(vethName string) (chan *types.PacketMsg, *pcap.Handle, error) {
- listenOnVethCalled = true
- return make(chan *types.PacketMsg, 1), nil, nil
- }
- spy := &ExecutorSpy{
- failRun: false,
- Calls: make(map[int][]string),
- }
-
- olt := OltDevice{}
- nni := NniPort{}
-
- err := createNNIPair(spy, &olt, &nni)
- olt.nniPktInChannel, olt.nniHandle, _ = nni.NewVethChan()
-
- assert.Equal(t, spy.CommandCallCount, 3)
- assert.Equal(t, startDHCPServerCalled, true)
- assert.Equal(t, listenOnVethCalled, true)
- assert.Equal(t, err, nil)
- assert.Assert(t, olt.nniPktInChannel != nil)
+type mockDhcpServer struct {
+ callCount int
+ fail bool
}
-type ExecutorSpy struct {
- failRun bool
-
- CommandCallCount int
- RunCallCount int
- Calls map[int][]string
-}
-
-func (s *ExecutorSpy) Command(name string, arg ...string) Runnable {
- s.CommandCallCount++
-
- s.Calls[s.CommandCallCount] = arg
-
- return s
-}
-
-func (s *ExecutorSpy) Run() error {
- s.RunCallCount++
- if s.failRun {
- return errors.New("fake-error")
+// being a Mock I just return the same packet I got
+func (s mockDhcpServer) HandleServerPacket(pkt gopacket.Packet) (gopacket.Packet, error) {
+ if s.fail {
+ return nil, errors.New("mocked-error")
}
- return nil
+ return pkt, nil
+}
+
+func createTestDhcpPacket(t *testing.T) gopacket.Packet {
+ dhcp := &layers.DHCPv4{
+ Operation: layers.DHCPOpRequest,
+ }
+
+ buffer := gopacket.NewSerializeBuffer()
+ opts := gopacket.SerializeOptions{FixLengths: true}
+ err := gopacket.SerializeLayers(buffer, opts, dhcp)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeDHCPv4, gopacket.DecodeOptions{})
}
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index c3e0866..beeffce 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -20,6 +20,7 @@
"context"
"encoding/hex"
"fmt"
+ "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
"github.com/opencord/voltha-protos/v4/go/ext/config"
"net"
"sync"
@@ -27,10 +28,8 @@
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
- "github.com/google/gopacket/pcap"
"github.com/looplab/fsm"
"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
- bbsim "github.com/opencord/bbsim/internal/bbsim/types"
"github.com/opencord/bbsim/internal/common"
omcisim "github.com/opencord/omci-sim"
common_protos "github.com/opencord/voltha-protos/v4/go/common"
@@ -58,8 +57,7 @@
NumOnuPerPon int
InternalState *fsm.FSM
channel chan Message
- nniPktInChannel chan *bbsim.PacketMsg // packets coming in from the NNI and going to VOLTHA
- nniHandle *pcap.Handle // handle on the NNI interface, close it when shutting down the NNI channel
+ dhcpServer dhcp.DHCPServerIf
Flows map[FlowKey]openolt.Flow
Delay int
ControlledActivation mode
@@ -111,6 +109,7 @@
enablePerf: options.BBSim.EnablePerf,
PublishEvents: options.BBSim.Events,
PortStatsInterval: options.Olt.PortStatsInterval,
+ dhcpServer: dhcp.NewDHCPServer(),
}
if val, ok := ControlledActivationModes[options.BBSim.ControlledActivation]; ok {
@@ -235,25 +234,12 @@
// create new channel for processOltMessages Go routine
o.channel = make(chan Message)
- o.nniPktInChannel = make(chan *bbsim.PacketMsg, 1024)
// FIXME we are assuming we have only one NNI
if o.Nnis[0] != nil {
// NOTE we want to make sure the state is down when we initialize the OLT,
// the NNI may be in a bad state after a disable/reboot as we are not disabling it for
// in-band management
o.Nnis[0].OperState.SetState("down")
- ch, handle, err := o.Nnis[0].NewVethChan()
- if err == nil {
- oltLogger.WithFields(log.Fields{
- "Type": o.Nnis[0].Type,
- "IntfId": o.Nnis[0].ID,
- "OperState": o.Nnis[0].OperState.Current(),
- }).Info("NNI Channel created")
- o.nniPktInChannel = ch
- o.nniHandle = handle
- } else {
- oltLogger.Errorf("Error getting NNI channel: %v", err)
- }
}
}
@@ -319,9 +305,7 @@
// terminate the OLT's processOltMessages go routine
close(o.channel)
- // terminate the OLT's processNniPacketIns go routine
- go o.nniHandle.Close()
- close(o.nniPktInChannel)
+
o.enableContextCancel()
time.Sleep(time.Duration(rebootDelay) * time.Second)
@@ -398,7 +382,6 @@
// create Go routine to process all OLT events
go o.processOltMessages(o.enableContext, stream, &wg)
- go o.processNniPacketIns(o.enableContext, stream, &wg)
// enable the OLT
oltMsg := Message{
@@ -753,82 +736,6 @@
oltLogger.Warn("Stopped handling OLT Indication Channel")
}
-// processNniPacketIns handles messages received over the NNI interface
-func (o *OltDevice) processNniPacketIns(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
- oltLogger.WithFields(log.Fields{
- "nniChannel": o.nniPktInChannel,
- }).Debug("Started Processing Packets arriving from the NNI")
- nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
-
- ch := o.nniPktInChannel
-
-loop:
- for {
- select {
- case <-ctx.Done():
- oltLogger.Debug("NNI Indication processing canceled via context")
- break loop
- case message, ok := <-ch:
- if !ok || ctx.Err() != nil {
- oltLogger.Debug("NNI Indication processing canceled via channel closed")
- break loop
- }
- oltLogger.Tracef("Received packets on NNI Channel")
-
- onuMac, err := packetHandlers.GetDstMacAddressFromPacket(message.Pkt)
-
- if err != nil {
- log.WithFields(log.Fields{
- "IntfType": "nni",
- "IntfId": nniId,
- "Pkt": message.Pkt.Data(),
- }).Error("Can't find Dst MacAddress in packet")
- return
- }
-
- s, err := o.FindServiceByMacAddress(onuMac)
- if err != nil {
- log.WithFields(log.Fields{
- "IntfType": "nni",
- "IntfId": nniId,
- "Pkt": message.Pkt.Data(),
- "MacAddress": onuMac.String(),
- }).Error("Can't find ONU with MacAddress")
- return
- }
-
- service := s.(*Service)
-
- doubleTaggedPkt, err := packetHandlers.PushDoubleTag(service.STag, service.CTag, message.Pkt, service.UsPonCTagPriority)
- if err != nil {
- log.Error("Fail to add double tag to packet")
- }
-
- data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
- IntfType: "nni",
- IntfId: nniId,
- Pkt: doubleTaggedPkt.Data()}}
- if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
- oltLogger.WithFields(log.Fields{
- "IntfType": data.PktInd.IntfType,
- "IntfId": nniId,
- "Pkt": doubleTaggedPkt.Data(),
- }).Errorf("Fail to send PktInd indication: %v", err)
- }
- oltLogger.WithFields(log.Fields{
- "IntfType": data.PktInd.IntfType,
- "IntfId": nniId,
- "Pkt": hex.EncodeToString(doubleTaggedPkt.Data()),
- "OnuSn": service.Onu.Sn(),
- }).Trace("Sent PktInd indication (from NNI to VOLTHA)")
- }
- }
- wg.Done()
- oltLogger.WithFields(log.Fields{
- "nniChannel": o.nniPktInChannel,
- }).Warn("Stopped handling NNI Channel")
-}
-
// returns an ONU with a given Serial Number
func (o *OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
// TODO this function can be a performance bottleneck when we have many ONUs,
@@ -1405,8 +1312,11 @@
func (o *OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
- _ = o.Nnis[0].sendNniPacket(pkt) // FIXME we are assuming we have only one NNI
- // NOTE should we return an error if sendNniPakcet fails?
+ err := o.Nnis[0].handleNniPacket(pkt) // FIXME we are assuming we have only one NNI
+
+ if err != nil {
+ return nil, err
+ }
return new(openolt.Empty), nil
}
diff --git a/internal/bbsim/packetHandlers/filters.go b/internal/bbsim/packetHandlers/filters.go
index c46f87d..a930b1e 100644
--- a/internal/bbsim/packetHandlers/filters.go
+++ b/internal/bbsim/packetHandlers/filters.go
@@ -44,16 +44,14 @@
return false
}
-// return true if the packet is coming in the OLT from the NNI port
-// it uses the ack to check if the source is the one we assigned to the
-// dhcp server
+// return true if the packet is coming in the OLT from the DHCP Server
+// given that we only check DHCP packets we can use the Operation
+// Request are outgoing (toward the server)
+// Replies are incoming (toward the OLT)
func IsIncomingPacket(packet gopacket.Packet) bool {
- if ipLayer := packet.Layer(layers.LayerTypeIPv4); ipLayer != nil {
-
- ip, _ := ipLayer.(*layers.IPv4)
-
- // FIXME find a better way to filter outgoing packets
- if ip.SrcIP.Equal(net.ParseIP("192.168.254.1")) {
+ layerDHCP := packet.Layer(layers.LayerTypeDHCPv4)
+ if dhcp, ok := layerDHCP.(*layers.DHCPv4); ok {
+ if dhcp.Operation == layers.DHCPOpReply {
return true
}
}
diff --git a/internal/bbsim/packetHandlers/filters_test.go b/internal/bbsim/packetHandlers/filters_test.go
index c182e82..5be7db2 100644
--- a/internal/bbsim/packetHandlers/filters_test.go
+++ b/internal/bbsim/packetHandlers/filters_test.go
@@ -131,9 +131,8 @@
}
func Test_IsIncomingPacket_True(t *testing.T) {
- eth := &layers.IPv4{
- SrcIP: net.ParseIP("192.168.254.1"),
- DstIP: net.ParseIP("182.21.0.122"),
+ eth := &layers.DHCPv4{
+ Operation: layers.DHCPOpReply,
}
buffer := gopacket.NewSerializeBuffer()
@@ -143,16 +142,15 @@
t.Fatal(err)
}
- ethernetPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeIPv4, gopacket.DecodeOptions{})
+ ethernetPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeDHCPv4, gopacket.DecodeOptions{})
res := packetHandlers.IsIncomingPacket(ethernetPkt)
assert.Equal(t, res, true)
}
func Test_IsIncomingPacket_False(t *testing.T) {
- eth := &layers.IPv4{
- SrcIP: net.ParseIP("182.21.0.122"),
- DstIP: net.ParseIP("192.168.254.1"),
+ eth := &layers.DHCPv4{
+ Operation: layers.DHCPOpRequest,
}
buffer := gopacket.NewSerializeBuffer()
@@ -162,7 +160,7 @@
t.Fatal(err)
}
- ethernetPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeIPv4, gopacket.DecodeOptions{})
+ ethernetPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeDHCPv4, gopacket.DecodeOptions{})
res := packetHandlers.IsIncomingPacket(ethernetPkt)
assert.Equal(t, res, false)
diff --git a/internal/bbsim/packetHandlers/packet_tags.go b/internal/bbsim/packetHandlers/packet_tags.go
index 1ea7be7..90186a8 100644
--- a/internal/bbsim/packetHandlers/packet_tags.go
+++ b/internal/bbsim/packetHandlers/packet_tags.go
@@ -144,3 +144,21 @@
}
return dot1q.Priority, nil
}
+
+// godet inner and outer tag from a packet
+// TODO unit test
+func GetTagsFromPacket(pkt gopacket.Packet) (uint16, uint16, error) {
+ sTag, err := GetVlanTag(pkt)
+ if err != nil {
+ return 0, 0, err
+ }
+ singleTagPkt, err := PopSingleTag(pkt)
+ if err != nil {
+ return 0, 0, err
+ }
+ cTag, err := GetVlanTag(singleTagPkt)
+ if err != nil {
+ return 0, 0, err
+ }
+ return sTag, cTag, nil
+}
diff --git a/internal/bbsim/responders/dhcp/dhcp.go b/internal/bbsim/responders/dhcp/dhcp.go
index f3c7e72..850d160 100644
--- a/internal/bbsim/responders/dhcp/dhcp.go
+++ b/internal/bbsim/responders/dhcp/dhcp.go
@@ -158,7 +158,7 @@
return &dhcpLayer
}
-func serializeDHCPPacket(intfId uint32, onuId uint32, cTag int, srcMac net.HardwareAddr, dhcp *layers.DHCPv4, pbit uint8) ([]byte, error) {
+func serializeDHCPPacket(cTag int, srcMac net.HardwareAddr, dhcp *layers.DHCPv4, pbit uint8) (gopacket.Packet, error) {
buffer := gopacket.NewSerializeBuffer()
options := gopacket.SerializeOptions{
@@ -200,7 +200,7 @@
return nil, err
}
- return gopacket.Payload(taggedPkt.Data()), nil
+ return taggedPkt, nil
}
func GetDhcpLayer(pkt gopacket.Packet) (*layers.DHCPv4, error) {
@@ -277,7 +277,7 @@
cTag int, gemPortId uint32, onuStateMachine *fsm.FSM, onuHwAddress net.HardwareAddr,
offeredIp net.IP, pbit uint8, stream bbsim.Stream) error {
dhcp := createDHCPReq(ponPortId, onuId, onuHwAddress, offeredIp, gemPortId)
- pkt, err := serializeDHCPPacket(ponPortId, onuId, cTag, onuHwAddress, dhcp, pbit)
+ pkt, err := serializeDHCPPacket(cTag, onuHwAddress, dhcp, pbit)
if err != nil {
dhcpLogger.WithFields(log.Fields{
@@ -297,7 +297,7 @@
msg := bbsim.ByteMsg{
IntfId: ponPortId,
OnuId: onuId,
- Bytes: pkt,
+ Bytes: pkt.Data(),
}
if err := sendDHCPPktIn(msg, portNo, gemPortId, stream); err != nil {
@@ -339,7 +339,7 @@
pbit uint8, stream bbsim.Stream) error {
dhcp := createDHCPDisc(ponPortId, onuId, gemPortId, onuHwAddress)
- pkt, err := serializeDHCPPacket(ponPortId, onuId, cTag, onuHwAddress, dhcp, pbit)
+ pkt, err := serializeDHCPPacket(cTag, onuHwAddress, dhcp, pbit)
if err != nil {
dhcpLogger.WithFields(log.Fields{
@@ -359,7 +359,7 @@
msg := bbsim.ByteMsg{
IntfId: ponPortId,
OnuId: onuId,
- Bytes: pkt,
+ Bytes: pkt.Data(),
}
if err := sendDHCPPktIn(msg, portNo, gemPortId, stream); err != nil {
@@ -574,6 +574,7 @@
"Type": dhcpType,
"error": err,
}).Error("Failed to send DHCP packet out of the NNI Port")
+ return err
}
dhcpLogger.WithFields(log.Fields{
"OnuId": onuId,
diff --git a/internal/bbsim/responders/dhcp/dhcp_server.go b/internal/bbsim/responders/dhcp/dhcp_server.go
new file mode 100644
index 0000000..7e7f361
--- /dev/null
+++ b/internal/bbsim/responders/dhcp/dhcp_server.go
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dhcp
+
+import (
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
+ log "github.com/sirupsen/logrus"
+ "net"
+)
+
+type DHCPServerIf interface {
+ HandleServerPacket(pkt gopacket.Packet) (gopacket.Packet, error)
+}
+
+type DHCPServer struct {
+ DHCPServerMacAddress net.HardwareAddr
+}
+
+func NewDHCPServer() *DHCPServer {
+ return &DHCPServer{
+ // NOTE we may need to make this configurable in case we'll need multiple servers
+ DHCPServerMacAddress: net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+ }
+}
+
+func (s *DHCPServer) getClientMacAddress(pkt gopacket.Packet) (net.HardwareAddr, error) {
+ dhcpLayer, err := GetDhcpLayer(pkt)
+ if err != nil {
+ return nil, err
+ }
+ return dhcpLayer.ClientHWAddr, nil
+}
+
+func (s *DHCPServer) getTxId(pkt gopacket.Packet) (uint32, error) {
+ dhcpLayer, err := GetDhcpLayer(pkt)
+ if err != nil {
+ return 0, err
+ }
+ return dhcpLayer.Xid, nil
+}
+
+func (s *DHCPServer) getPacketHostName(pkt gopacket.Packet) ([]byte, error) {
+ dhcpLayer, err := GetDhcpLayer(pkt)
+ if err != nil {
+ return nil, err
+ }
+ for _, option := range dhcpLayer.Options {
+ if option.Type == layers.DHCPOptHostname {
+ return option.Data, nil
+ }
+ }
+ return nil, errors.New("hostname-not-found")
+}
+
+func (s *DHCPServer) getOption82(pkt gopacket.Packet) ([]byte, error) {
+ dhcpLayer, err := GetDhcpLayer(pkt)
+ if err != nil {
+ return nil, err
+ }
+ for _, option := range dhcpLayer.Options {
+ if option.Type == 82 {
+ return option.Data, nil
+ }
+ }
+ log.WithFields(log.Fields{
+ "pkt": hex.EncodeToString(pkt.Data()),
+ }).Debug("option82-not-found")
+ return []byte{}, nil
+}
+
+func (s *DHCPServer) createDefaultDhcpReply(xid uint32, mac net.HardwareAddr) layers.DHCPv4 {
+ clientIp := s.createIpFromMacAddress(mac)
+ return layers.DHCPv4{
+ Operation: layers.DHCPOpReply,
+ HardwareType: layers.LinkTypeEthernet,
+ HardwareLen: 6,
+ HardwareOpts: 0,
+ Xid: xid,
+ ClientHWAddr: mac,
+ ClientIP: clientIp,
+ YourClientIP: clientIp,
+ }
+}
+
+func (s *DHCPServer) createIpFromMacAddress(mac net.HardwareAddr) net.IP {
+ ip := []byte{}
+ for i := 2; i < 6; i++ {
+ ip = append(ip, mac[i])
+ }
+ return net.IPv4(10+ip[0], ip[1], ip[2], ip[3])
+}
+
+func (s *DHCPServer) serializeServerDHCPPacket(clientMac net.HardwareAddr, dhcpLayer *layers.DHCPv4) (gopacket.Packet, error) {
+ buffer := gopacket.NewSerializeBuffer()
+
+ options := gopacket.SerializeOptions{
+ ComputeChecksums: true,
+ FixLengths: true,
+ }
+
+ ethernetLayer := &layers.Ethernet{
+ SrcMAC: s.DHCPServerMacAddress,
+ DstMAC: clientMac,
+ EthernetType: layers.EthernetTypeIPv4,
+ }
+
+ ipLayer := &layers.IPv4{
+ Version: 4,
+ TOS: 0x10,
+ TTL: 128,
+ SrcIP: []byte{0, 0, 0, 0},
+ DstIP: []byte{255, 255, 255, 255},
+ Protocol: layers.IPProtocolUDP,
+ }
+
+ udpLayer := &layers.UDP{
+ SrcPort: 67,
+ DstPort: 68,
+ }
+
+ _ = udpLayer.SetNetworkLayerForChecksum(ipLayer)
+ if err := gopacket.SerializeLayers(buffer, options, ethernetLayer, ipLayer, udpLayer, dhcpLayer); err != nil {
+ dhcpLogger.Error("SerializeLayers")
+ return nil, err
+ }
+
+ return gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeEthernet, gopacket.Default), nil
+
+}
+
+func (s *DHCPServer) getDefaultDhcpServerOptions(hostname []byte, option82 []byte) []layers.DHCPOption {
+ defaultOpts := []layers.DHCPOption{}
+ defaultOpts = append(defaultOpts, layers.DHCPOption{
+ Type: layers.DHCPOptHostname,
+ Data: hostname,
+ Length: uint8(len(hostname)),
+ })
+
+ defaultOpts = append(defaultOpts, layers.DHCPOption{
+ Type: 82,
+ Data: option82,
+ Length: uint8(len(option82)),
+ })
+
+ return defaultOpts
+}
+
+// get a Discover packet an return a valid Offer
+func (s *DHCPServer) handleDiscover(pkt gopacket.Packet) (gopacket.Packet, error) {
+
+ sTag, cTag, err := packetHandlers.GetTagsFromPacket(pkt)
+ if err != nil {
+ return nil, err
+ }
+
+ clientMac, err := s.getClientMacAddress(pkt)
+ if err != nil {
+ return nil, err
+ }
+
+ txId, err := s.getTxId(pkt)
+ if err != nil {
+ return nil, err
+ }
+
+ hostname, err := s.getPacketHostName(pkt)
+ if err != nil {
+ return nil, err
+ }
+
+ option82, err := s.getOption82(pkt)
+ if err != nil {
+ return nil, err
+ }
+
+ dhcpLogger.WithFields(log.Fields{
+ "sTag": sTag,
+ "cTag": cTag,
+ "clientMac": clientMac,
+ "txId": txId,
+ "hostname": string(hostname),
+ "option82": string(option82),
+ }).Debug("Handling DHCP Discovery packet")
+
+ dhcpLayer := s.createDefaultDhcpReply(txId, clientMac)
+ defaultOpts := s.getDefaultDhcpServerOptions(hostname, option82)
+
+ dhcpLayer.Options = append([]layers.DHCPOption{{
+ Type: layers.DHCPOptMessageType,
+ Data: []byte{byte(layers.DHCPMsgTypeOffer)},
+ Length: 1,
+ }}, defaultOpts...)
+
+ data := []byte{01}
+ data = append(data, clientMac...)
+ dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
+ Type: layers.DHCPOptClientID,
+ Data: data,
+ Length: uint8(len(data)),
+ })
+
+ // serialize the packet
+ responsePkt, err := s.serializeServerDHCPPacket(clientMac, &dhcpLayer)
+ if err != nil {
+ return nil, err
+ }
+
+ taggedResponsePkt, err := packetHandlers.PushDoubleTag(int(sTag), int(cTag), responsePkt, 0)
+ if err != nil {
+ return nil, err
+ }
+ return taggedResponsePkt, nil
+}
+
+func (s *DHCPServer) handleRequest(pkt gopacket.Packet) (gopacket.Packet, error) {
+ sTag, cTag, err := packetHandlers.GetTagsFromPacket(pkt)
+ if err != nil {
+ return nil, err
+ }
+
+ clientMac, err := s.getClientMacAddress(pkt)
+ if err != nil {
+ return nil, err
+ }
+
+ txId, err := s.getTxId(pkt)
+ if err != nil {
+ return nil, err
+ }
+
+ hostname, err := s.getPacketHostName(pkt)
+ if err != nil {
+ return nil, err
+ }
+
+ option82, err := s.getOption82(pkt)
+ if err != nil {
+ return nil, err
+ }
+
+ dhcpLogger.WithFields(log.Fields{
+ "sTag": sTag,
+ "cTag": cTag,
+ "clientMac": clientMac,
+ "txId": txId,
+ "hostname": string(hostname),
+ "option82": string(option82),
+ }).Debug("Handling DHCP Request packet")
+
+ dhcpLayer := s.createDefaultDhcpReply(txId, clientMac)
+ defaultOpts := s.getDefaultDhcpServerOptions(hostname, option82)
+
+ dhcpLayer.Options = append([]layers.DHCPOption{{
+ Type: layers.DHCPOptMessageType,
+ Data: []byte{byte(layers.DHCPMsgTypeAck)},
+ Length: 1,
+ }}, defaultOpts...)
+
+ // TODO can we move this in getDefaultDhcpServerOptions?
+ data := []byte{01}
+ data = append(data, clientMac...)
+ dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
+ Type: layers.DHCPOptClientID,
+ Data: data,
+ Length: uint8(len(data)),
+ })
+
+ // serialize the packet
+ responsePkt, err := s.serializeServerDHCPPacket(clientMac, &dhcpLayer)
+ if err != nil {
+ return nil, err
+ }
+
+ taggedResponsePkt, err := packetHandlers.PushDoubleTag(int(sTag), int(cTag), responsePkt, 0)
+ if err != nil {
+ return nil, err
+ }
+ return taggedResponsePkt, nil
+}
+
+// HandleServerPacket is a very simple implementation of a DHCP server
+// that only replies to DHCPDiscover and DHCPRequest packets
+func (s DHCPServer) HandleServerPacket(pkt gopacket.Packet) (gopacket.Packet, error) {
+ dhcpLayer, _ := GetDhcpLayer(pkt)
+
+ if dhcpLayer.Operation == layers.DHCPOpReply {
+ dhcpLogger.WithFields(log.Fields{
+ "pkt": hex.EncodeToString(pkt.Data()),
+ }).Error("Received DHCP Reply on the server. Ignoring the packet but this is a serious error.")
+ }
+
+ dhcpMessageType, _ := GetDhcpMessageType(dhcpLayer)
+
+ switch dhcpMessageType {
+ case layers.DHCPMsgTypeDiscover:
+ dhcpLogger.Info("Received DHCP Discover")
+ return s.handleDiscover(pkt)
+ case layers.DHCPMsgTypeRequest:
+ dhcpLogger.Info("Received DHCP Request")
+ return s.handleRequest(pkt)
+ }
+ return nil, fmt.Errorf("cannot-handle-dhcp-packet-of-type-%s", dhcpMessageType.String())
+}
diff --git a/internal/bbsim/responders/dhcp/dhcp_server_test.go b/internal/bbsim/responders/dhcp/dhcp_server_test.go
new file mode 100644
index 0000000..fa4a58d
--- /dev/null
+++ b/internal/bbsim/responders/dhcp/dhcp_server_test.go
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dhcp
+
+import (
+ "gotest.tools/assert"
+ "net"
+ "testing"
+)
+
+func TestCreateIpFromMacAddress(t *testing.T) {
+ dhcpServer := NewDHCPServer()
+
+ mac1 := net.HardwareAddr{0x2e, 0x60, 0x00, 0x0c, 0x0f, 0x02}
+ ip1 := dhcpServer.createIpFromMacAddress(mac1)
+ assert.Equal(t, "10.12.15.2", ip1.String())
+
+ mac2 := net.HardwareAddr{0x2e, 0x60, 0x00, 0x00, 0x00, 0x00}
+ ip2 := dhcpServer.createIpFromMacAddress(mac2)
+ assert.Equal(t, "10.0.0.0", ip2.String())
+}
diff --git a/vendor/github.com/google/gopacket/pcap/defs_windows_386.go b/vendor/github.com/google/gopacket/pcap/defs_windows_386.go
deleted file mode 100644
index 774e907..0000000
--- a/vendor/github.com/google/gopacket/pcap/defs_windows_386.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2019 The GoPacket Authors. 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.
-
-// This file contains necessary structs/constants generated from libpcap headers with cgo -godefs
-// generated with: generate_defs.exe
-// DO NOT MODIFY
-
-package pcap
-
-import "syscall"
-
-const errorBufferSize = 0x100
-
-const (
- pcapErrorNotActivated = -0x3
- pcapErrorActivated = -0x4
- pcapWarningPromisc = 0x2
- pcapErrorNoSuchDevice = -0x5
- pcapErrorDenied = -0x8
- pcapErrorNotUp = -0x9
- pcapError = -0x1
- pcapWarning = 0x1
- pcapDIN = 0x1
- pcapDOUT = 0x2
- pcapDINOUT = 0x0
- pcapNetmaskUnknown = 0xffffffff
- pcapTstampPrecisionMicro = 0x0
- pcapTstampPrecisionNano = 0x1
-)
-
-type timeval struct {
- Sec int32
- Usec int32
-}
-type pcapPkthdr struct {
- Ts timeval
- Caplen uint32
- Len uint32
-}
-type pcapTPtr uintptr
-type pcapBpfInstruction struct {
- Code uint16
- Jt uint8
- Jf uint8
- K uint32
-}
-type pcapBpfProgram struct {
- Len uint32
- Insns *pcapBpfInstruction
-}
-type pcapStats struct {
- Recv uint32
- Drop uint32
- Ifdrop uint32
-}
-type pcapCint int32
-type pcapIf struct {
- Next *pcapIf
- Name *int8
- Description *int8
- Addresses *pcapAddr
- Flags uint32
-}
-
-type pcapAddr struct {
- Next *pcapAddr
- Addr *syscall.RawSockaddr
- Netmask *syscall.RawSockaddr
- Broadaddr *syscall.RawSockaddr
- Dstaddr *syscall.RawSockaddr
-}
diff --git a/vendor/github.com/google/gopacket/pcap/defs_windows_amd64.go b/vendor/github.com/google/gopacket/pcap/defs_windows_amd64.go
deleted file mode 100644
index 9619215..0000000
--- a/vendor/github.com/google/gopacket/pcap/defs_windows_amd64.go
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2019 The GoPacket Authors. 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.
-
-// This file contains necessary structs/constants generated from libpcap headers with cgo -godefs
-// generated with: generate_defs.exe
-// DO NOT MODIFY
-
-package pcap
-
-import "syscall"
-
-const errorBufferSize = 0x100
-
-const (
- pcapErrorNotActivated = -0x3
- pcapErrorActivated = -0x4
- pcapWarningPromisc = 0x2
- pcapErrorNoSuchDevice = -0x5
- pcapErrorDenied = -0x8
- pcapErrorNotUp = -0x9
- pcapError = -0x1
- pcapWarning = 0x1
- pcapDIN = 0x1
- pcapDOUT = 0x2
- pcapDINOUT = 0x0
- pcapNetmaskUnknown = 0xffffffff
- pcapTstampPrecisionMicro = 0x0
- pcapTstampPrecisionNano = 0x1
-)
-
-type timeval struct {
- Sec int32
- Usec int32
-}
-type pcapPkthdr struct {
- Ts timeval
- Caplen uint32
- Len uint32
-}
-type pcapTPtr uintptr
-type pcapBpfInstruction struct {
- Code uint16
- Jt uint8
- Jf uint8
- K uint32
-}
-type pcapBpfProgram struct {
- Len uint32
- Pad_cgo_0 [4]byte
- Insns *pcapBpfInstruction
-}
-type pcapStats struct {
- Recv uint32
- Drop uint32
- Ifdrop uint32
-}
-type pcapCint int32
-type pcapIf struct {
- Next *pcapIf
- Name *int8
- Description *int8
- Addresses *pcapAddr
- Flags uint32
- Pad_cgo_0 [4]byte
-}
-
-type pcapAddr struct {
- Next *pcapAddr
- Addr *syscall.RawSockaddr
- Netmask *syscall.RawSockaddr
- Broadaddr *syscall.RawSockaddr
- Dstaddr *syscall.RawSockaddr
-}
diff --git a/vendor/github.com/google/gopacket/pcap/doc.go b/vendor/github.com/google/gopacket/pcap/doc.go
deleted file mode 100644
index 38b3141..0000000
--- a/vendor/github.com/google/gopacket/pcap/doc.go
+++ /dev/null
@@ -1,112 +0,0 @@
-// 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 pcap allows users of gopacket to read packets off the wire or from
-pcap files.
-
-This package is meant to be used with its parent,
-http://github.com/google/gopacket, although it can also be used independently
-if you just want to get packet data from the wire.
-
-Depending on libpcap version, os support, or file timestamp resolution,
-nanosecond resolution is used for the internal timestamps. Returned timestamps
-are always scaled to nanosecond resolution due to the usage of time.Time.
-libpcap must be at least version 1.5 to support nanosecond timestamps. OpenLive
-supports only microsecond resolution.
-
-Reading PCAP Files
-
-The following code can be used to read in data from a pcap file.
-
- if handle, err := pcap.OpenOffline("/path/to/my/file"); err != nil {
- panic(err)
- } else {
- packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
- for packet := range packetSource.Packets() {
- handlePacket(packet) // Do something with a packet here.
- }
- }
-
-Reading Live Packets
-
-The following code can be used to read in data from a live device, in this case
-"eth0". Be aware, that OpenLive only supports microsecond resolution.
-
- if handle, err := pcap.OpenLive("eth0", 1600, true, pcap.BlockForever); err != nil {
- panic(err)
- } else if err := handle.SetBPFFilter("tcp and port 80"); err != nil { // optional
- panic(err)
- } else {
- packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
- for packet := range packetSource.Packets() {
- handlePacket(packet) // Do something with a packet here.
- }
- }
-
-Inactive Handles
-
-Newer PCAP functionality requires the concept of an 'inactive' PCAP handle.
-Instead of constantly adding new arguments to pcap_open_live, users now call
-pcap_create to create a handle, set it up with a bunch of optional function
-calls, then call pcap_activate to activate it. This library mirrors that
-mechanism, for those that want to expose/use these new features:
-
- inactive, err := pcap.NewInactiveHandle(deviceName)
- if err != nil {
- log.Fatal(err)
- }
- defer inactive.CleanUp()
-
- // Call various functions on inactive to set it up the way you'd like:
- if err = inactive.SetTimeout(time.Minute); err != nil {
- log.Fatal(err)
- } else if err = inactive.SetTimestampSource("foo"); err != nil {
- log.Fatal(err)
- }
-
- // Finally, create the actual handle by calling Activate:
- handle, err := inactive.Activate() // after this, inactive is no longer valid
- if err != nil {
- log.Fatal(err)
- }
- defer handle.Close()
-
- // Now use your handle as you see fit.
-
-PCAP Timeouts
-
-pcap.OpenLive and pcap.SetTimeout both take timeouts.
-If you don't care about timeouts, just pass in BlockForever,
-which should do what you expect with minimal fuss.
-
-A timeout of 0 is not recommended. Some platforms, like Macs
-(http://www.manpages.info/macosx/pcap.3.html) say:
- The read timeout is used to arrange that the read not necessarily return
- immediately when a packet is seen, but that it wait for some amount of time
- to allow more packets to arrive and to read multiple packets from the OS
- kernel in one operation.
-This means that if you only capture one packet, the kernel might decide to wait
-'timeout' for more packets to batch with it before returning. A timeout of
-0, then, means 'wait forever for more packets', which is... not good.
-
-To get around this, we've introduced the following behavior: if a negative
-timeout is passed in, we set the positive timeout in the handle, then loop
-internally in ReadPacketData/ZeroCopyReadPacketData when we see timeout
-errors.
-
-PCAP File Writing
-
-This package does not implement PCAP file writing. However, gopacket/pcapgo
-does! Look there if you'd like to write PCAP files.
-
-Note For Windows Users
-
-gopacket can use winpcap or npcap. If both are installed at the same time,
-npcap is preferred. Make sure the right windows service is loaded (npcap for npcap
-and npf for winpcap).
-*/
-package pcap
diff --git a/vendor/github.com/google/gopacket/pcap/pcap.go b/vendor/github.com/google/gopacket/pcap/pcap.go
deleted file mode 100644
index 6a4ef63..0000000
--- a/vendor/github.com/google/gopacket/pcap/pcap.go
+++ /dev/null
@@ -1,866 +0,0 @@
-// Copyright 2012 Google, Inc. All rights reserved.
-// Copyright 2009-2011 Andreas Krennmair. 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 pcap
-
-import (
- "errors"
- "fmt"
- "io"
- "net"
- "os"
- "reflect"
- "runtime"
- "strconv"
- "sync"
- "sync/atomic"
- "syscall"
- "time"
- "unsafe"
-
- "github.com/google/gopacket"
- "github.com/google/gopacket/layers"
-)
-
-// ErrNotActive is returned if handle is not activated
-const ErrNotActive = pcapErrorNotActivated
-
-// MaxBpfInstructions is the maximum number of BPF instructions supported (BPF_MAXINSNS),
-// taken from Linux kernel: include/uapi/linux/bpf_common.h
-//
-// https://github.com/torvalds/linux/blob/master/include/uapi/linux/bpf_common.h
-const MaxBpfInstructions = 4096
-
-// 8 bytes per instruction, max 4096 instructions
-const bpfInstructionBufferSize = 8 * MaxBpfInstructions
-
-// Handle provides a connection to a pcap handle, allowing users to read packets
-// off the wire (Next), inject packets onto the wire (Inject), and
-// perform a number of other functions to affect and understand packet output.
-//
-// Handles are already pcap_activate'd
-type Handle struct {
- // stop is set to a non-zero value by Handle.Close to signal to
- // getNextBufPtrLocked to stop trying to read packets
- // This must be the first entry to ensure alignment for sync.atomic
- stop uint64
- // cptr is the handle for the actual pcap C object.
- cptr pcapTPtr
- timeout time.Duration
- device string
- deviceIndex int
- mu sync.Mutex
- closeMu sync.Mutex
- nanoSecsFactor int64
-
- // Since pointers to these objects are passed into a C function, if
- // they're declared locally then the Go compiler thinks they may have
- // escaped into C-land, so it allocates them on the heap. This causes a
- // huge memory hit, so to handle that we store them here instead.
- pkthdr *pcapPkthdr
- bufptr *uint8
-}
-
-// Stats contains statistics on how many packets were handled by a pcap handle,
-// and what was done with those packets.
-type Stats struct {
- PacketsReceived int
- PacketsDropped int
- PacketsIfDropped int
-}
-
-// Interface describes a single network interface on a machine.
-type Interface struct {
- Name string
- Description string
- Flags uint32
- Addresses []InterfaceAddress
-}
-
-// Datalink describes the datalink
-type Datalink struct {
- Name string
- Description string
-}
-
-// InterfaceAddress describes an address associated with an Interface.
-// Currently, it's IPv4/6 specific.
-type InterfaceAddress struct {
- IP net.IP
- Netmask net.IPMask // Netmask may be nil if we were unable to retrieve it.
- Broadaddr net.IP // Broadcast address for this IP may be nil
- P2P net.IP // P2P destination address for this IP may be nil
-}
-
-// BPF is a compiled filter program, useful for offline packet matching.
-type BPF struct {
- orig string
- bpf pcapBpfProgram // takes a finalizer, not overriden by outsiders
- hdr pcapPkthdr // allocate on the heap to enable optimizations
-}
-
-// BPFInstruction is a byte encoded structure holding a BPF instruction
-type BPFInstruction struct {
- Code uint16
- Jt uint8
- Jf uint8
- K uint32
-}
-
-// BlockForever causes it to block forever waiting for packets, when passed
-// into SetTimeout or OpenLive, while still returning incoming packets to userland relatively
-// quickly.
-const BlockForever = -time.Millisecond * 10
-
-func timeoutMillis(timeout time.Duration) int {
- // Flip sign if necessary. See package docs on timeout for reasoning behind this.
- if timeout < 0 {
- timeout *= -1
- }
- // Round up
- if timeout != 0 && timeout < time.Millisecond {
- timeout = time.Millisecond
- }
- return int(timeout / time.Millisecond)
-}
-
-// OpenLive opens a device and returns a *Handle.
-// It takes as arguments the name of the device ("eth0"), the maximum size to
-// read for each packet (snaplen), whether to put the interface in promiscuous
-// mode, and a timeout. Warning: this function supports only microsecond timestamps.
-// For nanosecond resolution use an InactiveHandle.
-//
-// See the package documentation for important details regarding 'timeout'.
-func OpenLive(device string, snaplen int32, promisc bool, timeout time.Duration) (handle *Handle, _ error) {
- var pro int
- if promisc {
- pro = 1
- }
-
- p, err := pcapOpenLive(device, int(snaplen), pro, timeoutMillis(timeout))
- if err != nil {
- return nil, err
- }
- p.timeout = timeout
- p.device = device
-
- ifc, err := net.InterfaceByName(device)
- if err != nil {
- // The device wasn't found in the OS, but could be "any"
- // Set index to 0
- p.deviceIndex = 0
- } else {
- p.deviceIndex = ifc.Index
- }
-
- p.nanoSecsFactor = 1000
-
- // Only set the PCAP handle into non-blocking mode if we have a timeout
- // greater than zero. If the user wants to block forever, we'll let libpcap
- // handle that.
- if p.timeout > 0 {
- if err := p.setNonBlocking(); err != nil {
- p.pcapClose()
- return nil, err
- }
- }
-
- return p, nil
-}
-
-// OpenOffline opens a file and returns its contents as a *Handle. Depending on libpcap support and
-// on the timestamp resolution used in the file, nanosecond or microsecond resolution is used
-// internally. All returned timestamps are scaled to nanosecond resolution. Resolution() can be used
-// to query the actual resolution used.
-func OpenOffline(file string) (handle *Handle, err error) {
- handle, err = openOffline(file)
- if err != nil {
- return
- }
- if pcapGetTstampPrecision(handle.cptr) == pcapTstampPrecisionNano {
- handle.nanoSecsFactor = 1
- } else {
- handle.nanoSecsFactor = 1000
- }
- return
-}
-
-// OpenOfflineFile returns contents of input file as a *Handle. Depending on libpcap support and
-// on the timestamp resolution used in the file, nanosecond or microsecond resolution is used
-// internally. All returned timestamps are scaled to nanosecond resolution. Resolution() can be used
-// to query the actual resolution used.
-func OpenOfflineFile(file *os.File) (handle *Handle, err error) {
- handle, err = openOfflineFile(file)
- if err != nil {
- return
- }
- if pcapGetTstampPrecision(handle.cptr) == pcapTstampPrecisionNano {
- handle.nanoSecsFactor = 1
- } else {
- handle.nanoSecsFactor = 1000
- }
- return
-}
-
-// NextError is the return code from a call to Next.
-type NextError int32
-
-// NextError implements the error interface.
-func (n NextError) Error() string {
- switch n {
- case NextErrorOk:
- return "OK"
- case NextErrorTimeoutExpired:
- return "Timeout Expired"
- case NextErrorReadError:
- return "Read Error"
- case NextErrorNoMorePackets:
- return "No More Packets In File"
- case NextErrorNotActivated:
- return "Not Activated"
- }
- return strconv.Itoa(int(n))
-}
-
-// NextError values.
-const (
- NextErrorOk NextError = 1
- NextErrorTimeoutExpired NextError = 0
- NextErrorReadError NextError = -1
- // NextErrorNoMorePackets is returned when reading from a file (OpenOffline) and
- // EOF is reached. When this happens, Next() returns io.EOF instead of this.
- NextErrorNoMorePackets NextError = -2
- NextErrorNotActivated NextError = -3
-)
-
-// ReadPacketData returns the next packet read from the pcap handle, along with an error
-// code associated with that packet. If the packet is read successfully, the
-// returned error is nil.
-func (p *Handle) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
- p.mu.Lock()
- err = p.getNextBufPtrLocked(&ci)
- if err == nil {
- data = make([]byte, ci.CaptureLength)
- copy(data, (*(*[1 << 30]byte)(unsafe.Pointer(p.bufptr)))[:])
- }
- p.mu.Unlock()
- if err == NextErrorTimeoutExpired {
- runtime.Gosched()
- }
- return
-}
-
-type activateError int
-
-const (
- aeNoError = activateError(0)
- aeActivated = activateError(pcapErrorActivated)
- aePromisc = activateError(pcapWarningPromisc)
- aeNoSuchDevice = activateError(pcapErrorNoSuchDevice)
- aeDenied = activateError(pcapErrorDenied)
- aeNotUp = activateError(pcapErrorNotUp)
- aeWarning = activateError(pcapWarning)
-)
-
-func (a activateError) Error() string {
- switch a {
- case aeNoError:
- return "No Error"
- case aeActivated:
- return "Already Activated"
- case aePromisc:
- return "Cannot set as promisc"
- case aeNoSuchDevice:
- return "No Such Device"
- case aeDenied:
- return "Permission Denied"
- case aeNotUp:
- return "Interface Not Up"
- case aeWarning:
- return fmt.Sprintf("Warning: %v", activateErrMsg.Error())
- default:
- return fmt.Sprintf("unknown activated error: %d", a)
- }
-}
-
-// getNextBufPtrLocked is shared code for ReadPacketData and
-// ZeroCopyReadPacketData.
-func (p *Handle) getNextBufPtrLocked(ci *gopacket.CaptureInfo) error {
- if !p.isOpen() {
- return io.EOF
- }
-
- // set after we have call waitForPacket for the first time
- var waited bool
-
- for atomic.LoadUint64(&p.stop) == 0 {
- // try to read a packet if one is immediately available
- result := p.pcapNextPacketEx()
-
- switch result {
- case NextErrorOk:
- sec := p.pkthdr.getSec()
- // convert micros to nanos
- nanos := int64(p.pkthdr.getUsec()) * p.nanoSecsFactor
-
- ci.Timestamp = time.Unix(sec, nanos)
- ci.CaptureLength = p.pkthdr.getCaplen()
- ci.Length = p.pkthdr.getLen()
- ci.InterfaceIndex = p.deviceIndex
-
- return nil
- case NextErrorNoMorePackets:
- // no more packets, return EOF rather than libpcap-specific error
- return io.EOF
- case NextErrorTimeoutExpired:
- // we've already waited for a packet and we're supposed to time out
- //
- // we should never actually hit this if we were passed BlockForever
- // since we should block on C.pcap_next_ex until there's a packet
- // to read.
- if waited && p.timeout > 0 {
- return result
- }
-
- // wait for packet before trying again
- p.waitForPacket()
- waited = true
- default:
- return result
- }
- }
-
- // stop must be set
- return io.EOF
-}
-
-// ZeroCopyReadPacketData reads the next packet off the wire, and returns its data.
-// The slice returned by ZeroCopyReadPacketData points to bytes owned by the
-// the Handle. Each call to ZeroCopyReadPacketData invalidates any data previously
-// returned by ZeroCopyReadPacketData. Care must be taken not to keep pointers
-// to old bytes when using ZeroCopyReadPacketData... if you need to keep data past
-// the next time you call ZeroCopyReadPacketData, use ReadPacketData, which copies
-// the bytes into a new buffer for you.
-// data1, _, _ := handle.ZeroCopyReadPacketData()
-// // do everything you want with data1 here, copying bytes out of it if you'd like to keep them around.
-// data2, _, _ := handle.ZeroCopyReadPacketData() // invalidates bytes in data1
-func (p *Handle) ZeroCopyReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
- p.mu.Lock()
- err = p.getNextBufPtrLocked(&ci)
- if err == nil {
- slice := (*reflect.SliceHeader)(unsafe.Pointer(&data))
- slice.Data = uintptr(unsafe.Pointer(p.bufptr))
- slice.Len = ci.CaptureLength
- slice.Cap = ci.CaptureLength
- }
- p.mu.Unlock()
- if err == NextErrorTimeoutExpired {
- runtime.Gosched()
- }
- return
-}
-
-// Close closes the underlying pcap handle.
-func (p *Handle) Close() {
- p.closeMu.Lock()
- defer p.closeMu.Unlock()
-
- if !p.isOpen() {
- return
- }
-
- atomic.StoreUint64(&p.stop, 1)
-
- // wait for packet reader to stop
- p.mu.Lock()
- defer p.mu.Unlock()
-
- p.pcapClose()
-}
-
-// Error returns the current error associated with a pcap handle (pcap_geterr).
-func (p *Handle) Error() error {
- return p.pcapGeterr()
-}
-
-// Stats returns statistics on the underlying pcap handle.
-func (p *Handle) Stats() (stat *Stats, err error) {
- return p.pcapStats()
-}
-
-// ListDataLinks obtains a list of all possible data link types supported for an interface.
-func (p *Handle) ListDataLinks() (datalinks []Datalink, err error) {
- return p.pcapListDatalinks()
-}
-
-// compileBPFFilter always returns an allocated C.struct_bpf_program
-// It is the callers responsibility to free the memory again, e.g.
-//
-// C.pcap_freecode(&bpf)
-//
-func (p *Handle) compileBPFFilter(expr string) (pcapBpfProgram, error) {
- var maskp = uint32(pcapNetmaskUnknown)
-
- // Only do the lookup on network interfaces.
- // No device indicates we're handling a pcap file.
- if len(p.device) > 0 {
- var err error
- _, maskp, err = pcapLookupnet(p.device)
- if err != nil {
- // We can't lookup the network, but that could be because the interface
- // doesn't have an IPv4.
- maskp = uint32(pcapNetmaskUnknown)
- }
- }
-
- return p.pcapCompile(expr, maskp)
-}
-
-// CompileBPFFilter compiles and returns a BPF filter with given a link type and capture length.
-func CompileBPFFilter(linkType layers.LinkType, captureLength int, expr string) ([]BPFInstruction, error) {
- h, err := pcapOpenDead(linkType, captureLength)
- if err != nil {
- return nil, err
- }
- defer h.Close()
- return h.CompileBPFFilter(expr)
-}
-
-// CompileBPFFilter compiles and returns a BPF filter for the pcap handle.
-func (p *Handle) CompileBPFFilter(expr string) ([]BPFInstruction, error) {
- bpf, err := p.compileBPFFilter(expr)
- defer bpf.free()
- if err != nil {
- return nil, err
- }
-
- return bpf.toBPFInstruction(), nil
-}
-
-// SetBPFFilter compiles and sets a BPF filter for the pcap handle.
-func (p *Handle) SetBPFFilter(expr string) (err error) {
- bpf, err := p.compileBPFFilter(expr)
- defer bpf.free()
- if err != nil {
- return err
- }
-
- return p.pcapSetfilter(bpf)
-}
-
-// SetBPFInstructionFilter may be used to apply a filter in BPF asm byte code format.
-//
-// Simplest way to generate BPF asm byte code is with tcpdump:
-// tcpdump -dd 'udp'
-//
-// The output may be used directly to add a filter, e.g.:
-// bpfInstructions := []pcap.BpfInstruction{
-// {0x28, 0, 0, 0x0000000c},
-// {0x15, 0, 9, 0x00000800},
-// {0x30, 0, 0, 0x00000017},
-// {0x15, 0, 7, 0x00000006},
-// {0x28, 0, 0, 0x00000014},
-// {0x45, 5, 0, 0x00001fff},
-// {0xb1, 0, 0, 0x0000000e},
-// {0x50, 0, 0, 0x0000001b},
-// {0x54, 0, 0, 0x00000012},
-// {0x15, 0, 1, 0x00000012},
-// {0x6, 0, 0, 0x0000ffff},
-// {0x6, 0, 0, 0x00000000},
-// }
-//
-// An other posibility is to write the bpf code in bpf asm.
-// Documentation: https://www.kernel.org/doc/Documentation/networking/filter.txt
-//
-// To compile the code use bpf_asm from
-// https://github.com/torvalds/linux/tree/master/tools/net
-//
-// The following command may be used to convert bpf_asm output to c/go struct, usable for SetBPFFilterByte:
-// bpf_asm -c tcp.bpf
-func (p *Handle) SetBPFInstructionFilter(bpfInstructions []BPFInstruction) (err error) {
- bpf, err := bpfInstructionFilter(bpfInstructions)
- if err != nil {
- return err
- }
- defer bpf.free()
-
- return p.pcapSetfilter(bpf)
-}
-
-func bpfInstructionFilter(bpfInstructions []BPFInstruction) (bpf pcapBpfProgram, err error) {
- if len(bpfInstructions) < 1 {
- return bpf, errors.New("bpfInstructions must not be empty")
- }
-
- if len(bpfInstructions) > MaxBpfInstructions {
- return bpf, fmt.Errorf("bpfInstructions must not be larger than %d", MaxBpfInstructions)
- }
-
- return pcapBpfProgramFromInstructions(bpfInstructions), nil
-}
-
-// NewBPF compiles the given string into a new filter program.
-//
-// BPF filters need to be created from activated handles, because they need to
-// know the underlying link type to correctly compile their offsets.
-func (p *Handle) NewBPF(expr string) (*BPF, error) {
- bpf := &BPF{orig: expr}
-
- var err error
- bpf.bpf, err = p.pcapCompile(expr, pcapNetmaskUnknown)
- if err != nil {
- return nil, err
- }
-
- runtime.SetFinalizer(bpf, destroyBPF)
- return bpf, nil
-}
-
-// NewBPF allows to create a BPF without requiring an existing handle.
-// This allows to match packets obtained from a-non GoPacket capture source
-// to be matched.
-//
-// buf := make([]byte, MaxFrameSize)
-// bpfi, _ := pcap.NewBPF(layers.LinkTypeEthernet, MaxFrameSize, "icmp")
-// n, _ := someIO.Read(buf)
-// ci := gopacket.CaptureInfo{CaptureLength: n, Length: n}
-// if bpfi.Matches(ci, buf) {
-// doSomething()
-// }
-func NewBPF(linkType layers.LinkType, captureLength int, expr string) (*BPF, error) {
- h, err := pcapOpenDead(linkType, captureLength)
- if err != nil {
- return nil, err
- }
- defer h.Close()
- return h.NewBPF(expr)
-}
-
-// NewBPFInstructionFilter sets the given BPFInstructions as new filter program.
-//
-// More details see func SetBPFInstructionFilter
-//
-// BPF filters need to be created from activated handles, because they need to
-// know the underlying link type to correctly compile their offsets.
-func (p *Handle) NewBPFInstructionFilter(bpfInstructions []BPFInstruction) (*BPF, error) {
- var err error
- bpf := &BPF{orig: "BPF Instruction Filter"}
-
- bpf.bpf, err = bpfInstructionFilter(bpfInstructions)
- if err != nil {
- return nil, err
- }
-
- runtime.SetFinalizer(bpf, destroyBPF)
- return bpf, nil
-}
-func destroyBPF(bpf *BPF) {
- bpf.bpf.free()
-}
-
-// String returns the original string this BPF filter was compiled from.
-func (b *BPF) String() string {
- return b.orig
-}
-
-// Matches returns true if the given packet data matches this filter.
-func (b *BPF) Matches(ci gopacket.CaptureInfo, data []byte) bool {
- return b.pcapOfflineFilter(ci, data)
-}
-
-// Version returns pcap_lib_version.
-func Version() string {
- return pcapLibVersion()
-}
-
-// LinkType returns pcap_datalink, as a layers.LinkType.
-func (p *Handle) LinkType() layers.LinkType {
- return p.pcapDatalink()
-}
-
-// SetLinkType calls pcap_set_datalink on the pcap handle.
-func (p *Handle) SetLinkType(dlt layers.LinkType) error {
- return p.pcapSetDatalink(dlt)
-}
-
-// DatalinkValToName returns pcap_datalink_val_to_name as string
-func DatalinkValToName(dlt int) string {
- return pcapDatalinkValToName(dlt)
-}
-
-// DatalinkValToDescription returns pcap_datalink_val_to_description as string
-func DatalinkValToDescription(dlt int) string {
- return pcapDatalinkValToDescription(dlt)
-}
-
-// DatalinkNameToVal returns pcap_datalink_name_to_val as int
-func DatalinkNameToVal(name string) int {
- return pcapDatalinkNameToVal(name)
-}
-
-// FindAllDevs attempts to enumerate all interfaces on the current machine.
-func FindAllDevs() (ifs []Interface, err error) {
- alldevsp, err := pcapFindAllDevs()
- if err != nil {
- return nil, err
- }
- defer alldevsp.free()
-
- for alldevsp.next() {
- var iface Interface
- iface.Name = alldevsp.name()
- iface.Description = alldevsp.description()
- iface.Addresses = findalladdresses(alldevsp.addresses())
- iface.Flags = alldevsp.flags()
- ifs = append(ifs, iface)
- }
- return
-}
-
-func findalladdresses(addresses pcapAddresses) (retval []InterfaceAddress) {
- // TODO - make it support more than IPv4 and IPv6?
- retval = make([]InterfaceAddress, 0, 1)
- for addresses.next() {
- // Strangely, it appears that in some cases, we get a pcap address back from
- // pcap_findalldevs with a nil .addr. It appears that we can skip over
- // these.
- if addresses.addr() == nil {
- continue
- }
- var a InterfaceAddress
- var err error
- if a.IP, err = sockaddrToIP(addresses.addr()); err != nil {
- continue
- }
- // To be safe, we'll also check for netmask.
- if addresses.netmask() == nil {
- continue
- }
- if a.Netmask, err = sockaddrToIP(addresses.netmask()); err != nil {
- // If we got an IP address but we can't get a netmask, just return the IP
- // address.
- a.Netmask = nil
- }
- if a.Broadaddr, err = sockaddrToIP(addresses.broadaddr()); err != nil {
- a.Broadaddr = nil
- }
- if a.P2P, err = sockaddrToIP(addresses.dstaddr()); err != nil {
- a.P2P = nil
- }
- retval = append(retval, a)
- }
- return
-}
-
-func sockaddrToIP(rsa *syscall.RawSockaddr) (IP []byte, err error) {
- if rsa == nil {
- err = errors.New("Value not set")
- return
- }
- switch rsa.Family {
- case syscall.AF_INET:
- pp := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa))
- IP = make([]byte, 4)
- for i := 0; i < len(IP); i++ {
- IP[i] = pp.Addr[i]
- }
- return
- case syscall.AF_INET6:
- pp := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa))
- IP = make([]byte, 16)
- for i := 0; i < len(IP); i++ {
- IP[i] = pp.Addr[i]
- }
- return
- }
- err = errors.New("Unsupported address type")
- return
-}
-
-// WritePacketData calls pcap_sendpacket, injecting the given data into the pcap handle.
-func (p *Handle) WritePacketData(data []byte) (err error) {
- return p.pcapSendpacket(data)
-}
-
-// Direction is used by Handle.SetDirection.
-type Direction uint8
-
-// Direction values for Handle.SetDirection.
-const (
- DirectionIn = Direction(pcapDIN)
- DirectionOut = Direction(pcapDOUT)
- DirectionInOut = Direction(pcapDINOUT)
-)
-
-// SetDirection sets the direction for which packets will be captured.
-func (p *Handle) SetDirection(direction Direction) error {
- if direction != DirectionIn && direction != DirectionOut && direction != DirectionInOut {
- return fmt.Errorf("Invalid direction: %v", direction)
- }
- return p.pcapSetdirection(direction)
-}
-
-// SnapLen returns the snapshot length
-func (p *Handle) SnapLen() int {
- return p.pcapSnapshot()
-}
-
-// Resolution returns the timestamp resolution of acquired timestamps before scaling to NanosecondTimestampResolution.
-func (p *Handle) Resolution() gopacket.TimestampResolution {
- if p.nanoSecsFactor == 1 {
- return gopacket.TimestampResolutionMicrosecond
- }
- return gopacket.TimestampResolutionNanosecond
-}
-
-// TimestampSource tells PCAP which type of timestamp to use for packets.
-type TimestampSource int
-
-// String returns the timestamp type as a human-readable string.
-func (t TimestampSource) String() string {
- return t.pcapTstampTypeValToName()
-}
-
-// TimestampSourceFromString translates a string into a timestamp type, case
-// insensitive.
-func TimestampSourceFromString(s string) (TimestampSource, error) {
- return pcapTstampTypeNameToVal(s)
-}
-
-// InactiveHandle allows you to call pre-pcap_activate functions on your pcap
-// handle to set it up just the way you'd like.
-type InactiveHandle struct {
- // cptr is the handle for the actual pcap C object.
- cptr pcapTPtr
- device string
- deviceIndex int
- timeout time.Duration
-}
-
-// holds the err messoge in case activation returned a Warning
-var activateErrMsg error
-
-// Error returns the current error associated with a pcap handle (pcap_geterr).
-func (p *InactiveHandle) Error() error {
- return p.pcapGeterr()
-}
-
-// Activate activates the handle. The current InactiveHandle becomes invalid
-// and all future function calls on it will fail.
-func (p *InactiveHandle) Activate() (*Handle, error) {
- // ignore error with set_tstamp_precision, since the actual precision is queried later anyway
- pcapSetTstampPrecision(p.cptr, pcapTstampPrecisionNano)
- handle, err := p.pcapActivate()
- if err != aeNoError {
- if err == aeWarning {
- activateErrMsg = p.Error()
- }
- return nil, err
- }
- handle.timeout = p.timeout
- if p.timeout > 0 {
- if err := handle.setNonBlocking(); err != nil {
- handle.pcapClose()
- return nil, err
- }
- }
- handle.device = p.device
- handle.deviceIndex = p.deviceIndex
- if pcapGetTstampPrecision(handle.cptr) == pcapTstampPrecisionNano {
- handle.nanoSecsFactor = 1
- } else {
- handle.nanoSecsFactor = 1000
- }
- return handle, nil
-}
-
-// CleanUp cleans up any stuff left over from a successful or failed building
-// of a handle.
-func (p *InactiveHandle) CleanUp() {
- p.pcapClose()
-}
-
-// NewInactiveHandle creates a new InactiveHandle, which wraps an un-activated PCAP handle.
-// Callers of NewInactiveHandle should immediately defer 'CleanUp', as in:
-// inactive := NewInactiveHandle("eth0")
-// defer inactive.CleanUp()
-func NewInactiveHandle(device string) (*InactiveHandle, error) {
- // Try to get the interface index, but iy could be something like "any"
- // in which case use 0, which doesn't exist in nature
- deviceIndex := 0
- ifc, err := net.InterfaceByName(device)
- if err == nil {
- deviceIndex = ifc.Index
- }
-
- // This copies a bunch of the pcap_open_live implementation from pcap.c:
- handle, err := pcapCreate(device)
- if err != nil {
- return nil, err
- }
- handle.device = device
- handle.deviceIndex = deviceIndex
- return handle, nil
-}
-
-// SetSnapLen sets the snap length (max bytes per packet to capture).
-func (p *InactiveHandle) SetSnapLen(snaplen int) error {
- return p.pcapSetSnaplen(snaplen)
-}
-
-// SetPromisc sets the handle to either be promiscuous (capture packets
-// unrelated to this host) or not.
-func (p *InactiveHandle) SetPromisc(promisc bool) error {
- return p.pcapSetPromisc(promisc)
-}
-
-// SetTimeout sets the read timeout for the handle.
-//
-// See the package documentation for important details regarding 'timeout'.
-func (p *InactiveHandle) SetTimeout(timeout time.Duration) error {
- err := p.pcapSetTimeout(timeout)
- if err != nil {
- return err
- }
- p.timeout = timeout
- return nil
-}
-
-// SupportedTimestamps returns a list of supported timstamp types for this
-// handle.
-func (p *InactiveHandle) SupportedTimestamps() (out []TimestampSource) {
- return p.pcapListTstampTypes()
-}
-
-// SetTimestampSource sets the type of timestamp generator PCAP uses when
-// attaching timestamps to packets.
-func (p *InactiveHandle) SetTimestampSource(t TimestampSource) error {
- return p.pcapSetTstampType(t)
-}
-
-// CannotSetRFMon is returned by SetRFMon if the handle does not allow
-// setting RFMon because pcap_can_set_rfmon returns 0.
-var CannotSetRFMon = errors.New("Cannot set rfmon for this handle")
-
-// SetRFMon turns on radio monitoring mode, similar to promiscuous mode but for
-// wireless networks. If this mode is enabled, the interface will not need to
-// associate with an access point before it can receive traffic.
-func (p *InactiveHandle) SetRFMon(monitor bool) error {
- return p.pcapSetRfmon(monitor)
-}
-
-// SetBufferSize sets the buffer size (in bytes) of the handle.
-func (p *InactiveHandle) SetBufferSize(bufferSize int) error {
- return p.pcapSetBufferSize(bufferSize)
-}
-
-// SetImmediateMode sets (or unsets) the immediate mode of the
-// handle. In immediate mode, packets are delivered to the application
-// as soon as they arrive. In other words, this overrides SetTimeout.
-func (p *InactiveHandle) SetImmediateMode(mode bool) error {
- return p.pcapSetImmediateMode(mode)
-}
diff --git a/vendor/github.com/google/gopacket/pcap/pcap_unix.go b/vendor/github.com/google/gopacket/pcap/pcap_unix.go
deleted file mode 100644
index 4d6a4fb..0000000
--- a/vendor/github.com/google/gopacket/pcap/pcap_unix.go
+++ /dev/null
@@ -1,709 +0,0 @@
-// Copyright 2012 Google, Inc. All rights reserved.
-// Copyright 2009-2011 Andreas Krennmair. 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.
-//
-// +build !windows
-
-package pcap
-
-import (
- "errors"
- "os"
- "sync"
- "syscall"
- "time"
- "unsafe"
-
- "github.com/google/gopacket"
-
- "github.com/google/gopacket/layers"
-)
-
-/*
-#cgo solaris LDFLAGS: -L /opt/local/lib -lpcap
-#cgo linux LDFLAGS: -lpcap
-#cgo dragonfly LDFLAGS: -lpcap
-#cgo freebsd LDFLAGS: -lpcap
-#cgo openbsd LDFLAGS: -lpcap
-#cgo netbsd LDFLAGS: -lpcap
-#cgo darwin LDFLAGS: -lpcap
-#include <stdlib.h>
-#include <pcap.h>
-#include <stdint.h>
-
-// Some old versions of pcap don't define this constant.
-#ifndef PCAP_NETMASK_UNKNOWN
-#define PCAP_NETMASK_UNKNOWN 0xffffffff
-#endif
-
-// libpcap doesn't actually export its version in a #define-guardable way,
-// so we have to use other defined things to differentiate versions.
-// We assume at least libpcap v1.1 at the moment.
-// See http://upstream-tracker.org/versions/libpcap.html
-
-#ifndef PCAP_ERROR_TSTAMP_PRECISION_NOTSUP // < v1.5
-#define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12
-
-int pcap_set_immediate_mode(pcap_t *p, int mode) {
- return PCAP_ERROR;
-}
-
-// libpcap version < v1.5 doesn't have timestamp precision (everything is microsecond)
-//
-// This means *_tstamp_* functions and macros are missing. Therefore, we emulate these
-// functions here and pretend the setting the precision works. This is actually the way
-// the pcap_open_offline_with_tstamp_precision works, because it doesn't return an error
-// if it was not possible to set the precision, which depends on support by the given file.
-// => The rest of the functions always pretend as if they could set nano precision and
-// verify the actual precision with pcap_get_tstamp_precision, which is emulated for <v1.5
-// to always return micro resolution.
-
-#define PCAP_TSTAMP_PRECISION_MICRO 0
-#define PCAP_TSTAMP_PRECISION_NANO 1
-
-pcap_t *pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
- char *errbuf) {
- return pcap_open_offline(fname, errbuf);
-}
-
-pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
- char *errbuf) {
- return pcap_fopen_offline(fp, errbuf);
-}
-
-int pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision) {
- if (tstamp_precision == PCAP_TSTAMP_PRECISION_MICRO)
- return 0;
- return PCAP_ERROR_TSTAMP_PRECISION_NOTSUP;
-}
-
-int pcap_get_tstamp_precision(pcap_t *p) {
- return PCAP_TSTAMP_PRECISION_MICRO;
-}
-
-#ifndef PCAP_TSTAMP_HOST // < v1.2
-
-int pcap_set_tstamp_type(pcap_t* p, int t) { return -1; }
-int pcap_list_tstamp_types(pcap_t* p, int** t) { return 0; }
-void pcap_free_tstamp_types(int *tstamp_types) {}
-const char* pcap_tstamp_type_val_to_name(int t) {
- return "pcap timestamp types not supported";
-}
-int pcap_tstamp_type_name_to_val(const char* t) {
- return PCAP_ERROR;
-}
-
-#endif // < v1.2
-#endif // < v1.5
-
-#ifndef PCAP_ERROR_PROMISC_PERM_DENIED
-#define PCAP_ERROR_PROMISC_PERM_DENIED -11
-#endif
-
-// Windows, Macs, and Linux all use different time types. Joy.
-#ifdef __APPLE__
-#define gopacket_time_secs_t __darwin_time_t
-#define gopacket_time_usecs_t __darwin_suseconds_t
-#elif __ANDROID__
-#define gopacket_time_secs_t __kernel_time_t
-#define gopacket_time_usecs_t __kernel_suseconds_t
-#elif __GLIBC__
-#define gopacket_time_secs_t __time_t
-#define gopacket_time_usecs_t __suseconds_t
-#else // Some form of linux/bsd/etc...
-#include <sys/param.h>
-#ifdef __OpenBSD__
-#define gopacket_time_secs_t u_int32_t
-#define gopacket_time_usecs_t u_int32_t
-#else
-#define gopacket_time_secs_t time_t
-#define gopacket_time_usecs_t suseconds_t
-#endif
-#endif
-
-// The things we do to avoid pointers escaping to the heap...
-// According to https://github.com/the-tcpdump-group/libpcap/blob/1131a7c26c6f4d4772e4a2beeaf7212f4dea74ac/pcap.c#L398-L406 ,
-// the return value of pcap_next_ex could be greater than 1 for success.
-// Let's just make it 1 if it comes bigger than 1.
-int pcap_next_ex_escaping(pcap_t *p, uintptr_t pkt_hdr, uintptr_t pkt_data) {
- int ex = pcap_next_ex(p, (struct pcap_pkthdr**)(pkt_hdr), (const u_char**)(pkt_data));
- if (ex > 1) {
- ex = 1;
- }
- return ex;
-}
-
-int pcap_offline_filter_escaping(struct bpf_program *fp, uintptr_t pkt_hdr, uintptr_t pkt) {
- return pcap_offline_filter(fp, (struct pcap_pkthdr*)(pkt_hdr), (const u_char*)(pkt));
-}
-
-// pcap_wait returns when the next packet is available or the timeout expires.
-// Since it uses pcap_get_selectable_fd, it will not work in Windows.
-int pcap_wait(pcap_t *p, int usec) {
- fd_set fds;
- int fd;
- struct timeval tv;
-
- fd = pcap_get_selectable_fd(p);
- if(fd < 0) {
- return fd;
- }
-
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
-
- tv.tv_sec = 0;
- tv.tv_usec = usec;
-
- if(usec != 0) {
- return select(fd+1, &fds, NULL, NULL, &tv);
- }
-
- // block indefinitely if no timeout provided
- return select(fd+1, &fds, NULL, NULL, NULL);
-}
-
-*/
-import "C"
-
-const errorBufferSize = C.PCAP_ERRBUF_SIZE
-
-const (
- pcapErrorNotActivated = C.PCAP_ERROR_NOT_ACTIVATED
- pcapErrorActivated = C.PCAP_ERROR_ACTIVATED
- pcapWarningPromisc = C.PCAP_WARNING_PROMISC_NOTSUP
- pcapErrorNoSuchDevice = C.PCAP_ERROR_NO_SUCH_DEVICE
- pcapErrorDenied = C.PCAP_ERROR_PERM_DENIED
- pcapErrorNotUp = C.PCAP_ERROR_IFACE_NOT_UP
- pcapWarning = C.PCAP_WARNING
- pcapDIN = C.PCAP_D_IN
- pcapDOUT = C.PCAP_D_OUT
- pcapDINOUT = C.PCAP_D_INOUT
- pcapNetmaskUnknown = C.PCAP_NETMASK_UNKNOWN
- pcapTstampPrecisionMicro = C.PCAP_TSTAMP_PRECISION_MICRO
- pcapTstampPrecisionNano = C.PCAP_TSTAMP_PRECISION_NANO
-)
-
-type pcapPkthdr C.struct_pcap_pkthdr
-type pcapTPtr *C.struct_pcap
-type pcapBpfProgram C.struct_bpf_program
-
-func (h *pcapPkthdr) getSec() int64 {
- return int64(h.ts.tv_sec)
-}
-
-func (h *pcapPkthdr) getUsec() int64 {
- return int64(h.ts.tv_usec)
-}
-
-func (h *pcapPkthdr) getLen() int {
- return int(h.len)
-}
-
-func (h *pcapPkthdr) getCaplen() int {
- return int(h.caplen)
-}
-
-func pcapGetTstampPrecision(cptr pcapTPtr) int {
- return int(C.pcap_get_tstamp_precision(cptr))
-}
-
-func pcapSetTstampPrecision(cptr pcapTPtr, precision int) error {
- ret := C.pcap_set_tstamp_precision(cptr, C.int(precision))
- if ret < 0 {
- return errors.New(C.GoString(C.pcap_geterr(cptr)))
- }
- return nil
-}
-
-func statusError(status C.int) error {
- return errors.New(C.GoString(C.pcap_statustostr(status)))
-}
-
-func pcapOpenLive(device string, snaplen int, pro int, timeout int) (*Handle, error) {
- buf := (*C.char)(C.calloc(errorBufferSize, 1))
- defer C.free(unsafe.Pointer(buf))
-
- dev := C.CString(device)
- defer C.free(unsafe.Pointer(dev))
-
- cptr := C.pcap_open_live(dev, C.int(snaplen), C.int(pro), C.int(timeout), buf)
- if cptr == nil {
- return nil, errors.New(C.GoString(buf))
- }
- return &Handle{cptr: cptr}, nil
-}
-
-func openOffline(file string) (handle *Handle, err error) {
- buf := (*C.char)(C.calloc(errorBufferSize, 1))
- defer C.free(unsafe.Pointer(buf))
- cf := C.CString(file)
- defer C.free(unsafe.Pointer(cf))
-
- cptr := C.pcap_open_offline_with_tstamp_precision(cf, C.PCAP_TSTAMP_PRECISION_NANO, buf)
- if cptr == nil {
- return nil, errors.New(C.GoString(buf))
- }
- return &Handle{cptr: cptr}, nil
-}
-
-func (p *Handle) pcapClose() {
- if p.cptr != nil {
- C.pcap_close(p.cptr)
- }
- p.cptr = nil
-}
-
-func (p *Handle) pcapGeterr() error {
- return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
-}
-
-func (p *Handle) pcapStats() (*Stats, error) {
- var cstats C.struct_pcap_stat
- if C.pcap_stats(p.cptr, &cstats) < 0 {
- return nil, p.pcapGeterr()
- }
- return &Stats{
- PacketsReceived: int(cstats.ps_recv),
- PacketsDropped: int(cstats.ps_drop),
- PacketsIfDropped: int(cstats.ps_ifdrop),
- }, nil
-}
-
-// for libpcap < 1.8 pcap_compile is NOT thread-safe, so protect it.
-var pcapCompileMu sync.Mutex
-
-func (p *Handle) pcapCompile(expr string, maskp uint32) (pcapBpfProgram, error) {
- var bpf pcapBpfProgram
- cexpr := C.CString(expr)
- defer C.free(unsafe.Pointer(cexpr))
-
- pcapCompileMu.Lock()
- defer pcapCompileMu.Unlock()
- if C.pcap_compile(p.cptr, (*C.struct_bpf_program)(&bpf), cexpr, 1, C.bpf_u_int32(maskp)) < 0 {
- return bpf, p.pcapGeterr()
- }
- return bpf, nil
-}
-
-func (p pcapBpfProgram) free() {
- C.pcap_freecode((*C.struct_bpf_program)(&p))
-}
-
-func (p pcapBpfProgram) toBPFInstruction() []BPFInstruction {
- bpfInsn := (*[bpfInstructionBufferSize]C.struct_bpf_insn)(unsafe.Pointer(p.bf_insns))[0:p.bf_len:p.bf_len]
- bpfInstruction := make([]BPFInstruction, len(bpfInsn), len(bpfInsn))
-
- for i, v := range bpfInsn {
- bpfInstruction[i].Code = uint16(v.code)
- bpfInstruction[i].Jt = uint8(v.jt)
- bpfInstruction[i].Jf = uint8(v.jf)
- bpfInstruction[i].K = uint32(v.k)
- }
- return bpfInstruction
-}
-
-func pcapBpfProgramFromInstructions(bpfInstructions []BPFInstruction) pcapBpfProgram {
- var bpf pcapBpfProgram
- bpf.bf_len = C.u_int(len(bpfInstructions))
- cbpfInsns := C.calloc(C.size_t(len(bpfInstructions)), C.size_t(unsafe.Sizeof(bpfInstructions[0])))
- gbpfInsns := (*[bpfInstructionBufferSize]C.struct_bpf_insn)(cbpfInsns)
-
- for i, v := range bpfInstructions {
- gbpfInsns[i].code = C.u_short(v.Code)
- gbpfInsns[i].jt = C.u_char(v.Jt)
- gbpfInsns[i].jf = C.u_char(v.Jf)
- gbpfInsns[i].k = C.bpf_u_int32(v.K)
- }
-
- bpf.bf_insns = (*C.struct_bpf_insn)(cbpfInsns)
- return bpf
-}
-
-func pcapLookupnet(device string) (netp, maskp uint32, err error) {
- errorBuf := (*C.char)(C.calloc(errorBufferSize, 1))
- defer C.free(unsafe.Pointer(errorBuf))
- dev := C.CString(device)
- defer C.free(unsafe.Pointer(dev))
- if C.pcap_lookupnet(
- dev,
- (*C.bpf_u_int32)(unsafe.Pointer(&netp)),
- (*C.bpf_u_int32)(unsafe.Pointer(&maskp)),
- errorBuf,
- ) < 0 {
- return 0, 0, errors.New(C.GoString(errorBuf))
- // We can't lookup the network, but that could be because the interface
- // doesn't have an IPv4.
- }
- return
-}
-
-func (b *BPF) pcapOfflineFilter(ci gopacket.CaptureInfo, data []byte) bool {
- hdr := (*C.struct_pcap_pkthdr)(&b.hdr)
- hdr.ts.tv_sec = C.gopacket_time_secs_t(ci.Timestamp.Unix())
- hdr.ts.tv_usec = C.gopacket_time_usecs_t(ci.Timestamp.Nanosecond() / 1000)
- hdr.caplen = C.bpf_u_int32(len(data)) // Trust actual length over ci.Length.
- hdr.len = C.bpf_u_int32(ci.Length)
- dataptr := (*C.u_char)(unsafe.Pointer(&data[0]))
- return C.pcap_offline_filter_escaping((*C.struct_bpf_program)(&b.bpf),
- C.uintptr_t(uintptr(unsafe.Pointer(hdr))),
- C.uintptr_t(uintptr(unsafe.Pointer(dataptr)))) != 0
-}
-
-func (p *Handle) pcapSetfilter(bpf pcapBpfProgram) error {
- if C.pcap_setfilter(p.cptr, (*C.struct_bpf_program)(&bpf)) < 0 {
- return p.pcapGeterr()
- }
- return nil
-}
-
-func (p *Handle) pcapListDatalinks() (datalinks []Datalink, err error) {
- var dltbuf *C.int
-
- n := int(C.pcap_list_datalinks(p.cptr, &dltbuf))
- if n < 0 {
- return nil, p.pcapGeterr()
- }
-
- defer C.pcap_free_datalinks(dltbuf)
-
- datalinks = make([]Datalink, n)
-
- dltArray := (*[1 << 28]C.int)(unsafe.Pointer(dltbuf))
-
- for i := 0; i < n; i++ {
- datalinks[i].Name = pcapDatalinkValToName(int((*dltArray)[i]))
- datalinks[i].Description = pcapDatalinkValToDescription(int((*dltArray)[i]))
- }
-
- return datalinks, nil
-}
-
-func pcapOpenDead(linkType layers.LinkType, captureLength int) (*Handle, error) {
- cptr := C.pcap_open_dead(C.int(linkType), C.int(captureLength))
- if cptr == nil {
- return nil, errors.New("error opening dead capture")
- }
-
- return &Handle{cptr: cptr}, nil
-}
-
-func (p *Handle) pcapNextPacketEx() NextError {
- // This horrible magic allows us to pass a ptr-to-ptr to pcap_next_ex
- // without causing that ptr-to-ptr to itself be allocated on the heap.
- // Since Handle itself survives through the duration of the pcap_next_ex
- // call, this should be perfectly safe for GC stuff, etc.
-
- return NextError(C.pcap_next_ex_escaping(p.cptr, C.uintptr_t(uintptr(unsafe.Pointer(&p.pkthdr))), C.uintptr_t(uintptr(unsafe.Pointer(&p.bufptr)))))
-}
-
-func (p *Handle) pcapDatalink() layers.LinkType {
- return layers.LinkType(C.pcap_datalink(p.cptr))
-}
-
-func (p *Handle) pcapSetDatalink(dlt layers.LinkType) error {
- if C.pcap_set_datalink(p.cptr, C.int(dlt)) < 0 {
- return p.pcapGeterr()
- }
- return nil
-}
-
-func pcapDatalinkValToName(dlt int) string {
- return C.GoString(C.pcap_datalink_val_to_name(C.int(dlt)))
-}
-
-func pcapDatalinkValToDescription(dlt int) string {
- return C.GoString(C.pcap_datalink_val_to_description(C.int(dlt)))
-}
-
-func pcapDatalinkNameToVal(name string) int {
- cptr := C.CString(name)
- defer C.free(unsafe.Pointer(cptr))
- return int(C.pcap_datalink_name_to_val(cptr))
-}
-
-func pcapLibVersion() string {
- return C.GoString(C.pcap_lib_version())
-}
-
-func (p *Handle) isOpen() bool {
- return p.cptr != nil
-}
-
-type pcapDevices struct {
- all, cur *C.pcap_if_t
-}
-
-func (p pcapDevices) free() {
- C.pcap_freealldevs((*C.pcap_if_t)(p.all))
-}
-
-func (p *pcapDevices) next() bool {
- if p.cur == nil {
- p.cur = p.all
- if p.cur == nil {
- return false
- }
- return true
- }
- if p.cur.next == nil {
- return false
- }
- p.cur = p.cur.next
- return true
-}
-
-func (p pcapDevices) name() string {
- return C.GoString(p.cur.name)
-}
-
-func (p pcapDevices) description() string {
- return C.GoString(p.cur.description)
-}
-
-func (p pcapDevices) flags() uint32 {
- return uint32(p.cur.flags)
-}
-
-type pcapAddresses struct {
- all, cur *C.pcap_addr_t
-}
-
-func (p *pcapAddresses) next() bool {
- if p.cur == nil {
- p.cur = p.all
- if p.cur == nil {
- return false
- }
- return true
- }
- if p.cur.next == nil {
- return false
- }
- p.cur = p.cur.next
- return true
-}
-
-func (p pcapAddresses) addr() *syscall.RawSockaddr {
- return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.addr))
-}
-
-func (p pcapAddresses) netmask() *syscall.RawSockaddr {
- return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.netmask))
-}
-
-func (p pcapAddresses) broadaddr() *syscall.RawSockaddr {
- return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.broadaddr))
-}
-
-func (p pcapAddresses) dstaddr() *syscall.RawSockaddr {
- return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.dstaddr))
-}
-
-func (p pcapDevices) addresses() pcapAddresses {
- return pcapAddresses{all: p.cur.addresses}
-}
-
-func pcapFindAllDevs() (pcapDevices, error) {
- var buf *C.char
- buf = (*C.char)(C.calloc(errorBufferSize, 1))
- defer C.free(unsafe.Pointer(buf))
- var alldevsp pcapDevices
-
- if C.pcap_findalldevs((**C.pcap_if_t)(&alldevsp.all), buf) < 0 {
- return pcapDevices{}, errors.New(C.GoString(buf))
- }
- return alldevsp, nil
-}
-
-func (p *Handle) pcapSendpacket(data []byte) error {
- if C.pcap_sendpacket(p.cptr, (*C.u_char)(&data[0]), (C.int)(len(data))) < 0 {
- return p.pcapGeterr()
- }
- return nil
-}
-
-func (p *Handle) pcapSetdirection(direction Direction) error {
- if status := C.pcap_setdirection(p.cptr, (C.pcap_direction_t)(direction)); status < 0 {
- return statusError(status)
- }
- return nil
-}
-
-func (p *Handle) pcapSnapshot() int {
- return int(C.pcap_snapshot(p.cptr))
-}
-
-func (t TimestampSource) pcapTstampTypeValToName() string {
- return C.GoString(C.pcap_tstamp_type_val_to_name(C.int(t)))
-}
-
-func pcapTstampTypeNameToVal(s string) (TimestampSource, error) {
- cs := C.CString(s)
- defer C.free(unsafe.Pointer(cs))
- t := C.pcap_tstamp_type_name_to_val(cs)
- if t < 0 {
- return 0, statusError(t)
- }
- return TimestampSource(t), nil
-}
-
-func (p *InactiveHandle) pcapGeterr() error {
- return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
-}
-
-func (p *InactiveHandle) pcapActivate() (*Handle, activateError) {
- ret := activateError(C.pcap_activate(p.cptr))
- if ret != aeNoError {
- return nil, ret
- }
- h := &Handle{
- cptr: p.cptr,
- }
- p.cptr = nil
- return h, ret
-}
-
-func (p *InactiveHandle) pcapClose() {
- if p.cptr != nil {
- C.pcap_close(p.cptr)
- }
-}
-
-func pcapCreate(device string) (*InactiveHandle, error) {
- buf := (*C.char)(C.calloc(errorBufferSize, 1))
- defer C.free(unsafe.Pointer(buf))
- dev := C.CString(device)
- defer C.free(unsafe.Pointer(dev))
-
- cptr := C.pcap_create(dev, buf)
- if cptr == nil {
- return nil, errors.New(C.GoString(buf))
- }
- return &InactiveHandle{cptr: cptr}, nil
-}
-
-func (p *InactiveHandle) pcapSetSnaplen(snaplen int) error {
- if status := C.pcap_set_snaplen(p.cptr, C.int(snaplen)); status < 0 {
- return statusError(status)
- }
- return nil
-}
-
-func (p *InactiveHandle) pcapSetPromisc(promisc bool) error {
- var pro C.int
- if promisc {
- pro = 1
- }
- if status := C.pcap_set_promisc(p.cptr, pro); status < 0 {
- return statusError(status)
- }
- return nil
-}
-
-func (p *InactiveHandle) pcapSetTimeout(timeout time.Duration) error {
- if status := C.pcap_set_timeout(p.cptr, C.int(timeoutMillis(timeout))); status < 0 {
- return statusError(status)
- }
- return nil
-}
-
-func (p *InactiveHandle) pcapListTstampTypes() (out []TimestampSource) {
- var types *C.int
- n := int(C.pcap_list_tstamp_types(p.cptr, &types))
- if n < 0 {
- return // public interface doesn't have error :(
- }
- defer C.pcap_free_tstamp_types(types)
- typesArray := (*[1 << 28]C.int)(unsafe.Pointer(types))
- for i := 0; i < n; i++ {
- out = append(out, TimestampSource((*typesArray)[i]))
- }
- return
-}
-
-func (p *InactiveHandle) pcapSetTstampType(t TimestampSource) error {
- if status := C.pcap_set_tstamp_type(p.cptr, C.int(t)); status < 0 {
- return statusError(status)
- }
- return nil
-}
-
-func (p *InactiveHandle) pcapSetRfmon(monitor bool) error {
- var mon C.int
- if monitor {
- mon = 1
- }
- switch canset := C.pcap_can_set_rfmon(p.cptr); canset {
- case 0:
- return CannotSetRFMon
- case 1:
- // success
- default:
- return statusError(canset)
- }
- if status := C.pcap_set_rfmon(p.cptr, mon); status != 0 {
- return statusError(status)
- }
- return nil
-}
-
-func (p *InactiveHandle) pcapSetBufferSize(bufferSize int) error {
- if status := C.pcap_set_buffer_size(p.cptr, C.int(bufferSize)); status < 0 {
- return statusError(status)
- }
- return nil
-}
-
-func (p *InactiveHandle) pcapSetImmediateMode(mode bool) error {
- var md C.int
- if mode {
- md = 1
- }
- if status := C.pcap_set_immediate_mode(p.cptr, md); status < 0 {
- return statusError(status)
- }
- return nil
-}
-
-func (p *Handle) setNonBlocking() error {
- buf := (*C.char)(C.calloc(errorBufferSize, 1))
- defer C.free(unsafe.Pointer(buf))
-
- // Change the device to non-blocking, we'll use pcap_wait to wait until the
- // handle is ready to read.
- if v := C.pcap_setnonblock(p.cptr, 1, buf); v < -1 {
- return errors.New(C.GoString(buf))
- }
-
- return nil
-}
-
-// waitForPacket waits for a packet or for the timeout to expire.
-func (p *Handle) waitForPacket() {
- // need to wait less than the read timeout according to pcap documentation.
- // timeoutMillis rounds up to at least one millisecond so we can safely
- // subtract up to a millisecond.
- usec := timeoutMillis(p.timeout) * 1000
- usec -= 100
-
- C.pcap_wait(p.cptr, C.int(usec))
-}
-
-// openOfflineFile returns contents of input file as a *Handle.
-func openOfflineFile(file *os.File) (handle *Handle, err error) {
- buf := (*C.char)(C.calloc(errorBufferSize, 1))
- defer C.free(unsafe.Pointer(buf))
- cmode := C.CString("rb")
- defer C.free(unsafe.Pointer(cmode))
- cf := C.fdopen(C.int(file.Fd()), cmode)
-
- cptr := C.pcap_fopen_offline_with_tstamp_precision(cf, C.PCAP_TSTAMP_PRECISION_NANO, buf)
- if cptr == nil {
- return nil, errors.New(C.GoString(buf))
- }
- return &Handle{cptr: cptr}, nil
-}
diff --git a/vendor/github.com/google/gopacket/pcap/pcap_windows.go b/vendor/github.com/google/gopacket/pcap/pcap_windows.go
deleted file mode 100644
index 0a53338..0000000
--- a/vendor/github.com/google/gopacket/pcap/pcap_windows.go
+++ /dev/null
@@ -1,885 +0,0 @@
-// Copyright 2012 Google, Inc. All rights reserved.
-// Copyright 2009-2011 Andreas Krennmair. 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 pcap
-
-import (
- "errors"
- "fmt"
- "os"
- "runtime"
- "sync"
- "syscall"
- "time"
- "unsafe"
-
- "github.com/google/gopacket"
- "github.com/google/gopacket/layers"
-)
-
-var pcapLoaded = false
-
-const npcapPath = "\\Npcap"
-
-func initDllPath(kernel32 syscall.Handle) {
- setDllDirectory, err := syscall.GetProcAddress(kernel32, "SetDllDirectoryA")
- if err != nil {
- // we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
- return
- }
- getSystemDirectory, err := syscall.GetProcAddress(kernel32, "GetSystemDirectoryA")
- if err != nil {
- // we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
- return
- }
- buf := make([]byte, 4096)
- r, _, _ := syscall.Syscall(getSystemDirectory, 2, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
- if r == 0 || r > 4096-uintptr(len(npcapPath))-1 {
- // we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
- return
- }
- copy(buf[r:], npcapPath)
- _, _, _ = syscall.Syscall(setDllDirectory, 1, uintptr(unsafe.Pointer(&buf[0])), 0, 0)
- // ignore errors here - we just fallback to load wpcap.dll from default locations
-}
-
-// loadedDllPath will hold the full pathname of the loaded wpcap.dll after init if possible
-var loadedDllPath = "wpcap.dll"
-
-func initLoadedDllPath(kernel32 syscall.Handle) {
- getModuleFileName, err := syscall.GetProcAddress(kernel32, "GetModuleFileNameA")
- if err != nil {
- // we can't get the filename of the loaded module in this case - just leave default of wpcap.dll
- return
- }
- buf := make([]byte, 4096)
- r, _, _ := syscall.Syscall(getModuleFileName, 3, uintptr(wpcapHandle), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
- if r == 0 {
- // we can't get the filename of the loaded module in this case - just leave default of wpcap.dll
- return
- }
- loadedDllPath = string(buf[:int(r)])
-}
-
-func mustLoad(fun string) uintptr {
- addr, err := syscall.GetProcAddress(wpcapHandle, fun)
- if err != nil {
- panic(fmt.Sprintf("Couldn't load function %s from %s", fun, loadedDllPath))
- }
- return addr
-}
-
-func mightLoad(fun string) uintptr {
- addr, err := syscall.GetProcAddress(wpcapHandle, fun)
- if err != nil {
- return 0
- }
- return addr
-}
-
-func byteSliceToString(bval []byte) string {
- for i := range bval {
- if bval[i] == 0 {
- return string(bval[:i])
- }
- }
- return string(bval[:])
-}
-
-// bytePtrToString returns a string copied from pointer to a null terminated byte array
-// WARNING: ONLY SAFE WITH IF r POINTS TO C MEMORY!
-// govet will complain about this function for the reason stated above
-func bytePtrToString(r uintptr) string {
- if r == 0 {
- return ""
- }
- bval := (*[1 << 30]byte)(unsafe.Pointer(r))
- return byteSliceToString(bval[:])
-}
-
-var wpcapHandle syscall.Handle
-var msvcrtHandle syscall.Handle
-var (
- callocPtr,
- pcapStrerrorPtr,
- pcapStatustostrPtr,
- pcapOpenLivePtr,
- pcapOpenOfflinePtr,
- pcapClosePtr,
- pcapGeterrPtr,
- pcapStatsPtr,
- pcapCompilePtr,
- pcapFreecodePtr,
- pcapLookupnetPtr,
- pcapOfflineFilterPtr,
- pcapSetfilterPtr,
- pcapListDatalinksPtr,
- pcapFreeDatalinksPtr,
- pcapDatalinkValToNamePtr,
- pcapDatalinkValToDescriptionPtr,
- pcapOpenDeadPtr,
- pcapNextExPtr,
- pcapDatalinkPtr,
- pcapSetDatalinkPtr,
- pcapDatalinkNameToValPtr,
- pcapLibVersionPtr,
- pcapFreealldevsPtr,
- pcapFindalldevsPtr,
- pcapSendpacketPtr,
- pcapSetdirectionPtr,
- pcapSnapshotPtr,
- pcapTstampTypeValToNamePtr,
- pcapTstampTypeNameToValPtr,
- pcapListTstampTypesPtr,
- pcapFreeTstampTypesPtr,
- pcapSetTstampTypePtr,
- pcapGetTstampPrecisionPtr,
- pcapSetTstampPrecisionPtr,
- pcapOpenOfflineWithTstampPrecisionPtr,
- pcapHOpenOfflineWithTstampPrecisionPtr,
- pcapActivatePtr,
- pcapCreatePtr,
- pcapSetSnaplenPtr,
- pcapSetPromiscPtr,
- pcapSetTimeoutPtr,
- pcapCanSetRfmonPtr,
- pcapSetRfmonPtr,
- pcapSetBufferSizePtr,
- pcapSetImmediateModePtr,
- pcapHopenOfflinePtr uintptr
-)
-
-func init() {
- LoadWinPCAP()
-}
-
-// LoadWinPCAP attempts to dynamically load the wpcap DLL and resolve necessary functions
-func LoadWinPCAP() error {
- if pcapLoaded {
- return nil
- }
-
- kernel32, err := syscall.LoadLibrary("kernel32.dll")
- if err != nil {
- return fmt.Errorf("couldn't load kernel32.dll")
- }
- defer syscall.FreeLibrary(kernel32)
-
- initDllPath(kernel32)
-
- wpcapHandle, err = syscall.LoadLibrary("wpcap.dll")
- if err != nil {
- return fmt.Errorf("couldn't load wpcap.dll")
- }
- initLoadedDllPath(kernel32)
- msvcrtHandle, err = syscall.LoadLibrary("msvcrt.dll")
- if err != nil {
- return fmt.Errorf("couldn't load msvcrt.dll")
- }
- callocPtr, err = syscall.GetProcAddress(msvcrtHandle, "calloc")
- if err != nil {
- return fmt.Errorf("couldn't get calloc function")
- }
-
- pcapStrerrorPtr = mustLoad("pcap_strerror")
- pcapStatustostrPtr = mightLoad("pcap_statustostr") // not available on winpcap
- pcapOpenLivePtr = mustLoad("pcap_open_live")
- pcapOpenOfflinePtr = mustLoad("pcap_open_offline")
- pcapClosePtr = mustLoad("pcap_close")
- pcapGeterrPtr = mustLoad("pcap_geterr")
- pcapStatsPtr = mustLoad("pcap_stats")
- pcapCompilePtr = mustLoad("pcap_compile")
- pcapFreecodePtr = mustLoad("pcap_freecode")
- pcapLookupnetPtr = mustLoad("pcap_lookupnet")
- pcapOfflineFilterPtr = mustLoad("pcap_offline_filter")
- pcapSetfilterPtr = mustLoad("pcap_setfilter")
- pcapListDatalinksPtr = mustLoad("pcap_list_datalinks")
- pcapFreeDatalinksPtr = mustLoad("pcap_free_datalinks")
- pcapDatalinkValToNamePtr = mustLoad("pcap_datalink_val_to_name")
- pcapDatalinkValToDescriptionPtr = mustLoad("pcap_datalink_val_to_description")
- pcapOpenDeadPtr = mustLoad("pcap_open_dead")
- pcapNextExPtr = mustLoad("pcap_next_ex")
- pcapDatalinkPtr = mustLoad("pcap_datalink")
- pcapSetDatalinkPtr = mustLoad("pcap_set_datalink")
- pcapDatalinkNameToValPtr = mustLoad("pcap_datalink_name_to_val")
- pcapLibVersionPtr = mustLoad("pcap_lib_version")
- pcapFreealldevsPtr = mustLoad("pcap_freealldevs")
- pcapFindalldevsPtr = mustLoad("pcap_findalldevs")
- pcapSendpacketPtr = mustLoad("pcap_sendpacket")
- pcapSetdirectionPtr = mustLoad("pcap_setdirection")
- pcapSnapshotPtr = mustLoad("pcap_snapshot")
- //libpcap <1.2 doesn't have pcap_*_tstamp_* functions
- pcapTstampTypeValToNamePtr = mightLoad("pcap_tstamp_type_val_to_name")
- pcapTstampTypeNameToValPtr = mightLoad("pcap_tstamp_type_name_to_val")
- pcapListTstampTypesPtr = mightLoad("pcap_list_tstamp_types")
- pcapFreeTstampTypesPtr = mightLoad("pcap_free_tstamp_types")
- pcapSetTstampTypePtr = mightLoad("pcap_set_tstamp_type")
- pcapGetTstampPrecisionPtr = mightLoad("pcap_get_tstamp_precision")
- pcapSetTstampPrecisionPtr = mightLoad("pcap_set_tstamp_precision")
- pcapOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_open_offline_with_tstamp_precision")
- pcapHOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_hopen_offline_with_tstamp_precision")
- pcapActivatePtr = mustLoad("pcap_activate")
- pcapCreatePtr = mustLoad("pcap_create")
- pcapSetSnaplenPtr = mustLoad("pcap_set_snaplen")
- pcapSetPromiscPtr = mustLoad("pcap_set_promisc")
- pcapSetTimeoutPtr = mustLoad("pcap_set_timeout")
- //winpcap does not support rfmon
- pcapCanSetRfmonPtr = mightLoad("pcap_can_set_rfmon")
- pcapSetRfmonPtr = mightLoad("pcap_set_rfmon")
- pcapSetBufferSizePtr = mustLoad("pcap_set_buffer_size")
- //libpcap <1.5 does not have pcap_set_immediate_mode
- pcapSetImmediateModePtr = mightLoad("pcap_set_immediate_mode")
- pcapHopenOfflinePtr = mustLoad("pcap_hopen_offline")
-
- pcapLoaded = true
- return nil
-}
-
-func (h *pcapPkthdr) getSec() int64 {
- return int64(h.Ts.Sec)
-}
-
-func (h *pcapPkthdr) getUsec() int64 {
- return int64(h.Ts.Usec)
-}
-
-func (h *pcapPkthdr) getLen() int {
- return int(h.Len)
-}
-
-func (h *pcapPkthdr) getCaplen() int {
- return int(h.Caplen)
-}
-
-func statusError(status pcapCint) error {
- var ret uintptr
- if pcapStatustostrPtr == 0 {
- ret, _, _ = syscall.Syscall(pcapStrerrorPtr, 1, uintptr(status), 0, 0)
- } else {
- ret, _, _ = syscall.Syscall(pcapStatustostrPtr, 1, uintptr(status), 0, 0)
- }
- return errors.New(bytePtrToString(ret))
-}
-
-func pcapGetTstampPrecision(cptr pcapTPtr) int {
- if pcapGetTstampPrecisionPtr == 0 {
- return pcapTstampPrecisionMicro
- }
- ret, _, _ := syscall.Syscall(pcapGetTstampPrecisionPtr, 1, uintptr(cptr), 0, 0)
- return int(pcapCint(ret))
-}
-
-func pcapSetTstampPrecision(cptr pcapTPtr, precision int) error {
- if pcapSetTstampPrecisionPtr == 0 {
- return errors.New("Not supported")
- }
- ret, _, _ := syscall.Syscall(pcapSetTstampPrecisionPtr, 2, uintptr(cptr), uintptr(precision), 0)
- if pcapCint(ret) < 0 {
- return errors.New("Not supported")
- }
- return nil
-}
-
-func pcapOpenLive(device string, snaplen int, pro int, timeout int) (*Handle, error) {
- err := LoadWinPCAP()
- if err != nil {
- return nil, err
- }
-
- buf := make([]byte, errorBufferSize)
- dev, err := syscall.BytePtrFromString(device)
- if err != nil {
- return nil, err
- }
-
- cptr, _, _ := syscall.Syscall6(pcapOpenLivePtr, 5, uintptr(unsafe.Pointer(dev)), uintptr(snaplen), uintptr(pro), uintptr(timeout), uintptr(unsafe.Pointer(&buf[0])), 0)
-
- if cptr == 0 {
- return nil, errors.New(byteSliceToString(buf))
- }
- return &Handle{cptr: pcapTPtr(cptr)}, nil
-}
-
-func openOffline(file string) (handle *Handle, err error) {
- err = LoadWinPCAP()
- if err != nil {
- return nil, err
- }
-
- buf := make([]byte, errorBufferSize)
- f, err := syscall.BytePtrFromString(file)
- if err != nil {
- return nil, err
- }
-
- var cptr uintptr
- if pcapOpenOfflineWithTstampPrecisionPtr == 0 {
- cptr, _, _ = syscall.Syscall(pcapOpenOfflinePtr, 2, uintptr(unsafe.Pointer(f)), uintptr(unsafe.Pointer(&buf[0])), 0)
- } else {
- cptr, _, _ = syscall.Syscall(pcapOpenOfflineWithTstampPrecisionPtr, 3, uintptr(unsafe.Pointer(f)), uintptr(pcapTstampPrecisionNano), uintptr(unsafe.Pointer(&buf[0])))
- }
-
- if cptr == 0 {
- return nil, errors.New(byteSliceToString(buf))
- }
-
- h := &Handle{cptr: pcapTPtr(cptr)}
- return h, nil
-}
-
-func (p *Handle) pcapClose() {
- if p.cptr != 0 {
- _, _, _ = syscall.Syscall(pcapClosePtr, 1, uintptr(p.cptr), 0, 0)
- }
- p.cptr = 0
-}
-
-func (p *Handle) pcapGeterr() error {
- ret, _, _ := syscall.Syscall(pcapGeterrPtr, 1, uintptr(p.cptr), 0, 0)
- return errors.New(bytePtrToString(ret))
-}
-
-func (p *Handle) pcapStats() (*Stats, error) {
- var cstats pcapStats
- ret, _, _ := syscall.Syscall(pcapStatsPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&cstats)), 0)
- if pcapCint(ret) < 0 {
- return nil, p.pcapGeterr()
- }
- return &Stats{
- PacketsReceived: int(cstats.Recv),
- PacketsDropped: int(cstats.Drop),
- PacketsIfDropped: int(cstats.Ifdrop),
- }, nil
-}
-
-// for libpcap < 1.8 pcap_compile is NOT thread-safe, so protect it.
-var pcapCompileMu sync.Mutex
-
-func (p *Handle) pcapCompile(expr string, maskp uint32) (pcapBpfProgram, error) {
- var bpf pcapBpfProgram
- cexpr, err := syscall.BytePtrFromString(expr)
- if err != nil {
- return pcapBpfProgram{}, err
- }
- pcapCompileMu.Lock()
- defer pcapCompileMu.Unlock()
- res, _, _ := syscall.Syscall6(pcapCompilePtr, 5, uintptr(p.cptr), uintptr(unsafe.Pointer(&bpf)), uintptr(unsafe.Pointer(cexpr)), uintptr(1), uintptr(maskp), 0)
- if pcapCint(res) < 0 {
- return bpf, p.pcapGeterr()
- }
- return bpf, nil
-}
-
-func (p pcapBpfProgram) free() {
- _, _, _ = syscall.Syscall(pcapFreecodePtr, 1, uintptr(unsafe.Pointer(&p)), 0, 0)
-}
-
-func (p pcapBpfProgram) toBPFInstruction() []BPFInstruction {
- bpfInsn := (*[bpfInstructionBufferSize]pcapBpfInstruction)(unsafe.Pointer(p.Insns))[0:p.Len:p.Len]
- bpfInstruction := make([]BPFInstruction, len(bpfInsn), len(bpfInsn))
-
- for i, v := range bpfInsn {
- bpfInstruction[i].Code = v.Code
- bpfInstruction[i].Jt = v.Jt
- bpfInstruction[i].Jf = v.Jf
- bpfInstruction[i].K = v.K
- }
- return bpfInstruction
-}
-
-func pcapBpfProgramFromInstructions(bpfInstructions []BPFInstruction) pcapBpfProgram {
- var bpf pcapBpfProgram
- bpf.Len = uint32(len(bpfInstructions))
- cbpfInsns, _, _ := syscall.Syscall(callocPtr, 2, uintptr(len(bpfInstructions)), uintptr(unsafe.Sizeof(bpfInstructions[0])), 0)
- gbpfInsns := (*[bpfInstructionBufferSize]pcapBpfInstruction)(unsafe.Pointer(cbpfInsns))
-
- for i, v := range bpfInstructions {
- gbpfInsns[i].Code = v.Code
- gbpfInsns[i].Jt = v.Jt
- gbpfInsns[i].Jf = v.Jf
- gbpfInsns[i].K = v.K
- }
-
- bpf.Insns = (*pcapBpfInstruction)(unsafe.Pointer(cbpfInsns))
- return bpf
-}
-
-func pcapLookupnet(device string) (netp, maskp uint32, err error) {
- err = LoadWinPCAP()
- if err != nil {
- return 0, 0, err
- }
-
- buf := make([]byte, errorBufferSize)
- dev, err := syscall.BytePtrFromString(device)
- if err != nil {
- return 0, 0, err
- }
- e, _, _ := syscall.Syscall6(pcapLookupnetPtr, 4, uintptr(unsafe.Pointer(dev)), uintptr(unsafe.Pointer(&netp)), uintptr(unsafe.Pointer(&maskp)), uintptr(unsafe.Pointer(&buf[0])), 0, 0)
- if pcapCint(e) < 0 {
- return 0, 0, errors.New(byteSliceToString(buf))
- }
- return
-}
-
-func (b *BPF) pcapOfflineFilter(ci gopacket.CaptureInfo, data []byte) bool {
- var hdr pcapPkthdr
- hdr.Ts.Sec = int32(ci.Timestamp.Unix())
- hdr.Ts.Usec = int32(ci.Timestamp.Nanosecond() / 1000)
- hdr.Caplen = uint32(len(data)) // Trust actual length over ci.Length.
- hdr.Len = uint32(ci.Length)
- e, _, _ := syscall.Syscall(pcapOfflineFilterPtr, 3, uintptr(unsafe.Pointer(&b.bpf)), uintptr(unsafe.Pointer(&hdr)), uintptr(unsafe.Pointer(&data[0])))
- return e != 0
-}
-
-func (p *Handle) pcapSetfilter(bpf pcapBpfProgram) error {
- e, _, _ := syscall.Syscall(pcapSetfilterPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&bpf)), 0)
- if pcapCint(e) < 0 {
- return p.pcapGeterr()
- }
- return nil
-}
-
-func (p *Handle) pcapListDatalinks() (datalinks []Datalink, err error) {
- var dltbuf *pcapCint
- ret, _, _ := syscall.Syscall(pcapListDatalinksPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&dltbuf)), 0)
-
- n := int(pcapCint(ret))
-
- if n < 0 {
- return nil, p.pcapGeterr()
- }
- defer syscall.Syscall(pcapFreeDatalinksPtr, 1, uintptr(unsafe.Pointer(dltbuf)), 0, 0)
-
- datalinks = make([]Datalink, n)
-
- dltArray := (*[1 << 28]pcapCint)(unsafe.Pointer(dltbuf))
-
- for i := 0; i < n; i++ {
- datalinks[i].Name = pcapDatalinkValToName(int((*dltArray)[i]))
- datalinks[i].Description = pcapDatalinkValToDescription(int((*dltArray)[i]))
- }
-
- return datalinks, nil
-}
-
-func pcapOpenDead(linkType layers.LinkType, captureLength int) (*Handle, error) {
- err := LoadWinPCAP()
- if err != nil {
- return nil, err
- }
-
- cptr, _, _ := syscall.Syscall(pcapOpenDeadPtr, 2, uintptr(linkType), uintptr(captureLength), 0)
- if cptr == 0 {
- return nil, errors.New("error opening dead capture")
- }
-
- return &Handle{cptr: pcapTPtr(cptr)}, nil
-}
-
-func (p *Handle) pcapNextPacketEx() NextError {
- r, _, _ := syscall.Syscall(pcapNextExPtr, 3, uintptr(p.cptr), uintptr(unsafe.Pointer(&p.pkthdr)), uintptr(unsafe.Pointer(&p.bufptr)))
- ret := pcapCint(r)
- // According to https://github.com/the-tcpdump-group/libpcap/blob/1131a7c26c6f4d4772e4a2beeaf7212f4dea74ac/pcap.c#L398-L406 ,
- // the return value of pcap_next_ex could be greater than 1 for success.
- // Let's just make it 1 if it comes bigger than 1.
- if ret > 1 {
- ret = 1
- }
- return NextError(ret)
-}
-
-func (p *Handle) pcapDatalink() layers.LinkType {
- ret, _, _ := syscall.Syscall(pcapDatalinkPtr, 1, uintptr(p.cptr), 0, 0)
- return layers.LinkType(ret)
-}
-
-func (p *Handle) pcapSetDatalink(dlt layers.LinkType) error {
- ret, _, _ := syscall.Syscall(pcapSetDatalinkPtr, 2, uintptr(p.cptr), uintptr(dlt), 0)
- if pcapCint(ret) < 0 {
- return p.pcapGeterr()
- }
- return nil
-}
-
-func pcapDatalinkValToName(dlt int) string {
- err := LoadWinPCAP()
- if err != nil {
- panic(err)
- }
- ret, _, _ := syscall.Syscall(pcapDatalinkValToNamePtr, 1, uintptr(dlt), 0, 0)
- return bytePtrToString(ret)
-}
-
-func pcapDatalinkValToDescription(dlt int) string {
- err := LoadWinPCAP()
- if err != nil {
- panic(err)
- }
- ret, _, _ := syscall.Syscall(pcapDatalinkValToDescriptionPtr, 1, uintptr(dlt), 0, 0)
- return bytePtrToString(ret)
-}
-
-func pcapDatalinkNameToVal(name string) int {
- err := LoadWinPCAP()
- if err != nil {
- panic(err)
- }
- cptr, err := syscall.BytePtrFromString(name)
- if err != nil {
- return 0
- }
- ret, _, _ := syscall.Syscall(pcapDatalinkNameToValPtr, 1, uintptr(unsafe.Pointer(cptr)), 0, 0)
- return int(pcapCint(ret))
-}
-
-func pcapLibVersion() string {
- err := LoadWinPCAP()
- if err != nil {
- panic(err)
- }
- ret, _, _ := syscall.Syscall(pcapLibVersionPtr, 0, 0, 0, 0)
- return bytePtrToString(ret)
-}
-
-func (p *Handle) isOpen() bool {
- return p.cptr != 0
-}
-
-type pcapDevices struct {
- all, cur *pcapIf
-}
-
-func (p pcapDevices) free() {
- syscall.Syscall(pcapFreealldevsPtr, 1, uintptr(unsafe.Pointer(p.all)), 0, 0)
-}
-
-func (p *pcapDevices) next() bool {
- if p.cur == nil {
- p.cur = p.all
- if p.cur == nil {
- return false
- }
- return true
- }
- if p.cur.Next == nil {
- return false
- }
- p.cur = p.cur.Next
- return true
-}
-
-func (p pcapDevices) name() string {
- return bytePtrToString(uintptr(unsafe.Pointer(p.cur.Name)))
-}
-
-func (p pcapDevices) description() string {
- return bytePtrToString(uintptr(unsafe.Pointer(p.cur.Description)))
-}
-
-func (p pcapDevices) flags() uint32 {
- return p.cur.Flags
-}
-
-type pcapAddresses struct {
- all, cur *pcapAddr
-}
-
-func (p *pcapAddresses) next() bool {
- if p.cur == nil {
- p.cur = p.all
- if p.cur == nil {
- return false
- }
- return true
- }
- if p.cur.Next == nil {
- return false
- }
- p.cur = p.cur.Next
- return true
-}
-
-func (p pcapAddresses) addr() *syscall.RawSockaddr {
- return p.cur.Addr
-}
-
-func (p pcapAddresses) netmask() *syscall.RawSockaddr {
- return p.cur.Netmask
-}
-
-func (p pcapAddresses) broadaddr() *syscall.RawSockaddr {
- return p.cur.Broadaddr
-}
-
-func (p pcapAddresses) dstaddr() *syscall.RawSockaddr {
- return p.cur.Dstaddr
-}
-
-func (p pcapDevices) addresses() pcapAddresses {
- return pcapAddresses{all: p.cur.Addresses}
-}
-
-func pcapFindAllDevs() (pcapDevices, error) {
- var alldevsp pcapDevices
- err := LoadWinPCAP()
- if err != nil {
- return alldevsp, err
- }
-
- buf := make([]byte, errorBufferSize)
-
- ret, _, _ := syscall.Syscall(pcapFindalldevsPtr, 2, uintptr(unsafe.Pointer(&alldevsp.all)), uintptr(unsafe.Pointer(&buf[0])), 0)
-
- if pcapCint(ret) < 0 {
- return pcapDevices{}, errors.New(byteSliceToString(buf))
- }
- return alldevsp, nil
-}
-
-func (p *Handle) pcapSendpacket(data []byte) error {
- ret, _, _ := syscall.Syscall(pcapSendpacketPtr, 3, uintptr(p.cptr), uintptr(unsafe.Pointer(&data[0])), uintptr(len(data)))
- if pcapCint(ret) < 0 {
- return p.pcapGeterr()
- }
- return nil
-}
-
-func (p *Handle) pcapSetdirection(direction Direction) error {
- status, _, _ := syscall.Syscall(pcapSetdirectionPtr, 2, uintptr(p.cptr), uintptr(direction), 0)
- if pcapCint(status) < 0 {
- return statusError(pcapCint(status))
- }
- return nil
-}
-
-func (p *Handle) pcapSnapshot() int {
- ret, _, _ := syscall.Syscall(pcapSnapshotPtr, 1, uintptr(p.cptr), 0, 0)
- return int(pcapCint(ret))
-}
-
-func (t TimestampSource) pcapTstampTypeValToName() string {
- err := LoadWinPCAP()
- if err != nil {
- return err.Error()
- }
-
- //libpcap <1.2 doesn't have pcap_*_tstamp_* functions
- if pcapTstampTypeValToNamePtr == 0 {
- return "pcap timestamp types not supported"
- }
- ret, _, _ := syscall.Syscall(pcapTstampTypeValToNamePtr, 1, uintptr(t), 0, 0)
- return bytePtrToString(ret)
-}
-
-func pcapTstampTypeNameToVal(s string) (TimestampSource, error) {
- err := LoadWinPCAP()
- if err != nil {
- return 0, err
- }
-
- //libpcap <1.2 doesn't have pcap_*_tstamp_* functions
- if pcapTstampTypeNameToValPtr == 0 {
- return 0, statusError(pcapCint(pcapError))
- }
- cs, err := syscall.BytePtrFromString(s)
- if err != nil {
- return 0, err
- }
- ret, _, _ := syscall.Syscall(pcapTstampTypeNameToValPtr, 1, uintptr(unsafe.Pointer(cs)), 0, 0)
- t := pcapCint(ret)
- if t < 0 {
- return 0, statusError(pcapCint(t))
- }
- return TimestampSource(t), nil
-}
-
-func (p *InactiveHandle) pcapGeterr() error {
- ret, _, _ := syscall.Syscall(pcapGeterrPtr, 1, uintptr(p.cptr), 0, 0)
- return errors.New(bytePtrToString(ret))
-}
-
-func (p *InactiveHandle) pcapActivate() (*Handle, activateError) {
- r, _, _ := syscall.Syscall(pcapActivatePtr, 1, uintptr(p.cptr), 0, 0)
- ret := activateError(pcapCint(r))
- if ret != aeNoError {
- return nil, ret
- }
- h := &Handle{
- cptr: p.cptr,
- }
- p.cptr = 0
- return h, ret
-}
-
-func (p *InactiveHandle) pcapClose() {
- if p.cptr != 0 {
- _, _, _ = syscall.Syscall(pcapClosePtr, 1, uintptr(p.cptr), 0, 0)
- }
- p.cptr = 0
-}
-
-func pcapCreate(device string) (*InactiveHandle, error) {
- err := LoadWinPCAP()
- if err != nil {
- return nil, err
- }
-
- buf := make([]byte, errorBufferSize)
- dev, err := syscall.BytePtrFromString(device)
- if err != nil {
- return nil, err
- }
- cptr, _, _ := syscall.Syscall(pcapCreatePtr, 2, uintptr(unsafe.Pointer(dev)), uintptr(unsafe.Pointer(&buf[0])), 0)
- if cptr == 0 {
- return nil, errors.New(byteSliceToString(buf))
- }
- return &InactiveHandle{cptr: pcapTPtr(cptr)}, nil
-}
-
-func (p *InactiveHandle) pcapSetSnaplen(snaplen int) error {
- status, _, _ := syscall.Syscall(pcapSetSnaplenPtr, 2, uintptr(p.cptr), uintptr(snaplen), 0)
- if pcapCint(status) < 0 {
- return statusError(pcapCint(status))
- }
- return nil
-}
-
-func (p *InactiveHandle) pcapSetPromisc(promisc bool) error {
- var pro uintptr
- if promisc {
- pro = 1
- }
- status, _, _ := syscall.Syscall(pcapSetPromiscPtr, 2, uintptr(p.cptr), pro, 0)
- if pcapCint(status) < 0 {
- return statusError(pcapCint(status))
- }
- return nil
-}
-
-func (p *InactiveHandle) pcapSetTimeout(timeout time.Duration) error {
- status, _, _ := syscall.Syscall(pcapSetTimeoutPtr, 2, uintptr(p.cptr), uintptr(timeoutMillis(timeout)), 0)
-
- if pcapCint(status) < 0 {
- return statusError(pcapCint(status))
- }
- return nil
-}
-
-func (p *InactiveHandle) pcapListTstampTypes() (out []TimestampSource) {
- //libpcap <1.2 doesn't have pcap_*_tstamp_* functions
- if pcapListTstampTypesPtr == 0 {
- return
- }
- var types *pcapCint
- ret, _, _ := syscall.Syscall(pcapListTstampTypesPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&types)), 0)
- n := int(pcapCint(ret))
- if n < 0 {
- return // public interface doesn't have error :(
- }
- defer syscall.Syscall(pcapFreeTstampTypesPtr, 1, uintptr(unsafe.Pointer(types)), 0, 0)
- typesArray := (*[1 << 28]pcapCint)(unsafe.Pointer(types))
- for i := 0; i < n; i++ {
- out = append(out, TimestampSource((*typesArray)[i]))
- }
- return
-}
-
-func (p *InactiveHandle) pcapSetTstampType(t TimestampSource) error {
- //libpcap <1.2 doesn't have pcap_*_tstamp_* functions
- if pcapSetTstampTypePtr == 0 {
- return statusError(pcapError)
- }
- status, _, _ := syscall.Syscall(pcapSetTstampTypePtr, 2, uintptr(p.cptr), uintptr(t), 0)
- if pcapCint(status) < 0 {
- return statusError(pcapCint(status))
- }
- return nil
-}
-
-func (p *InactiveHandle) pcapSetRfmon(monitor bool) error {
- //winpcap does not support rfmon
- if pcapCanSetRfmonPtr == 0 {
- return CannotSetRFMon
- }
- var mon uintptr
- if monitor {
- mon = 1
- }
- canset, _, _ := syscall.Syscall(pcapCanSetRfmonPtr, 1, uintptr(p.cptr), 0, 0)
- switch canset {
- case 0:
- return CannotSetRFMon
- case 1:
- // success
- default:
- return statusError(pcapCint(canset))
- }
- status, _, _ := syscall.Syscall(pcapSetRfmonPtr, 2, uintptr(p.cptr), mon, 0)
- if status != 0 {
- return statusError(pcapCint(status))
- }
- return nil
-}
-
-func (p *InactiveHandle) pcapSetBufferSize(bufferSize int) error {
- status, _, _ := syscall.Syscall(pcapSetBufferSizePtr, 2, uintptr(p.cptr), uintptr(bufferSize), 0)
- if pcapCint(status) < 0 {
- return statusError(pcapCint(status))
- }
- return nil
-}
-
-func (p *InactiveHandle) pcapSetImmediateMode(mode bool) error {
- //libpcap <1.5 does not have pcap_set_immediate_mode
- if pcapSetImmediateModePtr == 0 {
- return statusError(pcapError)
- }
- var md uintptr
- if mode {
- md = 1
- }
- status, _, _ := syscall.Syscall(pcapSetImmediateModePtr, 2, uintptr(p.cptr), md, 0)
- if pcapCint(status) < 0 {
- return statusError(pcapCint(status))
- }
- return nil
-}
-
-func (p *Handle) setNonBlocking() error {
- // do nothing
- return nil
-}
-
-// waitForPacket waits for a packet or for the timeout to expire.
-func (p *Handle) waitForPacket() {
- // can't use select() so instead just switch goroutines
- runtime.Gosched()
-}
-
-// openOfflineFile returns contents of input file as a *Handle.
-func openOfflineFile(file *os.File) (handle *Handle, err error) {
- err = LoadWinPCAP()
- if err != nil {
- return nil, err
- }
-
- buf := make([]byte, errorBufferSize)
- cf := file.Fd()
-
- var cptr uintptr
- if pcapOpenOfflineWithTstampPrecisionPtr == 0 {
- cptr, _, _ = syscall.Syscall(pcapHopenOfflinePtr, 2, cf, uintptr(unsafe.Pointer(&buf[0])), 0)
- } else {
- cptr, _, _ = syscall.Syscall(pcapHOpenOfflineWithTstampPrecisionPtr, 3, cf, uintptr(pcapTstampPrecisionNano), uintptr(unsafe.Pointer(&buf[0])))
- }
-
- if cptr == 0 {
- return nil, errors.New(byteSliceToString(buf))
- }
- return &Handle{cptr: pcapTPtr(cptr)}, nil
-}
diff --git a/vendor/github.com/google/gopacket/pcap/test_dns.pcap b/vendor/github.com/google/gopacket/pcap/test_dns.pcap
deleted file mode 100644
index 3a79f92..0000000
--- a/vendor/github.com/google/gopacket/pcap/test_dns.pcap
+++ /dev/null
Binary files differ
diff --git a/vendor/github.com/google/gopacket/pcap/test_ethernet.pcap b/vendor/github.com/google/gopacket/pcap/test_ethernet.pcap
deleted file mode 100644
index 1d01bd9..0000000
--- a/vendor/github.com/google/gopacket/pcap/test_ethernet.pcap
+++ /dev/null
Binary files differ
diff --git a/vendor/github.com/google/gopacket/pcap/test_loopback.pcap b/vendor/github.com/google/gopacket/pcap/test_loopback.pcap
deleted file mode 100644
index ddeb82c..0000000
--- a/vendor/github.com/google/gopacket/pcap/test_loopback.pcap
+++ /dev/null
Binary files differ
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 5a84d73..545e32f 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -39,7 +39,6 @@
# github.com/google/gopacket v1.1.17
github.com/google/gopacket
github.com/google/gopacket/layers
-github.com/google/gopacket/pcap
# github.com/google/uuid v1.1.2
github.com/google/uuid
# github.com/gorilla/mux v1.7.3